Public/Import-ServiceCertificate.ps1
<#
.SYNOPSIS Imports a certificate to the specified services of a system. .DESCRIPTION This CMDLET will import a PFX certificate with private key to a Service Account's Certificate Store. .PARAMETER PFXFile Path to the certificate file. .PARAMETER PFXPassword Password for the certificate file. Make sure to enter it as a secure string. .PARAMETER Service The available services on the system to import the certificate to. .PARAMETER KeepInLocalMachine This will keep a copy of the certificate in the Local Machine Store: LocalMachine\My. .EXAMPLE Import-ServiceCertificate -PFXFile Cert.PFX -Service NTDS -PFXPassword (ConvertTo-SecureString -String 'Test' -AsPlainText -Force) This example will take the certificate and specified password and import it to the Active Directory Domain Services Certificate Store .NOTES Current versions of PowerShell breaks the tab completion of the Service Parameter if the Password parameter is called first. Make sure to always call the service parameter before the password one. #> function Import-ServiceCertificate { [CmdletBinding()] #Requires -RunAsAdministrator param( [Parameter(Mandatory, HelpMessage = "The path to the PFX Certificate File.")] [string]$PFXFile, [Parameter(Mandatory, HelpMessage = "The password of the certificate to import.")] [System.Security.SecureString]$PFXPassword, [Parameter(HelpMessage = "Keep the certificate in the local machine certificate store.")] [switch]$KeepInLocalMachine ) DynamicParam { $ParameterName = 'Service' $RuntimeParameterDirectory = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $true $ParameterAttribute.HelpMessage = "List of service available on this system." $AttributeCollection.Add($ParameterAttribute) $arrSet = (Get-CimInstance -ClassName Win32_Service).Name $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) $AttributeCollection.Add($ValidateSetAttribute) $AttributeAlias = New-Object System.Management.Automation.AliasAttribute('Serv', 'S') $AttributeCollection.Add($AttributeAlias) $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [array], $AttributeCollection) $RuntimeParameterDirectory.Add($ParameterName, $RuntimeParameter) return $RuntimeParameterDirectory } begin { $Service = $PSBoundParameters[$ParameterName] Write-Verbose -Message "Importing PFX file." $PFXObject = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2($PFXFile, $PFXPassword, "Exportable,MachineKeySet,PersistKeySet") $Thumbprint = $PFXObject.Thumbprint Write-Verbose -Message "Getting list of available services" $RootServicePath = 'HKLM:\SOFTWARE\Microsoft\Cryptography\Services' $LocalMachinePath = "HKLM:\SOFTWARE\Microsoft\SystemCertificates\MY\Certificates" $Services = $Service | ForEach-Object { Get-CimInstance -ClassName Win32_Service -Filter "Name = '$_'" } $LocalMachineCertPath = Join-Path -Path $LocalMachinePath -ChildPath $Thumbprint } process { Write-Verbose -Message "Importing certificate into LocalMachine\Personal" $certificateStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store('My', 'LocalMachine') $certificateStore.Open('MaxAllowed') $certificateStore.Add($PFXObject) $certificateStore.Close() foreach ($S in $Services) { $Name = $S.Name Write-Verbose "Verifying registry path for the service." $ServicePath = Get-Item -Path "$RootServicePath\$Name\SystemCertificates\My\Certificates\" -ErrorAction SilentlyContinue If (!$ServicePath) { try { New-Item -Path "$RootServicePath\$Name\SystemCertificates\My\Certificates\" -ItemType Key -ErrorAction Stop -Force } catch [System.Management.Automation.ActionPreferenceStopException] { try { Write-ErrorMessage -ExceptionType "System.Exception" ` -Message "Requested registry access is not allowed." ` -Category "PermissionDenied" ` -CategoryActivity "New-Item" ` -TargetType "Microsoft.Win32.RegistryKey" ` -Source "$ServicePath\$Name" ` -ErrorId "RegistryAccessDenied" } Catch { $PSCmdlet.ThrowTerminatingError($PSItem) } } } Write-Verbose -Message "Copying certificate to $($S.DisplayName)" $CopyParam = @{ Path = "$LocalMachineCertPath" Destination = "$RootServicePath\$Name\SystemCertificates\My\Certificates\$Thumbprint" Recurse = $true } Copy-Item @CopyParam try { Add-CertificatePrivateKeyPermission -Thumbprint $Thumbprint -Identity $($S.StartName) -Permission ReadAndExecute } catch { $PSCmdlet.ThrowTerminatingError($PSItem) } } } end { if (!$KeepInLocalMachine) { Write-Verbose -Message "Perform cleanup of certificate stores." $removalParameters = @{ 'Path' = "$LocalMachineCertPath" 'Recurse' = $true } Remove-Item @removalParameters } } } |