Установка начального каталога при вызове Powershell из .NET?

Я использую API System.Management.Automation для вызова сценариев PowerShell в С# WPF-приложении. В следующем примере, как бы вы изменили начальный каталог ($ PWD), чтобы он выполнял foo.ps1 из C:\scripts\вместо местоположения .exe, он был вызван из?

using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
    runspace.Open();
    using (Pipeline pipeline = runspace.CreatePipeline())
    {
        pipeline.Commands.Add(@"C:\scripts\foo.ps1");
        pipeline.Invoke();
    }
    runspace.Close();
}

Ответы

Ответ 1

Вам не нужно изменять System.Environment.CurrentDirectory, чтобы изменить рабочий путь для ваших сценариев PowerShell. Это может быть довольно опасно, потому что это может иметь непреднамеренные побочные эффекты, если вы используете другой код, чувствительный к вашему текущему каталогу.

Поскольку вы предоставляете Runspace, все, что вам нужно сделать, это установить свойства Path в SessionStateProxy:

using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
    runspace.Open();
    runspace.SessionStateProxy.Path.SetLocation(directory);
    using (Pipeline pipeline = runspace.CreatePipeline())
    {
        pipeline.Commands.Add(@"C:\scripts\foo.ps1");
        pipeline.Invoke();
    }
    runspace.Close();
}

Ответ 2

Настройка System.Environment.CurrentDirectory заблаговременно сделает то, что вы хотите.

Вместо добавления Set-Location к вашему скрипту вы должны установить System.Environment.CurrentDirectory в любое время перед, открывая Runspace. Он наследует все, что было в CurrentDirectory при его открытии:

using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
    System.Environment.CurrentDirectory = "C:\\scripts";
    runspace.Open();
    using (Pipeline pipeline = runspace.CreatePipeline())
    {
        pipeline.Commands.Add(@".\foo.ps1");
        pipeline.Invoke();
    }
    runspace.Close();
}

И помните, Set-Location не устанавливает .net framework CurrentDirectory, поэтому, если вы вызываете .Net-методы, которые работают с "текущим" местоположением, вам нужно установить его самостоятельно.

Ответ 3

Что-то не так:

pipeline.Commands.AddScript(@"set-location c:\scripts;.\foo.ps1")

?

-Oisin

Ответ 4

Вы можете установить рабочий каталог в powershell с помощью следующей команды

set-location c:\mydirectory

Вы также можете попробовать запустить PowerShell script ($ profile). C:....\MyDocs\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 Но только если этот каталог исправлен и не меняет

Ответ 5

Вместо того, чтобы позволить приложению обрабатывать его, вы можете включить это в начало вашего скрипта,

Set-Location $PSScriptRoot

Он выполнит оставшуюся часть сценария в своем каталоге установки.

Но будьте осторожны, "текущее местоположение" PowerShell НЕ совпадает с рабочим каталогом вашего приложения, оно просто инициализируется при запуске powershell.

Set-Location может подшутить над вами, если вы запустите исполняемые файлы, которые зависят от текущего каталога, или если ваш скрипт содержит вызовы API-интерфейсов, как в этом примере:

PS C:\Users\luc> Set-Location C:\
PS C:\> [System.IO.Directory]::GetCurrentDirectory()
C:\Users\luc

При этом я бы предпочел ответ майка Бэйли. Я просто хотел дать решение, которое имеет свои достоинства, если сценарий не всегда установлен в одном и том же каталоге (как обычно, на компьютере разработчика отличается от пути к продукту).