Question:
I am trying to run a PowerShell script with C#, but I don’t have any success. Here is my function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
private void ExecutePowerShellCommand(string scriptfile) { RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create(); Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration); runspace.Open(); RunspaceInvoke scriptInvoker = new RunspaceInvoke(); scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); Pipeline pipeline = runspace.CreatePipeline(); //Here's how you add a new script with arguments Command myCommand = new Command(scriptfile); //CommandParameter testParam = new CommandParameter("key", "value"); //myCommand.Parameters.Add(testParam); pipeline.Commands.Add(myCommand); // Execute PowerShell script pipeline.Invoke(); } |
This is the error I get:
Access to the registry key ‘HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell’ is denied.
How can I solve this issue? I have seen ideas for impersonation, but I didn’t seem to find any good examples to impersonate. I would like to run this script as an administrator.
I have made the following declarations:
1 2 3 4 5 6 7 |
[DllImport("advapi32.dll")] private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("kernel32.dll")] private static extern bool CloseHandle(IntPtr handle); public delegate void IncognitoDelegate(params object[] args); |
I have created the following function for impersonation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static void Impersonate(IncognitoDelegate incognitoDelegate, params object[] args) { System.IntPtr token = new IntPtr(); WindowsIdentity wi; if (LogonUser("myusername", "", "mypassword", 8, 0, ref token)) { wi = new WindowsIdentity(token); WindowsImpersonationContext wic = wi.Impersonate(); incognitoDelegate(args); wic.Undo(); } CloseHandle(token); } |
I have created a function which is used as a delegate:
1 2 3 4 5 6 |
private static void GIncognito(params object[] args) { RunspaceInvoke scriptInvoker = new RunspaceInvoke(); scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); } |
And I have modified my method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
private void ExecutePowerShellCommand(string scriptfile) { RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create(); Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration); runspace.Open(); Impersonate(new Util.IncognitoDelegate(GIncognito)); //RunspaceInvoke scriptInvoker = new RunspaceInvoke(); //scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); Pipeline pipeline = runspace.CreatePipeline(); //Here's how you add a new script with arguments Command myCommand = new Command(scriptfile); //CommandParameter testParam = new CommandParameter("key", "value"); //myCommand.Parameters.Add(testParam); pipeline.Commands.Add(myCommand); // Execute PowerShell script pipeline.Invoke(); } |
The result was…
… the very sam error, telling me I can’t access registry keys.
Answer:
The default Set-ExecutionPolicy
command attempts to set the machine-wide value. You only want to change the setting within the scope of your C# application, so you should add the -Scope Process
option to the command.
Using Get-Help Set-ExecutionPolicy -detailed
reveals this information:
NOTE: To change the execution policy for the default (LocalMachine) scope, start Windows PowerShell with the “Run as administrator” option.
… and it also describes the -Scope
option.
This has the advantage of only impacting the execution policy for scripts run from your C# application, and it doesn’t unnecessarily change the execution policy for the default PowerShell behavior. (So it’s a lot safer, especially if you can make guarantees about the validity of the scripts your application runs.)