Powershell Remoting

Posted in automation, windows on March 11, 2017 by Adrian Wyssmann ‐ 6 min read

Powershell remoting enables to work on a remote computer as you may be used on Linux using ssh. In difference to Linux, where this is usually straight-forward, I find it a bit more complicated on Windows - however achievable. There are two was a remote PS connection can be established - via HTTP or HTTPS.

Configure Remote Host

In order to get PS remoting working the host needs to be configured accordingly. First and foremost, ensure that there are no firewall rules blocking traffic on port 5985 and 5986 - no company firewall, no windows firewall. After that running “Enable-PSremoting” on the remote host should do the trick, so let’s try to connect from my working machine to remote host POWERSHELLTEST (10.10.10.123) which is btw. not in a domain - an information which is essential as you can see in a little:

PS C:\Users\Administrator> New-PSSession -ComputerName POWERSHELLTEST
Enter-PSSession : Connecting to remote server POWERSHELLTEST failed with the following error message : WinRM cannot process the request. The following error occurred while using Kerberos authentication:
Cannot find the computer POWERSHELLTEST. Verify that the computer exists on the network and that the name provided is spelled correctly. For more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -Computername POWERSHELLTEST
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (POWERSHELLTEST:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

Nope. So if the host name cannot be found, let’s try with the IP then….

PS C:\Users\Administrator> New-PSSession 10.10.10.123
Enter-PSSession : Connecting to remote server 10.10.10.123 failed with the following error message : The WinRM client cannot process the request. Default authentication may be used with an IP address
under the following conditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided. Use winrm.cmd to configure TrustedHosts. Note that computers in
the TrustedHosts list might not be authenticated. For more information on how to set TrustedHosts run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting
Help topic.
At line:1 char:1
+ Enter-PSSession 10.10.10.123
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (10.10.10.123:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

Doesn’t work neither. Well at least the error message is more clear what I have to to if I want to use the IP address instead of the host name. However, more interestingly is that the host name cannot be found even so the name resolution is fine - I get a valid reply when I ping POWERSHELLTEST. So what is it then? After digging a bit I have found that the first error message is actually a bit misleading as you can read here:

When you are working with computers in workgroups or homegroups, you must either use HTTPS as the transport or add the remote machine to the TrustedHosts configuration settings. If you cannot connect to a remote host, verify that the service on the remote host is running and is accepting requests by running the following command on the remote host:

winrm quickconfig

In any case with my current setup - remote host not in a domain - I have to connect via https. So let’s run winrm quickconfigas suggested:

PS C:\Users\Administrator.POWERSHELLTEST> winrm quickconfig
WinRM service is already running on this machine.
WinRM is already set up for remote management on this computer.

My remote host seems already configured, so let’s check that

PS C:\Users\Administrator.POWERSHELLTEST> winrm g winrm/config/client
Client
    NetworkDelayms = 5000
    URLPrefix = wsman
    AllowUnencrypted = false
    Auth
        Basic = true
        Digest = true
        Kerberos = true
        Negotiate = true
        Certificate = true
        CredSSP = false
    DefaultPorts
        HTTP = 5985
        HTTPS = 5986
    TrustedHosts

As you can see there are not TrustedHosts defined, so we need to set this. You may use a * which allows any host to connect, but this is not really recommended. So let’s only set my local computer (WINDOWS10) to the list:

PS C:\Users\Administrator.POWERSHELLTEST> winrm s winrm/config/client '@{TrustedHosts="WINDOWS10"}'

Create a Session

Let’s give it another try to connect to the remote host:

PS C:\Users\Administrator> Enter-PSSession -ComputerName POWERSHELLTEST -UseSSL
Enter-PSSession : Connecting to remote server POWERSHELLTEST failed with the following error message : The server certificate on the destination computer (POWERSHELLTEST:5986) has the following errors:
The SSL certificate is signed by an unknown certificate authority.
The SSL certificate contains a common name (CN) that does not match the hostname. For more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -Computername POWERSHELLTEST -UseSSL
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (POWERSHELLTEST:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

For now I want to stick to the self-signed certificate therefore I have to find a way to disable the CA verification. Unfortunately New-PSSession does not list any specific parameter for that purpose, but -SessionOption {PSSessionOption} sounds promising. When looking into the details you can find the following

-SkipCACheck

Specifies that when it connects over HTTPS, the client does not validate that the server certificate is signed by a trusted certification authority (CA).

-SkipCNCheck

Specifies that the certificate common name (CN) of the server does not have to match the host name of the server. This option is used only in remote operations that use the HTTPS protocol.

Good, that shall help, so let’s create a PSSessionOption object with these options …

PS C:\Users\Administrator> $options = New-PSSessionOption  -SkipCACheck -SkipCNCheck
PS C:\Users\Administrator> $options


MaximumConnectionRedirectionCount : 5
NoCompression                     : False
NoMachineProfile                  : False
ProxyAccessType                   : None
ProxyAuthentication               : Negotiate
ProxyCredential                   :
SkipCACheck                       : True
SkipCNCheck                       : True
SkipRevocationCheck               : False
OperationTimeout                  : 00:03:00
NoEncryption                      : False
UseUTF16                          : False
IncludePortInSPN                  : False
OutputBufferingMode               : None
Culture                           :
UICulture                         :
MaximumReceivedDataSizePerCommand :
MaximumReceivedObjectSize         :
ApplicationArguments              :
OpenTimeout                       : 00:03:00
CancelTimeout                     : 00:01:00
IdleTimeout                       : -00:00:00.0010000

… and try to connect again

PS C:\Users\wyssmana> Enter-PSSession -ComputerName POWERSHELLTEST -UseSSL -SessionOption $options
Enter-PSSession : Connecting to remote server POWERSHELLTEST failed with the following error message : WinRM cannot process the request. The following error occurred while using Kerberos authentication:
Cannot find the computer POWERSHELLTEST. Verify that the computer exists on the network and that the name provided is spelled correctly. For more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -Computername POWERSHELLTEST -UseSSL -SessionOption $options
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (POWERSHELLTEST:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

Still not working. As usual, the error message does not give a real indication of the problem. If you check in description of New-Pssession you might realize that is uses current user for authentication per default. As the local user and the remote user are distinct ones, I have to specify valid credentials. So let’s create a credential object …

PS C:\Users\Administrator> $cred = Get-Credential

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PS C:\Users\Administrator> $cred

UserName                                    Password
--------                                    --------
Administrator           System.Security.SecureString

… and us this when creating your PS session.

Connect to Remote Host

Once the session options and the credentials are set properly the connection shall work

PS C:\Users\Administrator> Enter-PSSession -Computername POWERSHELLTEST -UseSSL -SessionOption $options -Credential $cred
[POWERSHELLTEST]: PS C:\Users\Administrator.POWERSHELLTEST>

Alternatively you can also create the session with New-PSSession

PS C:\Users\Administrator> New-PSSession -ComputerName POWERSHELLTEST -UseSSL -SessionOption $options -Credential $cred

 Id Name            ComputerName    State         ConfigurationName     Availability
 -- ----            ------------    -----         -----------------     ------------
 11 Session11       POWERSHELLTEST    Opened        Microsoft.PowerShell     Available

… and then connect to the session at any time

PS C:\Users\Administrator> Enter-PSSession $(Get-PSSession 11)
[POWERSHELLTEST]: PS C:\Users\Administrator.POWERSHELLTEST>