Remoting Week: Remoting Recap

Doctor Scripto

Summary: Richard Siddaway explains various ways to interact with remote machines. Hey, Scripting Guy! Question Hey, Scripting Guy! I’ve just starting learning Windows PowerShell, and I understand how to use it as a scripting language and shell on the local machine. How do I work with remote machines? —AP Hey, Scripting Guy! Answer Hello AP, Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the first part of a series of five posts about remoting:

  1. Remoting Recap
  2. Remoting Sessions
  3. Configuring Remoting
  4. Remoting Security
  5. Non-Domain Remoting

Let’s start at the beginning and recap the various ways you can access a remote machine through Windows PowerShell. When you add them up, you have a surprising number. Unless you work for an organization that has only one server that is stored under your desk, you need to be able to access your servers remotely. You could use RDP to log on to the server and work with the GUI tools. Sometimes that is the correct action. But for any process that involves multiple machines, you need to be able to access those servers through Windows PowerShell. Remote access in WindowsPowerShell 1.0 was only available through WMI. Since then, a number of options have been introduced with successive versions of Windows PowerShell, including:

  • Individual cmdlets provide access to remote machines in various versions
  • WMI cmdlets in Windows PowerShell 2.0
  • Windows PowerShell remoting over WSMAN in Windows PowerShell 2.0
  • WSMAN cmdlets in Windows PowerShell 2.0
  • CIM sessions in Windows PowerShell 3.0
  • Windows PowerShell Web Access in Windows Server 2012 

Windows PowerShell 4.0 doesn’t introduce any new remoting mechanisms. In addition, there are two models that you should keep in mind. First is fan-out remoting, where you administer many machines from a single administration machine. This is probably the most common approach. Your second option is fan-in remoting, where many connections can be made to a single machine. This is seen when you are administering Exchange Server or using Windows PowerShell Web Access. One approach isn’t superior to the other—it’s a matter of what works best in a given scenario. To start our dive into remoting, let’s look at how individual cmdlets work against remote machines. In Windows PowerShell 1.0, Get-WmiObject was the only cmdlet that had the ability to work with remote machines. It had a –ComputerName parameter. Since then, that parameter has been added to many other cmdlets. You can find out which cmdlets have remoting capability by using Get-Help:

Get-Help * -Parameter ComputerName The cmdlets with remoting capability enable you to work with:

  • Computers
  • Event logs
  • WMI
  • Connection (Ping)
  • Services
  • Windows PowerShell remoting sessions
  • Jobs
  • Command (Invoke-Command)
  • Processes
  • Hotfixes
  • CIM sessions

Windows Server 2012 R2 dramatically increases these options. Examples of using cmdlet-based remoting include:

Get-Service –ComputerName server02

Get-EventLog –LogName Application –ComputerName server02 Having the ability to work with remote computers from individual cmdlets is great for ad hoc work, but this approach has some drawbacks. The major issue is the way that the cmdlets connect to the remote machine. This is usually over DCOM, which is not a firewall-friendly protocol. If any firewalls on the network path to the remote server aren’t configured to pass DCOM traffic, the remoting won’t work. The WMI cmdlets have the same issue. They access remote machines over DCOM.

Get-WmiObject –Class Win32_OperatingSystem –ComputerName server02 If DCOM isn’t configured on the remote machine, or firewalls aren’t configured to pass DCOM, the remoting connection will fail—usually with an “RPC server not available” type of message. The other issue with remoting at this level is that the remote connection is created and destroyed every time you use the cmdlet. This adds an overhead to your processing that can significantly increase run times if you are making many calls against the same remote machine. Windows PowerShell 2.0 introduced remoting. This works over the industry standard WSMAN protocol (WinRm is Microsoft’s implementation of WSMAN). This approach is much more firewall friendly because it works over HTTP (and HTTPS, if desired). You need to enable the remote machine for remoting:

Enable-PSRemoting –Force

Note  Recent Windows Server operating systems automatically enable remoting when they are installed. The WinRm service will be configured to receive requests and for remote management. The –Force parameter removes the need for interactive confirmation during the enablement process. After you have enabled remoting on the remote machine, you have three choices:

  • You can create an interactive remote session.
  • You can use Invoke-Command and give it the name of the remote machine.
  • You can create a remote session to the machine and pass your commands to the session by using Invoke-Command

You will learn more about these options tomorrow when we look at remote sessions in detail. Today, we’ll stick at the cmdlet level and look at using Invoke-Command with the ComputerName parameter:

Invoke-Command -ComputerName server02 -ScriptBlock {Get-Service} This command appears to return the same information as using the cmdlet directly, but there is a significant difference in the object type that is returned by using the remoting capability that is built-in to a cmdlet and using Windows PowerShell remoting. Compare the output of these two statements (output is cut for brevity):

£> Get-Service -ComputerName server02 | Get-Member

   TypeName: System.ServiceProcess.ServiceController

 

