logo

Introduction to PowerShell Invoke-Command

The Invoke-Command cmdlet in PowerShell enables IT admins to execute commands and scripts on remote machines, and even to redirect the output of those remote scripts to their own console. As a result, they can manage multiple machines from a central location. Key use cases include:

  • Managing configuration settings on multiple servers
  • Deploying software updates and patches across an entire fleet
  • Running scripts as background jobs for long-running operations

Invoke-Command offers all of the following valuable capabilities:

  • Support for Windows, Linux and macOS systems
  • Built-in error handling and reporting
  • Parallel execution
  • Secure communication using WinRM (Windows Remote Management)

Benefits of using Invoke-Command include:

  • Reduced IT workload through automation of repetitive tasks
  • Efficient management of multiple systems
  • Reduced network traffic because commands execute locally on the target

Syntax and Parameters

The Invoke-Command has two forms, depending on how you want to provide the code to be run:

  • To specify the PowerShell code to be run right in the command, use the -ScriptBlock parameter. This option is ideal when you execute short, inline scripts or run dynamic code generated at runtime. Here is the basic syntax:
Invoke-Command -ScriptBlock { <commands> } -ComputerName <targetComputer> [-Credential <userCredential>] [-ArgumentList <parameters>]

And here is an example:

Invoke-Command -ScriptBlock { Get-Service } -ComputerName "Server01"
  • To provide a script, use the -FilePath parameter. This is the preferred method if you are running longer, more complex scripts or need to run consistent code across multiple remote sessions. The basic syntax is as follows:
Invoke-Command -FilePath “pathtoscript” -ComputerName <targetComputer> [-Credential <userCredential>] [-ArgumentList <parameters>]

Here is an example:

Invoke-Command -FilePath "C:\Scripts\MyScript.ps1" -ComputerName "Server01"

In either case, the -ComputerName parameter specifies the names or IP addresses of the target computers where the specified PowerShell commands will be executed. It accepts a single computer name or a comma-separated list of computer names, as shown here:

Invoke-Command -ScriptBlock { Get-Process } -ComputerName "Server01", "Server02"

Setting Up PowerShell Remoting

Before you can start running PowerShell remotely, you need to meet some basic requirements:

  • Your computer must be running PowerShell 2.0 or later.
  • You must have network connectivity between systems.
  • WinRM must be enabled and running.
  • Appropriate firewall rules must be configured to allow ports 5985 (HTTP) and 5986 (HTTPS).
  • The PowerShell user needs administrative rights on remote computers.

You also need to configure the computer to receive remote commands by running the Enable-PSRemoting cmdlet, as shown below. To suppress all prompts during command execution, use the -Force option; note that this is necessary for automated scripts.

Running Commands on Local and Remote Systems

Executing Commands Locally

To execute most local commands, you can simply run the command directly without using Invoke-Command. However, if you are developing scripts intended for remote execution, using Invoke-Command locally can help simulate the remote environment and ensure the script behaves correctly. This allows the same code structure for local and remote executions.

There are multiple ways to do this. One is to simply run a command and omit the -ComputerName parameter:

Invoke-Command -ScriptBlock { Get-Process }

To make the intention to execute locally explicit, you can explicitly specify localhost in the ?ComputerName parameter:

Invoke-Command -ComputerName localhost - ScriptBlock { Get-Process }

Alternatively, you can use a dot (.) to represent the local computer:

Invoke-Command -ComputerName . -- ScriptBlock { Get-Process }

Executing Commands on Remote Computers 

Of course, the real purpose of Invoke-Command is to execute commands on remote computers. The example below shows how to use Invoke-Command to retrieve the Windows time service from a single remote computer:

Invoke-Command -ComputerName "Server01" -ScriptBlock { Get-Service -Name "W32Time"}

And here is an example that shows how to execute the same command on multiple computers simultaneously:

Invoke-Command -ComputerName "Server01", "Server02" -ScriptBlock {

    Get-Service -Name "W32Time"

}

Alternatively, we could use a variable to represent the two computers:

# Define the remote computers

$computers = "Server1", "Server2"

# Use Invoke-Command to run Get-Service on the remote computers

