13 Remote control: One-to-one and one-to-many

Let’s take a look at the Invoke-ScriptBlock command. Notice that it has a -ComputerName parameter. Hmmm . . . does that mean it can run commands on other hosts too? After a bit of experimenting, you’ll discover that’s exactly what it does. How many other commands have the ability to connect to remote machines? While there is not a way to obtain a concrete number to answer this question, there are quite a lot.

What we’ve realized is that PowerShell’s creators are a bit lazy—and that’s a good thing. Because they didn’t want to have to code a -HostName parameter for every single cmdlet, they created a shell-wide system called remoting. This system enables you to run any cmdlet 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 you don’t always have to install every administrative cmdlet on your workstation. This remoting system is powerful, and it offers interesting administrative capabilities.

Note Remoting is a huge, complex technology. We introduce you to it in this chapter and cover usage scenarios that you’ll deal with 80% to 90% of the time. But we can’t cover it all, so in the “Further exploration” section at the end of this chapter, we point you to a must-have resource that covers remoting’s configuration options.

13.1 The idea behind remote PowerShell

Remote PowerShell works somewhat similarly to Telnet and other age-old remote-control technologies. When you run a command, it’s running on the remote computer—only the results of that command come back to your computer.

13.1.1 Remoting on Windows devices

PowerShell uses a communications protocol called Web Services for Management (WSMan). WSMan operates entirely over HTTP or HTTPS (HTTP by default), making it easy to route through firewalls if necessary (because each of those protocols uses a single port to communicate). Microsoft’s implementation of WSMan comes in the form of a background service, Windows Remote Management (WinRM). WinRM is installed by default on Windows 10 devices and Server 2012 and up. By default, these services are disabled but can easily be enabled individually or by group policy.

13.1.2 Remoting on macOS and Linux devices

As you can guess, WSMan and WinRM are Windows-only services. So in order for PowerShell to have remoting capabilities, the team decided that it would be best to use the industry standard Secure Shell (SSH). SSH makes it easy to route through firewalls if necessary (because that protocol uses a single port to communicate) and has been used by Linux professionals for decades. Microsoft has ported OpenSSH to Windows, so you can even use this to remote into Windows.

Setting up PSRP over SSH on Windows

You may want to set up PowerShell remoting protocol (PSRP) over SSH on any Windows machine you have PowerShell Core installed on. We won’t go into the details on how to set this up, but the instructions are available in Microsoft’s documentation: http://mng.bz/laPd.

13.1.3 Cross-platform remoting

You’ve already learned that PowerShell cmdlets all produce objects as their output. When you run a remote command, its output objects need to be put into a form that can be easily transmitted over a network. XML, it turns out, is an excellent way to do that, so PowerShell automatically serializes those output objects into XML. The XML is transmitted across the network and is then deserialized on your computer back into objects that you can work with inside PowerShell. Serialization and deserialization are really just a form of format conversion: from objects to XML (serialization), and from XML to objects (deserialization).

Why should you care how this output is returned? Because those serialized-then-deserialized objects are only snapshots, of sorts; they don’t update themselves continually. For example, if you were to get the objects that represent the processes running on a remote computer, what you’d get back would be accurate for only the exact point in time at which those objects were generated. Values such as memory usage and CPU utilization won’t be updated to reflect subsequent conditions. In addition, you can’t tell the deserialized objects to do anything—you can’t instruct one to stop itself, for example.

Those are basic limitations of remoting, but they don’t stop you from doing some amazing stuff. In fact, you can tell a remote process to stop itself, but you have to be clever about it. We’ll show you how later in this chapter. To make remoting work, you have two basic requirements:

  • Both your computer and the one you want to send commands to must be running PowerShell v7.1 or later.

  • Ideally, both computers need to be members of the same domain, or of trusted/ trusting domains. It’s possible to get remoting to work outside a domain, but it’s trickier, and we don’t cover it in this chapter. To learn more about that scenario, open PowerShell and run help about_remote_troubleshooting.

Try it Now We hope you’ll be able to follow along with some of the examples in this chapter. To participate, you’ll ideally have a second test computer (or a virtual machine) that’s in the same Active Directory domain as the test computer you’ve been using up to this point. You can run any version of Windows on that second computer, provided you have PowerShell v7.1 or later installed. If you are using two Windows devices, it will make your life a lot easier if they are part of the same domain. If you can’t set up an additional computer or virtual machine, use localhost to create remoting connections to your current computer. You’re still using remoting, but it isn’t as exciting to be “remote controlling” the computer at which you’re sitting.

