Today's fun involves adding a menu item to the PowerShell ISE to make it easy to sign your scripts. I'm not going to go into the details about getting and installing a code signing certificate. I also assume you only have one installed. You can get this certificate by seasrching the CERT: PSDrive.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
[cc lang="PowerShell"]
PS S:\> dir cert:\CurrentUser\My -CodeSigningCert
Directory: Microsoft.PowerShell.Security\Certificate::CurrentUser\My
Thumbprint Subject
---------- -------
6372DB82AEB690C620E45675C464254FD58FAA97 CN=Jeffery Hicks
[/cc]
To sign a script use the Set-AuthenticodeSignature cmdlet specifying the file and certificate. With these two pieces of information I wrote a function to be used in the ISE that signs the currently active script.
[cc lang="PowerShell"]
Function Sign-ISEScript {
Param()
Set-StrictMode -Version Latest
#get the certificate
$cert=get-childitem -Path cert:\currentuser\my -CodeSigningCert
if ($cert) {
#save the file if necessary
if (!$psise.currentfile.IsSaved) {
$psise.CurrentFile.Save()
}
#if the file is encoded as BigEndian, resave as Unicode
if ($psise.currentfile.encoding.encodingname -match "Big-Endian") {
$psise.CurrentFile.Save([Text.Encoding]::Unicode) | Out-Null
}
#save the filepath for the current file so it can be re-opened later
$filepath=$psise.CurrentFile.FullPath
#sign the file
Try {
Set-AuthenticodeSignature -FilePath $filepath -Certificate $cert -errorAction Stop
#close the file
$psise.CurrentPowerShellTab.Files.remove($psise.currentfile) | Out-Null
#reopen the file
$psise.CurrentPowerShellTab.Files.add($filepath) | out-null
}
Catch {
Write-Warning ("Script signing failed. {0}" -f $_.Exception.message)
}
} #if code cert found
else {
Write-Warning "No code signing certificate found."
}
} #end function
[/cc]
The function saves the script if it needs to be so that it can be properly signed. The other check I have to make is the file encoding. By default when you create a new script in the ISE, the encoding is set to Big-Endian. Unfortunately, you can't sign scripts with this type of encoding so if the encoding is Big-Endian, the file gets saved as a Unicode file.
[cc lang="PowerShell"]
if ($psise.currentfile.encoding.encodingname -match "Big-Endian") {
$psise.CurrentFile.Save([Text.Encoding]::Unicode) | Out-Null
}
[/cc]
Now we're ready to sign the script. But first I grab the full path and save it to a variable because after I sign the script I want to close the file and re-open it so you can see that it has been signed.
[cc lang="PowerShell"]
#save the filepath for the current file so it can be re-opened later
$filepath=$psise.CurrentFile.FullPath
#sign the file
Try {
Set-AuthenticodeSignature -FilePath $filepath -Certificate $cert -errorAction Stop
#close the file
$psise.CurrentPowerShellTab.Files.remove($psise.currentfile) | Out-Null
#reopen the file
$psise.CurrentPowerShellTab.Files.add($filepath) | out-null
}
[/cc]
Once the function is loaded in the ISE, I could run it any time from the command prompt to sign the current file. But I add the script file to my ISE profile and then insert a menu item.
[cc lang="PowerShell"]
#this goes in my ISE profile
. c:\scripts\Sign-ISEScript.ps1
$psISE.CurrentPowerShellTab.AddOnsMenu.submenus.Add("Sign Script",{Sign-ISEScript},$null) | Out-Null
[/cc]
Now I have a menu choice under Add-Ons for "Sign Script". I can click it and the current file will be signed, closed and reopened. If you edit the file again, don't forget you'll need to resign the script. Commercial editors like PrimalScript can be configured to automatically sign scripts whenever they are saved. The ISE is much more limited.
Still, I hope you can have some fun with this and maybe even pick up a PowerShell tidbit or two.
Download Sign-ISEScript.ps1.