[英]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.