Friday, January 18, 2013

Signing multiple PowerShell Scripts at once

I have an environment where Active Directory GPO ensures that Script Execution Policy is set to "Allsigned".  As you know, only signed script will be allowed to be executed.   I will not go into the details on how to sign a script, you can look at the following link to learn more about it:

Signing PowerShell Scripts by Scott Hanselman

Ok, where were we?  Yes, so you want to automate the process of signing bunch of scripts that already gone through some sort of gate-keeping process (you validated, tested, inspected, re-validated,re-tested,re-inspected ... and so on). Scripts are stored in a secure share \\network.location.com\Repository\scripts2Bsigned\.

Although this is not the best security practice to allow automation to sign bunch of scripts, I had to go that route for this specific instance.  So svc_signer's personal store had the script-signing certificate associated with it.   (IF svc_signer were to interactively logged into that server, and run certmgr.msc, it would see the correct cert under its personal store).  So for this purpose, a task runs frequently to look for ps1 files  in that location for signing:

# Create Log output$logpath = “\\network.location.com\Repository\logs” $Outputfile = “{0}\{1:yyyy.MM.dd-hh.mm.ss}-sign-scripts.txt” -f $logpath, $(Get-Date) $starttime = Get-Date
write-output
“**** Script signing time: $starttime ****” | Out-File $Outputfile -append # Looks for ps1 file for signing$scriptdir = “\\network.location.com\Repository\scripts2Bsigned\” $scripts = get-childitem -recurse $scriptdir | where-object{($_.Extension -ieq '.PS1')} #Ensures the files are converted to UTF8 format $list = @() foreach ($script in $scripts) {
$list += $script.fullname }
foreach($File in $list){ $TempFile = “$($File).UTF8" get-content $File | out-file $TempFile -Encoding UTF8 remove-item $File rename-item $TempFile $File }
# If a code-signing cert already not present, enter SmartCard device that has the certificate

$cert = Get-ChildItem cert:\CurrentUser\my -codesigning

# look for all the scripts with ps1 extension
$Files = Get-ChildItem $scriptdir *.ps1 -Recurse

# For each file found get its file path and sign the script Foreach($file in $Files) {
$a = $file.fullname Set-AuthenticodeSignature -filepath $a -Certificate $cert -IncludeChain ALL -force | Out-File $Outputfile -append }
$finishtime = Get-Date write-output “**** script finished $finishtime ****” | Out-File $Outputfile -append #END

In my scenario, I also decided to move the scripts to another folder, so only scripts stays in the share are those that need signing.  Even if you leave the signed script there, and they get signed again, it is not a big deal.