Updated 2017-06-08: Fixed some bugs (d'oh!) and added option to export certificate to .pfx
Assuming you have Microsoft PKI in place in your organization, then requesting webserver certificates is easy. But when you suddenly got 20 or 2000 new certificates that you need, clicking through the Microsoft Active Directory Certificate Services dialogues and submitting requests, manually issuing pending requests (you should not automatically issue a certificate with any subject name, only after approval - hey, it's security!) and copying the certificates back to you computer - starts to feel like too much work.
I stumbled upon a nice PowerShell script which after some modifications I turned into a custom function "New-MyCompanyCertificate". To the function you can pass hostname, SANs, IPAddresses, Emails and other values as parameters and it will generate the certificate request, submit it, issue pending certificate request and retrieve the newly generated certificate for you. With this updated version (June 8th, 2017) you can export the certificate to .pfx file. Nice, huh?
I hope you'll find this helpful, please ping me at Twitter @arisaastamoinen
Cheers, Ari
function New-MyCompanyCertificate{
<#
.Synopsis
Create new Certificate
.DESCRIPTION
Create new MyCompany CA issued certificate
.EXAMPLE
New-MyCompanyCertificate -Hostname my-dmz-host -ExportPFX -Verbose
This will generate new .cer and .pfx certificate files to be copied and imported to host "my-dmz-host"
.EXAMPLE
New-MyCompanyCertificate -Hostname MyHost -FriendlyName "My Super Host" -SubjectAlternateName "host1","host2" -OrganizationalUnit "Dev"
Creates a new certificate for MyHost with a frienldy name My Super Host. Certificate has two alternate names, issuing organization unit is Dev.
.EXAMPLE
New-MyCompanyCertificate -Hostname mhheltps1 -FriendlyName "MyCompany Super Server" -SubjectAlternateName "aaa1.local","aaa1.dmz","aaa1.dmz.local" -Email admin@MyCompany.com -IPAddress 172.20.0.34 -ExportPFX -Verbose
Create new certificate for My Super Server with three alternate names
#>
[CmdletBinding()]
param(
[Parameter(ParameterSetName='Default',
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Hostname,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$FriendlyName=$Hostname,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string[]]$SubjectAlternateName,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string[]]$Email,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string[]]$IPAddress,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Organization='MyCompany Co.',
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$OrganizationalUnit='IT',
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Locality='City',
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$State='Province',
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Country='FI', # hell yeah!
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[ValidateSet("mycompanyca01.local\MyCompany CA 01", "mycompanyca02.local\MyCompany CA 02", IgnoreCase=$true)]
[string]$CertificateAuthority='mycompanyca01.local\MyCompany CA 01',
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[int]$KeyLength = 2048,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[ValidateSet("MyCompanyWebServer", IgnoreCase=$true)]
[string]$CertificateTemplate = "MyCompanyWebServer",
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[switch]$ExportPFX=$true,
[Parameter(ParameterSetName='Default',
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string]$PFXPassword='Passw0rd!'
)
[string]$workDir = $env:Temp
[string]$outDir = 'C:\Temp'
[string]$fileBaseName = $Hostname -replace "\.", "_"
$fileBaseName = $fileBaseName -replace "\*", ""
[string]$infFile = $workDir + "\" + $fileBaseName + ".inf"
[string]$requestFile = $workDir + "\" + $fileBaseName + ".req"
[string]$CertFileOut = $workDir + "\" + $fileBaseName + ".cer"
[string]$PFXFileOut = $workDir + "\" + $fileBaseName + ".pfx"
[string]$certSubject = "CN=$Hostname, OU=$OrganizationalUnit, O=$Organization, L=$Locality, S=$State, C=$Country"
Try {
Write-Verbose "Creating the certificate request information file ..."
$inf = @"
[Version]
Signature="`$Windows NT`$"
[NewRequest]
Subject = "$certSubject"
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
"@
if ($SubjectAlternateName -ne $null -or $Email -ne $null -or $IPAddress -ne $null) {
$inf += @"
`n
[Extensions]
2.5.29.17 = "{text}"`n
"@
Write-Verbose "Include Hostname in SAN"
$inf += @"
_continue_ = "dns=$Hostname&"`n
"@
if ($SubjectAlternateName -ne $null) {
$arr = $SubjectAlternateName.Split(",")
foreach ($item in $arr) {
$inf += @"
_continue_ = "dns=$item&"`n
"@
}
} # if SubjectAlternateName
if ($Email -ne $null) {
$arr = $Email.Split(",")
foreach ($item in $arr) {
$inf += @"
_continue_ = "email=$item&"`n
"@
}
} # if Email
if ($IPAddress -ne $null) {
$arr = $IPAddress.Split(",")
foreach ($item in $arr) {
$inf += @"
_continue_ = "ipaddress=$item&"`n
"@
}
} # if IPAddress
}
write-verbose "Generating INF: $inf"
$inf | Set-Content -Path $infFile
Write-Verbose "Creating the certificate request ..."
$catchOutput = [string](& certreq.exe -new "$infFile" "$requestFile")
Write-Verbose $catchOutput
Write-Verbose "Submitting the certificate request to the certificate authority ..."
$catchOutput = [string](& certreq.exe -submit -config "$CertificateAuthority" -attrib "CertificateTemplate:$($CertificateTemplate)" "$requestFile" "$CertFileOut")
Write-Verbose $catchOutput
$findString = [string]$catchOutput
if ($findString -match "RequestId:(?<requestid>.*)RequestId:") {
$RequestId = [int]$matches['requestid']
Write-Verbose "Found RequestID ($RequestId) in reponse, trying to re-submit and recieve"
Get-ChildItem "$workDir\$fileBaseName.rsp" | remove-item
$catchOutput = [string](& certutil.exe -config $CertificateAuthority -resubmit $RequestId )
Write-Verbose [$catchOutput
$catchOutput = [string](& certreq.exe -config $CertificateAuthority -Retrieve $RequestId $CertFileOut)
Write-Verbose $catchOutput
write-Verbose "Recieved certificate:"
Get-Content $CertFileOut
Copy-Item $CertFileOut $outDir + "\" + $fileBaseName.cer
}
if ($ExportPFX) {
Write-Verbose "Exporting certificate to PFX file"
Write-Verbose "Importing certificate to Personal Store"
$catchOutput = [string](& certutil.exe -addstore -f MY $CertFileOut)
Write-Verbose $catchOutput
Write-Verbose "Repairing Personal Store"
$catchOutput = [string](& certutil.exe -repairstore MY $Hostname)
Write-Verbose $catchOutput
Write-Verbose "Exporting certificate to PFX file"
$catchOutput = [string](& certutil.exe -p $PFXPassword -exportPFX $Hostname $PFXFileOut)
Write-Verbose $catchOutput
Write-Verbose "Delete certificate from Personal Store"
$catchOutput = [string](& certutil.exe -privatekey -delstore MY $Hostname)
Write-Verbose $catchOutput
Copy-Item $PFXFileOut $outDir + "\" + $fileBaseName.pfx
}
}
Finally {
Get-ChildItem "$workDir\$fileBaseName.*" | remove-item
}
}
Mar 22, 2017
Mar 19, 2017
Day 0: Blog opens
Finally, a blog about my adventures in the land of IT !
During my 10+ years in IT I've found many blogs and posts very helpful.As my daily activities in the IT world consist of many different kind of tasks and many of those are not so trivial, I decided it's time to return something back to the community.
So my plan is to write something not about basic instructions of setting things up but more of those Level 400 things that really counts. Like "why and how should you setup tempdb in MSSQL" or "SCCM and what I did with CI/CB".
Active Directory, oh man! "Creating shadow groups that automatically update" will be one interesting topic. "Running AD without Domain Admin rights (aka 'Ditch Admin Rights' @samilaiho)" is my target and it already has risen some serious opinions against it in my current workplace. PKI isn't that hard as you might think.
PowerShell - sure. I'll show you what I did and why. Scripts and tools. I do, when ever possible, everything remotelly and with PS. And PKI with PowerShell is sooo easy.
Sure there will be more topics and posts, in the meanwhile please follow and DM me in Twitter @arisaastamoinen
During my 10+ years in IT I've found many blogs and posts very helpful.As my daily activities in the IT world consist of many different kind of tasks and many of those are not so trivial, I decided it's time to return something back to the community.
So my plan is to write something not about basic instructions of setting things up but more of those Level 400 things that really counts. Like "why and how should you setup tempdb in MSSQL" or "SCCM and what I did with CI/CB".
Active Directory, oh man! "Creating shadow groups that automatically update" will be one interesting topic. "Running AD without Domain Admin rights (aka 'Ditch Admin Rights' @samilaiho)" is my target and it already has risen some serious opinions against it in my current workplace. PKI isn't that hard as you might think.
PowerShell - sure. I'll show you what I did and why. Scripts and tools. I do, when ever possible, everything remotelly and with PS. And PKI with PowerShell is sooo easy.
Sure there will be more topics and posts, in the meanwhile please follow and DM me in Twitter @arisaastamoinen
Subscribe to:
Posts (Atom)