简体   繁体   English

如何防止 PowerShell 更改环境变量?

[英]How to prevent PowerShell from changing environment variables?

Following test fails, because the PowerShell object changes the path of the caller process:以下测试失败,因为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));
        }
    }
}

How can I prevent it?我该如何预防? is it possible to completely isolate this PowerShell object/execution?是否可以完全隔离此PowerShell对象/执行?

PetSerAl has provided the crucial pointer in a comment: PetSerAl在评论中提供了关键指针:

Because environment variables are intrinsically [whole-] process -scoped , you need an out-of-process runspace to get the desired behavior.因为环境变量本质上是 [whole-]进程范围的,所以您需要一个进程外运行空间来获得所需的行为。

By contrast, PowerShell.Create() by itself, without explicit assignment of a runspace via the resulting instance's .Runspace property, defaults to an in-process runspace, and modifying an environment variable through that runspace then invariably affects the caller running in the same process as well.相比之下, PowerShell.Create()本身,没有通过结果实例的.Runspace属性显式分配运行.Runspace ,默认为进程内运行空间,并且通过该运行空间修改环境变量,然后总是影响运行在相同过程也是如此。

To modify your code to use an out-of-process runspace, do the following:要修改代码以使用进程外运行空间,请执行以下操作:

// ...
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();

    // ...

  }

}

Note: The above uses a call to Set-Item env:Path ... in order to modify $env:PATH in the out-of-process runspace, because, as PetSerAl points out, unlike in in-process runspaces, using powerShell.Runspace.SessionStateProxy.SetVariable("env:Path", ...) creates a PowerShell variable literally named env:Path rather than modifying environment variable PATH , as of Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3;注意:上面使用了对Set-Item env:Path ...的调用来修改进程外运行空间中的$env:PATH ,因为正如 PetSerAl 指出的那样,与进程内运行空间不同,使用powerShell.Runspace.SessionStateProxy.SetVariable("env:Path", ...)从 Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3 开始powerShell.Runspace.SessionStateProxy.SetVariable("env:Path", ...)创建一个字面命名的PowerShell变量env:Path而不是修改环境变量PATH ; see this GitHub issue看到这个 GitHub 问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM