Public/Set-WinRMCertificate.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
function Set-WinRMCertificate {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,Position=0,ValueFromPipelineByPropertyName)]
        [Alias('Thumbprint')]
        [string]$CertThumbprint,
        [Parameter(Position=1,ValueFromPipelineByPropertyName)]
        [string]$PfxFile,
        [Parameter(Position=2,ValueFromPipelineByPropertyName)]
        [securestring]$PfxPass,
        [string]$Address='*',
        [string]$Transport='HTTPS',
        [switch]$RemoveOldCert
    )

    Process {

        # install the cert if necessary
        if (!(Test-CertInstalled $CertThumbprint)) {
            if ($PfxFile) {
                $PfxFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($PfxFile)
                Import-PfxCertInternal $PfxFile -PfxPass $PfxPass
            } else {
                throw "Certificate thumbprint not found and PfxFile not specified."
            }
        }

        # get a reference to the existing listener
        $listener = Get-WSManInstance -ResourceURI 'winrm/config/Listener' -Enumerate |
            Where-Object { $_.Address -eq $Address -and $_.Transport -eq $Transport }
        if (-not $listener) {
            throw "Listener with Transport $Transport and Address $Address not found."
        }

        # update the cert thumbprint if it's different
        if ($CertThumbprint -ne $listener.CertificateThumbprint) {

            # save the old thumbprint
            $oldThumb = $listener.CertificateThumbprint

            # Set-WSManInstance fails if the existing hostname on the listener doesn't match
            # the CN value of the certificate's subject (which seems broken to me, but *shrug*).
            # So we're going to parse the hostname from the subject and make sure we set it
            # at the same time as the thumbprint.
            $subject = (Get-Item "Cert:\LocalMachine\My\$CertThumbprint").Subject
            if ($subject -match 'CN=(?<host>[^,]+)') {
                $certHost = $matches['host']
                Write-Verbose "Parsed hostname $certHost from cert subject."
            }

            # set the new thumbprint
            Write-Verbose "Setting Listener with Transport $Transport and Address $Address to certificate thumbprint $CertThumbprint and hostname $certHost."
            $setParams = @{
                ResourceURI = 'winrm/config/Listener'
                SelectorSet = @{
                    Address = $Address
                    Transport = $Transport
                }
                ValueSet = @{
                    Hostname = $certHost
                    CertificateThumbprint = $CertThumbprint
                }
            }
            Set-WSManInstance @setParams -EA Stop | Out-Null

            # remove the old cert if specified
            if ($RemoveOldCert) { Remove-OldCert $oldThumb }

        } else {
            Write-Warning "Specified certificate is already configured for Listener with Transport $Transport and Address $Address."
        }

    }





    <#
    .SYNOPSIS
        Configure a WinRM HTTPS listener to use the specified certificate.
 
    .DESCRIPTION
        Intended to be used with the output from Posh-ACME's New-PACertificate or Submit-Renewal.
 
    .PARAMETER CertThumbprint
        Thumbprint/Fingerprint for the certificate to configure.
 
    .PARAMETER PfxFile
        Path to a PFX containing a certificate and private key. Not required if the certificate is already in the local system's Personal certificate store.
 
    .PARAMETER PfxPass
        The export password for the specified PfxFile parameter. Not required if the Pfx does not require an export password.
 
    .PARAMETER Address
        The address value of the WinRM listener. Defaults to '*'.
 
    .PARAMETER Transport
        The transport of the WinRM listener. Defaults to 'HTTPS'.
 
    .EXAMPLE
        New-PACertificate site1.example.com | Set-WinRMCertificate
 
        Create a new certificate and configure it for the listener on this system.
 
    .EXAMPLE
        Submit-Renewal site1.example.com | Set-RDSHCertificate
 
        Renew a certificate and configure it for the listener on this system.
 
    .LINK
        Project: https://github.com/rmbolger/Posh-ACME.Deploy
 
    #>

}