Templates/ScriptSigner.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 <#
.Synopsis
    Sign scripts
.DESCRIPTION
    Sign target script(s) using existing certificate. If existing certificate is missing a new is generated.
.PARAMETER Path
       Target path for file to sign or folder name to sign all files.
.PARAMETER FileType
       Suffix for files to sign. Default is ".ps1"
.PARAMETER Recurse
   If Path is a folder the signijng will be done recursive
.Notes
    Author: Jack Olsson
    Changes: 2018-07-11 First draft
     
    2018-07-20
    Added support for file types to sign.
#>

[CmdletBinding(SupportsShouldProcess = $True)]
param (
    [Parameter(Mandatory = $true,
               ValueFromPipelineByPropertyName=$true)]
    [string]$Path,
    [string]$FileType = ".ps1",
    [switch]$Recurse
)

#region Init

if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
    [Security.Principal.WindowsBuiltInRole] "Administrator"))
{
    Write-Warning "You do not have Administrator rights to run this script!`nPlease re-run this script as an Administrator!"
    Break
}

#endregion

#region local functions
function New-CodeSigningCert {
<#
    .SYNOPSIS
        Get a certificate!
    .DESCRIPTION
         
#>

[CmdletBinding()]
param()
    Write-Verbose "Create a certificate to use for signing powershell scripts"
    $selfsigncert = New-SelfSignedCertificate `
                -Subject "CN=PowerShell Code Signing" `
                -FriendlyName "Local self-signed code signing certificate" `
                -KeyAlgorithm RSA `
                -KeyLength 2048 `
                -Type CodeSigningCert `
                -CertStoreLocation Cert:\LocalMachine\My\

    Write-Verbose "Move the root cert into Trusted Root CAs"
    Move-Item "Cert:\LocalMachine\My\$($selfsigncert.Thumbprint)" Cert:\LocalMachine\Root

    Write-Verbose "Obtain a reference to the code signing cert in Trusted Root"
    $cert = (Get-ChildItem -Path "Cert:\LocalMachine\Root\$($selfsigncert.Thumbprint)")
    $cert
}
#end region

Write-Output "Start Execution"

Write-Verbose "Enumerate Cert:\LocalMachine\Root"
Get-ChildItem -Path Cert:\LocalMachine\Root -CodeSigningCert | ForEach-Object {       
    if ($_.Verify()) {
        Write-Verbose "Found existing certificate Cert:\LocalMachine\Root\$($_.Thumbprint)"
        $cert = $_        
    }
}

if ($cert -eq $null) {
    Write-Verbose "No valid certificate found. Generating a new one."
    
    if ($pscmdlet.ShouldProcess("N/A", "New-CodeSigningCert")) {
        $cert = New-CodeSigningCert
        Write-Verbose "Copy cert into Trusted publishers"
        Export-Certificate  -Cert $cert -FilePath ".\$($selfsigncert.Thumbprint).cer"
        Import-Certificate -FilePath ".\$($selfsigncert.Thumbprint).cer" -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
        Remove-Item -Path ".\$($selfsigncert.Thumbprint).cer" -Force
    }
}

Get-ChildItem -Path $Path -Filter "*$FileType" -Recurse:$Recurse.IsPresent | ForEach-Object {    
    if ($pscmdlet.ShouldProcess($_.FullName, "Set-AuthenticodeSignature")) {
        $result = Set-AuthenticodeSignature $_.FullName -Certificate $cert
        Write-Output "$($result.Status);$($_.FullName)"
    }
}



Write-Output "End Execution"