Invoke-Command -ComputerName $computers -ScriptBlock {

    Get-Service -Name "W32Time"

}

Using -ScriptBlock with Invoke-Command

A script block in PowerShell is a precompiled block of script text enclosed in curly braces {}. Using a script block, you can:

  • Package multiple commands into a single execution 
  • Package code for later execution
  • Use parameters to enable dynamic execution based on input

Script blocks can be also stored in variables and reused across multiple Invoke-Command calls. For example, below we define a script block that retrieves processes with CPU usage greater than 10% and executes that script block on two remote servers using Invoke-Command:

$scriptBlock = { Get-Process | Where-Object { $_.CPU -gt 10 } }

Invoke-Command -ComputerName "Server01", "Server02" -ScriptBlock $scriptBlock

Here is a similar example:

$checkDiskSpace = {

    Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Free -lt 1GB }

}

Invoke-Command -ComputerName "RemotePC1" -ScriptBlock $checkDiskSpace

Using -FilePath with Invoke-Command

Using the -FilePath parameter lets you manage your script’s content in a single, central file. This makes updates, version control and debugging more straightforward compared to embedding long scripts in script blocks. Using the -FilePath parameter offers the following benefits:

  • Allows for centralized script management as you can execute the single script file on multiple remote computers without copying it to each machine.
  • Allows for easy updates to the script in one location, which then propagates to all remote executions.
  • No need to transfer large blocks of code to multiple servers.
  • Ensures all remote computers execute the exact same script, reducing errors from manual script distribution.

The command below will execute the script DiskCollect.ps1 on three servers simultaneously:

Invoke-Command -ComputerName Server01, Server02, Server03 -FilePath C:\Scripts\DiskCollect.ps1

Here is another example using -FilePath:

$servers = @("Server1", "Server2", "Server3")

Invoke-Command -ComputerName $servers -FilePath "C:\Scripts\MaintenanceScript.ps1"

Managing Persistent Sessions

The New-PSSession cmdlet in PowerShell creates a persistent session with a remote computer, enabling you to execute multiple commands without establishing a new connection each time. This can significantly improve efficiency and performance when managing remote systems.

First, create a session and store it in a variable:

$session = New-PSSession -ComputerName Server01

Then use the session with Invoke-Command to run commands remotely:

Invoke-Command -Session $session -ScriptBlock { Get-Process }

You can also create multiple sessions and use them in a single Invoke-Command:

$sessions = New-PSSession -ComputerName Server01,Server02,Server03

Invoke-Command -Session $sessions -ScriptBlock { Get-Service }

To enter an interactive session, use Enter-PSSession:

Enter-PSSession -Session $session

Advanced Features of Invoke-Command

Running Commands as Background Jobs with -AsJob

The -AsJob parameter lets you run remote commands as background jobs. This is beneficial when you need to execute long-running tasks, as it frees up your console for other work while the job executes. When you use -AsJob, the command runs asynchronously on the remote computer.

The command below starts a background job that runs Get-Process on Server01 and Server02. The job object is stored in the $job variable, allowing you to manage and retrieve results later using cmdlets like Get-Job and Receive-Job :

$job = Invoke-Command -ComputerName Server01, Server02 -ScriptBlock {Get-Process} -AsJob

And here is a command that starts a job on Server1, waits for 30 seconds, and then retrieves a list of running processes:

$job = Invoke-Command -ComputerName Server1 -ScriptBlock { Start-Sleep -Seconds 30; Get-Process } -AsJob

Using Local Variables in Remote Commands with the Scope Modifier Using

The scope modifier Using allows you to use local variables in remote commands. This feature is particularly useful when you need to pass local data to a remote session.

In the example below, the $logName variable is defined locally but used in the remote command on Server01. The Using modifier tells PowerShell to use the value of the local variable in the remote session.

$logName = 'PowerShellCore/Operational'

Invoke-Command -ComputerName Server01 -ScriptBlock {

    Get-WinEvent -LogName $Using:logName -MaxEvents 10

}

Best Practices for Secure Remote Execution

Credential Management with -Credential

Security is paramount when operating remotely on critical systems. To operate a command session using PowerShell, you must have the required privileges. Using the -Credential parameter when running Invoke-Command will prompt you for credentials with the appropriate rights to be used for the remote session. Here is an example:

