internal/functions/Get-ADCertificate.ps1
function Get-ADCertificate { <# .SYNOPSIS Returns forest certificates. .DESCRIPTION Returns forest certificates. .PARAMETER Parameters Hashtable containing AD connection values. May contain Server and Credential nodes but nothing else. .PARAMETER Type The kind of certificate to retrieve .EXAMPLE PS C:\> Get-ADCertificate -Parameters $parameters -Type NTAuthCA Returns all NTAuth certificates in the targeted forest. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [hashtable] $Parameters, [Parameter(Mandatory = $true)] [ValidateSet('NTAuthCA', 'RootCA', 'SubCA', 'CrossCA', 'KRA')] [string] $Type ) begin { #region Utility Functions function Get-CertificateInternal { [CmdletBinding()] param ( [string] $Object, [string] $Path, [string] $AltPath, [string] $NotInPath, [string] $AttributeName = 'cACertificate', [System.Collections.Hashtable] $Parameters ) #region Single Object Processing if ($Object -eq 'Single') { try { $adObject = Get-ADObject @Parameters -Identity $Path -ErrorAction Stop -Properties $AttributeName } catch { return } # Object doesn't exist foreach ($certData in $adObject.$AttributeName) { $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certData) [pscustomobject]@{ Certificate = $certificate Subject = $certificate.Subject Thumbprint = $certificate.Thumbprint ADObject = $adObject AltADObject = $null AttributeName = $AttributeName } | Add-Member -MemberType ScriptMethod -Name ToString -Value { '{0} (<{1:yyyy-MM-dd})' -f $this.Subject, $this.Certificate.NotAfter } -Force -PassThru } return } #endregion Single Object Processing $adObjects = Get-ADObject @Parameters -SearchBase $Path -SearchScope OneLevel -Filter * -ErrorAction Stop -Properties $AttributeName $existingCerts = foreach ($adObject in $adObjects) { foreach ($certData in $adObject.$AttributeName) { if (-not $certData) { continue } $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certData) [pscustomobject]@{ Certificate = $certificate Subject = $certificate.Subject Thumbprint = $certificate.Thumbprint ADObject = $adObject AltADObject = $null AttributeName = $AttributeName } | Add-Member -MemberType ScriptMethod -Name ToString -Value { '{0} (<{1:yyyy-MM-dd})' -f $this.Subject, $this.Certificate.NotAfter } -Force -PassThru } } #region AltPath # Contained in the original container and ALSO in the alternative container (e.g. RootCA Certificate) if ($AltPath) { $altAdObjects = Get-ADObject @Parameters -SearchBase $AltPath -SearchScope OneLevel -Filter * -ErrorAction Stop -Properties $AttributeName foreach ($adObject in $altAdObjects) { $certificates = foreach ($certData in $adObject.$AttributeName) { if (-not $certData) { continue } [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certData) } foreach ($existingCert in $existingCerts) { if ($existingCert.Thumbprint -notin $certificates.Thumbprint) { continue } $existingCert.AltADObject = $adObject } } $existingCerts = $existingCerts | Where-Object AltADObject } #endregion AltPath #region NotInPath # Contained in the original container and NOT in the alternative container (e.g. SubCA Certificate) if ($NotInPath) { $notInAdObjects = Get-ADObject @Parameters -SearchBase $NotInPath -SearchScope OneLevel -Filter * -ErrorAction Stop -Properties $AttributeName $certificates = foreach ($adObject in $notInAdObjects) { foreach ($certData in $adObject.$AttributeName) { if (-not $certData) { continue } [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certData) } } $existingCerts = $existingCerts | Where-Object Thumbprint -NotIn $certificates.Thumbprint } #endregion NotInPath $existingCerts } #endregion Utility Functions $rootDSE = Get-ADRootDSE @parameters $mapping = @{ NTAuthCA = @{ Object = 'Single' Path = "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" } RootCA = @{ Object = 'Multi' Path = "CN=Certification Authorities,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" AltPath = "CN=AIA,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" } SubCA = @{ Object = 'Multi' Path = "CN=AIA,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" NotInPath = "CN=Certification Authorities,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" } CrossCA = @{ Object = 'Multi' Path = "CN=AIA,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" AttributeName = 'crossCertificatePair' } KRA = @{ Object = 'Multi' Path = "CN=KRA,CN=Public Key Services,CN=Services,$($rootDSE.configurationNamingContext)" AttributeName = 'userCertificate' } } } process { $table = $mapping[$type] Get-CertificateInternal -Parameters $parameters @table } } |