£> Invoke-Command -ComputerName server02 -ScriptBlock {Get-Service} | Get-Member

   TypeName: Deserialized.System.ServiceProcess.ServiceController Using the cmdlet provides us with a System.ServiceProcess.ServiceController object for each service on the remote machine. This is exactly the same object you would get if you ran Get-Service against the local machine. By using remoting, you get a Deserialized.System.ServiceProcess.ServiceController object. If you look closely at the output of Get-Member, you will see the methods such as Start and Stop aren’t available for the deserialized object. It’s an inert object. In a nutshell, when you use the Windows PowerShell remoting technology and connect over WSMAN, the results are serialized, that is, turned into XML. They are passed over the WSMAN connection, back to the local machine, and then deserialized. The object’s methods are lost in this serialization-deserialization process. An important point to note is that this happens across any WSMAN-based connection, including the WSMAN cmdlets, the CIM cmdlets and CIM sessions. I explained the implications of this in my recent post Hey, Dude! Where Are My Methods?. When you look around the wide variety of information that is available about Windows PowerShell, you won’t find very much about the WSMAN cmdlets. The best current reference (of which I’m aware) is Chapter 17 of PowerShell and WMI. The WSMAN cmdlets enable you to access remote machines to work with WMI and the WSMAN configuration. The syntax for these cmdlets can become a bit messy, but they are useful. The reason for that usefulness is that they work over WSMAN rather than DCOM, so you can bypass some of the firewall restrictions. They will also work against non-Windows devices, assuming those devices are configured with a WMI (usually referred to as the more generic CIMON) provider and a WSMAN stack. For example, VMware host servers can be interrogated by using the WSMAN cmdlets. As an example of their use, consider:

Get-WSManInstance -ResourceURI wmicimv2/Win32_Process -SelectorSet @{Handle=6588} -ComputerName $computer This retrieves the Win32_Process class instance for a given handle. In this case, it’s an instance of Windows PowerShell. How can you find the handle?

Get-WSManInstance -ResourceURI wmicimv2/Win32_Process -Enumerate  -ComputerName $computer  | select Name, Handle, ExecutablePath This is one of the quirks of using the WSMAN cmdlets. You can only retrieve individual instances of a WMI class if you know the property that is the key for that class. For a tip about how to find the key, see PowerTip: Use PowerShell to Find key of WMI Class. The data returned from the WSMAN cmdlets has an amazing type name:

System.Xml.XmlElement#http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process#Win32_Process Notice that it is XML, not a deserialized object as is returned by remoting. The content of the data can also seem odd in that an empty property doesn’t return a null value—it returns the name of the property, as this example shows:

SessionId                  : 1

Status                     : Status

TerminationDate            : TerminationDate

ThreadCount                : 10

Note  I’ll be talking about the WSMAN cmdlets at the Windows PowerShell Summit North America in April 2014. If Ed is agreeable I’ll write up the talk for the Hey, Scripting Guy! Blog after the summit. Windows PowerShell 3.0 provides you with another way to access WMI over the WSMAN protocol. You can use the CIM cmdlets and CIM sessions:

Get-CimInstance -ClassName Win32_Process -ComputerName $computer -Filter “Name=’powershell.exe'” This is the equivalent of using Get-WmiObject against the remote machine, except you are connecting over WSMAN rather than DCOM. If you want to run multiple commands against a remote machine, create a CIM session to save you the overhead of the continual set up and tear down of the connections:

$sess = New-CimSession -ComputerName $computer

Get-CimInstance -ClassName Win32_Process -CimSession $sess -Filter “Name=’powershell.exe'” You create a session to the remote machine by supplying its name to New-CimSession. You can then use the session in the call to Get-CimInstance. There is a drawback to this. The CIM cmdlets and sessions fail if you run them against a machine running Windows PowerShell 2.0 because the WSMAN stacks are incompatible. You need to revert to DCOM:

$opt = New-CimSessionOption -Protocol DCOM

$sessd = New-CimSession -ComputerName $computer -SessionOption $opt

Get-CimInstance -ClassName Win32_Process -CimSession $sessd -Filter “Name=’powershell.exe'” The great thing is that you can mix and match WSMAN-based and DCOM-based CIM sessions in your scripts to access multiple machines with different versions of WSMAN. You can use Test-WSMan to determine the WSMAN version of the remote machine. The last remoting option that I want to mention is Windows PowerShell Web Access. This was introduced in Windows Server 2012 and enhanced in Windows Server 2012 R2. You install Windows PowerShell Web Access on a server and configure it to point to one or more remoting endpoints on remote machines. Each remote machine has to be specified individually to Windows PowerShell Web Access. The endpoints can be locked down with regard to the cmdlets, the Windows PowerShell language features that they expose, and the users who are allowed to access that remote machine and endpoint. You can connect to Windows PowerShell Web Access through a browser, and after you are authenticated, you effectively get Windows PowerShell running in a browser. The browser can run on any device. I demonstrated connecting to Windows PowerShell Web Access from a Linux system at the 2013 PowerShell Summit. I’ll discuss configuring Windows PowerShell Web Access in more detail in a later post in this series. Bye for now. ~Richard Thanks, Richard. This will be an excellent series! I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace. Ed Wilson, Microsoft Scripting Guy 

0 comments

Discussion is closed.

Feedback usabilla icon