New-DomainSignedCertificate.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<#
    .SYNOPSIS
        This commandlet requests a certificate from the active directory certificate services and adds it to the store
 
    .DESCRIPTION
        This commandlet requests a certificate from the active directory certificate services and adds it to the store. The commandlet automates the flow of certreq.exe.
 
    .PARAMETER Hostname
        The hostname of the certificate also known as the Common Name (CN)
 
    .PARAMETER Organization
        The organization of the certificate (O)
 
    .PARAMETER OrganizationalUnit
        The organization unit of the certificate (OU)
 
    .PARAMETER Locality
        The locality unit of the certificate also known as the city (L)
 
    .PARAMETER State
        The state of the certificate (S)
 
    .PARAMETER Country
        The country of the certificate (C)
 
    .PARAMETER CertificateAuthority
        The the certificate authority that will issue the certificate. For a sever attached to a domain use the certutil to find the value.
 
    .PARAMETER FriendlyName
        The friendly name of the certificate. Defaults to yyyyMMdd.<hostname>
 
    .PARAMETER Keylength
        The key length of the certificate
 
    .PARAMETER SANDns
        The SubjectAltName extension fields of type=DNS. By default the <hostname> parameter is already added.
 
    .PARAMETER SANEmail
        The SubjectAltName extension fields of type=EMail.
 
    .PARAMETER CertificateTemplate
        The certificate template name. Defaults to 'WebServer'
 
    .PARAMETER attrib
        Certreq's -attrib <AttributeString> value.
        Specifies the Name and Value string pairs, separated by a colon.
        Separate Name and Value string pairs with \n (for example, Name1:Value1\nName2:Value2).
 
    .PARAMETER workdir
        The path where the temporary files are generated. Default is the %temp%
 
    .EXAMPLE
        New-DomainSignedCertificate -Hostname "server1.example.com" -CertificateAuthority ""
 
    .LINK
        http://serverfault.com/questions/670160/how-can-i-create-and-install-a-domain-signed-certificate-in-iis-using-powershell
#>

function New-DomainSignedCertificate {
    [CmdletBinding()]
    param(
        [parameter(Mandatory=$true)]
        [string]
        $Hostname,

        [parameter(Mandatory=$false)]
        [string]
        $Organization="",

        [parameter(Mandatory=$false)]
        [string]
        $OrganizationalUnit="",

        [parameter(Mandatory=$false)]
        [string]
        $Locality="",

        [parameter(Mandatory=$false)]
        [string]
        $State="",

        [parameter(Mandatory=$false)]
        [string]
        $Country="",

        [parameter(Mandatory=$true)]
        [string]
        $CertificateAuthority,

        [parameter(Mandatory=$false)]
        [string]
        $FriendlyName="$(Get-Date -Format "yyyyMMdd").$Hostname",

        [parameter(Mandatory=$false)]
        [string]
        $Keylength = "2048",

        [Parameter(Mandatory=$false)]
        [string[]]
        $SANDns,

        [parameter(Mandatory=$false)]
        [string[]]
        $SANEmail,

        [parameter(Mandatory=$false)]
        [string]
        $CertificateTemplate = "WebServer",

        [string]
        $attrib,

        [string]
        $workdir = $env:Temp
    )

    $fileBaseName = $Hostname -replace "\.", "_" 
    $fileBaseName = $fileBaseName -replace "\*", ""

    $infFile = $workdir + "\" + $fileBaseName + ".inf"
    $requestFile = $workdir + "\" + $fileBaseName + ".req"
    $CertFileOut = $workdir + "\" + $fileBaseName + ".cer"

    Try {
        Write-Verbose "Creating the certificate request information file ..."
        $inf = @"
[Version]
Signature="`$Windows NT`$"
 
[NewRequest]
Subject = "CN=$Hostname, OU=$OrganizationalUnit, O=$Organization, L=$Locality, S=$State, C=$Country"
KeySpec = 1
KeyLength = $Keylength
Exportable = TRUE
FriendlyName = "$FriendlyName"
MachineKeySet = TRUE
SMIME = False
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
 
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "dns=$Hostname&"
"@


        $inf | Set-Content -Path $infFile -Force

        if ($SANDns) {
            foreach ($value in $SANDns) {
                $temp = '_continue_ = "dns=' + $value + '&"'
                add-content $infFile $temp
            }
        }

        if ($SANEmail) {
            foreach ($value in $SANEmail) {
                $temp = '_continue_ = "email=' + $value + '&"'
                add-content $infFile $temp
            }
        }

        $attr = @"
 
[RequestAttributes]
CertificateTemplate = $CertificateTemplate
"@


        add-content $infFile $attr

        Write-Verbose "Creating the certificate request ..."
        $certreqArgs=@(
            "-new"
            $infFile
            $requestFile
        )

        Start-Process -FilePath "certreq.exe" -ArgumentList $certreqArgs -NoNewWindow -Wait

        #Split because of conditional $attrib parameter
        $certreqArgs=@(
            "-submit"
            "-config"
            """$CertificateAuthority"""
        )

        if ($attrib) {
            $certreqArgs += ""
            $certreqArgs += $attrib
        }

        $certreqArgs += $requestFile
        $certreqArgs += $CertFileOut

        Write-Verbose "Submitting the certificate request to the certificate authority ..."
        Start-Process -FilePath "certreq.exe" -ArgumentList $certreqArgs -NoNewWindow -Wait

        if (Test-Path "$CertFileOut") {
            Write-Verbose "Installing the generated certificate ..."
            $certreqArgs=@(
                "-accept"
                $CertFileOut
            )
            Start-Process -FilePath "certreq.exe" -ArgumentList $certreqArgs -NoNewWindow -Wait
            $certificate=[System.Security.Cryptography.X509Certificates.X509Certificate2]::CreateFromCertFile($CertFileOut)
            $certificate2=New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $certificate
            Get-ChildItem Cert:\LocalMachine\My |Where-Object -Property Thumbprint -EQ $certificate2.Thumbprint
        }
    }
    Finally {
        if (-not ($PSBoundParameters['Debug'])) {
            Get-ChildItem "$workdir\$fileBaseName.*" | remove-item
        }
    }
}