The ampersand (&) is a powerful tool in PowerShell. Also known as the "call operator", it allows you to invoke commands, scripts, functions and programs. In this comprehensive guide, we‘ll dig deep into everything you need to know to master the call operator.

What Exactly is the Call Operator?

The call operator enables PowerShell to execute commands, scripts and programs that have been assigned to a variable or passed as a string argument.

For example:

$ScriptBlock = {Get-Process}
& $ScriptBlock

Here we have assigned a script block containing the Get-Process cmdlet to the $ScriptBlock variable. By putting the ampersand before the variable name, PowerShell will execute or "call" that script block, returning a process list.

Without the ampersand, PowerShell would simply output the contents of $ScriptBlock without actually running it.

So in essence, the call operator calls or invokes commands rather than just evaluating them. This allows you to store reusable chunks of code in variables and execute them on demand.

Key Differences Between Call & Background Operators

It‘s important not to confuse the call operator (&) with the background operator (&).

While they look identical, their behaviors are very different:

  • Call operator – Invokes commands, like & {Get-Date}
  • Background operator – Runs commands in the background, like Get-Process &

The position of the ampersand determines its function. Leading ampersands are for calling, trailing ampersands are for backgrounding.

Calling Commands in Strings

A common use case for the call operator is executing commands stored as strings.

For example, let‘s store the Get-Process cmdlet in a string variable:

$Command = ‘Get-Process‘

If you try to execute this string directly without the call operator, it will just print the literal string:

PS > $Command
Get-Process

By using the call operator, PowerShell will parse the string and execute it properly:

PS > & $Command

   NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
   ------    -----      -----     ------      --  -- -----------
    101   173.92     217.11       8.33    54892   9 ApplicationFrameHost
     63   105.13     130.53      28.77   128496   0 audiodg

This makes the call operator extremely useful for re-running commands from histories and logs, building parameterized scripts, and much more.

The same concept applies equally to calling functions from strings:

$Function = ‘Get-ChildItem‘
& $Function

And even invoking executable programs and scripts by their path:

& ‘C:\Windows\System32\PING.EXE‘

As you can see, leveraging the call operator opens up many possibilities!

Calling Script Blocks

Script blocks provide another excellent use case for the call operator.

Script blocks are reusable chunks of PowerShell code wrapped in curly braces {}. We can assign them to variables, pass them as arguments, pipeline them together – they form the backbone of much PowerShell logic.

Here is script block containing a Get-Process call assigned to a variable:

$ScriptBlock = {Get-Process} 

By default, this will not execute automatically – PowerShell will treat $ScriptBlock like any other variable.

We need to use the call operator to invoke execution:

& $ScriptBlock

Now PowerShell will call that script block, running Get-Process and returning the results.

This pattern is useful for:

  • Abstracting and reusing logic
  • Parameterizing scripts
  • Executing pipeline output
  • Encapsulating functions and logic
  • Constructing disposable script blocks for parallel execution

Later in this post we‘ll dig deeper into some of these advanced examples.

Calling Operators Directly

We‘re not limited to calling variables – we can invoke operators directly using the call syntax as well.

For example, to repeat the last command run in the shell:

PS> Get-Process

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------

PS> & !!

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName 
-------  ------    -----      -----     ------     --  -- -----------
236      46    99176     120176              524   1 aliendalvik
822      45    78748      89416              788   1 android.process

The double-bang (!!) repeats the last command. By calling it directly with & rather than evaluating, PowerShell executes it again.

This shows that & can invoke more than just variables and strings – it calls operators and commands directly too.

Calling Functions from Variables

The call operator allows us to call function references stored in variables.

For example:

$Function = Get-ChildItem
& $Function

First we assign the Get-ChildItem cmdlet to $Function. This stores a reference to the function itself.

When we call & $Function, PowerShell looks up and invokes that function dynamically based on the variable value.

This technique has several uses:

  • Calling module functions not exported to your PATH
  • Dynamically running functions based on arguments or pipeline input
  • Safely calling functions from untrusted code using imprisoned code blocks

The same approach works for calling scripts, aliases, operators and more from variables too.

Bypassing Scope Rules

PowerShell‘s scoping rules normally prevent child scopes (like functions) from updating variables in parent scopes (like the global scope).

The call operator lets you bypass scoping restrictions entirely.

By calling a child function with &, any variable changes propagate back to the parent scope instead of remaining isolated.

For example:


$Test = ‘Old Value‘

function Update-Test {
   $script:Test = ‘New Value‘ 
}

Update-Test

$Test # Old Value 

& Update-Test  

$Test # New Value

Even though $Test exists in the parent scope, calling Update-Test with & lets the function overwrite the global variable. Effectively ignoring standard PowerShell scoping rules between child and parent scopes.

This can be incredibly useful at times, but use this behavior carefully as it can lead to unintended side-effects in larger scripts.

Parameterizing and Scripting with Ampersand

The call operator combines extremely well with parameterized script blocks.

For example, we can build a simple script block that greets a specific person:

$SayHello = { 
   param($Name)
   "Hello $Name!" 
}

Let‘s call this script block with the parameter value Alice:

& $SayHello -Name Alice
Hello Alice!

The script block executes with Alice substituted for $Name.

We can easily call it again with other names too without rewriting any logic:

& $SayHello -Name Bob
Hello Bob!

This pattern allows reusable, parameterized logic without needing traditional functions.

Splatting Parameters with Call Operator

We can even splat parameters from a hashtable into a called script block using the @ syntax:


