How to easily sign PowerShell scripts

I am a SysAdmin and whenever I need to type interactive commands I use ISE because I can work simultaneously on several servers from several script panes.

However, when I write scripts, functions or modules I use VSCode. Unfortunately, at the time of this writing, in VSCode there is no builtin feature, nor extension to assist us in signing PowerShell code.

There is an open feature request on Github, but “this is currently not a priority”…
If you are interested in this feature, you can upvote the issue or leave a comment so that the team in charge of VSCode knows that this point is important for the community.
https://github.com/PowerShell/vscode-powershell/issues/548

However, meanwhile, I need something to help me to sign my scripts without too much repetitive work. That’s why I have added a function to my profile. And now I can quickly and easily sign my script:

Set-Signature -FilePath MyScript.ps1

And because I have added the ValueFromPipeline attribute, the pipeline can be used:

Get-ChildItem *.ps1 | Set-Signature

And because I have added an alias and also a positional parameter, the command line can be very minimal:

sig MyScript.ps1

By adding the function to the profile, it automatically loads whenever your profile is loaded. But if you don’t need it that often, you can add the function to a .psm1 file and load it only when you need it with the Import-Module cmdlet.

Here is the function:

function Set-Signature {
    [CmdletBinding()]

    [Alias('sig')]

    param(

        [Parameter(
            Mandatory,
            Position = 0,
            ValueFromPipeline,
            ValueFromPipelineByPropertyName
        )]
        [ValidateScript({Test-Path -Path $PSItem})]
        [ValidateNotNullOrEmpty()]
        [string[]]$FilePath
    )

    begin{
        $Certificate = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert |
            Where-Object -Property NotAfter -GT (Get-Date) |
            Sort-Object -Property NotAfter -Descending |
            Select-Object -First 1
    }

    process{
        foreach ($Path in $FilePath) {
            $TimeStampServer = @(
                'http://timestamp.verisign.com/scripts/timstamp.dll'
                'http://timestamp.globalsign.com/scripts/timstamp.dll'
                'http://timestamp.comodoca.com/authenticode'
            ) | Get-Random

            $Params = @{
                Certificate = $Certificate
                TimestampServer = $TimeStampServer
                HashAlgorithm = 'SHA256'
                FilePath = $Path
                Verbose = $True
            }

            Set-AuthenticodeSignature @Params
        }
    }
}

For those who are wondering, what a timestamp server is, it is a server that garantees the validity of your signature even when you certificate has expired.

Feel free to adapt this function to your needs.
And if you know other ways to assist us when signing scripts in VSCode please share them in the comments below…

3 thoughts on “How to easily sign PowerShell scripts

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s