How to enable PowerShell remoting
You've heard how PowerShell remoting is changing in v3 of the product; now, learn how to use it -- and avoid traps.
Remoting was the most eagerly awaited feature in PowerShell v2. As a result, PowerShell's capabilities reached...
Continue Reading This Article
Enjoy this article as well as all of our content, including E-Guides, news, tips and more.
new heights. The following excerpt, provided by Manning Publications, describes enabling remoting. It is based on chapter 10 of PowerShell in Depth, by Don Jones, Richard Siddaway and Jeffery Hicks. See how remoting is improved in v3.
Want the whole thing? Manning Publications is offering a 40% discount on PowerShell in Depth to TechTarget readers. Use the promotional code 12pidtt at manning.com; if you buy the print book, the e-book is free.
Remoting needs to be enabled on any machine that will receive connections, which can include computers running either the Server or a client version of the Windows operating system. The easy way to set up remoting is to simply run Enable-PSRemoting. This command performs several tasks:
- Start (or restart, if it’s already started) the WinRM service.
- Set the WinRM service to start automatically from now on.
- Create a WinRM listener for HTTP traffic on port 5985 for all local IP addresses.
- Create a Windows Firewall exception for the WinRM listener. Note that this will fail on client versions of Windows if any network cards are configured to have a type of “Public,” because the firewall will refuse to create new exceptions on those cards. If this happens, change the network card’s type to something else (like “Work” or “Private,” as appropriate), and run Enable-PSRemoting again. Alternately, if you know you have some Public network cards, add the –SkipNetworkProfileCheck parameter to Enable-PSRemoting. Doing so will successfully create a firewall exception that allows incoming Remoting traffic only from the computer’s local subnet.
The command will also set up one or more of these four endpoints:
- PowerShell 32-bit
- PowerShell 64-bit
- PowerShell Server Manager Workflow
- PowerShell Workflow
Table 1 illustrates some example end point configurations. On a 32-bit machine, the endpoint is referred to as PowerShell rather than PowerShell32.
Table 1: Example endpoint configurations
PowerShell Version
|
PowerShell
32 bit |
PowerShell 64bit
|
Server manager
|
PowerShell
workflow |
|
Windows Server 2008 R2 | 2 |
Y |
Y |
Y |
|
Windows 7 64 bit | 3 |
Y |
Y |
|
Y |
Windows 8 32 bit client | 3 |
Y |
|
|
Y |
Windows 8 Server | 3 |
Y |
Y |
Y |
Y |
Windows 7 client 32 bit standalone | 2 |
Y |
|
|
|
You’ll be prompted several times as the command runs; be sure to reply “Y” for “Yes” so that each step can complete properly.
One-to-one remoting
The most straightforward way to use remoting is called one-to-one remoting, in which you essentially bring up an interactive PowerShell prompt on a remote computer. It’s pretty simple once remoting is enabled on the remote machine:
PS C:\> enter-pssession -ComputerName Win8
[Win8]: PS C:\Users\Administrator\Documents>
Note If you want to experiment with this, just use localhost as the computer name once you’ve enabled remoting on your computer. You’ll be “remotely controlling” your local machine but you’ll get the full remoting experience.
Notice how the PowerShell prompt changes to include the name of the computer you’re now connected to. From here, it’s almost exactly as if you were physically standing in front of that computer, and you can run any command that the remote machine contains. There are a few important caveats to keep in mind:
- By default, when the PowerShell prompt contains any computer name (even localhost), you cannot execute any other commands that initiate a Remoting connection. Doing so would create a “second hop,” which won’t work by default.
- You cannot run any commands that start a graphical application. If you do so, the shell may appear to freeze; hit Ctrl+C to end the process and regain control.
- You can’t run any command program that has its own “shell” like nslookup or netsh.
- You can only run scripts on the remote machine if its execution policy permits you to do so.
- You are not connected to an interactive desktop session; your connection will be audited as a “network logon,” much as if you were connecting to a file share on the remote machine. As a result of the connection type, Windows won’t execute profile scripts, although you will be connected to your profile home folder on the remote machine.
- Nothing you do will be visible by any other user who is connected to the same machine, even if they’re interactively logged on to its desktop console. In other words, you can’t run some application and have it “pop up” in front of the logged-on user.
- You must specify the computer’s name as it appears in Active Directory or in your local Trusted Hosts list; you can’t use IP addresses or DNS CNAME aliases unless those have been added to your Trusted Hosts list.
When you’re done with the remote machine, run Exit-PSSession. This will return you to your local prompt, close the connection to the remote machine, and free up resources on the remote machine. This will also happen automatically if you just close the PowerShell window.
[Win8]: PS C:\Users\Administrator\Documents> Exit-PSSession
PS C:\>
The way we’ve used Enter-PSSession will always connect to the remote machine’s default PowerShell endpoint. On a 64-bit operating system, that’ll be the 64-bit version of PowerShell. Later, we’ll show you how to connect to other endpoints (remembering that Enable-PSRemoting can create up to four endpoints in total).
One-to-many remoting
This is a powerful technique that really highlights the value of remoting. You’ll basically be transmitting a command (or a series of commands) to multiple remote computers. They’ll each execute the command, serialize the results into XML, and send the results back to you. Your copy of PowerShell will deserialize the XML into objects, and put them in the pipeline. For example, suppose we wanted to get a list of all processes whose names start with the letter “s,” from two different computers:
PS C:\> invoke-command -ScriptBlock { Get-Process -name s* } -computername
localhost,win8
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessN PSCompu
ame terName
------- ------ ----- ----- ----- ------ -- -------- -------
217 11 3200 7080 33 1.23 496 services win8
50 3 304 980 5 0.13 248 smss win8
315 16 2880 8372 46 0.03 12 spoolsv win8
472 36 8908 11540 60 0.31 348 svchost win8
306 12 2088 7428 36 0.19 600 svchost win8
295 15 2372 5384 29 0.61 636 svchost win8
380 15 17368 19428 55 0.56 728 svchost win8
1080 41 12740 25456 120 2.19 764 svchost win8
347 19 3892 8812 93 0.03 788 svchost win8
614 52 13820 18220 1129 2.28 924 svchost win8
45 4 508 2320 13 0.02 1248 svchost win8
211 18 9228 8408 1118 0.05 1296 svchost win8
71 6 804 3540 28 0.00 1728 svchost win8
2090 0 120 292 3 10.59 4 System win8
217 11 3200 7080 33 1.23 496 services loca...
50 3 304 980 5 0.13 248 smss loca...
315 16 2880 8372 46 0.03 12 spoolsv loca...
469 36 8856 11524 59 0.31 348 svchost loca...
306 12 2088 7428 36 0.19 600 svchost loca...
295 15 2372 5384 29 0.61 636 svchost loca...
380 15 17368 19428 55 0.56 728 svchost loca...
1080 41 12740 25456 120 2.19 764 svchost loca...
347 19 3892 8812 93 0.03 788 svchost loca...
607 49 13756 18132 1129 2.28 924 svchost loca...
45 4 508 2320 13 0.02 1248 svchost loca...
211 18 9228 8408 1118 0.05 1296 svchost loca...
71 6 804 3540 28 0.00 1728 svchost loca...
2089 0 120 292 3 10.59 4 System loca...
The command is Invoke-Command. Its –ScriptBlock parameter accepts the commands (use semicolons to separate multiple commands) you want transmitted to the remote machines; the –ComputerName parameter specifies the machine names. Alternatively, for longer commands a script block object could be created:
$sb = {Get-Process -Name s*}
Invoke-Command -ComputerName localhost,win8 -ScriptBlock $sb
As with Enter-PSSession, you must specify the computer’s name as it appears in Active Directory or in your local Trusted Hosts list; you can’t use IP addresses or DNS CNAME aliases unless those have been added to your Trusted Hosts list.
Notice anything interesting about the output? It contains an extra column named PSComputerName, which contains the name of the computer each result row came from. This is a handy way to separate, sort, group, and otherwise organize your results. This property is always added to the incoming results by PowerShell; if you’d rather not see the property in the output, add the –HideComputerName parameter to Invoke-Command. The property will still exist (and can be used for sorting and so forth), but it won’t be displayed in the output by default.
As with Enter-PSSession, Invoke-Command will use the default PowerShell endpoint on the remote machine, which in the case of a 64-bit OS will be the 64-bit shell.
By default, Invoke-Command will only talk to 32 computers at once. Doing so requires it to maintain a PowerShell instance in memory for each remote machine it’s talking to; 32 is a number Microsoft came up with that seems to work well in a variety of situations. If you specify more than 32 computers, the extra ones will just queue up, and Invoke-Command will start working with them as the first 32 begin to complete. You can change the level of parallelism by using the command’s –ThrottleLimit parameter, keeping in mind that higher numbers place a greater load on your computer, but no extra load on the remote machines.
Remoting caveats
The data sent from a remote machine to your computer has to be packaged in a way that makes it easy to transmit over the network. Serialization and deserialization, which we’ve already mentioned, makes it possible—but with some loss of functionality. For example, consider the type of object produced by Get-Service:
PS C:\> get-service | get-member
TypeName: System.ServiceProcess.ServiceController
Name MemberType Definition
---- ---------- ----------
Name AliasProperty Name = ServiceName
RequiredServices AliasProperty RequiredServices = ServicesDepe...
Disposed Event System.EventHandler Disposed(Sy...
Close Method System.Void Close()
Continue Method System.Void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef ...
Dispose Method System.Void Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method System.Void ExecuteCommand(int ...
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetim...
Pause Method System.Void Pause()
Refresh Method System.Void Refresh()
Start Method System.Void Start(), System.Voi...
Stop Method System.Void Stop()
WaitForStatus Method System.Void WaitForStatus(Syste...
CanPauseAndContinue Property bool CanPauseAndContinue {get;}
CanShutdown Property bool CanShutdown {get;}
CanStop Property bool CanStop {get;}
Container Property System.ComponentModel.IContaine...
DependentServices Property System.ServiceProcess.ServiceCo...
DisplayName Property string DisplayName {get;set;}
MachineName Property string MachineName {get;set;}
ServiceHandle Property System.Runtime.InteropServices....
ServiceName Property string ServiceName {get;set;}
ServicesDependedOn Property System.ServiceProcess.ServiceCo...
ServiceType Property System.ServiceProcess.ServiceTy...
Site Property System.ComponentModel.ISite Sit...
Status Property System.ServiceProcess.ServiceCo...
ToString ScriptMethod System.Object ToString();
As you can see, these objects’ members include several properties, which let you stop the service, pause it, and so on. Now. consider that exact same kind of object retrieved, via remoting, from a remote machine:
PS C:\> invoke-command -ComputerName win8 -ScriptBlock { Get-Service } |
>> Get-Member
>>
TypeName: Deserialized.System.ServiceProcess.ServiceController
Name MemberType Definition
---- ---------- ----------
ToString Method string ToString(), string ToString(str...
Name NoteProperty System.String Name=AeLookupSvc
PSComputerName NoteProperty System.String PSComputerName=win8
PSShowComputerName NoteProperty System.Boolean PSShowComputerName=True
RequiredServices NoteProperty Deserialized.System.ServiceProcess.Ser...
RunspaceId NoteProperty System.Guid RunspaceId=00e784f7-6c27-4...
CanPauseAndContinue Property System.Boolean {get;set;}
CanShutdown Property System.Boolean {get;set;}
CanStop Property System.Boolean {get;set;}
Container Property {get;set;}
DependentServices Property Deserialized.System.ServiceProcess.Ser...
DisplayName Property System.String {get;set;}
MachineName Property System.String {get;set;}
ServiceHandle Property System.String {get;set;}
ServiceName Property System.String {get;set;}
ServicesDependedOn Property Deserialized.System.ServiceProcess.Ser...
ServiceType Property System.String {get;set;}
Site Property {get;set;}
Status Property System.String {get;set;}
The methods (excepting the universal ToString() method) are gone. That’s because you’re looking at a deserialized version of the object (it says so right in the TypeName at the top of the output), and the methods are stripped off. Essentially, you’re getting a read-only, static version of the object.
This isn’t necessarily a downside, as serialization and the removal of methods don’t occur until the remote commands finish executing and their output is being packaged for transmission. The objects are still “live” objects when they’re on the remote computer, so you simply have to start them, stop them, pause them, or whatever on the remote machine. In other words, any “actions” you need to take need to be part of the command you send to the remote machine for execution.