Reputation: 499
I need to use a PowerShell script to pick the certificate with "Certificate Template Name" as "Machine." In certmgr.msc, this has "Certificate Template" with value of "Computer." In Details, the same one has "Certificate Template Name" as "Machine."
How can I use either of these values in a PowerShell script?
Thus far, I have:
get-childitem cert:\localmachine\my | where-object {$_.}
I've tried just about every method that intellisense loads, but have not been able to find anything that meets my needs.
Thank You,
Upvotes: 9
Views: 40524
Reputation: 13588
All current answers assume, that you can parse the template name from one of the following OIDs:
OID | FriendlyName |
---|---|
1.3.6.1.4.1.311.20.2 | Certificate Template Name |
1.3.6.1.4.1.311.21.7 | Certificate Template Information |
In my case, the certificate does not contain the extension "Certificate Template Name". It does contain the extension "Certificate Template Information" though, but I cannot parse a name from it, because it does only contain the OID of the template. So, as Mathias R. Jessen already mentioned in the comments, you have to look this OID up in your AD to get the template name.
As a workaround (not every machine has access to the Get-ADObject
cmdlet), you can use certutil
to do the lookup for you:
certutil -store My "Computer*" | Select-String -Pattern '\(sha1\): ' | ForEach-Object {$_ -split ' ' | Select-Object -Last 1 | ForEach-Object {Get-ChildItem -Path "Cert:\LocalMachine\*$_" -Recurse}}
certutil
will print all certificates of the "My" certificate store which use a template that begins with Computer
. From the output, I parse the thumbprint of the certificate and use that to look the certificate up again in the store.
Upvotes: 1
Reputation: 4382
In addition to the answers already posted, let me share what works for me:
# Example usage:
# ls 'Cert:\LocalMachine\My' | ForEach-Object { Get-CertificateTemplateName $_ }
#
function Get-CertificateTemplateName($certificate)
{
# The template name is stored in the Extension data.
# If available, the best is the extension named "Certificate Template Name", since it contains the exact name.
$templateExt = $certificate.Extensions | Where-Object{ ( $_.Oid.FriendlyName -eq 'Certificate Template Name') } | Select-Object -First 1
if($templateExt) {
return $templateExt.Format(1)
}
else {
# Our fallback option is the "Certificate Template Information" extension, it contains the name as part of a string like:
# "Template=Web Server v2(1.3.6.1.4.1.311.21.8.2499889.12054413.13650051.8431889.13164297.111.14326010.6783216)"
$templateExt = $certificate.Extensions | Where-Object{ ( $_.Oid.FriendlyName -eq 'Certificate Template Information') } | Select-Object -First 1
if($templateExt) {
$information = $templateExt.Format(1)
# Extract just the template name in $Matches[1]
if($information -match "^Template=(.+)\([0-9\.]+\)") {
return $Matches[1]
} else {
# No regex match, just return the complete information then
return $information
}
} else {
# No template name found
return $null
}
}
}
Upvotes: 3
Reputation: 499
Here is a solution sans-modules:
$templateName = 'Super Cool *'
Get-ChildItem 'Cert:\LocalMachine\My' | Where-Object{ $_.Extensions | Where-Object{ ($_.Oid.FriendlyName -eq 'Certificate Template Information') -and ($_.Format(0) -match $templateName) }}
Upvotes: 9
Reputation: 46
$cert.Extension.format(0) and format(1) will return these attributes in a human-readable manner.
# Retrieves CRL distribution point if present
function Get-CRLDistPoint {
Param ($cert)
$extension = $cert.Extensions | where {$_.OID.FriendlyName -eq "CRL Distribution Points"}
if ($extension) {
$crlURL = $extension.Format(0)
# trim header
$crlURL = $crlURL -replace "^.*URL=", ""
}
$crlURL
}
Get-ChildItem Cert:\LocalMachine\my | %{ Get-CRLDistPoint}
Upvotes: 1
Reputation: 3181
Here's a native PowerShell solution:
Thanks go to the PowerShell Gallery
<#
.SYNOPSIS
Outputs an object consisting of the template name (Template), an OID (OID), the minor version (MinorVersion), and the major version (MajorVersion).
.DESCRIPTION
Outputs an object consisting of the template name (Template), an OID (OID), the minor version (MinorVersion), and the major version (MajorVersion).
This information is derived from the Certificate Extensions.
.PARAMETER Certificate
A X509Certificate2 object
.EXAMPLE
Get-ChildItem "Cert:\LocalMachine\My" | Get-CertificateTemplate
.EXAMPLE
Get-ChildItem "Cert:\LocalMachine\My" | Select-Object Name,Thumbprint,@{Name="Template";Expression={Get-CertificateTemplate $_}}
.INPUTS
Any X509Certificate2 object
.OUTPUTS
[PSCustomObject] @{Template=<template name; OID=<oid string>; MajorVersion=<major version num>; MinorVersion=<minor version num> }
#>
function Get-CertificateTemplate {
[CmdletBinding(SupportsShouldProcess=$false)]
[OutputType([string])]
Param([Parameter(Mandatory=$true, ValueFromPipeline=$true)] [ValidateNotNull()] [Security.Cryptography.X509Certificates.X509Certificate2]$Certificate)
Process {
$regExPrimary=[System.Text.RegularExpressions.Regex]::new("Template=([\w\s\d\.]+)\(((?:\d+.)+)\), Major Version Number=(\d+), Minor Version Number=(\d+)",[System.Text.RegularExpressions.RegexOptions]::None)
$regExSecondary=[System.Text.RegularExpressions.Regex]::new("Template=((?:\d+.)+), Major Version Number=(\d+), Minor Version Number=(\d+)",[System.Text.RegularExpressions.RegexOptions]::None)
$temp = $Certificate.Extensions | Where-Object { $_.Oid.FriendlyName -eq "Certificate Template Name" }
if ($temp -eq $null) {
Write-Verbose "Did not find 'Certificate Template Name' extension"
$temp=$Certificate.Extensions | Where-Object { $_.Oid.Value -eq "1.3.6.1.4.1.311.21.7" }
}
else { Write-Verbose "Found 'Certificate Template Name' extension" }
$Matches=$regExPrimary.Matches($temp.Format($false))
if ($Matches.Count -gt 0) {
$object=@{Template=$Matches[0].Groups[1].Value; OID=$Matches[0].Groups[2].Value;
MajorVersion=$Matches[0].Groups[3].Value; MinorVersion=$Matches[0].Groups[4].Value;
Thumbprint=$Certificate.Thumbprint }
}
else {
$Matches=$regExSecondary.Matches($temp.Format($false))
if ($Matches.Count -gt 0) {
Write-Verbose "Found certificate without a valid Template Name"
$object=@{Template=$Matches[0].Groups[1].Value; OID=$Matches[0].Groups[1].Value;
MajorVersion=$Matches[0].Groups[2].Value; MinorVersion=$Matches[0].Groups[3].Value;
Thumbprint=$Certificate.Thumbprint }
}
else {
Write-Verbose "Found root certificate"
$object=@{Template="Root Certificate"; OID=""; MajorVersion=""; MinorVersion=""; Thumbprint=$Certificate.Thumbprint }
}
}
return [PSCustomObject]$object
}
}
Upvotes: 1
Reputation: 674
Try this powershell module CertificatePS. Inside there is this cmdlet Get-CertificateTemplate
that does exactly what you need. I developed it and I use it myself to distinguish between machine and web template certificates.
This is an example of use although there are other possibilities such as adding a PSNoteProperty into each return object
# With Select-Object
Get-ChildItem "Cert:\LocalMachine\My" | Select-Object Name,Thumbprint,@{Name="Template";Expression={Get-CertificateTemplate $_}}
# With Where-Object
Get-ChildItem "Cert:\LocalMachine\My" | Where-Object {Get-CertificateTemplate $_ -eq "Template"}}
Check out more examples about this module here.
The module is not perfect so if you have any feedback or contributions please do so on the github project.
Upvotes: 0