The Invoke-Command cmdlet allows you to execute commands or PowerShell scripts remotely on one or more remote computers
How to Enable PowerShell Remoting (WinRM) on Windows
The Invoke-Command cmdlet relies on PowerShell Remoting sessions to execute commands on remote computers. PowerShell Remoting is used to remotely control and execute commands and is based on the WS-Management protocol (implemented by WinRM, Windows Remote Management service). The HTTP (TCP/5985 port) or HTTPS (TCP/5986 port) protocol is used for communication with remote computers. By default, the HTTP protocol is used, but even this traffic is encrypted using an AES-256 key (although there is a risk of man-in-the-middle attacks). Authentication for PowerShell Remoting over WinRM can use Kerberos (for domain-joined systems), NTLM, or certificate-based (WinRM over HTTPS) auth.
To establish a PSSession with a remote computer, you must enable the WinRM service on that computer and allow remote connections:
Ensure that the WinRM service is running and a listener is properly configured on the target (client) computer:
Get-Service -Name "*WinRM*" | fl
WinRM enumerate winrm/config/listener
The WinRM service is not configured in this case. To enable it and allow remote connections through WinRM, run the following command:
winrm quickconfig
or
Enable-PSRemoting -Force
WinRM has been updated to receive requests. WinRM service started. WinRM is already set up for remote management on this computer.
This command starts the WinRM service (sets its startup type to Automatic), configures the default WinRM settings, and creates the necessary Windows Firewall exceptions.
Now, check if it is possible to remotely connect to the computer via PSRemoting:
Enable-PSRemoting -SkipNetworkProfileCheck
Set-NetFirewallRule -Name WINRM-HTTP-In-TCP -RemoteAddress Any
If the remote hosts are not joined to the AD domain (i.e., when using a workgroup) or if the computers are accessed via IP addresses, NTLM authentication is used instead of Kerberos. To enable NTLM authentication through WimRM, add the name (or IP address) of the remote host to the trusted list on the administrator’s computer:
Set-Item wsman:\localhost\Client\TrustedHosts -value 192.168.1.201
Or you can allow PSRemote connection to all computers (not recommended, because one of the drawbacks of NTLM is that it doesn’t support mutual authentication).
Set-Item wsman:\localhost\Client\TrustedHosts -value *
The same settings must be applied to remote hosts.
List trusted hosts using the command:
Get-Item WSMan:\localhost\Client\TrustedHosts
Restart the WinRM service to apply the changes:
Restart-Service WinRM
Using Invoke-Commands to Run Commands on Remote Computers
To execute a single command on a remote computer, specify the computer name (-ComputerName
) and the command itself in the -ScriptBlock {[command]}
.
Invoke-Command -ComputerName dc01 -ScriptBlock {Get-Service wuauclt}
The cmdlet sends the specified command to the remote computer and prints the result to the console (the result is returned as a PowerShell object). In this case, we received the Windows Update service status on a remote computer.
CTRL+C
in the console.The Invoke-Command cmdlet runs commands on behalf of the user who is running the PowerShell console. Use the -Credential parameter to run a command as a different user:
$cred = Get-Credential
Invoke-Command -ComputerName dc01 -Credential $cred -ScriptBlock {Get-NetAdapter}
This PowerShell command lists the network interfaces on a remote computer:
- By default, only the members of the local ‘Administrators‘ and ‘Remote Management Users‘ groups have permission to connect remotely via PSRemoting.
- If the command sent to the remote computer includes a request to access a remote resource (for example, a shared network folder), authentication to the second resource will fail. This problem is called Double-Hop and is related to Windows security restrictions that prevent credentials from being passed to a third party.
To run multiple commands sequentially on a remote computer, separate them with semicolons within the ScriptBlock. For example, the following command will display the current time zone and change it to another one:
Invoke-Command -Computername dc01 -ScriptBlock {Get-TimeZone| select DisplayName;Set-TimeZone -Name "Central Europe Standard Time"}
The Invoke-Command cmdlet allows you to run not only individual commands but also PowerShell scripts. To do this, specify the path to the local PS1 file with the script in the -FilePath parameter:
Invoke-Command -ComputerName DC01 -FilePath C:\PS\Scripts\CheckSMBversion.ps1
- This method of running remote scripts eliminates the need to manually copy the PowerShell script file to remote computers
- The PowerShell execution policy settings are ignored in this case.
Use the $using construct when you need to pass the value of a local variable from a script to an Invoke-Command block:
$localVar = Get-Date
Invoke-Command -ComputerName Server01 -ScriptBlock {
"Date = $using:localVar"
}
Running Commands on Multiple Computers with Invoke-Command
The Invoke-Command cmdlet allows you to run commands simultaneously (in parallel) on multiple remote computers. The simplest way is to use commas to separate the names of the computers on which the PowerShell commands will be executed:
Invoke-Command server1, server2, server3 -ScriptBlock {get-date}
You can save the list of remote hosts in a variable (array):
$servers = @("server1","server2","server3")
Invoke-Command -ScriptBlock { get-date} -ComputerName $servers
Or get from a text file:
Invoke-Command -ScriptBlock {Restart-Service spooler} -ComputerName(Get-Content c:\ps\servers.txt)
You can also retrieve a list of computers from Active Directory using the Get-ADComputer cmdlet from the AD PowerShell module. For example, to run a command on all Windows Server hosts in a domain, use this code:
$computers = (Get-ADComputer -Filter 'OperatingSystem -like "*Windows server*" -and Enabled -eq "true"').Name
Invoke-Command -ComputerName $computers -ScriptBlock {Get-Date} -ErrorAction SilentlyContinue
If the computer is powered off or unavailable, the SilentlyContinue parameter will prevent the script from halting, allowing it to continue running on other computers.
To understand from which computer the results were received, you need to use a special environment variable, PSComputerName.
$results = Invoke-Command server1, server2, server3 -ScriptBlock {get-date}
$results | Select-Object PSComputerName, DateTime
Invoke-Command has a limit on the maximum number of simultaneous sessions with remote computers. The default is 32 (determined by the ThrottleLimit parameter). If you need to run the command on more than 32 computers simultaneously (for example, 128), use the -ThrottleLimit 128
parameter.
To run commands on a remote computer in the background using Invoke-Command, a special –AsJob
option is used. The result of remote command execution is not returned to the console in this case. Use the Receive-Job
cmdlet to get the results of the remote command.
PowerShell Remoting Persistent Connections
If you frequently need to run commands on a remote computer, you can establish a persistent PSRemoting session with that computer. This prevents the Invoke-Command cmdlet from initiating a new remote connection each time.
Let’s create a persistent session with one or more remote computers:
$s = New-PSSession -ComputerName Server01, Server02
Now use the -Session parameter to run a command in the PSSession that you created:
Invoke-Command -Session $s -ScriptBlock { Get-ComputerInfo|select OsLastBootUpTime }
To close the remote persistent session, close the PowerShell console or run:
Remove-PSSession $s
1 comment
great job. thx a lot