You can use PowerShell Remoting (which appeared in PowerShell 2.0) to run commands or scripts on one or several remote computers. PS Remoting is based on the Web Services for Management protocol (WS-Management).
You can use the PS remoting interactive session mode or persistent connection to a remote computer. In this article, we will take a look at several examples of how to run a PowerShell script remotely.
Table of Contents
Configuring WinRM for PowerShell Remoting
To connect to a computer remotely via PowerShell, the WinRM (Windows Remote Management service) must be enabled and configured on the remote client device (it is disabled by default). Communication between computers is performed over HTTP or HTTPS protocols, and all network traffic between computers is encrypted. You can use NTLM and Kerberos to authenticate on a remote computer.
In order to quickly enable and configure the computer for remote management via PowerShell Remoting and WinRM, run the command:
Enable-PSRemoting
This command prepares the computer for remote management:
- Starts the WinRM service and changes the startup type to Automatic;
- Adds exceptions to Windows Defender Firewall;
- Configures WinRM listener to accept remote connections;
- Enables session configuration for PowerShell.
If the computer’s network connection is set to Public, you will receive an error when you run the Enable-PSRemoting command:
WinRM firewall exception will not work since one of the network connection types on this machine is set to Public
You can change the network type to Private using the command:
Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private
Or you can ignore the network profile for WinRM:
Enable-PSRemoting –SkipNetworkProfileCheck -Force
PowerShell Remoting uses TCP ports HTTP (5985) and HTTPS (5986) for network communications. If the remote computer is protected with the Windows Defender Firewall with Advanced Security, the following Windows Remote Management (HTTP-In) rules will be enabled automatically after running the Enable-PSRemoting command:
- WINRM-HTTP-In-TCP
- WINRM-HTTP-In-TCP-NoScope
You can enable Windows Defender rules manually from the graphical console or using PowerShell:
Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" -RemoteAddress Any Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP-NoScope" -RemoteAddress Any
If the remote computer is in a workgroup (not joined to the Active Directory domain), and a Public network profile is applied to LAN connection (instead of Domain or Private), you need to explicitly allow incoming WinRM traffic in Windows Firewall:
Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP-PUBLIC" -RemoteAddress Any
Check the WinRM service state with the Get-Service command:
Get-Service WinRM
As you can see, the WS-Management service is running. You can now establish sessions with this remote host and send PowerShell commands.
To test the connection to a remote computer via WinRM use the following command:
Test-WSMan server1
If you get a response, then the remote computer is accessible through PowerShell Remoting.
Hint. If you are connecting to a remote computer via PS Remoting by an IP address, you may receive an error:
Connecting to remote server 192.168.1.70 failed with the following error message: The WinRM client cannot process the request. Default authentication may be used with an IP address under the following conditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided.
In this case, you need to install an HTTPS certificate for PowerShell Remoting on the remote computer (the long way), or add this host to the trusted ones on your management computer:
Set-Item wsman:\localhost\Client\TrustedHosts -value 192.168.1.70
Then restart the WinRM service:
Restart-Service WinRM
By default, PSRemoting connections can be used by users with local administrator permissions or by local Remote Management Users group members. You can get the current registered session configuration settings for PowerShell with the command:
Get-PSSessionConfiguration -name microsoft.powershell
If you need to change the permissions of the remote PowerShell Endpoint on Windows, run the command:
Set-PSSessionConfiguration -Name Microsoft.PowerShell -ShowSecurityDescriptorUI -Force
Change the current ACL.
Running Remote Commands with PowerShell Remoting
To interactively connect to a remote computer (with a hostname Server1) via PowerShell, run the following command:
Enter-PSSession Server1
The PowerShell CLI view will change. At the beginning of the line, there will be the name of the remote computer to which you are connected via WinRM. After the remote session is established, all commands that are being entered in the PowerShell console are executed on the remote computer. PS Remoting works as follows: the commands entered on the local computer are transmitted to the remote computer and executed there, then the result is transmitted back. Since all commands are executed locally, there is no need to worry about compatibility with the PowerShell version and modules.
To end the remote interactive session run the command:
Exit-PSSession
Only simple management tasks are typically performed on remote computers in interactive mode. To run a complex command or run the PowerShell script remotely, use the Invoke-Command cmdlet.
Note. You can also check our post on how to create a GUI for PowerShell scripts.
Using Invoke-Command to Run PowerShell Scripts Remotely
The following command will create a remote connection with the computer Server1 and run the block of commands specified in the ScriptBlock parameter. After that, the remote session will automatically close.
Invoke-Command -ScriptBlock {Restart-Service spooler} -ComputerName server1
If you need to execute multiple sequential PowerShell commands on a remote machine, separate commands in the ScriptBlock using semicolons:
Invoke-Command -ScriptBlock {Restart-Service spooler;Get-Date; wmic qfe list} -ComputerName server1
You can run the task in the background by running Invoke-Command with the -AsJob parameter. But, in this case, the command will not return the result to the PoSh console. To get detailed background job information, use the Receive-Job cmdlet.
PowerShell allows you to run local PS1 scripts on remote computers. The idea is that you store all PowerShell instructions in a local .PS1 file on your computer. With PowerShell Remoting, you can transfer a PS1 file to a remote computer and execute it there.
To do this, use the -FilePath parameter in the Invoke-Command cmdlet instead of -ScriptBlock. For example, to run the c:\ps\tune.ps1 script on three remote servers, you can use the following command:
Invoke-Command -FilePath c:\ps\tune.ps1 -ComputerName server1,server2,server3
The main advantage of this way of running PowerShell scripts is that you don’t need to copy the PS1 script file to remote computers. The PowerShell script file can be placed on a local drive or a shared network folder. In this case, to run the PS1 script file you need to specify the full UNC path:
Invoke-Command -FilePath "\\dc03\Share\pstune.ps1" -ComputerName PCS12dd2
If PowerShell scripts are not allowed to run on the remote computer, an error will appear:
Invoke-Command : File c:\Share\pstune.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies
You can change the PowerShell Execution Policy settings on a remote computer or sign your PowerShell script file with a certificate.
If you need to run PowerShell scripts with credentials other than the current user, you need to use the -Credential parameter.
First, you need to get the credential and save them to a variable:
$cred = Get-Credential
Now you can run the PS script on remote computers with the alternative credentials:
Invoke-Command -FilePath c:\ps\tune.ps1 -ComputerName server1,server2,server3 -Credential $cred
You can save the list of computers in a text file and run the PowerShell script remotely on all computers at once:
Invoke-command -ComputerName (get-content c:\ps\servers.txt) -filepath c:\ps\tune.ps1
By default, the Invoke-Command cmdlet sends the PS1 script to 32 remote computers from the list at the same time. If there are more than 32 computers, then PoSh checks the execution status of the script on the first 32 computers. The command is executed on the next computer if the script is completed. With the ThrottleLimit parameter, you can increase this limit, but be careful not to overload your network.
When you run the Invoke-Command cmdlet on multiple computers, you can pre-check if the remote computer is accessible via WinRM. If the computer is available, you can run PowerShell code on it using Invoke-Command:
$RemoteComputers= get-content c:\ps\servers.txt ForEach $RemoteComputer in $RemoteComputers) { If (Test-WSMan -ComputerName $RemoteComputer) { Invoke-Command -ComputerName $RemoteComputer -FilePath c:\ps\tune.ps1 }
If you want to pass local session variables to a remote PowerShell session use the $Using prefix:
$name=”script1.ps1” Invoke-Command -ComputerName dc03 -Scriptblock{ write-host $using:Name}
You can use the ConnectionUri parameter in Invoke-Command to run the command against backend applications like Exchange or Azure/AWS cloud services. For example:
$Creds = Get-Credential $params = @{ ConfigurationName = 'Microsoft.Exchange' ConnectionUri = 'https://lonexch1.theitbros.com/PowerShell' Credential = $Creds Authentication = 'Basic' ScriptBlock = {Get-Mailbox BJackson -DisplayName "Brian Jackson"} } Invoke-Command @params
Using Persistent PowerShell Connections (Sessions)
Each time you run Invoke-Command, a new session is created with the remote computer. This takes time and system resources. In PowerShell, you can create one session and execute all commands and scripts in it.
Using the New-PSSession cmdlet, you can create persistent PowerShell sessions with remote computers.
For example, let’s create sessions with three computers and save them in the $PSSess variable:
Invoke-Command -FilePath c:\ps\tune.ps1 -ComputerName server1,server2,server3 $PSSess = New-PSSession -ComputerName server1, server2, server3
After establishing a session, you can use it to run commands and scripts. Because sessions are persistent, you can get data from them and use it in other commands and scripts.
For example, the following command will get a list of processes on remote servers and store them in the $RemoteProcesses variable:
Invoke-Command -Session $PSSess {$RemoteProcesses = Get-Process}
Now you can use this variable in other commands in the same sessions. In the following example, we use the Where-Object cmdlet to find processes that use more than 500MB of RAM):
Invoke-Command -Session $PSSess {$RemoteProcesses | where-object {$_.WorkingSet -GT 500000*1024}|select processname,@{l="Working Memory (MB)"; e={$_.workingset / 1mb}} |sort "Working Memory (MB)" -Descending}
The persistent remote PowerShell session will remain active until you close the PowerShell console, or forcefully close or delete the session using the Disconnect-PSSession or Remove-PSSession cmdlets, respectively.
How to Run PowerShell Command from PSexec?
You can use the PsExec tool from Sysinternals to run PowerShell commands against a remote computer. In this case, you don’t need to enable and configure WinRM on the remote host.
To execute a PowerShell command on a remote Windows host:
- Download and extract the PsExec (https://docs.microsoft.com/en-us/sysinternals/downloads/psexec);
- Open a command prompt as an administrator and change to the directory with psexec.exe: cd c:\ps\tools
- Now you can run a single PowerShell command on a remote computer:
psexec.exe \\SrvNY01 powershell.exe -command "& {get-process}"
You can run several commands at once:
psexec.exe \\SrvNY01 powershell.exe -command "& {get-process;Get-Services; Get-CimInstance -ClassName Win32_OperatingSystem | Select LastBootUpTime
Your PowerShell commands will be run on the remote machine and psexec will return exit code 0.
If you need to remotely run a local PS1 script file:
psexec -s \\ SrvNY01 Powershell -ExecutionPolicy Bypass -File \\dc1\netlogon\scripts\Get-Info.ps1
Also, note that many built-in PowerShell commands have a ComputerName parameter that allows you to directly access a remote computer over the network. You can get a list of such commands:
Get-Command | Where-Object {$_.parameters.keys -contains "ComputerName"}
For example, you can get Event Logs from a remote computer:
Get-EventLog -LogName System -computername SrvNY01| where {$_.EventId -eq 1074}
Or reboot remote hosts:
Restart-Computer -ComputerName SrvNY03, SrvNY02, SrvNY01
As you can see, PowerShell provides ample opportunities for running scripts and commands on remote computers.