Invoke-PsExec for PowerShell
Invoke-PsExec is a function ("cmdlet") that lets you execute PowerShell and batch/cmd.exe code asynchronously on target Windows computers, using PsExec.exe.
PsExec can be downloaded from the SysInternals suite on Microsoft's site here.
It works with PowerShell version 2 and up. Tested superficially with versions 2, 3 and 4. Also see known issues.
You might find yourself in a situation where you have access to an environment in which PowerShell remoting is not configured and/or allowed through a firewall, but PsExec works. Maybe you want to do inventory or just execute a command against 10 or 1000 servers and collect the exit codes and output (STDOUT and STDERR is collected).
Whatever the need, this might just fit the bill if you're playing with PowerShell and PsExec in conjunction.
The script should be able to process tens or hundreds of servers per minute, depending on what you have it do, of course. Don't forget to increase the timeout if the script/code is long-running.
I noticed during testing (note made 2016-07-23) that setting the -ThrottleLimit to something like 4 is more robust than the default of 32 threads. It seems you get no results back for some of the computers if the limit is too high. Might upload a new version where I change only this value.
Invoke-PsExec.ps1.txt - right-click and download. Remember to unblock. Dot-source to import the function "Invoke-PsExec", which is documented in this article.
Previous versions (if any): File:Invoke-PsExec.ps1.txt
If you have Windows Management Framework 5 or higher (WMF 5 is available for Windows 7 and up), you can install my InvokePsExec module from the PowerShell gallery, a Microsoft site and online repository for scripts.
To install with WMF 5 and up (to get the latest InvokePsExec module version available), simply run this command (requires an internet connection):
Install-Module -Name InvokePsExec
To install for your user only, without the need for an elevated administrator shell, use this command:
Install-Module -Name InvokePsExec -Scope CurrentUser
There's a PsExec.exe bundled with the module in the PSGallery, but if you put a newer version in the current working directory you run Invoke-PsExec from, that will be used instead of the one in the module directory.
Example of running PowerShell code using Invoke-PsExec
I'll use my regular, silly example of collecting the hardware model as defined in the system BIOS from the computers, using PowerShell code with the -IsPSCommand parameter.
Dot-source the script, run a command, collect and display results.
Example of running batch code using Invoke-PsExec
Similar to the example above, but now without the summary, and without the -IsPSCommand parameter, so that the code is run as regular batch code (cmd.exe).
- You might have to change the -ThrottleLimit to, say, 4 or 8, rather than the default of 32 if you get partially missing results. The version in the PowerShell gallery has 8, I think. Wiki version has 32, which seems excessive in retrospect.
- The -Credential parameter only works for batch code - or PowerShell code that does not base64-encode to more than 260 characters, meaning you do not have to use -IsLongPSCommand or -PSFile, since these parameters use a temporary file on the remote server, and Copy-Item does not support the -Credential parameter. The only file system provider cmdlet that supports custom credentials is New-PSDrive (in PS v4, at least). A nice opportunity to practice code golfing. I suppose I could work around it by actually using New-PSDrive; on the to do list, then?
- Testing has been limited. "Your mileage may vary".
- Even though I use the -NoNewWindow parameter for Start-Process in the script, some PsExec cmd.exe windows initially pop up and clutter the screen, before they close, when I test, but in my environment it stops happening after it's processed about 5-10 of them. No idea what that's all about, but it might be a bug in PowerShell (ISE). Using PowerShell ISE to launch. Not seeing that in v2 and powershell.exe.
- You need to specify a full path if using -PSFile (".\file.ps1" won't work). Something like "-PSFile ((Resolve-Path .\file.ps1).Path)" should work, though, as a workaround.
- I have no idea why, but for some reason -IsLongPSCommand does not work on my PSv2 computer, but -PSFile does. Works on v3.
Parameters for Invoke-PsExec
These are the parameters you can use with Invoke-PsExec. I already documented it in the code, so you can check it with Get-Help Invoke-PsExec -Detailed, or similar, and I'm now just reusing that documentation here.
.PARAMETER ComputerName IP address or computer name. .PARAMETER Command PowerShell or batch/cmd.exe code to execute. .PARAMETER IsPSCommand This indicates that the specified command string is pure PowerShell code (you will usually want single quotes around that to avoid escaping). .PARAMETER IsLongPSCommand Use this if the PowerShell code produces a base64-encoded string of a length greater than 260, so you get 'Argument to long' [SIC] from PsExec. This uses a temporary file that's created on the remote computer. .PARAMETER CustomPsExecParameters Custom parameters for PsExec. .PARAMETER PSFile PowerShell file in an accessible file system to be run via PsExec on the remote computer. .PARAMETER Dns Perform a DNS lookup. .PARAMETER Credential Pass in alternate credentials. Get-Help Get-Credential. .PARAMETER ContinueOnPingFail Attempt PsExec command even if ping fails. .PARAMETER ThrottleLimit Number of concurrent threads. .PARAMETER HideProgress Do not display progress with Write-Progress. .PARAMETER Timeout Timeout in seconds. Causes problems if too short. 30 as a default seems OK. Increase if doing a lot of processing with PsExec. .PARAMETER HideSummary Do not display the end summary with start and end time, using Write-Host.