Windows Management and Scripting

A wealth of tutorials Windows Operating Systems SQL Server and Azure

Powershell Remote control: one to one,and one to many

Posted by Alin D on July 26, 2011

When I first started using PowerShell (in version 1), I was playing around with the Get-Service command, and noticed that it had a -computerName parameter. Hmmm … does that mean it can get services from other computers, too? After a bit of experimenting, I discovered that’s exactly what it did. I got very excited and started looking for -computerName parameters on other cmdlets, and was disappointed to find that there were very few. A few more were added in v2, but the commands that have this parameter are vastly outnumbered by the commands that

don’t.

What I’ve realized since is that PowerShell’s creators are a bit lazy—and that’s a good thing! They didn’t want to have to code a -computerName parameter for every single cmdlet, so they created a shell-wide system called remoting. Basically, it enables any cmdlet to be run on a remote computer. In fact, you can even run commands that exist on the remote computer but that don’t exist on your own computer— meaning that you don’t always have to install every single administrative cmdlet on your workstation. This remoting system is powerful, and it offers a number of interesting administrative capabilities.

WinRM overview

Let’s talk a bit about WinRM, because you’re going to have to configure it in order to start using remoting. Once again, you only need to configure WinRM—and PowerShell remoting—on those computers that will receive incoming commands. In most of the environments I’ve worked in, the administrators have enabled remoting on every Windows-based computer (keep in mind that PowerShell and remoting are supported all the way back to Windows XP). Doing so gives you the ability to remote into client desktop and laptop computers in the background (meaning the users of those computers won’t know you’re doing so), which can be tremendously useful. WinRM isn’t unique to PowerShell. In fact, it’s likely that Microsoft will start using it for more and more administrative communications—even things that use other protocols today. With that in mind, Microsoft made WinRM able to route traffic to multiple administrative applications—not just PowerShell. WinRM essentially acts as a dispatcher: when traffic comes in, WinRM decides which application needs to deal with that traffic. All WinRM traffic is tagged with the name of a recipient application, and those applications must register with WinRM to listen for incoming traffic on their behalf. In other words, you’ll not only need to enable WinRM, but you’ll also need to tell PowerShell to register as an endpoint with WinRM.

One way to do that is to open a copy of PowerShell—making sure that you’re running it as an Administrator—and run the Enable-PSRemoting cmdlet. You might sometimes see references to a different cmdlet, called Set-WSManQuickConfig. There’s no need to run that one; Enable-PSRemoting will call it for you, and Enable-PSRemoting does a few extra steps that are necessary to get remoting up and running. All told, the cmdlet will start the WinRM service, configure it to start automatically, register PowerShell as an endpoint, and even set up a Windows Firewall exception to permit incoming WinRM traffic.

If you’re not excited about having to run around to every computer to enable remoting, don’t worry: you can also do it with a Group Policy object (GPO), too. The necessaryGPO settings are built into Windows Server 2008 R2 domain controllers (and you can download an ADM template from download.Microsoft.com to add these GPO settings to an older domain’s domain controllers). Just open a Group Policy object and look under the Computer Configuration, then under Administrative Templates, then under Windows Components. Near the bottom of the list, you’ll find both Remote Shell and Windows Remote Management. For now, I’m going to assume that you’ll run Enable-PSRemoting on those computers that you want to configure, because at this point you’re probably just playing around with a virtual machine or two.

WinRM v2 (which is what PowerShell uses) defaults to using TCP port 5985 for HTTP and 5986 for HTTPS. Those ports help to ensure it won’t conflict with any locally installed web servers, which tend to listen to 80 and 443 instead. You can configure WinRM to use alternative ports, but I don’t recommend doing so. If you leave those ports alone, all of PowerShell’s remoting commands will run normally. If you change the ports, you’ll have to always specify an alternative port when you run a remoting command, which just means more typing for you.

If you absolutely must change the port, you can do so by running this command:

Winrm set winrm/config/listener?Address=*+Transport=HTTP@{Port=”1234″}

In this example, “1234” is the port you want. Modify the command to use HTTPS instead of HTTP to set the new HTTPS port

