X509Store.Open() 抛出异常

X509Store.Open() throwing an Exception

为什么 $store.Open($openFlags) 抛出异常,有没有比我的 "work around" 更好的方法让它工作?

<#
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Cert:\CurrentUser\My")
$openFlags = [System.Security.Cryptography.X509Certificates.OpenFlags]::MaxAllowed

$store.Open($openFlags) #Exception calling "Open" with "1" argument(s): "The parameter is incorrect.
#>

#Work Around:
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Cert:\CurrentUser\My")
$openFlags = [System.Security.Cryptography.X509Certificates.OpenFlags]::MaxAllowed

$startIndexOfStoreName = $store.Name.LastIndexOf("\") + 1
$lengthOfStoreName = $store.Name.Length - $startIndexOfStoreName
$storeNameString = $store.Name.Substring($startIndexOfStoreName, $lengthOfStoreName)
$storeName = [System.Security.Cryptography.X509Certificates.StoreName]$storeNameString
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store($storeName, $store.Location)

$store.Open($openFlags) #No Exception thrown!

更新: 似乎在使用 X509Store(String) 构造函数时,不允许使用任何斜杠(如果我错了请纠正我)。所以 $store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My") 有效。

使用

定义您的证书存储
$store = Get-Item "Cert:\CurrentUser\My"

而不是

$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Cert:\CurrentUser\My")

老实说,我仍在努力弄清楚它为何起作用或如何起作用。

第一种方法 returns 一个名为 "My" 的 $store,所以我假设它专门针对商店,您可以使用

打开它
$store.Open($openFlags)

第二种方法 returns 一个名为 "Cert:\CurrentUser\My" 的 $store。对此的打开方法将失败。

其实你是在混方法。一种是通过提供商 (Cert:),另一种是 .Net 类型 (X509Store)。附加到证书商店和提取证书详细信息的过程非常不同。

将 "Cert:" 想象成 PSDrive(它基本上就是)。所以你可以get-childitem等,不需要"open"商店。在这种思维方式下,证书存储位置是文件夹,证书是单个对象:

# List the store locations
gci Cert:\
# List store names in CurrentUser store location
gci Cert:\CurrentUser
# List certs in the My store of CurrentUser store location
gci Cert:\CurrentUser\My | format-list

使用 Cert: 提供程序的要点是,如果您想在远程系统上使用证书,则需要启用远程处理 (WinRM),这样您就可以 "Invoke-Command"。并非每个环境都允许这样做。这就是 .Net X509Store 的用武之地。不确定它与 "CurrentUser" 的配合情况如何,但我从来没有担心过这一点 - 我对 "LocalMachine" 商店中的内容更感兴趣(特别是"My" 因为那是系统保存 web 和 auth 证书的地方)。修改后的代码段以列出这些证书(从我为询问 SharePoint 场中的所有服务器而构建的脚本中提取)。

# Change as necessary
$strTarget = $env:computername
$strCertStoreLocation = 'LocalMachine'
$strCertStoreName = 'My'
# Set up store parameters, connect and open store
[System.Security.Cryptography.X509Certificates.StoreLocation]$strStoreLoc = [String]$strCertStoreLocation
[System.Security.Cryptography.X509Certificates.StoreName]$strStoreName = [String]$strCertStoreName
$objCertStore  = New-Object System.Security.Cryptography.X509Certificates.X509Store -ArgumentList "\$($strTarget)$($strStoreName)", $strStoreLoc
$objCertStore.Open('ReadOnly')

# List cert details in bulk
$objCertStore.Certificates | Format-List
# List specific props
foreach ($Cert in $objCertStore.Certificates) {
    "Subject: $($Cert.Subject)"
    "Issuer:  $($Cert.Issuer)"
    "Issued:  $($Cert.NotBefore)"
    "Expires: $($Cert.NotAfter)"
    ""
}

有关每个的更多详细信息,请访问您最喜欢的技术存储库(MSDN、PowerShell.org、嘿脚本专家等):)

我想对此发表评论,因为正如前面的示例中已经指出的那样,"the mixing of .NET Framework and the use of PowerShell Providers"。对我来说,我需要它作为一种纯 .NET 的方式来获取证书来测试一些 C# 等效代码,而无需用户计算机上的完整开发环境。

这是我想出的方法:

$Location = [Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
$StoreName = [Security.Cryptography.X509Certificates.StoreName]::My
$Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $StoreName, $Location
$OpenFlags = [System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly
$Store.Open($OpenFlags)
$Store.Certificates