$cred = Get-Credential

Invoke-Command -ComputerName Server01 -Credential $cred -ScriptBlock { Get-Process }

Here are some best practices to keep in mind:

  • Avoid the use of hardcoding credentials.
  • Never store plaintext credentials in scripts.
  • Use tools like Windows Credential Manager or PowerShell’s Get-Credential cmdlet when handling sensitive information.
  • Use encrypted storage to store credentials.
  • Grant only the minimum necessary permissions for remote execution. 
  • Use dedicated service accounts with limited privileges for automated tasks.

Leveraging Secure Shell (SSH) for Cross-Platform Remoting

While we typically associate PowerShell with the Windows operating system, it does support other platforms. To ensure proper security in cross-platform remote scenarios, you should leverage SSH, which provides strong encryption as well as key-based authentication, which you should consider using instead of passwords for SSH connections.

To enable SSH-based remoting:

  1. Install the PowerShell SSH remoting package.
  2. Configure SSH on the target system.
  3. Use the -HostName parameter with SSH syntax:
Enter-PSSession -HostName user@linuxhost

Common Errors and Troubleshooting

Resolving Connectivity Issues

Connectivity issues are highly common and are often the first issue to either confirm or rule out. Here are some basic connectivity troubleshooting tips.

  • Check whether the firewall is blocking the necessary WinRM ports using Test-NetConnection:
Test-NetConnection -ComputerName <RemoteComputerName> -Port 5985
  • You can use PowerShell to create the necessary firewall rule to allow PS remote traffic: 
New-NetFirewallRule -Name "Allow WinRM" -DisplayName "Allow WinRM" -Protocol TCP -LocalPort 5985,5986 -Action Allow
  • If the WinRM service is not enabled on the remote machine, remoting will fail. To enable WinRM, run the following command:
Enable-PSRemoting -Force
  • When using HTTPS (port 5986), SSL/TLS errors can prevent the connection if there are issues with certificates or if certificates aren’t properly installed on both the client and server. Ensure that the SSL certificates on both the local and remote systems are valid and trusted.
  • Ensure the remote system’s hostname resolves correctly. If it does not, use the IP address:
Invoke-Command -ComputerName 192.168.1.10 -ScriptBlock { Get-Service }

Resolving Parameter Mismatches and Script Errors

Parameter mismatches and script errors can lead to unexpected behavior or failed executions. Here are some tips to help you identify problems:

  • Ensure parameter names match exactly, including case sensitivity. 
  • Verify that parameter types (such as string vs. integer) are correct.
  • Double-check the syntax and required parameters for the Invoke-Command cmdlet. For instance, the -ScriptBlock parameter is mandatory unless you’re using -FilePath.
  • Make sure that all variables are defined, and remember that local variables need the Using modifier to be available within the remote script block.
  • When using -FilePath, ensure the script file is accessible and trusted. Verify the file path and permissions.

Getting Detailed Logs

To get more information about a problem, you can use the -Verbose flag to get detailed logs about what PowerShell is doing.

Invoke-Command -ComputerName RemotePC -ScriptBlock { Get-Service } -Verbose

Real-World Examples

Automating Software Installations and Updates

Maintaining up-to-date software across a large fleet of computers can be a daunting task. With PowerShell remoting, administrators can create a single script that handles the download and installation of software updates and use the Invoke-Command cmdlet to execute the script remotely on all applicable machines. Here is what the script might look like:

$computers = @("Server1", "Server2", "Server3")

$installScript = {

    Start-Process -FilePath "C:\Temp\Installer.exe" -ArgumentList "/silent" -Wait

    Write-Output "Software installed on $env:COMPUTERNAME"

}

Gathering System Information from Multiple Machines

Collecting system data, such as disk space, memory usage or installed software, is a common requirement for monitoring and reporting. You can use Invoke-Command to query multiple systems simultaneously. For instance, the script below will gather operating system information from a list of servers and export the results to a CSV file:

$servers = Get-Content "Machines.txt"

$systemInfo = Invoke-Command -ComputerName $servers -ScriptBlock {

    Get-WmiObject Win32_OperatingSystem | Select-Object CSName, Version, OSArchitecture

}

