'Program triggered by msi can not create xml files on network volume

I have a HMI program that uses xml files for some machine specific settings. Theese xml files are stored on the machine itself while the HMI is running on a computer in the machine network. A folder on the machines hdd is mapped as a network volume in the HMI computer, this is where the xml files are located. During installation of the HMI a small program runs to verify if the xml files are present, if they are not defualt files are created.

The issue I have is that when this small program is ran by the installer package the volume does not seem to be present but if i run the program manually from visual studio or just execute the compiled exe file seperately the volume is recognised.

Could this be some issue with how the msi package triggers execution of the program?

using System;
using System.IO;
using System.Xml;

/// <summary>
/// This is executed during installation of the hmi to verify the presence of plcsettings.xml on the machine.
/// If a file is missing a default file is added which must be edited manually after intallation is complete.
/// </summary>
namespace Install.Xml
{
    class Program
    {
        #region fields
        private const string plcSettingsPath = @"Settings\HMI Settings\PlcSettings.xml";
        private const string heatExPlcSettingsPath = @"Settings\HMI Settings\HeatExPlcSettings.xml";
        private const string xmlDirectoryPath = @"Settings\HMI Settings\";
        private const string volume = @"Y:\";
        #endregion

        /// <summary>
        /// Entrypoint for the installer.
        /// </summary>
        /// <param name="args">Not used.</param>
        static void Main(string[] args)
        {
            Console.WriteLine("Starting installation checks..");
            Console.WriteLine();

            InstallXmlFiles();

            Console.WriteLine();
            Console.WriteLine("Done!");
        }
        /// <summary>
        /// Main logic.
        /// </summary>
        private static void InstallXmlFiles()
        {
            if (CheckIfXmlDirectoryExists())
            {
                Console.WriteLine("Installing xml settings file(s)..");

                if (!File.Exists(volume + plcSettingsPath))
                    CreatePlcSettingsXml();
                else
                    Console.WriteLine("PLC Settings already present, skipping..");

                if (!File.Exists(volume + heatExPlcSettingsPath))
                    CreateHeatExPlcSettingsXml();
                else
                    Console.WriteLine("HeatEx PLC Settings already present, skipping..");
            }
            else
            {
                Console.WriteLine(volume + xmlDirectoryPath);
                Console.WriteLine("The directory for xml settings does not exist or is un-available.");
                Console.WriteLine("The installation will continue but the files must be added manually.");
                Console.WriteLine();
                Console.Write("Press any key to continue..");
                Console.ReadKey();
            }
        }
        /// <summary>
        /// Checks xml path and creates directory if missing.
        /// </summary>
        /// <returns></returns>
        private static bool CheckIfXmlDirectoryExists()
        {
            if (!Directory.Exists(volume))
                return false;
            Directory.CreateDirectory(volume + xmlDirectoryPath);
            return true;

        }
        /// <summary>
        /// Checks path and creates file if missing.
        /// </summary>
        private static void CreateHeatExPlcSettingsXml()
        {
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><root><field plcnetid=\"000.000.000.000.0.0\" plcport=\"801\" TcVersion=\"V2\"/></root >");
            xDoc.Save(volume + heatExPlcSettingsPath);
            Console.WriteLine("Default HeatEx PLC settings installed!");
        }
        /// <summary>
        /// Checks path and creates file if missing.
        /// </summary>
        private static void CreatePlcSettingsXml()
        {
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><root><field plcnetid=\"000.000.000.000.0.0\" machineId=\"DuoSystem #000\" databaseIp=\"192.168.100.0\" duomode=\"Standard\" NewMfcSetting=\"false\" useopcua=\"false\" plcport=\"801\" TcVersion=\"V2\"/></root>");
            xDoc.Save(volume + plcSettingsPath);
            Console.WriteLine("Default PLC settings installed!");
        }
    }
}

EDIT::

I have modified the intstaller to use the above logic using class override in the installer itself. This is the new implementation.

using System;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Xml;

namespace DuoSystem.Installer
{
    [RunInstaller(true)]
    public partial class CustomActions : System.Configuration.Install.Installer
    {
        #region On After Install
        protected override void OnAfterInstall(IDictionary savedState)
        {
            base.OnAfterInstall(savedState);
            XmlInstall xmlInstall = new XmlInstall();
            xmlInstall.Start();
        }
        #endregion

        #region On After Uninstall
        protected override void OnAfterUninstall(IDictionary savedState)
        {       
            base.OnAfterUninstall(savedState);
        }
        #endregion
    }

    #region Supporting Classes
    class XmlInstall
    {
        #region fields
        private const string plcSettingsPath = @"Settings\HMI Settings\PlcSettings.xml";
        private const string heatExPlcSettingsPath = @"Settings\HMI Settings\HeatExPlcSettings.xml";
        private const string xmlDirectoryPath = @"Settings\HMI Settings\";
        private const string volume = @"Y:\";
        #endregion

        /// <summary>
        /// Entrypoint for the installer.
        /// </summary>
        /// <param name="args">Not used.</param>
        public void Start()
        {
            InstallPlcSettingsXml();
        }
        /// <summary>
        /// Main logic.
        /// </summary>
        private void InstallPlcSettingsXml()
        {
            if (CheckIfXmlDirectoryExists())
            {   
                if (!File.Exists(volume + plcSettingsPath))
                    CreatePlcSettingsXml();

                if (!File.Exists(volume + heatExPlcSettingsPath))
                    CreateHeatExPlcSettingsXml();
            }
            else
            {
                
                MessageBox.Show( volume + xmlDirectoryPath 
                    + Environment.NewLine
                    + "The directory for xml settings does not exist or is un-available."
                    + Environment.NewLine
                    + "The installation will continue but the files must be added manually."
                    +Environment.NewLine); 
            }
        }
        /// <summary>
        /// Checks xml path and creates directory if missing.
        /// </summary>
        /// <returns></returns>
        private bool CheckIfXmlDirectoryExists()
        {
            if (!Directory.Exists(volume))
                return false;
            Directory.CreateDirectory(volume + xmlDirectoryPath);
            return true;
        }
        /// <summary>
        /// Checks path and creates file if missing.
        /// </summary>
        private void CreateHeatExPlcSettingsXml()
        {
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><root><field plcnetid=\"000.000.000.000.0.0\" plcport=\"801\" TcVersion=\"V2\"/></root >");
            xDoc.Save(volume + heatExPlcSettingsPath);
            Console.WriteLine("Default HeatEx PLC settings installed!");
        }
        /// <summary>
        /// Checks path and creates file if missing.
        /// </summary>
        private void CreatePlcSettingsXml()
        {
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><root><field plcnetid=\"000.000.000.000.0.0\" machineId=\"DuoSystem #000\" databaseIp=\"192.168.100.0\" duomode=\"Standard\" NewMfcSetting=\"false\" useopcua=\"false\" plcport=\"801\" TcVersion=\"V2\"/></root>");
            xDoc.Save(volume + plcSettingsPath);
            Console.WriteLine("Default PLC settings installed!");
        }
    }
    #endregion
}

This is a prettier implementation and I hoped it simultaneously would solve the possible impersonation issue mentioned below, however it did not. The behaviour is still the same.



Solution 1:[1]

You don't share how the program is being called by the installer but my guess is your calling it without impersonation so that it's running in the system context. In this scenario it's not running as (impersonating) the logged in user and doesn't have permissions to the network resoruce.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Christopher Painter