13.2 Setting up PSRP over SSH

Let’s spend some time getting SSH set up in your environment.

13.2.1 macOS and Linux

On the computer, make sure that the SSH server and client are installed. On Ubuntu, these are the instructions:

sudo apt install openssh-client
sudo apt install openssh-server

For macOS, the client is installed by default. Here is the command to enable the server:

sudo systemsetup -setremotelogin on

Next, we need to install the module that enables PSRP over SSH:

Install-Module EnableSSHRemoting

Then, run the command to enable PSRP over SSH:

sudo pwsh -c Enable-SSHRemoting

Next, you need to restart the OpenSSH service. On Ubuntu, this is the command to restart the service:

sudo service sshd restart

On macOS, this is the command:

sudo launchctl stop com.openssh.sshd
sudo launchctl start com.openssh.sshd

13.2.2 Setting up SSH on Windows

SSH can run on Windows desktops and servers as well. In fact, you can disable WinRM if you really want to (we don’t suggest you do that). Most likely, if you are using SSH for remoting on a Windows device, you are either remoting to or from a Linux or macOS device.

Install the OpenSSH client and server:

Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
 
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

Here is the initial configuration of the SSH server:

Start-Service sshd
 
Set-Service -Name sshd -StartupType 'Automatic'

Confirm the firewall rule is configured. It should be created automatically by setup:

Get-NetFirewallRule -Name *ssh*

There should be a firewall rule named OpenSSH-Server-In-TCP, which should be enabled. Configure and edit the sshd_config file located at $env:ProgramDatassh on the target machine (figure 13.1).

Figure 13.1 This is what the sshd_config file looks like with the PowerShell changes added.

Verify that password authentication is enabled by removing the # sign:

PasswordAuthentication yes

Add the Subsystem for PowerShell. You can see that we are using the 8.3 short names for the file paths that contain spaces.

Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -NoLogo 
 -NoProfile

The 8.3 short name for the Program Files folder in Windows is usually Progra~1. However, you can use the following command to make sure:

Get-CimInstance Win32_Directory -Filter 'Name="C:\Program Files"' | 
 Select-Object EightDotThreeFileName

An optional enable-key authentication is

PubkeyAuthentication yes

Restart the OpenSSH service:

Restart-Service sshd

Be sure to secure your SSH server

You should research current standards for securing OpenSSH. At the time of writing, the basics are only to enable private-key authentication. Also, be sure to secure your private key. Here are links on how to do this for major platforms:

macOS: http://mng.bz/Bxyw

Ubuntu: http://mng.bz/do9g

13.3 PSRP over SSH overview

Let’s talk about SSH, because you’re going to have to configure it in order to use remoting. Once again, you need to configure PSRP over SSH—and PowerShell remoting—on only those computers that will receive incoming commands. In most of the environments we’ve worked in, the administrators have enabled remoting on every computer. 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.

SSH allows multiple subsystems to register. This allows different protocols to work over the same port. When you enable SSH remoting, PowerShell registers as a subsystem, and incoming connections from PSRP are routed to that subsystem. Figure 13.2 illustrates how the pieces fit together.

Figure 13.2 The relationship between OpenSSH and PowerShell

As shown, you can have dozens or even hundreds of sshd subsystems on your system. Each endpoint can point to a different application.

Figure 13.2 also illustrates the sshd listener. sshd acts as a listener sitting and waiting for incoming network traffic—kind of like a web server listening for incoming requests. A listener “listens” on a specific port and on a specific IP address.

Try it Now Go ahead and enable remoting on your second computer (or on the first one, if that’s the only one you have to work with). If you receive an error message when you enable remoting, stop and figure it out.

13.4 WinRM overview

Let’s talk about WinRM, because you’re going to have to configure it in order to use remoting. Once again, you need to configure WinRM—and PowerShell remoting—on only those computers that will receive incoming commands. In most of the environments we’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. Microsoft is starting to use it for more and more administrative communications—even things that use other protocols today. With that in mind, Microsoft made WinRM capable of routing traffic to multiple administrative applications—not only PowerShell. WinRM 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 as endpoints with WinRM so that WinRM will listen for incoming traffic on their behalf. This means you need to not only enable WinRM, but also tell PowerShell to register as an endpoint with WinRM. Figure 13.3 illustrates how the pieces fit together.

