尝试使用模拟在远程计算机上运行 PowerShell 脚本时“不允许请求的注册表访问”

Posted

技术标签:

【中文标题】尝试使用模拟在远程计算机上运行 PowerShell 脚本时“不允许请求的注册表访问”【英文标题】:"Requested registry access is not allowed" When Attempting to Run PowerShell Script on Remote Machine Using Impersonation 【发布时间】:2014-03-25 14:11:09 【问题描述】:

这是我第一次尝试从 C# 应用程序执行 PowerShell 脚本。我正在使用 PowerShell,因为我需要在远程机器上执行的 .exe 的输出。我能够使用 WMI 在远程计算机上运行 .exe,但无法获得所需的输出。

无论如何,过去一天左右我一直在研究这个问题,我在网上和 SO 上查看了类似的问题,但似乎无法找出问题所在。我正在尝试从远程计算机上的 .NET 4.0 应用程序运行一个简单的 PowerShell 命令。当我以管理员身份运行 Visual Studio 2013 时,以下代码可以正常执行:

PowerShell ps = PowerShell.Create();
ps.AddScript(@"Invoke-Command c:\path\to\file.exe /p -computername <computerName>");
results = ps.Invoke();

我得到了预期的结果。但是,当我以非管理员身份运行 VS 时,代码似乎执行得很好(没有例外),但我没有得到任何结果。看了一圈后,我添加了如下模拟:

using (var impersonator = new Impersonator("username", "domain", "password"))

    PowerShell ps = PowerShell.Create();
    ps.AddScript(@"Invoke-Command c:\path\to\file.exe /p -computername <computerName>");
    results = ps.Invoke();

但是,ps.Invoke 方法开始抛出 System.Security.SecurityException -“不允许请求的注册表访问”。这是堆栈跟踪:

在 Microsoft.Win32.RegistryKey.OpenSubKey(字符串名称,布尔可写) 在 System.Environment.GetEnvironmentVariable(字符串变量,EnvironmentVariableTarget 目标) 在 System.Management.Automation.ModuleIntrinsics.GetExpandedEnvironmentVariable(字符串名称,EnvironmentVariableTarget 目标) 在 System.Management.Automation.ModuleIntrinsics.SetModulePath() 在 System.Management.Automation.ModuleIntrinsics..ctor(ExecutionContext 上下文) 在 System.Management.Automation.ExecutionContext.InitializeCommon(AutomationEngine 引擎,PSHost 主机接口) 在 System.Management.Automation.ExecutionContext..ctor(AutomationEngine 引擎,PSHost 主机接口,RunspaceConfiguration runspaceConfiguration) 在 System.Management.Automation.AutomationEngine..ctor(PSHost 主机接口,RunspaceConfiguration runspaceConfiguration,InitialSessionState iss) 在 System.Management.Automation.Runspaces.LocalRunspace.DoOpenHelper() 在 System.Management.Automation.Runspaces.LocalRunspace.OpenHelper(布尔同步调用) 在 System.Management.Automation.Runspaces.RunspaceBase.CoreOpen(布尔同步调用) 在 System.Management.Automation.Runspaces.RunspaceBase.Open() 在 System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(运行空间 rsToUse,布尔 isSync) 在 System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection1 input, PSDataCollection1 输出,PSInvocationSettings 设置) 在 System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection1 input, PSDataCollection1 输出,PSInvocationSettings 设置) 在 System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable 输入,PSDataCollection`1 输出,PSInvocationSettings 设置) 在 System.Management.Automation.PowerShell.Invoke(IEnumerable 输入,PSInvocationSettings 设置) 在 System.Management.Automation.PowerShell.Invoke()

当我运行的管理员帐户有权访问注册表时,我不确定为什么会收到 SecurityException,不仅在我的机器上,而且在整个企业的机器上。而且我什至不确定它在哪个注册表上获得了异常,我的机器还是远程机器。

【问题讨论】:

你检查了两台机器的安全事件日志,看看有没有线索? 我在远程机器上看不到任何东西,但在我运行代码时,我确实在我的机器上看到了审核失败。这是 4673“敏感特权使用”。进程名称是 JetBrains.ReSharper.TaskRunner.CLR4.MSIL.exe,这似乎是正确的,因为我正在使用 ReSharper 运行我的集成测试。但除此之外没有更多信息。 【参考方案1】:

在模拟之前为您的 PowerShell 对象创建底层 RunSpace:

PowerShell ps = PowerShell.Create();
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
powerShell.Runspace = runspace;

using (var impersonator = new Impersonator("username", "domain", "password"))

    ps.AddScript(@"Invoke-Command c:\path\to\file.exe /p -computername <computerName>");
    results = ps.Invoke();

runspace.Close()

RunSpace 对象封装了脚本执行的操作系统环境。正在访问的密钥可能是 HKCU\Environment。这就是我在使用Perfmon 时看到的。 RunSpace 可能使用 HKCU\Environment 来填充变量,例如 $PATH。

因此,在创建 RunSpace 时,您希望当前用户能够访问 HKCU\Environment。

Pulling RunSpace.Open 模拟块在其他地方被称为a hack for avoiding the registry access problem。但是,仅创建 PowerShell 对象并不能保证调用 Runspace.Open()。

【讨论】:

另外值得注意的是,按照上面的顺序做这个很重要,在创建powershell实例和runspace之前不要冒充。

以上是关于尝试使用模拟在远程计算机上运行 PowerShell 脚本时“不允许请求的注册表访问”的主要内容,如果未能解决你的问题,请参考以下文章

我如何使用模拟功能通过UNC在远程计算机上操纵文件/目录?

如何获得在没有 WMI 的远程计算机上运行的进程的所有者

在远程计算机上使用 rsh 运行命令

Firebase 推送通知无法在手机上使用,但可以在模拟器中使用

使用 PowerShell 2.0 在远程计算机上运行批处理文件

Powershell在远程计算机上使用命令行参数执行远程exe