I want to read the SMART-attributes of an USB-attached HDD via Powershell.
Calling DeviceIOControl works fine if the HDD is build-in, but I dont understand the correct logics for getting the same info via USB. Here is a code snippet I have so far to get the SMART-version, but at this point I dont know how to continue. Can someone please explain the right sequence that should follow?
cls
Remove-Variable * -ea 0
$ErrorActionPreference = 'stop'
#requires -runasadmin
$drvId = 0
$marshal = [Runtime.InteropServices.Marshal]
$getSmartVersion = '0x074080'
$kernel32 = Add-Type -Name 'kernel32' -Namespace 'Win32' -PassThru -MemberDefinition #"
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
String lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint oControlCode,
IntPtr InBuffer,
uint nInBufferSize,
IntPtr OutBuffer,
uint nOutBufferSize,
ref uint pBytesReturned,
IntPtr Overlapped);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CloseHandle(IntPtr hObject);
"#
$handle = $kernel32::CreateFile("\\.\PhysicalDrive$DrvId", [uint32]'0xc0000000', 3, [System.IntPtr]::Zero, 3, 64, [System.IntPtr]::Zero);
if ([int]$handle -lt 1) {throw 'cannot get handle.'}
# struct for SMART-version:
Add-Type -TypeDefinition #"
using System;
using System.Runtime.InteropServices;
public struct GETVERSIONINPARAMS_EX {
public Byte bVersion;
public Byte bRevision;
public Byte bReserved;
public Byte bIDEDeviceMap;
public UInt32 fCapabilities;
public UInt32 dwDeviceMapEx;
public UInt16 wIdentifier;
public UInt16 wControllerId;
public UInt64 dwReserved;
};
"#
# inBuffer:
$ptrInBuffer = [System.IntPtr]::Zero
$inBufferSize = 0
# outBuffer:
$smartVersionStruct = New-Object GETVERSIONINPARAMS_EX
$outBufferSize = $marshal::SizeOf($smartVersionStruct)
$ptrOutBuffer = $marshal::AllocHGlobal($OutBufferSize)
$resultSize = 0
$ioControlCode = [uint32]$getSmartVersion
if ($kernel32::DeviceIoControl($handle, $ioControlCode, $ptrInBuffer, $inBufferSize, $ptrOutBuffer, $outBufferSize, [ref]$resultSize, [System.IntPtr]::Zero)) {
$smartVersionStruct = $marshal::PtrToStructure($ptrOutBuffer, [type]'GETVERSIONINPARAMS_EX')
$smartVersionStruct | ft -AutoSize
}
$null = $kernel32::CloseHandle($handle)
# now the same for an USB-connected SSD:
$mediaList = gwmi -namespace root\Microsoft\Windows\Storage -class MSFT_PhysicalDisk
$usbMedia = $mediaList | ?{$_.BusType -eq 7}
$diskList = gwmi -namespace root\cimv2 –class Win32_DiskDrive
$usbDisk = $diskList.where({$_.Index -eq $usbMedia.DeviceId})
$usbMapping = gwmi -query "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"
$mapping = #($usbMapping).where({([wmi]$_.Dependent).PnPDeviceId -eq $usbDisk.PnPDeviceId})
$usbHost = [wmi]$mapping.Antecedent
# what should come next?
# getting the 'Root-Hub-Name' or not?
# check if UAS/USAP (USB Attached SCSI Protocol) is supported?
# IoControlCode = SCSCI-PassThrough or SCSIPassThroughDirect (each with or without Buffer)?
The PowerShell command below turns off the screen when run from a batch file (or command prompt). I would prefer to run this as a PowerShell script.
Turn Off Screen - TechNet Script Center
powershell (Add-Type '[DllImport(\"user32.dll\")]^public static
extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);'
-Name a
-Pas)::SendMessage(-1,0x0112,0xF170,2)
I looked at Add-Type - Microsoft Docs, but I could not get the parameters correct.
What is the equivalent PowerShell script for this?
Add-Type -MemberDefinition #"
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);
"# -Name "Win32SendMessage" -Namespace "Win32Functions"
[Win32Functions.Win32SendMessage]::SendMessage(-1,0x0112,0xF170,2)
I can open internet explorer doing this, is it posible doing the same with firefox?
$ie = new-object -comobject InternetExplorer.Application;
$ie.visible = $true;
#$ie2 = $ie.Width = 200;
$ie.top = 0; $ie.width = 1000; $ie.height = 600 ; $ie.Left = 200;
$ie.navigate('https://google.com');
See this discussion and answer
Setting window size and position in PowerShell 5 and 6
# Call Firefox and set to window position on its process
Start-Process -FilePath 'C:\Program Files\Mozilla Firefox\firefox.exe'
Start-Sleep -Seconds 2
Set-Window -ProcessName firefox -x 1 -y 1 -Width 615 -Height 345 -Passthru
Firefox has command-line arguments for width and height, but I could not find anything for window position.
This works in 61.0.2. You may have to modify the parameters to FindWindow() based on your usage.
Note that this is not the most robust code ever, but it may suit your needs.
& "C:\Program Files\Mozilla Firefox\firefox.exe" -width 1000 -height 600 https://google.com
$Assem = (
"System.Runtime.InteropServices"
)
$Source = #"
using System;
using System.Runtime.InteropServices; // For the P/Invoke signatures.
namespace Code42 {
public static class PositionWindowDemo
{
// P/Invoke declarations.
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOZORDER = 0x0004;
public static void MoveWindow(string name)
{
// Find (the first-in-Z-order) Notepad window.
IntPtr hWnd = FindWindow(null, name);
// If found, position it.
if (hWnd != IntPtr.Zero)
{
// Move the window to (0,0) without changing its size or position
// in the Z order.
SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 200, SWP_NOSIZE | SWP_NOZORDER);
}
}
}
}
"#
Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp
[Code42.PositionWindowDemo]::MoveWindow("Google - Mozilla Firefox")
Sources:
https://stackoverflow.com/a/42306412/3608792
https://blogs.technet.microsoft.com/stefan_gossner/2010/05/07/using-csharp-c-code-in-powershell-scripts/
https://www.pinvoke.net/default.aspx/user32.FindWindow
https://www.pinvoke.net/default.aspx/user32.SetWindowPos
I am trying get window of the Notepad using the following PowerShell script:
$pinvokes = #'
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr Connect(string className, string Notepad);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
'#
Add-Type -AssemblyName System.Windows.Forms
Add-Type -MemberDefinition $pinvokes -Name NativeMethods -Namespace MyUtils
$hwnd = [MyUtils.NativeMethods]::FindWindow($null, "Notepad")
But when I use FindWindow() I am getting the error below:
Method invocation failed because [MyUtils.NativeMethods] doesn't contain a method named 'FindWindow'.
At line:1 char:44
+ $hwnd = [MyUtils.NativeMethods]::FindWindow <<<< ($null, "Notepad")
+ CategoryInfo : InvalidOperation: (FindWindow:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
You haven't specified the "FindWindow" method in your $pinvokes definition.
Do the following after e.g. your last method in $pinvokes:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Example:
$pinvokes = #'
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr Connect(string className, string Notepad);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
'#
Add-Type -AssemblyName System.Windows.Forms
# Using Passthru for example to show you how to return type directly
$t = Add-Type -MemberDefinition $pinvokes -Name NativeMethods -Namespace MyUtils -PassThru
$hwnd = $t::FindWindow($null, "Notepad")
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 able to distribute to end users, so it should be self sufficient. My first issue is reading the certificates on the card. I do not want to affect any certificates not on the smart card, so I looked for solution that directly read from the card, and I found this gem:
How to enumerate all certificates on a smart card (PowerShell)
It's old, but it looks like it should do what I need. It really does seem to work in general but PowerShell ISE crashes when I get to the line:
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
I can create a generic store which defaults to the 'My' store by excluding the ($hwStore) from that line without issues, but specifying that store reliably crashes my PowerShell ISE.
Here is the function from that site, the line I have issue with is near the bottom.
function Get-SCUserStore {
[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
}
I don't have any experience with P/Invoke (I think I said that right), so I am unsure how to troubleshoot commands derived from things imported that way.
Edit: The providers that are listed by certutil -scinfo -silent are:
Microsoft Base Smart Card Crypto Provider
Microsoft Smart Card Key Storage Provider
I have tried both of those in the below script with the same end result. The second of which gives me � characters when the script tells me what my default user key container is, so I have a feeling that it is not correct.
I did also try the x86 version of PowerShell, as suggested by Vesper. The application does not crash, and it does return a valid store with my smart card's certificate(s) on it. Now the issue is that I can't send that out to users, because expecting them to be able to navigate to the x86 version of PowerShell and then run a script with it is like expecting my dog to make me waffles... I suppose it could happen, but more likely than not something will go wrong and I'll end up having to do it myself anyway.
Edit2: Ok, so I guess I'll force that part of the script to run in x86 mode. I will post an answer with my updated code and accept it. If #Vesper posts an answer about the 64/32 bit thing (hopefully with a hair more info) I will accept his answer so that he gets credit since his comment is what lead me to the solution.
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"
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()
}
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
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)
}