Export Multiple PFX Certificates using Orchestrator

Following on from my last post, I had to throw this runbook together in order to create a batch of PFX files ready for manual SCCM client installations on *nix systems. The certificate requests needed to be targeted at a CA in the relevant Active Directory forest. (PreProd, Production, or ST).

Overview



The parent runbook imports a list of servers from a CSV containing the hostname and domain name, then invokes a child runbook on the relevant Orchestrator Runbook Server, depending on the domain name.

The CSV is formatted as follows:

Server,Domain
HOST1,PROD
HOST2,PREPROD



Runbook Activity's

  • Initialize Data: Nothing configured here yet.
  • Read Line: Pointed at the location of the CSV file.



  • GetRecords: PowerShell to ingest each line from the CSV and published to the Orchestrator data bus with $ArrayList variable.
$ArrayList = @()

@"
{Line text from "Read Line"}
"@.Split("'`n") | foreach {
   $ArrayList += "$_"
}

  • ProcessRecords: PowerShell to split the $ArrayList string into individual variables ready to be used for subsequent activity's.

$Computer= "[Field({ArrayList from "GetRecords"},',',1)]"
$Domain= "[Field({ArrayList from "GetRecords"},',',2)]"


  • Invoke the Request PFX Runbook: This runbook will be run on the corresponding Orchestrator Runbook Server depending on the 'Domain' value.


(The Server name is translated into the CN parameter.)
  • Request and Export PFX Certificate
The 'Domain' and 'Server' values from the CSV are parsed into the script which ultimately exports a PFX file to D:\SCORCH ready to be transferred to the target Linux system and used during SCCM client installation.

This is the contents of the PowerShell 'Run .Net Script' activity.
  • Define variables using values from the Orchestrator data bus:

  • Determine the issuing CA server and Certificate Template name using the 'Domain' Initialize Data value.
if ($Domain -like "PREPROD")
{
$CAName = "#SERVERNAME#\PreProd CA"
$TemplateName = "ConfigMgrClientCertificateforExport"
}
elseif ($Domain -like "PROD")
{
$CAName = "#SERVERNAME#\IssuingCA"
$TemplateName = "ConfigMgrClientCertificateforExport"
}
elseif ($Domain -like "ST")
{
$CAName = "#SERVERNAME#\ST CA"
$TemplateName = "ConfigMgrClientCertificateforExport"
}

  • Define a function to remove temporary certificate request files.
function Remove-ReqTempfiles()
{
param(
[String[]]$tempfiles
)
Write-Verbose "Cleanup temp files and pending requests"
    
#delete pending request (if a request exists for the CN)
$certstore = new-object system.security.cryptography.x509certificates.x509Store('REQUEST', 'LocalMachine')
$certstore.Open('ReadWrite')
foreach($certreq in $($certstore.Certificates))
{
if($certreq.Subject -eq "CN=$CN")
{
$certstore.Remove($certreq)
}
}
$certstore.close()

foreach($file in $tempfiles){remove-item ".\$file" -ErrorAction silentlycontinue}
}

  • Remove temporary request files (in case left over from previous requests)
Remove-ReqTempfiles -tempfiles "certreq.inf","certreq.req","$CN.cer","$CN.rsp"
  • Build certificate request file
$file = @"
[NewRequest]
Subject = "CN=$CN"
MachineKeySet = TRUE
KeyLength = 2048
Exportable = TRUE
[RequestAttributes]
CertificateTemplate = "$TemplateName"
"@

Set-Content .\certreq.inf $file
  • Submit certificate request and add to local cert store.
Invoke-Expression -Command "certreq -new certreq.inf certreq.req"
Invoke-Expression -Command "certreq -submit -config `"$CAName`" certreq.req $CN.cer"
Invoke-Expression -Command "certreq -accept $CN.cer"

  • Export PFX file to D:\SCORCH directory
$certpath = "d:\SCORCH\$CN.pfx"
Invoke-Expression -Command "certutil -privatekey -exportPFX -p 'Password' my $CN $certpath"
  • Remove certificate from local cert store, and remove temporary files.
$cert = Get-Childitem "cert:\LocalMachine\My" | where-object {$_.Thumbprint -eq (New-Object System.Security.Cryptography.X509Certificates.X509Certificate2((Get-Item "$CN.cer").FullName,"")).Thumbprint}

$certstore = new-object system.security.cryptography.x509certificates.x509Store('My', 'LocalMachine')
$certstore.Open('ReadWrite')
$certstore.Remove($cert)
$certstore.close() 

Remove-ReqTempfiles -tempfiles "certreq.inf","certreq.req","$CN.cer","$CN.rsp"


The PFX file will be located on each Orchestrator server in the D:\SCORCH directory, which then needs to be manually copied to where ever it's needed.



0 comments:

Post a Comment

About Me

My photo
Senior Consultant at CDW UK specialising in Microsoft workspace and cloud technologies.