Figure 13.3 The relationship between WinRM, WSMan, endpoints, and PowerShell

As shown, you can have dozens or even hundreds of WinRM endpoints on your system (PowerShell calls them session configurations). Each endpoint can point to a different application, and you can even have endpoints that point to the same application but provide different permissions and functionality. For example, you could create a PowerShell endpoint that allows only one or two commands, and make it available to specific users in your environment. We don’t dive that deep into remoting in this chapter, but we do later in the book.

Figure 13.3 also illustrates the WinRM listener, which in the figure is of the HTTP variety. A listener sits and waits for incoming network traffic on behalf of WinRM—kind of like a web server listening for incoming requests. A listener “listens” on a specific port and on a specific IP address, although the default listener created by Enable-PSRemoting listens on all local IP addresses.

The listener connects to the defined endpoint. One way to create an endpoint 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. You don’t need to run that one; Enable-PSRemoting will call it for you, and Enable-PSRemoting performs 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.

Try it Now Go ahead and enable remoting on your second computer (or on the first one, if that’s the only one you have to work with). Make sure you’re running PowerShell as an administrator if you are on a Windows device (the Window’s title bar should read Administrator). If you’re not, close the shell, right-click the PowerShell icon in the Start menu, and select Run as Administrator from the context menu.

The most common error you will receive is “WinRM firewall exception will not work since one of the network connection types on this machine is set to Public.” Any network connection set to Public can’t have Windows Firewall exceptions, so when Enable-PSRemoting tries to create one, it fails. The only solution is to go into Windows and modify the network adapter setting so that whatever network you’re on is either Work or Home. But don’t do this if you’re connected to a public network (e.g., a public wireless hotspot), because you’ll be turning off some valuable security protections.

Note You don’t have to worry about PowerShell remoting and public networks as much on server operating systems, because they don’t have the same restrictions in the OS.

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). The necessary GPO settings are built into your domain controllers (you can download an ADM template from www.microsoft.com/en-us/download to add these GPO settings to an older domain’s domain controllers). Open a GPO and look under Computer Configuration > Administrative Templates > Windows Components. Near the bottom of the list, you’ll find both Remote Shell and Windows Remote Management. For now, we’ll assume you’ll run Enable-PSRemoting on those computers that you want to configure, because at this point you’re probably playing around with only a virtual machine or two.

Note PowerShell’s about_remote_troubleshooting help topic provides more coverage on using GPOs. Look for the “How to enable remoting in an enterprise” and “How to enable listeners by using a Group Policy” sections within that help topic.

13.5 Using Enter-PSSession and Exit-PSSession for one-to-one remoting

PowerShell uses remoting in two distinct ways. The first is one-to-one, or 1:1, remoting. The second is one-to-many, or 1:N, remoting (and you’ll see it in the next section). With one-to-one remoting, you’re 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 SSH or Remote Desktop Connection, except you are limited to the command-line environment of Windows PowerShell. This kind of remoting also uses a fraction of the resources that Remote Desktop requires, so it imposes much less overhead on your servers.

Before we can connect to a remote computer, we need you to understand the difference between -hostname and -computername parameters:

  • -hostname—Use this to use SSH.

  • -computername—Use this to connect via WinRM.

PowerShell has no way of knowing what protocol you are trying to use, so you have to tell it. To establish a one-to-one connection with a remote computer, run the following command:

Enter-PSSession -HostName Ubuntu1 -UserName tylerl
Enter-PSSession -ComputerName SRV2 -UserName contoso	ylerl

Alternatively, you can use this syntax:

Enter-PSSession -HostName tylerl@Ubuntu1

(You need to provide the correct computer name instead of SRV2 or Ubuntu1.)

Assuming that you enabled remoting on your remote computer, and you’re all in the same domain, and your network is functioning correctly, you should get a connection established. PowerShell lets you know that you’ve succeeded by changing the shell prompt:

[Ubuntu1] PS /home/tylerl>
 
[SRV2] PS C:>

The shell prompt tells you that everything you’re doing is taking place on Ubunut1 (or whichever server you connected to). You can run whatever commands you like. You can even import modules.

