Create and reuse a powershell scriptblock
Countless time people asked me how they could pass arguments to parameters inside a powershell scriptblock.
The usual approach
Here are a few examples when using Invoke-Command:
# Without argument
Invoke-Command -ScriptBlock {Get-ChildItem}
# With one argument
Invoke-Command -ScriptBlock {Get-ChildItem $args} -ArgumentList 'C:\Windows'
# With multiple arguments - Option A
Invoke-Command -ScriptBlock {Get-ChildItem $args[0] $args[1]} -ArgumentList 'C:\Windows','*.log'
# With multiple arguments - Option B
Invoke-Command -ScriptBlock {PARAM($Path,$Filter) Get-ChildItem $Path $Filter} -ArgumentList 'C:\Windows','*.log'
# You can also be explicit and specify the parameters for more clarity
# The argumentlist items will be sent in the same order as the parameters declared in
# the PARAM() block.
Invoke-Command -ScriptBlock {PARAM($Path,$Filter) Get-ChildItem -Path $Path -Filter $Filter} -ArgumentList 'C:\Windows','*.log'
If the above scenario, you need to know the order of the parameters accepted by the Cmdlet you use, for example Get-Help Get-ChildItem
You’ll see that one of the syntax accepted is:
Get-ChildItem [[-Path] <String[]>] [[-Filter] <String>] [-Attributes {ReadOnly | Hidden | System | Directory |
Archive | Device | Normal | Temporary | SparseFile | ReparsePoint | Compressed | Offline | NotContentIndexed |
Encrypted | IntegrityStream | NoScrubData}] [-Depth <UInt32>] [-Directory] [-Exclude <String[]>] [-File] [-Force]
[-Hidden] [-Include <String[]>] [-Name] [-ReadOnly] [-Recurse] [-System] [-UseTransaction] [<CommonParameters>]
First is Path, Second is Filter, Third is Attributes, etc…
Creating your own ScriptBlock
Another option is to create your own ScriptBlock
object ([System.Management.Automation.ScriptBlock]
) and add your parameters to it before the execution
# Create your own scriptblock without argument
$NewScriptBlock = [scriptblock]::Create("Get-ChildItem")
# Executing the scriptblock
$NewScriptBlock.Invoke()
# It also can be reused, example with Invoke-Command
Invoke-Command -ScriptBlock $NewScriptBlock
# Pass one parameter
$MyPath = 'c:\windows'
$NewScriptBlock = [scriptblock]::Create("Get-Childitem -path $MyPath")
# Execute the scriptblock
$NewScriptBlock.Invoke()
# Pass multiple parameters
$MyPath = 'c:\windows'
$MyFilter = '*.log'
$NewScriptBlock = [scriptblock]::Create("Get-Childitem -path $MyPath -filter $MyFilter")
# Execute the scriptblock
$NewScriptBlock.Invoke()
# Or Using it with invoke-command
Invoke-Command -ScriptBlock $NewScriptBlock
# Works as well against one or multiple machines
Invoke-Command -ScriptBlock $NewScriptBlock -ComputerName MyServer
$Using
Beginning in Windows PowerShell 3.0, you can use the Using scope modifier to identify a local variable in a remote command.
$MyPath = 'c:\windows'
$MyFilter = '*.log'
Invoke-Command -ScriptBlock {Get-ChildItem -Path $using:MyPath -Filter $using:MyFilter}
Resources
You’ll find more information on this topic on this page: about_Remote_Variables
Leave a comment