简体   繁体   中英

“Requested registry access is not allowed” When Attempting to Run PowerShell Script on Remote Machine Using Impersonation

This is the first time I try to execute PowerShell scripts from a C# application. I'm using PowerShell because I need the output from the .exe I'm executing on the remote machine. I was able to run the .exe on the remote machine using WMI, but I couldn't get the output I needed.

At any rate, I've been going at this for the past day or so, and I've looked around the web and here at SO for similar issues, but can't seem to figure out the problem. I'm trying to run a simple PowerShell command from my .NET 4.0 application on a remote machine. The following code executes fine when I run Visual Studio 2013 as an administrator:

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

I get the expected results. However, when I run VS as a non-administrator, the code seems to execute fine (no exceptions), but I get no results back. After looking around a bit I added impersonation as follows:

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();
}

However, the ps.Invoke method starts throwing a System.Security.SecurityException - "Requested registry access is not allowed." Here is the stack trace:

at Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable) at System.Environment.GetEnvironmentVariable(String variable, EnvironmentVariableTarget target) at System.Management.Automation.ModuleIntrinsics.GetExpandedEnvironmentVariable(String name, EnvironmentVariableTarget target) at System.Management.Automation.ModuleIntrinsics.SetModulePath() at System.Management.Automation.ModuleIntrinsics..ctor(ExecutionContext context) at System.Management.Automation.ExecutionContext.InitializeCommon(AutomationEngine engine, PSHost hostInterface) at System.Management.Automation.ExecutionContext..ctor(AutomationEngine engine, PSHost hostInterface, RunspaceConfiguration runspaceConfiguration) at System.Management.Automation.AutomationEngine..ctor(PSHost hostInterface, RunspaceConfiguration runspaceConfiguration, InitialSessionState iss) at System.Management.Automation.Runspaces.LocalRunspace.DoOpenHelper() at System.Management.Automation.Runspaces.LocalRunspace.OpenHelper(Boolean syncC all) at System.Management.Automation.Runspaces.RunspaceBase.CoreOpen(Boolean syncCall) at System.Management.Automation.Runspaces.RunspaceBase.Open() at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync) at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection 1 input, PSDataCollection 1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection 1 input, PSDataCollection 1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke()

I'm not sure why I'm getting the SecurityException when the administrator account I'm running as has access to the registry, not only on my machine but on machines across the enterprise. And I'm not even sure which registry it's getting the exception on, my machine or the remote machine.

Create the underlying RunSpace for your PowerShell object before impersonating:

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()

The RunSpace object encapsulates the OS environment for script execution. the key being accessed is probably HKCU\\Environment. That is what I saw when using Perfmon . RunSpace probably uses the HKCU\\Environment to populate variables such as $PATH.

Therefore, when the RunSpace is created, you want it the current user to have access to HKCU\\Environment.

Pulling RunSpace.Open of the impersonated block is mentioned elsewhere as a hack for avoiding the registry access problem . However, merely creating the PowerShell object does not guarantee that the Runspace.Open() is called.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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