Try it Now Try to create a remoting connection to your second computer or virtual machine. If you haven’t done so, you’ll also need to enable remoting on that computer before you try to connect to it. Note that you need to know the hostname or IP address.

Any command you run on the remote computer will run under the credentials you use to authenticate, so you’ll be able to do anything you’d normally have permission to do. It’s as if you logged into that computer’s console and used its copy of PowerShell directly.

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 yet (they’re in chapter 26), but suffice it to say, 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.

Aside from this fairly minor caveat, you should be good to go. But wait—what do you do when you’re finished 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; run it and your shell prompt will change back to normal, and the remote connection will close automatically.

Try it Now Exit the remoting session, if you created one. We’re done with it for now.

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

We 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 Ubuntu, and you remote into SRV2. Then, at the PowerShell prompt, you run this:

[Ubuntu1] PS /home/tylerl>
Enter-PSSession -computername SRV2 -UserName contsco	ylerl

This causes Ubuntu1 to maintain an open connection to SRV2, which can start to create a remoting chain that’s hard to keep track of and that imposes unnecessary overhead on your servers. At times you may have to do this—we’re thinking mainly of instances where a computer such as SRV2 sits behind a firewall and you can’t access it directly, so you use SRV1 as a middleman to hop over to Server-DC4. But, as a general rule, try to avoid remote chaining. The PowerShell team has a great article on making a second hop in PowerShell Remoting at http://mng.bz/AxXe.

Caution Some people refer to remote chaining as the second hop, and it’s a major PowerShell gotcha. We offer a hint: If the PowerShell prompt is displaying a computer name, then you’re finished. You can’t issue any more remote control commands until you exit that session and “come back” to your computer.

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 running, as you’d expect it to.

13.6 Using Invoke-ScriptBlock for one-to-many remoting

The next trick—and honestly, this is one of the coolest things in PowerShell—is to send a command to multiple remote computers at the same time. That’s right, full-scale distributed computing. Each computer will independently execute the command and send the results back to you. It’s all done with the Invoke-ScriptBlock cmdlet, and it’s called one-to-many, or 1:N, remoting. The command looks like this:

Invoke-ScriptBlock -ComputerName SRV2,DC3,SRV4
-ScriptBlock { Get-Process pwsh } -UserName tylerl

Try it Now Run this command. Substitute the name of your remote computer (or computers) and username where we put our three server names.

Everything in those curly braces {} gets transmitted to the remote computers—all three of them. By default, PowerShell talks to up to 32 computers at once; if you specify more than that, it will queue them up, and as one computer completes, the next one in line will begin. If you have an awesome network and powerful computers, you could raise that number by specifying the -throttleLimit parameter of Invoke-ScriptBlock. Read the command’s help for more information.

Be careful about the punctuation

We need to further consider the syntax for a one-to-many remoting example, because in this case PowerShell’s punctuation can get confusing. That confusion can make you do the wrong thing when you start constructing these command lines on your own.

Here’s an example to consider:

Invoke-ScriptBlock -HostName SRV2,DC3,SRV4
-ScriptBlock { Get-Process pwsh  | 
Where-Object {$_.Parent.ProcessName -like '*term*'}} -UserName

Two commands in this example use curly braces: Invoke-ScriptBlock and Where-Object. Where-Object is entirely nested within the outer set of braces. The outermost set of braces encloses everything that’s being sent to the remote computers for execution:

Get-Process pwsh  | Where-Object {$_.Parent.ProcessName -like '*term*'}

Following that nesting of commands can be tough, particularly in a book like this one, where the physical width of the page makes it necessary to display the command across several lines of text.

Be sure you can identify the exact command that’s being sent to the remote computer and that you understand the use for each matched set of curly braces.

If you carefully read the help for Invoke-ScriptBlock (see how we’re continuing to push those help files?), you’ll also notice a parameter that lets you specify a script file, rather than a command. That parameter lets you send an entire script from your local computer to the remote computers—meaning you can automate some complex tasks and have each computer do its own share of the work.

Try it Now Make sure you can identify the -ScriptBlock parameter in the help for Invoke-ScriptBlock and that you can spot the parameter that would enable you to specify a file path and name instead of a script block.

