Установка ProcessStartInfo.WorkingDirectory в UNC-путь - PullRequest
3 голосов
/ 06 апреля 2010

У меня есть утилита, написанная на VB.net, которая запускается как запланированные задачи. Он внутренне вызывает другой исполняемый файл и должен получить доступ к подключенному диску. Очевидно, у Windows есть проблемы с запланированными задачами, обращающимися к подключенным дискам, когда пользователь не вошел в систему, даже когда учетные данные аутентификации предоставлены самой задаче. Хорошо, хорошо.

Чтобы обойти это, я просто передал приложению путь UNC.

process.StartInfo.FileName = 'name of executable'
process.StartInfo.WorkingDirectory = '\\unc path\'
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
process.StartInfo.Arguments = 'arguments to executable'
process.Start()

Это та же реализация, которую я использовал с подключенным диском, однако при использовании пути UNC процесс не ведет себя так, как если бы путь UNC был рабочим каталогом.

Известны ли какие-либо проблемы с установкой ProcessStartInfo.WorkingDirectory в UNC-путь? Если нет, то что я делаю не так?

Ответы [ 2 ]

7 голосов
/ 06 апреля 2010

Ваша проблема с подключенными дисками, когда пользователи не вошли в систему, состоит в том, что они не существуют. Диски отображаются только и доступны для текущего пользователя. Если никто не вошел в систему, никакие диски не отображаются.

В качестве обходного пути вы можете запустить через CMD, вызвать PUSHD, который сопоставит ваш UNC с диском за кулисами, а затем выполнит ваш код. Я скопировал файл tree.com из моей system32 и поместил его на мой файловый сервер как «tree4.com», и этот код работает как положено (я также перенаправляю стандартный вывод, чтобы видеть результаты вызова, но это не обязательно)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Using P As New Process()
        'Launch a standard hidden command window
        P.StartInfo.FileName = "cmd.exe"
        P.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
        P.StartInfo.CreateNoWindow = True

        'Needed to redirect standard error/output/input
        P.StartInfo.UseShellExecute = False

        P.StartInfo.RedirectStandardInput = True
        P.StartInfo.RedirectStandardOutput = True

        'Add handler for when data is received
        AddHandler P.OutputDataReceived, AddressOf SDR

        'Start the process
        P.Start()

        'Begin async data reading
        P.BeginOutputReadLine()

        '"Map" our drive
        P.StandardInput.WriteLine("pushd \\file-server\File-Server")

        'Call our command, you could pass args here if you wanted
        P.StandardInput.WriteLine("tree2.com  c:\3ea7025b247d0dfb7731a50bf2632f")

        'Once our command is done CMD.EXE will still be sitting around so manually exit
        P.StandardInput.WriteLine("exit")
        P.WaitForExit()
    End Using

    Me.Close()
End Sub
Private Sub SDR(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
    Trace.WriteLine(e.Data)
End Sub
1 голос
/ 15 декабря 2015

Я столкнулся с этой проблемой, и принятое решение немного сложнее для меня. Я выбрал путь UNC и скопировал его содержимое в [Path.GetTempDir()]\[Guid.NewGuid().ToString()], а затем использовал его как мой рабочий каталог для process.StartInfo.WorkingDirectory. Оберните эту функциональность в класс «Environment», который будет реализовывать IDisposable, а в утилите очистить созданный вами временный каталог. Как то так (игнорируем ссылки на настройки):

 using (var env = new ProcessEnvironment(settings))
                {
                    filePath = Path.Combine(env.WorkingDirectory, settings.ApplicationEXE);
                    var psi = new ProcessStartInfo
                    {
                        UseShellExecute = false,
                        FileName = filePath,
                        WorkingDirectory = env.WorkingDirectory,
                        Arguments = (args != null && args.Length > 0 ? String.Join(" ", args) : null)
                    };

                    var proc = Process.Start(psi);

                    if (env.ExecutingFromTempDir || settings.WaitForExit)
                        proc.WaitForExit();
                }

И ProcessEnvironment выглядит так:

 class ProcessEnvironment : IDisposable
    {
        private Settings itsSettings;
        private string itsTempDestDirectory;
        public string WorkingDirectory { get; set; }
        public bool ExecutingFromTempDir { get { return !String.IsNullOrEmpty(itsTempDestDirectory); } }

        public ProcessEnvironment(Settings settings)
        {
            this.itsSettings = settings;

            WorkingDirectory = GetWorkingDirectory();
        }

        private string GetWorkingDirectory()
        {
            var dirInfo = new DirectoryInfo(itsSettings.StartupFolder);

            if (!IsUncDrive(dirInfo))
                return itsSettings.StartupFolder;

            return CreateWorkingDirectory(dirInfo);
        }

        private string CreateWorkingDirectory(DirectoryInfo dirInfo)
        {
            var srcPath = dirInfo.FullName;
            itsTempDestDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            Directory.CreateDirectory(itsTempDestDirectory);

            //Now Create all of the directories
            foreach (string dirPath in Directory.GetDirectories(srcPath, "*", SearchOption.AllDirectories))
                Directory.CreateDirectory(dirPath.Replace(srcPath, itsTempDestDirectory));

            //Copy all the files & Replaces any files with the same name
            foreach (string newPath in Directory.GetFiles(srcPath, "*.*", SearchOption.AllDirectories))
                File.Copy(newPath, newPath.Replace(srcPath, itsTempDestDirectory), true);

            return itsTempDestDirectory;
        }

        private bool IsUncDrive(DirectoryInfo dirInfo)
        {
            Uri uri = null;
            if (!Uri.TryCreate(dirInfo.FullName, UriKind.Absolute, out uri))
            {
                return false;
            }
            return uri.IsUnc;
        }



        public void Dispose()
        {
            try
            {
                if (ExecutingFromTempDir)
                    Directory.Delete(itsTempDestDirectory, true);

            }
            catch (Exception ex)
            {  //do nothing - if we can't delete then we can't do it
                Console.WriteLine("Failed in Dispose: " + ex);
            }
        }
    }
...