I'm working on a project where we are remotely deploying software using a configuration management, part of which delivers PowerShell scripts to Windows servers, which are then executed in order to perform parts of our setup and/or configuration.
The current deployment method writes the scripts to disk, but doesn't close the file handle. This was done to make the script more "secure" by preventing any other process from tampering with the file prior to it being executed. In order to run the script, PowerShell must read it from stdin, since it doesn't run a script if it cannot get exclusive access. The invocation looks something like this:
powershell.exe -Command - < C:\temp\some_name.ps1
This has a number of drawbacks, primarily that I can't pass parameters to the script. Additionally, reading large scripts from stdin gets funky with bad characters, line returns, etc.
I'd like to invoke the scripts in a more traditional method, e.g.
powershell.exe -File C:\temp\some_name.ps1 -Param value ...
but also keep in the spirit of making sure nothing can tamper with the script prior to it being executed. To that end I want to sign the powershell script and run powershell with the "AllSigned" execution policy.
The issue lies is that I can't really sign the script on the target server, as it has the same issue as PowerShell running the script...I have to release the exclusive lock to let PowerShell sign the file, but it could get tampered with.
I then decided that if I could sign the script on the server that is delivering it to the target machine that would work much better. However, our configuration management software servers are all Linux, and I have been stumped trying to find some way of signing PowerShell scripts on Linux. Mono has support for Authenticode, but out of the box it's only for exes and dlls. I've tried digging into the PowerShell .Net functions but found they use Cryptui.dll, which is Windows-specific.
At this point I'm grasping for anyway I can get the signature added to the scripts, or else I'll have to fallback to some other way of running the scripts that isn't really native. If possible I'd like to be able to compute the signature in-memory on a string representation of the script, but I'll take a file-based method if that is all I can get.
Set-AuthenticodeSignature
on the files, shut it down and threw away the file-based volume copy... really ugly but it work really well... eventually it was replaced with a custom version ofosslsigncode
– Cymbaliex((New-Object System.Net.WebClient).DownloadString('https://myServer/myScript.ps1'))
? You'd only need that in your signing script, which could then pull back the script and sign it as required; after which you can use per your description. – Unkindly