We want to circle back to the -HostName parameter we mentioned at the beginning of the chapter. When we first used Invoke-ScriptBlock, we typed a comma-separated list of hostnames, as we did in the previous example. But we work with a lot of computers, and we don’t want to have to type them all in every time. We keep text files for some of our common computer categories, such as web servers and domain controllers. Each text file contains one computer name per line, and that’s it—no commas, no quotes, no nothing. PowerShell makes it easy for us to use those files:

Invoke-ScriptBlock -ScriptBlock { dir } 
-HostName (Get-Content webservers.txt) -UserName tylerl

The parentheses here force PowerShell to execute Get-Content first—the same way parentheses work in math. The results of Get-ScriptBlock are then stuck into the -HostName parameter, which works against each of the computers listed in the file.

13.7 Differences between remote and local commands

We want to explain the differences between running commands by using Invoke-ScriptBlock and running those same commands locally, as well as the differences between remoting and other forms of remote connectivity. For this discussion, we’ll use this command as our example:

Invoke-ScriptBlock -HostName SRV2,DC3,SRV4
-ScriptBlock { Get-Process pwsh -UserName tylerl  | 
Where-Object {$_.Parent.ProcessName -like '*term*'}}

13.7.1 Deserialized objects

Another caveat to keep in mind about remoting is that the objects that come back to your computer aren’t fully functional. In most cases, they lack methods, because they’re no longer “attached” to “live” software.

For example, run this on your local computer, and you’ll notice that a System .Diagnostics.Process object has numerous methods associated with it:

PS > Get-Process | Get-Member
 
 
   TypeName: System.Diagnostics.Process
 
