鉴于证书指纹,我想找到本地文件系统上证书的绝对文件路径。
这个片段几乎总是有效。
$thumb = <mythumbprint string>
$cert = Get-ChildItem "Cert:\LocalMachine\My" | Where-Object {$_.Thumbprint -eq $thumb};
$keyName = (($cert.PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
$keyPath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"
$fullPath = $keyPath+$keyName
在PrivateKey不可导出的证书上失败。标记为NOT Exportable时,$cert.PrivateKey
不再可访问,因此无法构建证书的完整路径。
是否有用于确定证书的UniqueKeyContainerName的powershell替代方案?
更新 我关注的所有证书都有私钥。问题是我不能假设它们被标记为可导出。如果未标记为可导出,则无法引用.PrivateKey。我需要另一种方法来获取UniqueKeyContainerName而不链接.Privatekey
答案 0 :(得分:0)
关于此主题的有用信息似乎很少,更不用说 PowerShell 5.1 和 7.1 (.NET Core)。希望这 helps 个人。
我改编自 Vadims Podāns 'Retrieve CNG key container name and unique name'
请注意:
Get-Item 'Cert:\LocalMachine\My\FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' | Get-CertificateContainerAbsolutePath
if(-not ('EmbeddedTemporary.PKITools' -as [type])) {
$PKIToolsDefinition = @"
[DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CertGetCertificateContextProperty(
IntPtr pCertContext,
uint dwPropId,
IntPtr pvData,
ref uint pcbData
);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CRYPT_KEY_PROV_INFO {
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszContainerName;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszProvName;
public uint dwProvType;
public uint dwFlags;
public uint cProvParam;
public IntPtr rgProvParam;
public uint dwKeySpec;
}
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptOpenStorageProvider(
ref IntPtr phProvider,
[MarshalAs(UnmanagedType.LPWStr)]
string pszProviderName,
uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptOpenKey(
IntPtr hProvider,
ref IntPtr phKey,
[MarshalAs(UnmanagedType.LPWStr)]
string pszKeyName,
uint dwLegacyKeySpec,
uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptGetProperty(
IntPtr hObject,
[MarshalAs(UnmanagedType.LPWStr)]
string pszProperty,
byte[] pbOutput,
int cbOutput,
ref int pcbResult,
int dwFlags
);
[DllImport("ncrypt.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int NCryptFreeObject(
IntPtr hObject
);
"@
Add-Type -MemberDefinition $PKIToolsDefinition -Namespace 'EmbeddedTemporary' -Name 'PKITools'
}
Function Get-CertificateContainerAbsolutePath {
[CmdletBinding()]
Param(
[Parameter(Mandatory,ValuefromPipeline)]
$Certificate
)
$CERT_KEY_PROV_INFO_PROP_ID = 0x2 # from Wincrypt.h header file
$pcbData = 0
[EmbeddedTemporary.PKITools]::CertGetCertificateContextProperty($Certificate.Handle, $CERT_KEY_PROV_INFO_PROP_ID, [IntPtr]::Zero, [ref]$pcbData) | Out-Null
$pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbData)
[EmbeddedTemporary.PKITools]::CertGetCertificateContextProperty($Certificate.Handle, $CERT_KEY_PROV_INFO_PROP_ID, $pvData, [ref]$pcbData) | Out-Null
$keyProv = [Runtime.InteropServices.Marshal]::PtrToStructure($pvData, [type][EmbeddedTemporary.PKITools+CRYPT_KEY_PROV_INFO])
[Runtime.InteropServices.Marshal]::FreeHGlobal($pvData) | Out-Null
$CngProvider = [System.Security.Cryptography.CngProvider]::new($keyProv.pwszProvName)
$CngKey = [System.Security.Cryptography.CngKey]::Open($keyProv.pwszContainerName, $CngProvider, [System.Security.Cryptography.CngKeyOpenOptions]::MachineKey)
$UniqueName = $CngKey.UniqueName
$CngKey.Dispose()
$Certificates = Get-ChildItem -Path (Join-Path -Path $Env:ProgramData -ChildPath 'Microsoft\Crypto') -Recurse -Filter $UniqueName
$Certificates.FullName
}
答案 1 :(得分:-1)
如果我关注您,您可以过滤具有HasPrivateKey的证书:
Get-ChildItem Cert:\LocalMachine\my |
Where-Object {$_.Thumbprint -eq $thumb -and $_.HasPrivateKey} | ForEach-Object {
Join-Path $env:ProgramData\Microsoft\Crypto\RSA\MachineKeys $_.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
}