View All Certificates On Smart Card

前端 未结 4 1252
无人共我
无人共我 2020-12-21 04:51

I am trying to create a script to remove all but the newest certificate from any given smart card (in the SC Reader at the time). This is something that I intend to be abl

相关标签:
4条回答
  • A complete example to convert mstest coverage file into an xml file is provided below. This example includes passing of parameters and a way to identify the current script location.

    <#
    .SYNOPSIS
        Script to convert code coverage report into xml format that can then be published by external tools.
    
    .DESCRIPTION
        Covering code coverage staistics as part of quality improvement initiatives .
    
        https://stackoverflow.com/questions/30215324/vstest-code-coverage-report-in-jenkins
    #>
    Param(
        [String] $InputCoveragePath =@("..\GeneratedFiles\Docs\Reports"),
        [String] $OutputCoverageFileExtension =@(".coveragexml"),
        [String] $CoverageAnalysisAssembly =@("Microsoft.VisualStudio.Coverage.Analysis.dll"),
        [String[]] $ExecutablePaths =@(""),
        [String[]] $SymbolPaths =@("")
    )
        $ScriptLocation = Split-Path $script:MyInvocation.MyCommand.Path -Parent
        Write-Host $ScriptLocation
    <#
        if(!(Test-Path "$OutputCoverageFile")){
            Write-Host "Creating empty coveragle file $OutputCoverageFile"
            New-Item "$OutputCoverageFile" -ItemType "file" 
        }
    #>
    
    $RunAs32Bit = {
        Param(
            [String] $InputCoveragePath =@("..\GeneratedFiles\Docs\Reports"),
            [String] $OutputCoverageFileExtension =@(".coveragexml"),
            [String] $CoverageAnalysisAssembly =@("Microsoft.VisualStudio.Coverage.Analysis.dll"),
            [String[]] $ExecutablePaths =@(""),
            [String[]] $SymbolPaths =@(""),
            [String] $ScriptLocation =@(".")
        )
        Write-Host "[CoverageConverter][Begin]: Coverage conversion started..."
    
        Write-Host "[CoverageConverter][InputCoveragePath]: $InputCoveragePath"
        Write-Host "[CoverageConverter][OutputCoverageFileExtension]: $OutputCoverageFileExtension"
        Write-Host "[CoverageConverter][CoverageAnalysisAssembly]: $CoverageAnalysisAssembly"
        Write-Host "[CoverageConverter][ExecutablePaths]: $ExecutablePaths"
        Write-Host "[CoverageConverter][SymbolPaths]: $SymbolPaths"
        Write-Host "[CoverageConverter][ScriptLocation]: $ScriptLocation"
        
        Import-Module -Force -Name (Join-Path "$ScriptLocation" "Utilities.psm1")
        Add-Type -path "$CoverageAnalysisAssembly"
    
        $Result = 0
        if($InputCoveragePath -and (Test-Path "$InputCoveragePath") )
        {
            [string[]] $coverageFiles = $(Get-ChildItem -Path $InputCoveragePath -Recurse -Include *coverage)
            
            @($coverageFiles) | ForEach-Object {
                $coverageFile = $_
                $coverageFileOut = (Join-Path -Path $(Split-Path $_ -Parent) -ChildPath  ($(Get-Item $_).BaseName + "$OutputCoverageFileExtension"))
    
                Write-Host "If all OK the xml will be written to: $coverageFileOut"
    
                $info = [Microsoft.VisualStudio.Coverage.Analysis.CoverageInfo]::CreateFromFile($coverageFile, $ExecutablePaths, $SymbolPaths);
                if($info){
                    $data = $info.BuildDataSet()
                    $data.WriteXml($coverageFileOut)
                }
            }
        }
        else
        {
            Write-Host "Please specify a valid input coverage file."
            $Result = 1
        }
    
        Write-Host "[CoverageConverter][End]: Coverage conversion completed with result $Result"
        return $Result  
    }
    
    #Run the code in 32bit mode if PowerShell isn't already running in 32bit mode
    If($env:PROCESSOR_ARCHITECTURE -ne "x86"){
        Write-Warning "Non-32bit architecture detected, processing original request in separate 32bit process."
        $Job = Start-Job $RunAs32Bit -RunAs32 -ArgumentList ($InputCoveragePath, $OutputCoverageFileExtension, $CoverageAnalysisAssembly, $ExecutablePaths, $SymbolPaths, $ScriptLocation)
        $Result = $Job | Wait-Job | Receive-Job
    }Else{
        $Result = Invoke-Command -ScriptBlock $RunAs32Bit -ArgumentList ($InputCoveragePath, $OutputCoverageFileExtension, $CoverageAnalysisAssembly, $ExecutablePaths, $SymbolPaths, $ScriptLocation)
    }
    
    0 讨论(0)
  • 2020-12-21 05:04

    So my solution was to check if the powershell session is running in 32 or 64 bit mode, and if it is running in 64 bit mode (most likely) then it will run the original script as a job using the -RunAs32 argument switch. If it's already running in 32 bit mode it will simply invoke the scriptblock in the current session. Final script to get certificates off a smart card (as an x509 Certificate Store) ended up being:

    $RunAs32Bit = {
    [string]$providerName ="Microsoft Base Smart Card Crypto Provider"
    # import CrytoAPI from advapi32.dll
    $signature = @"
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptGetProvParam(
        IntPtr hProv,
        uint dwParam,
        byte[] pbProvData,
        ref uint pdwProvDataLen, 
        uint dwFlags); 
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptDestroyKey(
        IntPtr hKey);   
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptAcquireContext(
        ref IntPtr hProv,
        string pszContainer,
        string pszProvider,
        uint dwProvType,
        long dwFlags);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptGetUserKey(
        IntPtr hProv, 
        uint dwKeySpec,
        ref IntPtr phUserKey);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptGetKeyParam(
        IntPtr hKey,
        uint dwParam,
        byte[] pbData,
        ref uint pdwDataLen,
        uint dwFlags);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    
    public static extern bool CryptReleaseContext(
        IntPtr hProv,
        uint dwFlags);
    "@
    
    $CryptoAPI = Add-Type -member $signature -name advapiUtils -Namespace CryptoAPI -passthru
    
    # set some constants for CryptoAPI
    $AT_KEYEXCHANGE = 1
    $AT_SIGNATURE = 2
    $PROV_RSA_FULL = 1
    $KP_CERTIFICATE = 26
    $PP_ENUMCONTAINERS = 2
    $PP_CONTAINER = 6
    $PP_USER_CERTSTORE = 42
    $CRYPT_FIRST = 1
    $CRYPT_NEXT = 2
    $CRYPT_VERIFYCONTEXT = 0xF0000000
    
    [System.IntPtr]$hProvParent=0
    $contextRet = $CryptoAPI::CryptAcquireContext([ref]$hprovParent,$null,$providerName,$PROV_RSA_FULL,$CRYPT_VERIFYCONTEXT)
    
    [Uint32]$pdwProvDataLen = 0
    [byte[]]$pbProvData = $null
    $GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$pbProvData,[ref]$pdwProvDataLen,0)
    
    if($pdwProvDataLen -gt 0) 
        {
        $ProvData = new-Object byte[] $pdwProvDataLen
        $GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$ProvData,[ref]$pdwProvDataLen,0)
        }
    
    $enc = new-object System.Text.UTF8Encoding($null)
    $keyContainer = $enc.GetString($ProvData)
    
        write-host " The Default User Key Container:" $keyContainer
    
    [Uint32]$pdwProvDataLen = 0
    [byte[]]$pbProvData = $null
    $GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$pbProvData,[ref]$pdwProvDataLen,0)
    if($pdwProvDataLen -gt 0) 
        {
        $ProvData = new-Object byte[] $pdwProvDataLen
        $GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$ProvData,[ref]$pdwProvDataLen,0)
        [uint32]$provdataInt = [System.BitConverter]::ToUInt32($provdata,0)
        [System.IntPtr]$hwStore = $provdataInt
        }
    
        $store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
    
    # release smart card
    $ReleaseContextRet = $CryptoAPI::CryptReleaseContext($hprovParent,0)
    
    return $store
    }
    
    #Run the code in 32bit mode if PowerShell isn't already running in 32bit mode
    If($env:PROCESSOR_ARCHITECTURE -ne "x86"){
        Write-Warning "Non-32bit architecture detected, collecting certificate information in separate 32bit process."
        $Job = Start-Job $RunAs32Bit -RunAs32
        $SCStore = $Job | Wait-Job | Receive-Job
    }Else{
        $SCStore = $RunAs32Bit.Invoke()
    }
    
    0 讨论(0)
  • 2020-12-21 05:20

    So, the main problem is actually that you're linking an x86 DLL into a x64 Powershell process. You can check whether your Powershell process is x64 like here (by querying (Get-Process -Id $PID).StartInfo.EnvironmentVariables["PROCESSOR_ARCHITECTURE"]), and if an x64 Powershell detected, start manually a Powershell (x86) located at $env:windir\syswow64\WindowsPowerShell\v1.0\powershell.exe with the same script. To get the full name of the script, use $MyInvocation.MyCommand.Definition. If Powershell is detected as x86, you proceed with importing the type and run the enumeration. An example:

    $Arch = (Get-Process -Id $PID).StartInfo.EnvironmentVariables["PROCESSOR_ARCHITECTURE"];
    $Arch
    if ($arch -eq "AMD64") {
        $here=$myinvocation.mycommand.definition
        "$here launched as $arch!"
        start-process C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NoNewWindow -ArgumentList $here -wait
        return
    }
    "now running under x86"
    
    0 讨论(0)
  • 2020-12-21 05:27

    I have been attempting to solve this same problem, and have come up with the following code. This is exactly what you have, with a couple of additions to deal with the 64-bit environment. This should do what you want without re-launching PowerShell as a 32-bit process.

    function Get-SCUserStore {
        [CmdletBinding()]
        param(
              [string]$providerName ="Microsoft Base Smart Card Crypto Provider"
            )
        # import CrytoAPI from advapi32.dll
        $signature = @"
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptGetProvParam(
        IntPtr hProv,
        uint dwParam,
        byte[] pbProvData,
        ref uint pdwProvDataLen, 
        uint dwFlags); 
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptDestroyKey(
        IntPtr hKey);   
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptAcquireContext(
        ref IntPtr hProv,
        string pszContainer,
        string pszProvider,
        uint dwProvType,
        long dwFlags);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptGetUserKey(
        IntPtr hProv, 
        uint dwKeySpec,
        ref IntPtr phUserKey);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptGetKeyParam(
        IntPtr hKey,
        uint dwParam,
        byte[] pbData,
        ref uint pdwDataLen,
        uint dwFlags);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool CryptReleaseContext(
        IntPtr hProv,
        uint dwFlags);
    "@
    
        $CryptoAPI = Add-Type -member $signature -name advapiUtils -Namespace CryptoAPI -passthru
    
        # set some constants for CryptoAPI
        $AT_KEYEXCHANGE = 1
        $AT_SIGNATURE = 2
        $PROV_RSA_FULL = 1
        $KP_CERTIFICATE = 26
        $PP_ENUMCONTAINERS = 2
        $PP_CONTAINER = 6
        $PP_USER_CERTSTORE = 42
        $CRYPT_FIRST = 1
        $CRYPT_NEXT = 2
        $CRYPT_VERIFYCONTEXT = 0xF0000000
    
    
        [System.IntPtr]$hProvParent=0
    
        if([Environment]::Is64BitProcess) {
            [Uint64]$pdwProvDataLen = 0
        } else {
            [Uint32]$pdwProvDataLen = 0    
        }
        $contextRet = $CryptoAPI::CryptAcquireContext([ref]$hprovParent,$null,$providerName,$PROV_RSA_FULL,$CRYPT_VERIFYCONTEXT)
    
        [byte[]]$pbProvData = $null
        $GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$pbProvData,[ref]$pdwProvDataLen,0)
    
        if($pdwProvDataLen -gt 0) 
        {
            $ProvData = new-Object byte[] $pdwProvDataLen
            $GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$ProvData,[ref]$pdwProvDataLen,0)
        }
    
        $enc = new-object System.Text.UTF8Encoding($null)
        $keyContainer = $enc.GetString($ProvData)
    
        Write-Verbose ("The Default User Key Container:{0}" -f $keyContainer)
    
        if([Environment]::Is64BitProcess) {
            [Uint64]$pdwProvDataLen = 0
        } else {
            [Uint32]$pdwProvDataLen = 0
        }
    
        [byte[]]$pbProvData = $null
        $GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$pbProvData,[ref]$pdwProvDataLen,0)
    
        if($pdwProvDataLen -gt 0) 
        {
            $ProvData = new-Object byte[] $pdwProvDataLen
            $GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$ProvData,[ref]$pdwProvDataLen,0)
    
            if([Environment]::Is64BitProcess) {
                [UInt64]$provdataInt = [System.BitConverter]::ToUInt64($provdata,0)
                [System.IntPtr]$hwStore = [Long]$provdataInt
            } else {
                [UInt32]$provdataInt = [System.BitConverter]::ToUInt32($provdata,0)
                [System.IntPtr]$hwStore = $provdataInt
            }
        }
    
        $store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
    
        # release smart card
        $ReleaseContextRet = $CryptoAPI::CryptReleaseContext($hprovParent,0)
    
        return $store
    }
    
    write-host ((get-WmiObject win32_PnPSignedDriver|where{$_.deviceID -like "*smartcard*"}).devicename) "reports the following certificates;" 
    
    # returns System.Security.Cryptography.X509Certificates.X509Store object representing PP_USER_CERTSTORE on Smart Card
    $SCcertStore = Get-SCuserSTore
    
    # enumerate certificates
    $SCcertStore.certificates
    
    0 讨论(0)
提交回复
热议问题