Name                       MemberType     Definition
----                       ----------     ----------
Handles                    AliasProperty  Handles = Handlecount
Name                       AliasProperty  Name = ProcessName
NPM                        AliasProperty  NPM = NonpagedSystemMemory...
PM                         AliasProperty  PM = PagedMemorySize64
SI                         AliasProperty  SI = SessionId
VM                         AliasProperty  VM = VirtualMemorySize64
WS                         AliasProperty  WS = WorkingSet64
Parent                     CodeProperty   System.Object Parent{get=G...
Disposed                   Event          System.EventHandler Dispos...
ErrorDataReceived          Event          System.Diagnostics.DataRec...
Exited                     Event          System.EventHandler Exited...
OutputDataReceived         Event          System.Diagnostics.DataRec...
BeginErrorReadLine         Method         void BeginErrorReadLine()
BeginOutputReadLine        Method         void BeginOutputReadLine()
CancelErrorRead            Method         void CancelErrorRead()
CancelOutputRead           Method         void CancelOutputRead()
Close                      Method         void Close()
CloseMainWindow            Method         bool CloseMainWindow()
Dispose                    Method         void Dispose(), void IDisp...
Equals                     Method         bool Equals(System.Object ...
GetHashCode                Method         int GetHashCode()
GetLifetimeService         Method         System.Object GetLifetimeS...
GetType                    Method         type GetType()
InitializeLifetimeService  Method         System.Object InitializeLi...
Kill                       Method         void Kill(), void Kill(boo...
Refresh                    Method         void Refresh()
Start                      Method         bool Start()
ToString                   Method         string ToString()
WaitForExit                Method         void WaitForExit(), bool W...
WaitForInputIdle           Method         bool WaitForInputIdle(), b...
__NounName                 NoteProperty   string __NounName=Process

Now get some of those same objects via remoting:

PS > Invoke-ScriptBlock {Get-Process} -HostName localhost -UserName tylerl | 
    Get-Member
 
 
   TypeName: Deserialized.System.Diagnostics.Process
 
Name                       MemberType   Definition
----                       ----------   ----------
GetType                    Method       type GetType()
ToString                   Method       string ToString(), string To...
Company                    NoteProperty object Company=null
CPU                        NoteProperty object CPU=null
Description                NoteProperty object Description=null
FileVersion                NoteProperty object FileVersion=null
Handles                    NoteProperty int Handles=0
Name                       NoteProperty string Name=
NPM                        NoteProperty long NPM=0
Parent                     NoteProperty object Parent=null
Path                       NoteProperty object Path=null
PM                         NoteProperty long PM=0
Product                    NoteProperty object Product=null
ProductVersion             NoteProperty object ProductVersion=null
PSComputerName             NoteProperty string PSComputerName=localh...
PSShowComputerName         NoteProperty bool PSShowComputerName=True
RunspaceId                 NoteProperty guid RunspaceId=26297051-1cb...
SI                         NoteProperty int SI=53860
VM                         NoteProperty long VM=0
WS                         NoteProperty long WS=0
__NounName                 NoteProperty string __NounName=Process
BasePriority               Property     System.Int32 {get;set;}
Container                  Property      {get;set;}
EnableRaisingEvents        Property     System.Boolean {get;set;}              

The methods—except the universal ToString() and GetType() methods common to all objects—are gone. This is a read-only copy of the object; you can’t tell it to do things like stop, pause, resume, and so forth. So any actions you want taken as the result of your command should be included in the script block that’s sent to the remote computer; that way, the objects are still live and contain all of their methods.

13.7.2 Local vs. remote processing

We’ll cite our original example again:

Invoke-ScriptBlock -HostName SRV2,DC3,SRV4
-ScriptBlock { Get-Process pwsh -UserName tylerl  | 
Where-Object {$_.Parent.ProcessName -like '*term*'}}

Here’s what happens here:

  • The computers are contacted in parallel, meaning the command can complete somewhat more quickly.

  • Each computer queries the records and filters them locally. The only data transmitted across the network is the result of that filtering, meaning that only the records we care about are transmitted.

  • Before transmitting, each computer serializes its output into XML. Our computer receives that XML and deserializes it back into something that looks like objects. But they aren’t real event log objects, and that might limit what we can do with them once they’re on our computer.

Now, compare it to this alternative:

Invoke-ScriptBlock -HostName SRV2,DC3,SRV4
-ScriptBlock { Get-Process pwsh } -UserName tylerl  | 
Where-Object {$_.Parent.ProcessName -like '*term*'}

The differences are subtle. Well, we see only one difference: we moved one of those curly braces.

In the second version, only Get-Process is being invoked remotely. All of the results generated by Get-Process are serialized and sent to our computer, where they’re deserialized into objects and then piped to Where and filtered. The second version of the command is less efficient, because a lot of unnecessary data is being transmitted across the network, and our one computer has to filter the results from three computers, rather than those three computers filtering their own results for us. The second version, then, is a bad idea.

Let’s look at two versions of another command, starting with the following:

Invoke-ScriptBlock -ComputerName SRV2 
-ScriptBlock { Get-Process -name pwsh } -UserName tylerl |
Stop-Process

Now let’s look at the second version:

Invoke-ScriptBlock -ComputerName SRV2
-ScriptBlock { Get-Process -name pwsh } -UserName tylerl |
Stop-Process }

Once again, the only difference between these two is the placement of a curly brace. But in this example, the first version of the command won’t work.

Look carefully: we’re sending Get-Process -name pwsh to the remote computer. The remote computer retrieves the specified process, serializes it into XML, and sends it to us across the network. Our computer receives that XML, deserializes it back into an object, and pipes it to Stop-Process. The problem is that the deserialized XML doesn’t contain enough information for our computer to realize that the process came from a remote machine. Instead, our computer will try to stop the pwsh process running locally, which isn’t what we want at all.

The moral of the story is to always complete as much of your processing on the remote computer as possible. The only thing you should expect to do with the results of Invoke-ScriptBlock is to display them or store them as a report, or a data file, and so forth. The second version of our command follows that advice: what’s being sent to the remote computer is Get-Process -name pwsh | Stop-Process, so the entire command—both getting the process and stopping it—happens on the remote computer. Because Stop-Process doesn’t normally produce any output, there won’t be any objects to serialize and send to us, so we won’t see anything on our local console. But the command will do what we want: stop the pwsh process on the remote computer, not on our local machine.

Whenever we use Invoke-ScriptBlock, we always look at the commands after it. If we see commands for formatting, or for exporting data, we’re fine, because it’s okay to do those things with the results of Invoke-ScriptBlock. But if Invoke-ScriptBlock is followed by action cmdlets—ones that start, stop, set, change, or do something else—then we sit back and try to think about what we’re doing. Ideally, we want all of those actions to happen on the remote computer, not on our local computer.

13.8 But wait, there’s more

The previous examples have all used ad hoc remoting connections, meaning that we specified hostnames. If you’re going to be reconnecting to the same computer (or computers) several times within a short period of time, you can create reusable, persistent connections to use instead. We cover that technique in chapter 18.

We should also acknowledge that not every company is going to allow PowerShell remoting to be enabled—at least, not right away. Companies with extremely restrictive security policies may, for example, have firewalls on all client and server computers, which would block the remoting connection. If your company is one of those, see whether an exception is in place for SSH or WinRM. We find that’s a common exception, because administrators obviously need some remote connectivity to servers. If SSH or WinRM is allowed, then you can user PowerShell remoting over SSH.

13.9 Common points of confusion

Whenever beginners using remoting, some common problems crop up over the course of the day:

  • Remoting is designed to be more or less automatically configured. If every computer involved is on the same domain, and your username is the same, things will typically work great. If not, you need to run help about_remote_troubleshooting and dig into the details.

  • When you invoke a command, you’re asking the remote computer to launch PowerShell, run your command, and then close PowerShell. The next command you invoke on that same remote computer will be starting from scratch—anything that was run in the first invocation will no longer be in effect. If you need to run a whole series of related commands, put them all into the same invocation.

13.10 Lab

Note For this lab, you need a computer running PowerShell v7 or later. Ideally, you should have two computers on the same network with remoting enabled.

It’s time to combine some of what you’ve learned about remoting with what you’ve learned in previous chapters. See if you can accomplish the following tasks:

  1. Make a one-to-one connection with a remote computer (or with localhost if you have only one computer). Launch your favorite text editor. What happens?

  2. Using Invoke-ScriptBlock, retrieve a list of processes currently running from one or two remote computers (it’s okay to use localhost twice if you have only one computer). Format the results as a wide list. (Hint: It’s okay to retrieve results and have the formatting occur on your computer—don’t include the Format- cmdlets in the commands that are invoked remotely.)

  3. Use Invoke-ScriptBlock to get a list of the top 10 processes for virtual memory (VM) usage. Target one or two remote computers, if you can; if you have only one computer, target localhost twice.

  4. Create a text file that contains three computer names, with one name per line. It’s okay to use the same computer name, or localhost, three times if you have access to only one computer. Then use Invoke-ScriptBlock to retrieve the 10 newest files from the home directory (~).

  5. Using Invoke-ScriptBlock, query one or more remote computers to display the property PSVersion from the $PSVersionTable variable. (Hint: This requires you to get the property of an item.)

13.11 Lab answers

  1. Enter-PSSession Server01

    [Ubuntu1] /home/tylerl> nano

    The nano process will launch, but there won’t be any interactive process either locally or remotely. In fact, run this way, the prompt won’t return until the nano process ends—although an alternative command to launch it is Start-Process nano.

    [SRV2] PS C:UsersAdministratorDocuments> Notepad

    The Notepad process will launch, but there won’t be any interactive process either locally or remotely. In fact, run this way, the prompt won’t return until the Notepad process ends—although an alternative command to launch it is Start-Process Notepad.

  2. Invoke-ScriptBlock –scriptblock {Get-Process } -HostName

    Server01,Server02 -UserName yourUser | Format-Wide -Column 4

  3. Invoke-ScriptBlock -scriptblock {get-process | sort VM -Descending |

    Select-first 10} –HostName Server01,Server02 -UserN

  4. Invoke-ScriptBlock -scriptblock { Get-ChildItem ~/* | Sort-Object

    -Property LastWriteTime -Descending | Select-Object -First 10}

    -HostName (Get-Content computers.txt) -UserName yourUser

  5. Invoke-ScriptBlock –scriptblock $ -Server01,Server02 -UserName yourUser

13.12 Further exploration

We could cover a lot more about remoting in PowerShell—enough that you’d be reading about it for another month of lunches. Unfortunately, some of its trickier bits aren’t well documented. We suggest heading up to PowerShell.org, and more specifically to their e-book resources, where Don and fellow MVP Dr. Tobias Weltner have put together a comprehensive (and free!) Secrets of PowerShell Remoting mini e-book for you (see https://leanpub.com/secretsofpowershellremoting). The guide rehashes some of the basics you learned in this chapter, but it primarily focuses on detailed, step-by-step directions (with color screenshots) that show how to configure a variety of remoting scenarios. The guide also digs into some of the grittier details of the protocol and troubleshooting, and even has a short section on how to talk to information security people about remoting. The guide is updated periodically, so check back every few months to make sure you have the latest edition.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.147.160