$Parameters = @{
   Name = "Sarah"
   Number = 42
}

$SayHelloAdvanced = {
   param($Name, $Number) 
   "Hello $Name! Your lucky number is $Number"
}

& $SayHelloAdvanced @Parameters

Hello Sarah! Your lucky number is 42

Here we splat the hashtable $Parameters in as arguments when calling $SayHelloAdvanced. Cleanly passing multiple parameters from the table through the call operator!

Accessing Pipeline Objects with $args

When used in pipelines, the call operator provides access to pipeline input through the special $args automatic variable.

For example:

Get-Process | & { 
   "Received $($args.Count) pipeline objects"  
}
Received 408 pipeline objects

Here $args contains the Get-Process output passed via the pipeline into the called script block.

We can process $args just like the regular pipeline-bound $_ variable too:

Get-Process | & {
   foreach ($process in $args) {
      $process
   }
}

So $args gives us a way to access piped objects from within called code blocks.

Disposing of Returned Objects

One lesser known use of the call operator is disposing of returned .NET objects properly in PowerShell pipelines.

Certain cmdlets return .NET objects that tie up limited system resources. The garbage collector usually cleans up these objects automatically when they go out of scope.

But in pipelines, objects often flow directly downstream to the next command without going out of scope. This prevents proper disposal and leads to resource leakage over time.

We can force disposal by calling Remove-Variable with the call operator:

Start-Job {Get-Process} | & {Remove-Variable *_}

Here Start-Job returns a job object that ties up resources on the system. Calling Remove-Variable explicitly disposes of the piped in job object, freeing those resources.

This highlights a creative troubleshooting use case for forcibly destroying pipeline objects.

Calling Scripts from Remote URLs

The call operator allows remotely running PowerShell code using absolute URLs, with a few caveats.

For example, to invoke a public Gist script from GitHub:

& ‘https://gist.githubusercontent.com/joshduffney/5abab81957c617bb5fa0c897042fae3a/raw/0e2ac8552b8c0bfe9389b8e95f2bc5ca89cc5d1c/Get-TopProcesses.ps1‘

Note: For security reasons, PowerShell disables this by default. You must adjust your execution policies to allow remote script execution.

Since all web content contains risks, only use trusted sources with this technique. Malicious remote scripts can compromise systems.

But for calling trusted scripts, this unlocks some interesting possibilities directly from URLs!

Calling Your Favorite Console Programs

The Windows CLI contains all sorts of useful console programs worth utilizing from PowerShell.

Thanks to the call operator, we can invoke CLI commands seamlessly via absolute paths:

& ‘C:\Windows\System32\ipconfig.exe‘
& ‘C:\Users\jdoe\Downloads\Cleanup.bat‘
& ‘C:\Users\jdoe\Desktop\viruscan.ps1‘

PowerShell will call and execute anything you reference via the filesystem. Treat it like an integrated command prompt!

This offers both convenience and consistency when working across CLI and PowerShell.

Combining with Backgrounding for Asynchronous Invocation

As covered earlier, trailing ampersands (&) run code in the background.

We can combine both operators together for powerful asynchronous invocation:

& $ScriptBlock > output.log &

Here we:

  1. Call $ScriptBlock to execute it
  2. Redirect output to a file
  3. Background the invocation

This runs $ScriptBlock asynchronously, saving results without waiting.

We can build on it further with Start-Job too:

Start-Job { & $ScriptBlock > $using:logFile }

Now we asynchronously call $ScriptBlock in a background job while redirecting to a thread-safe parent scope variable!

Mixing call, background and jobs unlocks asynchronous scripting scenarios.

Putting It All Together: Build a PowerShell Menu System

Now that we‘ve covered the key concepts and capabilities behind the call operator, let‘s put our knowledge to work by building a simple console menu driven by called script blocks.


$MenuOptions = {

   ‘"Please select an option:"‘
   ‘"1. Display date & time"‘ 
   ‘"2. List files in current folder"‘
   ‘"3. Exit"‘

}

$Option1 = { Get-Date }
$Option2 = { Get-ChildItem } 
$Option3 = { Exit }

while ($true) {

   # Show menu
   & $MenuOptions

   # Read choice
   $option = Read-Host "Option"

   switch ($option) {

      ‘1‘ { & $option1 }
      ‘2‘ { & $option2 } 
      ‘3‘ { & $option3 }

   }

}

In this example we:

  1. Define reusable script blocks for each menu option
  2. Use a loop to show options and read input
  3. Call script blocks dynamically based on input

We end up with a simple but effective menu system with reusable modular logic – all thanks to the mighty ampersand!

This illustrates how the call operator facilitates parameterized, reusable scripting.

Key Takeaways

The call operator & unlocks all sorts of scripting functionality:

  • Invoking code – Call commands, scripts, functions from strings, variables and pipelines
  • Bypassing scopes – Ignore standard scoping rules between child and parent scopes
  • Parameterizing – Pass arguments into reusable script blocks
  • Asynchronous control – Background and job enablement
  • CLI access – Directly invoke console programs and scripts
  • Disposal – Destroy pipeline objects explicitly
  • Much more – Script menus, remote invocation, disposable code blocks, and everything between!

So hopefully this deep dive gives you ideas and examples to better utilize the call operator in your daily scripting.

Ampersand might seem simple at first glance, but mastering it truly allows you to take your PowerShell skills to the next level.

Let me know if you have any other call operator techniques worth covering!

Happy scripting!

Similar Posts