When you need to run a command from PowerShell there are several options. In this TechNet article you can find no less than 10 methods. I will not recite them all here, just click the link.
Things get interesting when you want to pass parameters. We’ll discuss Invoke-Expression
and Invoke-Command
.
Invoke-Expression (IEX)
Microsoft documentation. Invoke-Expression
or IEX
is an easy way to just run a string as a Powershell command. Such as ping 127.0.0.1
. When you need to pass arguments, you need to change the string like this.
# Ping 192.168.1.1
$Expression = "ping 192.168.1.1"
Invoke-Expression $Expression
# Ping 192.168.1.2
$Expression = "ping 192.168.1.2"
Invoke-Expression $Expression
Invoke-Command ()
Microsoft documentation. Invoke-Command
or ICM
runs commands on local or remote computers and returns all output from the commands, including the errors. The cmdlet needs a ScriptBlock to run, this can be an inline ScriptBlock or from a file.
A trivial example
# All ScriptBlocks are built with curly braces
$ScriptBlock = {Get-Service}
Invoke-Command $ScriptBlock
# Or more descriptive
$ScriptBlock = [scriptblock]::Create({Get-Service})
Invoke-Command $ScriptBlock
# Of course, you could also just run
Invoke-Command {Get-Service}
Let’s add a parameter. Imagine that we want to restart a service with Restart-Service
, then we need to pass a service name, for instance the print spooler aka Spooler
.
# The idea is to pass parameters, so let's define one
$ServiceName = "Spooler"
Invoke-Command {param($SN) Restart-Service -Name $SN} -ArgumentList $ServiceName
Notice that we create a param()
section in the scriptblock.
What if we have multiple parameters?
# The script
$ScriptBlock = {
param(
$ServiceName,
$FileName = "TestFile",
$Path = "C:\Temp"
)
Stop-Service -Name $ServiceName
New-Item -ItemType File -Name $FileName -Path $Path
}
# Just add the arguments after -ArgumentList
Invoke-Command $ScriptBlock -ArgumentList @("Spooler", "AnOutputFile.log")
For passing parameters I like to work with hashtables, so that I can use named parameters. So I want to call the scriptblock like this Invoke-Command $ScriptBlock -Argumentlist $Hashtable
.
# The script
$ScriptBlock = {
param(
$ServiceName,
$FileName = "TestFile",
$Path = "C:\Temp"
)
Stop-Service -Name $ServiceName
New-Item -ItemType File -Name $FileName -Path $Path
}
# A hashtable containing the parameters
$Parameters = @{
ServiceName = "Spooler"
FileName = "TestFile$(Get-Random)"
}
# Here we actualy create a new scriptblok, passing the paramters to splat the hash.
Invoke-Command -ScriptBlock {param($P) &($ScriptBlock) @P} -ArgumentList $Parameters
A step further is when the scriptblock is stored somewhere and we want to run it with a hashtable. In this example the script is stored on C:\Temp\script.ps1
.
# A hashtable containing the parameters
$Parameters = @{
ServiceName = "Spooler"
FileName = "TestFile$(Get-Random)"
}
# Get the script from C:\Temp\script.ps1 and splat the hashtable as arguments
$ScriptBlock = [scriptblock]::create(".{$(Get-Content -Path C:\Temp\script.ps1 -Raw)} $(&{$args} @Parameters)")
# No need to pass any parameters anymore, they are already in the scriptblock.
Invoke-Command -ScriptBlock $ScriptBlock
The above examples are not very exciting, but remember that you can combine Invoke-Command
with Powershell Direct. This means that you can run commands on Virtual Machines regardless of network configuration or remote management settings.
I don’t want to pretend I’m a Powershell expert because I’m not, but these work for me.