$systemInfo | Export-Csv -Path "SystemInfo.csv" -NoTypeInformation

Running Maintenance Scripts on Remote Servers

You can use Invoke-Command to automate routine maintenance tasks such as clearing logs, updating configurations and restarting services. For instance, the script below will restart the IIS service on a web server:

$webServers = @("WebServer1", "WebServer2", "WebServer3")

$restartServiceScript = {

    Restart-Service -Name "W3SVC"

    Write-Output "IIS restarted on $env:COMPUTERNAME"

}

Invoke-Command -ComputerName $webServers -ScriptBlock $restartServiceScript

Common Questions about Invoke-Command

What is the difference between -ScriptBlock and -FilePath?

The -ScriptBlock parameter defines a block of code within curly braces that can be then executed directly. It is ideal for short, self-contained commands or scripts that don’t require separate files.

The -FilePath parameter is used for external script files. This parameter allows you to specify the path to a PowerShell script file (.ps1) that will be executed on the remote computer. This is beneficial when you have longer, more complex scripts that you want to run remotely without having to embed them directly in your command

How does ThrottleLimit affect execution?

Every computer has a limit for how many concurrent operations it can run. ThrottleLimit limits the number of remote operations that can be executed at the same time. The default value of ThrottleLimit for Invoke-Command is 32, meaning it can run commands on up to 32 remote computers concurrently. You can specify a different value, either greater or less than 32. Setting an appropriate value can help balance performance and resource utilization.

Can Invoke-Command handle multiple remote servers simultaneously?

Yes, you can use Invoke-Command to run commands on multiple remote servers simultaneously. The default limit is 32 simultaneous connections, but this can be altered using the ThrottleLimit parameter.

Conclusion

Invoke-Command is a versatile PowerShell cmdlet that can greatly simplify tasks like installing and updating software across a fleet of computers or running maintenance scripts on remote servers. Any modern Windows operating system today comes with the latest PowerShell version that supports the Invoke-Command, so there is no need to purchase any third-party tools.

FAQ

What is Invoke-Command in PowerShell?

Invoke-Command is a powerful cmdlet in PowerShell that allows you to execute commands or scripts on local or remote computers. It can prove a highly effective tool for administrators managing multiple systems, providing an efficient way to automate tasks, gather information and perform maintenance across a network.

How can I invoke PowerShell from CMD?

To open PowerShell from the command prompt (CMD) on a Windows computer, simply enter the powershell.exe command.

To execute a single PowerShell command from CMD, you would type something like this:

powershell -Command "<PowerShell_Command>"

To execute a PowerShell script, enter the powershell.exe command followed by the full path to the script, as shown below:

powershell.exe -File "C:\path\to\your\script.ps1"

What is Invoke-Expression in PowerShell?

Invoke-Expression is a PowerShell cmdlet that evaluates or runs a specified string as a command and returns the results. It essentially converts a string into executable PowerShell code.

What is the difference between Enter PSSession and Invoke-Command?

While Enter-PSSession and Invoke-Command are both PowerShell cmdlets used for remote management, they serve different purposes:

  • Enter-PSSession creates an interactive, one-to-one real-time connection with a single remote computer, allowing for live troubleshooting and exploration as if you were physically at the machine. The session remains open for executing commands one at a time until you explicitly exit using Exit-PSSession.
  • Invoke-Command executes commands or scripts on one or multiple remote computers simultaneously. This makes it ideal for running operations across multiple systems in a single, temporary connection that closes upon completion.

What does Invoke-Item do in PowerShell?

The Invoke-Item cmdlet provides a convenient way to interact with files and folders directly from the PowerShell command line. It is used to open or run a file or application in its associated program; for instance, it can open a .doc file in Microsoft Word or a .xls file in Excel. It acts similarly to double-clicking a file in File Explorer and launching it with its default handler. Here is an example:

Invoke-Item "C:\path\to\file.txt"
Since 2012, Jonathan Blackwell, an engineer and innovator, has provided engineering leadership that has put Netwrix GroupID at the forefront of group and user management for Active Directory and Azure AD environments. His experience in development, marketing, and sales allows Jonathan to fully understand the Identity market and how buyers think.