ps/Modules/Alkami.DevOps.Certificates/Public/Export-CertificatesToFileSystem.ps1

168 lines
7.2 KiB
PowerShell
Raw Normal View History

2023-05-30 22:51:22 -07:00
function Export-CertificatesToFileSystem {
<#
.SYNOPSIS
Exports certificates from desired stores (My, CertificateAuthority, Root, and TrustedPeople by default)
onto the file system.
.DESCRIPTION
This script will export all public certificates and private keys in a given store to the file system. The
certificate chain is also exported in an individualized folder along with the certificate so that you
can delineate what certificates are needed for the one exported.
A password is generated for private keys, if ADGroups are given they are assigned to the private keys as well.
This script also returns a model of the data exported. With this model the file system data is more
easily manipulated and was originally intended to be used by a module for uploading these certificates
and their chains to individual secrets in secret server.
.PARAMETER PodName
String
Used to create a leaf folder with in which the certificates will be exported and set as a property
on the model returned as a result of this cmdlet.
.PARAMETER CertRoot
String
Location that this cmdlet will be working out of. This is set to LocalMachine but could be set to Personal
or other certificate providers.
.PARAMETER StoresToExport
StoreName[]
All certificates in these stores will be exported along with their certificate chains and private keys.
.PARAMETER ADGroups
String[]
Any ADGroups or UserAccounts that are given will be assigned to private keys exported. These users
will be able to import the private keys without a password, although one is generated and set
by this cmdlet regardless
.EXAMPLE
Export-CertificatesToFileSystem -PodName "Pod 1.1.1"
Base usage, will export all certificates in the default stores and their private keys to the Default Export Root
Folder under leaf folder 'Pod 1.1.1'. A password will be generated for the private keys and returned to the
caller in the model object.
.EXAMPLE
Export-CertificatesToFileSystem -PodName "Pod 7.0.5" -ADGroups "corp\JSmith","corp\CCarter" -RootExportFolder "C:\Exports"
Will export all certificates in the default stores and their private keys to the C:\Exports
Folder under leaf folder 'Pod 7.0.5'. Users JSmith and CCarter will be able to import the private keys
without the password, however passwords generated for these certificates will be returned with the
model object that this cmdlet produces.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True)]
[string]$PodName,
[Parameter(Mandatory = $False)]
[string]$CertRoot = "Cert:\LocalMachine\",
[Parameter(Mandatory = $False)]
[string]$RootExportFolder = "c:\temp\CertExports",
[Parameter(Mandatory = $False)]
$StoresToExport = @([System.Security.Cryptography.X509Certificates.StoreName]::My,
[System.Security.Cryptography.X509Certificates.StoreName]::CertificateAuthority,
[System.Security.Cryptography.X509Certificates.StoreName]::Root,
[System.Security.Cryptography.X509Certificates.StoreName]::TrustedPeople),
[Parameter(Mandatory = $False)]
[string[]]$ADGroups = ""
)
begin {
$logLead = Get-LogLeadName
$Pod = [PSObject]@{
PodName = $PodName
ExportFolder = (Join-Path $RootExportFolder $PodName)
StoresToExport = $StoresToExport
CertRoot = $CertRoot
Stores = @{ }
}
if (Test-Path -Path $Pod.ExportFolder) {
Write-Host "$logLead : Removing items from $($Pod.ExportFolder) before beginning"
Remove-FileSystemItem -Path $Pod.ExportFolder -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
if (-not (Test-Path -PathType Container -Path $Pod.ExportFolder)) {
New-Item $Pod.ExportFolder -ItemType Directory | Out-Null
}
}
process {
foreach ($storeName in $Pod.StoresToExport) {
$store = [PSObject]@{
Name = $storeName
ExportStorePath = Join-Path $Pod.ExportFolder $storeName
StorePath = Join-Path $Pod.CertRoot $storeName
Certificates = @{ }
}
# Powershell's Paths don't match the X509 enum. So here we do a poor man's lookup. If we ever need more stores than just the CA, this needs to be expanded to something more robust and clean.
if ($store.Name -eq "CertificateAuthority") {
$store.StorePath = "Cert:\LocalMachine\CA"
}
$Pod.Stores.Add($storeName, $store)
$Pod.Stores | Add-Member -MemberType NoteProperty -Name $storeName -Value $store
New-Item $store.ExportStorePath -ItemType Directory | Out-Null
#foreach cert in store
try {
$certificates = Get-ChildItem $store.StorePath;
}
catch {
Write-Warning "Cannot find Certificates in $storeName"
}
if ($certificates.Count -gt 0) {
foreach ($cert in $certificates) {
try {
$exportInfo = Export-CertificateToFileSystem -cert $cert -exportStorePath $store.ExportStorePath -ADGroups $ADGroups
if ($null -eq $exportInfo) { continue }
$chainInfo = Export-CertChain -cert $cert -exportStorePath $store.ExportStorePath -exportCertPath $exportInfo.exportCertPath -ADGroups $ADGroups
$CertificateChain = [PSObject]@{
Folder = Join-Path $exportInfo.ExportCertPath "ChainedCertificates"
Certificates = @{ }
}
foreach ($chainedCert in $chainInfo) {
$CertificateChain.Certificates.Add($chainedCert.certName, $chainedCert)
$CertificateChain.Certificates | Add-Member -MemberType NoteProperty -Name $chainedCert.certName -Value $chainedCert
}
$certificate = [PSObject]@{
Name = $exportInfo.certName
FilePath = $exportInfo.exportCertFile
Folder = $exportInfo.exportCertPath
Password = $exportInfo.certPassword
CertificateChain = $CertificateChain
ADGroups = $exportInfo.ADGroups
ExpirationDate = $exportInfo.ExpirationDate
Thumbprint = $exportInfo.Thumbprint
}
$store.Certificates.Add($certificate.Name, $certificate)
$store.Certificates | Add-Member -MemberType NoteProperty -Name $certificate.Name -Value $certificate
}
catch {
Write-Error "Certificate has failed to export
Name: $($certificate.Name), FriendlyName: $($cert.FriendlyName), Thumprint: $($cert.Thumbprint), Store: $storeName
$($_.Exception) $($_.Message) $($_.ScriptStackTrace)"
}
}
}
}
}
end {
return $Pod
}
}