Summary: Richard Siddaway explains how to use Windows PowerShell remoting to access machines that aren’t in your domain.

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 final part of a series of five posts about remoting. To catch up on the previous posts, see:

  1. Remoting Recap
  2. Remoting Sessions
  3. Configuring Remoting
  4. Remoting Security

So far in this series, you have seen how to perform ad hoc remoting to systems by using the ComputerName parameter on various cmdlets. This leads into Windows PowerShell remoting sessions where you create a persistent connection to one or more remote machines. You can use that connection to run multiple commands, and only set up and tear down the connection once, instead of once per command.

Any remote connectivity system needs to be secure and that is certainly true of Windows PowerShell remoting. In the third part of the series, you saw how HTTPS can be used to secure traffic between the remote system and your administration machine. You also saw how the configuration of the endpoints can be modified to give you more control and lock down the endpoint.

Custom endpoints can be used to control who can access the endpoint and what they can do. This includes the Windows PowerShell language features and the cmdlets that are available. You can control a range; for example, you can make available the full language and all the installed cmdlets, or you can create a situation where the admin who is connecting to that endpoint can’t use the Windows PowerShell language and can only run a hand full of cmdlets. You can connect to that endpoint by using the Windows PowerShell tools, or you can use Windows PowerShell Web Access to give you a Windows PowerShell session that is hosted in your browser by accessing that endpoint.

In all of these examples, the assumption is that you are remoting within the domain. You may think that Windows PowerShell Web Access doesn’t fit this model, but the Windows PowerShell Web Access server may be in the domain, so the remoting sessions are between machines in the same domain.

What about the situation where the machines aren’t in the same domain? You can recognize three broad scenarios for non-domain remoting:

  1. Remoting into a domain
  2. Remoting across domains
  3. Remoting in workgroups

Remember that you need network connectivity to the remote machine over the ports that WSMAN will be using. The defaults are HTTP over port 5985 or HTTPS over port 5986.

You have already seen one way to solve the issues around options 1 and 2: use Windows PowerShell Web Access.  It provides a gateway into the domain that can be used to easily access remoting endpoints within that domain in a secure manner.

If the domain to which you are remoting is in the same forest, your environment may be configured to allow the use of your standard credentials. If not, you are back to a situation that can span all three options: you need to remote to a system that isn’t in your current domain. Even the workgroup situation can be regarded as a special case in this scenario.

So what happens if you try to remote to a machine that isn’t in your domain?

£> $cred = Get-Credential

£> $sess = New-PSSession -ComputerName server02

New-PSSession : [server02] Connecting to remote server server02 failed with the following error message : The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help

config. For more information, see the about_Remote_Troubleshooting Help topic.

At line:1 char:9

+ $sess = New-PSSession -ComputerName server02

+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotin

   gTransportException

    + FullyQualifiedErrorId : ServerNotTrusted,PSSessionOpenFailed

Trying to use an IP address such as the following will generate a similar error:

$sess = New-PSSession -ComputerName 10.10.54.201 -Credential $cred

The issue is that the client machine and the remote machine are not able to mutually authenticate as they would within a domain. The error messages are useful in that they provide a couple of possible answers:

  • Install a SSL certificate, and use HTTPS to connect to the remote machine.
  • Add the machine to the trusted hosts list.

I discussed using HTTPS in Configuring Remoting, so this time I will solve the issue by using the trusted hosts list. The trusted hosts list effectively bypasses the mutual authentication at the machine level. By placing a system in the list, you are explicitly stating that you trust the system and that it is safe to connect to that system.

You can view the contents of the trusted hosts list by accessing the WSMAN provider:

£> Get-Item -Path WSMan:\localhost\Client\TrustedHosts

   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client

Type            Name                           SourceOfValue   Value

----            ----                           -------------   -----

System.String   TrustedHosts

In this case, the list is empty. Remember that you can also connect to the WSMAN provider on a remote machine by using Connect-WSMan and examine the settings there. Another way is to use the WSMAN cmdlets:

£> Get-WSManInstance -ResourceURI winrm/config/client

cfg              : http://schemas.microsoft.com/wbem/wsman/1/config/client

lang             : en-GB

NetworkDelayms   : 5000

URLPrefix        : wsman

AllowUnencrypted : false

Auth             : Auth

DefaultPorts     : DefaultPorts

TrustedHosts     :

Set-Item can be used to modify the trusted hosts list:

£> Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value 'server02'

WinRM Security Configuration.

This command modifies the TrustedHosts list for the WinRM client. The computers in the TrustedHosts list might not be authenticated. The client might send credential information to these computers. Are you sure that you want to modify this list?

[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): Y

The WSMAN provider adds –Concatenate as dynamic parameter to Set-Item.  You can also use –Force to bypass the confirm message:

£> Get-Item -Path WSMan:\localhost\Client\TrustedHosts | fl Name, Value

Name  : TrustedHosts

Value : server02

£> Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value '10.10.54.201' -Concatenate -Force

£> Get-Item -Path WSMan:\localhost\Client\TrustedHosts | fl Name, Value

Name  : TrustedHosts

Value : server02,10.10.54.201

Again the WSMAN cmdlets are an alternative:

£> $hosts = 'server02,10.10.54.201'

£> Set-WSManInstance -ResourceURI winrm/config/client -ValueSet @{TrustedHosts=$hosts}

cfg              : http://schemas.microsoft.com/wbem/wsman/1/config/client

lang             : en-GB

NetworkDelayms   : 5000

URLPrefix        : wsman

AllowUnencrypted : false

Auth             : Auth

DefaultPorts     : DefaultPorts

TrustedHosts     : server02,10.10.54.201

When you have the correct values in the trusted host list, you need to define a credential to access that machine. It can be a local domain or machine, depending on the scenario. If it’s a local machine, remember to present UserId as <machine name>/userid. Otherwise, Windows PowerShell will think the credential is on your local machine.

$cred = Get-Credential

You then create a session to that remote machine as normal, and use the credential you created:

$sess = New-PSSession -ComputerName server02 -Credential $cred

Invoke-Command -Session $sess -ScriptBlock{Get-Service}

Normally, you can’t create remoting sessions to IP addresses. But because the IP address is in the trusted hosts list, you can do this:

$sess2 = New-PSSession -ComputerName 10.10.54.201 -Credential $cred

Invoke-Command -Session $sess2 -ScriptBlock{Get-Service}

You may see references on the Internet to having a single value in the trusted hosts list of *. This acts as a wildcard character that says trust every machine, everywhere. I have one simple piece of advice: Don’t do it! I don’t do that in a lab environment, not to mention in production.

One possibility to consider is to script the setting of the trusted hosts list and then script the removal of the values after you have done your work. This reduces the security impact of using the trusted hosts file.

If you are working wholly within your network, using the trusted hosts file is a workable solution. If you are accessing a remote machine from outside your environment, consider using Windows PowerShell Web Access.

This concludes my mini-series about Windows PowerShell remoting. You have seen various ways that you can connect to a remote machine, and I made recommendations as to when particular techniques should be used. More information is available in the Windows PowerShell Help files, and you can discover further details about configuring remoting and some other edge cases in Chapter 10 of PowerShell in Depth by myself, Don Jones, and Jeffery Hicks.

Bye for now.

~Richard

Thanks, Richard! This has been an awesome 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