Как предотвратить PowerShell от изменения переменных среды? - PullRequest
0 голосов
/ 14 января 2019

Следующий тест не пройден, поскольку объект PowerShell меняет путь процесса вызывающего:

using System;
using System.IO;
using System.Linq;
using System.Management.Automation;
using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace Helpers.Tests.ShellHelper {
    [TestClass]
    public class PowerShellEnvAlteration_Tests {
        [TestMethod]
        public void TestPath() {
            var searchTarget = @"C:\LandingZone";

            using (PowerShell powerShell = PowerShell.Create()) {
                powerShell.Runspace.SessionStateProxy.SetVariable("env:Path",
                    $"{searchTarget}{Path.PathSeparator}{Environment.GetEnvironmentVariable("PATH")}");
            }

            var pathDirs = Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator);
            Assert.IsFalse(pathDirs.Contains(searchTarget));
        }
    }
}

Как я могу предотвратить это? Можно ли полностью изолировать этот PowerShell объект / выполнение?

1 Ответ

0 голосов
/ 14 января 2019

PetSerAl предоставил критический указатель в комментарии:

Поскольку переменные окружения по своей природе [целые -] процесс -области , вам нужен внепроцессный пространство выполнения для получить желаемое поведение.

Напротив, PowerShell.Create() сам по себе, без явного присвоения пространства выполнения через свойство .Runspace результирующего экземпляра, по умолчанию используется внутрипроцессное пространство выполнения, и затем изменяется переменная среды через это пространство выполнения. неизменно влияет и на вызывающего абонента, работающего в том же процессе.

Чтобы изменить код для использования внепроцессного пространства выполнения, выполните следующие действия:

// ...
using System.Management.Automation.Runspaces;

// ...

// Create an out-of-process runspace...
using (var runspace = RunspaceFactory.CreateOutOfProcessRunspace(null))
{
  runspace.Open(); // ... open it ...
  using (PowerShell powerShell = PowerShell.Create())
  {
    powerShell.Runspace = runspace; // ... and assign it to the PowerShell instance.

    // Now setting $env:PATH only takes effect for the separate process
    // in which the runspace is hosted.
    // Note: `powerShell.Runspace.SessionStateProxy.SetVariable("env:Path", ...)` does 
    // does NOT work with OUT-OF-PROCESS runspaces, so a call to
    // `Set-Item env:PATH ...` is used to modify the other process' PATH env. var.
    // (Environment.SetEnvironmentVariable() is NOT an option, because
    //  it would modify the *calling* process' environment).
    powerShell.AddCommand("Set-Item")
      .AddParameter("LiteralPath", "env:Path")
      .AddParameter("Value", $"{searchTarget}{Path.PathSeparator}{Environment.GetEnvironmentVariable("Path")}")
      .Invoke();
    powerShell.Commands.Clear();

    // ...

  }

}

Примечание. Выше используется вызов Set-Item env:Path ... для изменения $env:PATH в пространстве выполнения вне процесса, поскольку, как указывает PetSerAl, в отличие от внутрипроцессных областей выполнения, использование powerShell.Runspace.SessionStateProxy.SetVariable("env:Path", ...) создает переменную PowerShell с буквальным именем env:Path вместо изменения среда переменная PATH, начиная с Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview. 3; см. этот выпуск GitHub

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...