I should admit that there is a way to configure WinRM on client computers to use alternative default ports, so that you’re not constantly having to specify an alternative port when you run commands. But for now let’s stick with the defaults Microsoft came up with.

How to Use Enter-PSSession and Exit-PSSession for one to one remoting

PowerShell uses remoting in two distinct ways. The first is called one-to-one, or 1:1, remoting (the second way is one-to-many remoting, and you’ll see it in the next section). With this kind of remoting, you’re basically accessing a shell prompt on a single remote computer. Any commands you run will run directly on that computer, and you’ll see results in the shell window. This is vaguely similar to using Remote Desktop Connection, except that you’re limited to the command-line environment of Windows PowerShell. Oh, and this kind of remoting uses a fraction of the resources that Remote Desktop requires, so it imposes much less overhead on your servers!

To establish a one-to-one connection with a remote computer, run this command:

Enter-PSSession -computerName Server-R2

Of course, you’ll need to provide the correct computer name instead of Server-R2. Assuming you enabled remoting on that computer, that you’re all in the same domain, and that your network is functioning correctly, you should get a connection going. PowerShell lets you know that you’ve succeeded by changing the shell prompt:

[server-r2] PS C:>

That prompt tells you that everything you’re doing is taking place on Server-R2 (or whatever server you connected to). You can run whatever commands you like. You can even import any modules, or add any PSSnapins, that happen to reside on that remote computer.

Even your permissions and privileges carry over across the remote connection. Your copy of PowerShell will pass along whatever security token it’s running under (it does this with Kerberos, so it doesn’t pass your username or password across the network).

Any command you run on the remote computer will run under your credentials, so you’ll be able to do anything you’d normally have permission to do. It’s just like logging directly into that computer’s console and using its copy of PowerShell directly.

Well, almost. There are a couple of differences:

  • Even if you have a PowerShell profile script on the remote computer, it won’t run when you connect using remoting. We haven’t fully covered profile scripts, but suffice to say that they’re a batch of commands that run automatically each time you open the shell. Folks use them to automatically load shell extensions and modules and so forth. That doesn’t happen when you remote into a computer, so be aware of that.
  • You’re still restricted by the remote computer’s execution policy. Let’s say your local computer’s policy is set to RemoteSigned, so that you can run local, unsigned scripts. That’s great, but if the remote computer’s policy is set to the default, Restricted, it won’t be running any scripts for you when you’re remoting into it.

Aside from those two fairly minor caveats, you should be good to go. Oh, wait—whatdo you do when you’re done running commands on the remote computer? Many PowerShell cmdlets come in pairs, with one cmdlet doing something and the other doing the opposite. In this case, if Enter-PSSession gets you into the remote computer, can you guess what would get you out of the remote computer? If you guessed Exit-PSSession, give yourself a prize. The command doesn’t need any parameters; just run it and your shell prompt will change back to normal, and the remote connection will close automatically.

What if you forget to run Exit-PSSession and instead close the PowerShell window? Don’t worry. PowerShell and WinRM are smart enough to figure out what you did, and the remote connection will close all by itself.

I do have one caution to offer. When you’re remoting into a computer, don’t run Enter-PSSession from that computer unless you fully understand what you’re doing.

Let’s say you work on Computer A, which runs Windows 7. You remote into Server-R2. Then, at the PowerShell prompt, you run this:

[server-r2] PS C:>enter-pssession server-dc4

Now, Server-R2 is maintaining an open connection to Server-DC4. That can start to create a “remoting chain” that’s hard to keep track of, and which imposes unnecessary overhead on your servers. There are times when you might have to do this—I’m thinking mainly of instances where a computer like Server-DC4 sits behind a firewall and you can’t access it directly, so you use Server-R2 as a middleman to hop over to Server-DC4. But, as a general rule, try to avoid remote chaining.

When you’re using this one-to-one remoting, you don’t need to worry about objects being serialized and deserialized. As far as you’re concerned, you’re typing directly on the remote computer’s console. If you retrieve a process and pipe it to Stop-Process, it’ll stop as you would expect it to.

Leave a comment