简体   繁体   中英

X509Store.Open() throwing an Exception

why does $store.Open($openFlags) throw an exception, and is there a better way than my "work around" to make it work?

<#
$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!

Update: Seems as though when using the X509Store(String) constructor, you are NOT allowed to have any slashes (correct me if I'm wrong). So $store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My") works.

Define you certificate store using

$store = Get-Item "Cert:\CurrentUser\My"

instead of

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

To be honest I'm still trying to figure out why it works, or how.

The first method returns a $store called "My", so I'm assuming that it targets the store specifically and you can open it with

$store.Open($openFlags)

The second method returns a $store called "Cert:\\CurrentUser\\My". Open method on this will fail.

I wanted to comment on this, since, as is already pointed out, "the mixing of .NET Framework and the use of PowerShell Providers" in the previous examples. For me, I needed this to work as a pure .NET way of getting the certs to test out some C# equivalent code without the full development environment on a users computer.

Here's what I came up with, which worked:

$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

Actually, you are mixing methods. One is via a provider (Cert:) the other is a .Net type (X509Store). Very different processes for attaching to the cert stores and pulling cert details.

Think of "Cert:" like a PSDrive (which it basically is). So you can get-childitem, etc. and don't need to "open" the store. In this mindset, the cert store locations are folders, and certs are individual objects:

# 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

The catch to using the Cert: provider is that if you want to work with certs on remote systems, remoting (WinRM) needs to be enabled so you can "Invoke-Command". Not every environment allows this. That is where the .Net X509Store comes in. Not sure how well it works with "CurrentUser", but I've never been concerned about that - I am more interested in what is in the "LocalMachine" stores (specifically "My" since that is where the system holds web and auth certs). Modified snippet to list these certs (pulled from a script I built for interrogating all the servers in SharePoint farms).

# 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)"
    ""
}

For a bit more details about each, hit up your favorite tech repository (MSDN, PowerShell.org, Hey Scripting Guy, etc.) :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM