5

I am trying to run a PowerShell script with C#, but I don't have any success. Here is my function:

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:

[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:

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:

private static void GIncognito(params object[] args)
{
    RunspaceInvoke scriptInvoker = new RunspaceInvoke();
    scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
}

And I have modified my method:

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • re: can't access registry keys-- You will have to either use an account that can modify registry keys or use a technique that does involve changing the execution policy from inside a running powershell instance. – MatthewMartin Nov 20 '12 at 22:01
  • @Lajos: impersonation is a lot of overkill for this... all you need to do is change the scope that the `Set-ExecutionPolicy` uses... see my answer below. – JaredReisinger May 02 '13 at 18:17

3 Answers3

2

Here is method b, that doesn't require elevated rights or Registry modification rights.

Using Process.Start launch this and add the relevant initial -command or -file args.

%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy bypass

Here is another technique, http://dmitrysotnikov.wordpress.com/2008/06/27/powershell-script-in-a-bat-file/

That relies on executing by encoding it first and passing int through the -EncodedCommand arg of powershell.exe, which appears to bypass execution policy.

Patrick D'Souza
  • 3,491
  • 2
  • 22
  • 39
MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
  • I'm trying to run a git command and if I do it this way it asks for username and password. The problem is that I would like to make this fully automatic. If user name or password is needed, then human work is needed for each run. Can I make this fully automatic? Thanks. – Lajos Arpad Nov 20 '12 at 19:11
  • git asks for a username password or windows? What's in your scriptfile? – MatthewMartin Nov 20 '12 at 19:39
  • git is out of my range of experience. I'm guessing you are getting prompted by git for credentials, maybe this will help: http://superuser.com/questions/338511/how-do-i-disable-password-prompts-when-doing-git-push-pull – MatthewMartin Nov 20 '12 at 19:47
  • I have edited my question. I have tried to implement an impersonate method. I don't know what is wrong, but something is certainly not right. – Lajos Arpad Nov 20 '12 at 20:47
1

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JaredReisinger
  • 6,955
  • 1
  • 22
  • 21
0

You could try something like the following

using ( new Impersonator( "Username", "DomainName", "Password" ) )
{
    using (RunspaceInvoke invoker = new RunspaceInvoke())
    {
        invoker.Invoke("Set-ExecutionPolicy Unrestricted");
    }
}

Here is a link you can look at to get an idea as an example, Class For Impersonating a User.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MethodMan
  • 18,625
  • 6
  • 34
  • 52
  • Thank you for your post. To do this I need to use the Impersonator class, but I have no clue where can I find it or how can I implement it. I don't find a download link, only a link pointing to another page where an impersonator is described, but that can't be downloaded either, only the function shared there. Should I register to the site to be able to download these? – Lajos Arpad Nov 20 '12 at 18:47
  • Looks like this code: http://stackoverflow.com/questions/9909784/c-sharp-impersonator – MatthewMartin Nov 20 '12 at 18:56
  • Check out the link that Matthew Martin has posted as well I hope this information helps in getting started here is the link I posted as well in case it did not work from my initial post http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User – MethodMan Nov 20 '12 at 19:00
  • Ok, now I have the following error: Requested registry access is not allowed. – Lajos Arpad Nov 20 '12 at 19:00
  • do you have the proper permissions / rights to run a powershell script..? – MethodMan Nov 20 '12 at 19:01
  • @DJ KRAZE, your link worked and I've registered to the web-site to be able to download the demo project. I have pasted the impersonator class which is the same as in the class linked by MatthewMartin, but I get an error, namely: Requested registry access is not allowed. – Lajos Arpad Nov 20 '12 at 19:02
  • I posted a separate answer. I have the same issue on my work machine were I don't have admin rights, there are about 3 techniques for executing scripts w/o admin rights. – MatthewMartin Nov 20 '12 at 19:02
  • Yes, I have, but I can't seem to be able to do that from C#. – Lajos Arpad Nov 20 '12 at 19:02
  • Also, I'm not sure I know what should be passed as 'domain' for a windows 7 user. Maybe localhost? – Lajos Arpad Nov 20 '12 at 19:27
  • I have edited my question. I have tried to implement an impersonate method. I don't know what is wrong, but something is certainly not right. – Lajos Arpad Nov 20 '12 at 20:50