Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run Only signed powershell scripts from c#

I have a windows service that downloads a script and then runs it.

I've been trying to make my windows service more secure, making it accept only signed power-shell scripts.

I have ran the Set-ExecutionPolicy AllSigned command on the server, and this works in the windows power shell command prompt.

However, my code still runs both signed and unsigned scripts, even if the set-executionpolicy is set to restricted.

I have tried two approaches:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
        runspace.Open();

        RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
        Pipeline pipeline = runspace.CreatePipeline();         
        pipeline.Commands.AddScript(@"Set-ExecutionPolicy AllSigned");
        pipeline.Commands.AddScript(@"Get-ExecutionPolicy");
        pipeline.Commands.AddScript(script);
        Collection<PSObject> results = pipeline.Invoke();

And another approach:

using (PowerShell ps = PowerShell.Create())
                {
                    ps.AddCommand("Set-ExecutionPolicy").AddArgument("Restricted");
                    ps.AddScript("Set-ExecutionPolicy Restricted");
                    ps.AddScript(script);
                    Collection<PSObject> results = ps.Invoke();
                  }

In both situations the code runs unsigned scripts as well.

Have I missed something?

like image 581
Dan Gheorghe Avatar asked Nov 13 '22 08:11

Dan Gheorghe


1 Answers

I found the solution. The only way to restrict the code from running unsigned scripts was to check the scripts myself with Get-AuthenticodSignature:

 public bool checkSignature(string path)
    {

        Runspace runspace = RunspaceFactory.CreateRunspace();
        runspace.Open();
        RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
        Pipeline pipeline = runspace.CreatePipeline();
        pipeline.Commands.AddScript(String.Format("Get-AuthenticodeSignature \"{0}\"", path));
        Collection<PSObject> results = pipeline.Invoke();
        Signature check = (Signature)results[0].BaseObject;
        runspace.Close();
        if (check.Status == SignatureStatus.Valid)
        {
            return true;
        }
        return false;
    }

Thanks,

Dan

like image 62
Dan Gheorghe Avatar answered Nov 14 '22 23:11

Dan Gheorghe