In this guide, you will learn how to use Enter-PSSession and Invoke-Command to securely manage remote Windows machines with PowerShell over HTTPS using a self-signed SSL certificate that we create with PowerShell.
Avatar
Latest posts by Michael Pietroforte (see all)

Many PowerShell blogs like to mention that WinRM encrypts data and is therefore secure even if you only work with HTTP (which is the default configuration) and not with HTTPS. Indeed, Microsoft’s documentation for Invoke-Command confirms that WS-Management encrypts all transmitted PowerShell data. (An older version of WinRM on Windows Server 2003 R2 doesn’t encrypt.) Unfortunately, if not configured properly, PowerShell Remoting is insecure and it some cases you need to change the default configuration.

Allowing unencrypted PowerShell Remoting

First, it is possible to allow unencrypted WS-Management communication. This command configures the WinRM service to allow unencrypted traffic (you need an elevated console as for most things we do in this post):

winrm set winrm/config/service '@{AllowUnencrypted="true"}'

Allowing unencrypted WSMan traffic on the server

Allowing unencrypted WSMan traffic on the server

And this one does the same on the client side:

winrm set winrm/config/client '@{AllowUnencrypted="true"}'

Even though WS-Management encrypts all traffic by default, it is possible that someone (unknowingly) transmits unencrypted data because the default configuration has been changed. I guess this is why this Microsoft article about WinRM warns that “under no circumstances should unencrypted HTTP requests be sent through proxy servers.”

Allowing unencrypted WSMan traffic on the client

Allowing unencrypted WSMan traffic on the client

To check how your machines are configured, you can run this command:

winrm get winrm/config

Check WinRM configuration

Checking WinRM configuration

You can also view the configuration in PowerShell:

dir WSMan:\localhost\Service | ? Name -eq AllowUnencrypted
dir WSMan:\localhost\Client | ? Name -eq AllowUnencrypted

Why HTTPS with Invoke-Command and Enter-PSSession

The second and, in my view, bigger problem is that, if you are working with machines that are not in an Active Directory domain, you don’t have any trust relationship with the remote computers. You are then dealing only with symmetric encryption, so man-in-the-middle attacks are theoretically possible because the key has to be transferred first.

In a previous post, I explained that you have to add the remote machines that are not in an Active Directory domain to your TrustedHosts list on the client. However, you don’t improve security just by “defining” IP addresses or computer names as trustworthy. This is just an extra hurdle that Microsoft added so you know that you are about to do something risky.

This is where PowerShell Remoting via SSL comes in. For one, HTTPS traffic is always encrypted. Thus, you can always automate your tasks remotely, free of worry. And, because SSL uses asymmetric encryption and certificates, you can be sure that you are securely and directly connected to your remote machine and not to the computer of an attacker that intercepts and relays your traffic.

On the downside, configuring PowerShell Remoting for use with SSL is a bit more difficult than just running Enable-PSRemoting. Quite a few tutorials exist that explain how to use HTTPS with Enter-PSSession and Invoke-Command, and most of them make this task appear unnecessarily complicated.

The main problem is that you need an SSL certificate. If you just want to manage some standalone servers or workstations, you probably don’t like to acquire a publicly-signed certificate and want to work with a self-signed certificate instead.

Because many of these guides predate PowerShell 4, they recommend using IIS Manager or download tools such as OpenSSL or the Windows SDK, which contains makecert.exe and pvk2pfx.exe that you can use to create a self-signed certificate. I suppose these guides deter many admins from working with SSL and so they choose the easier way of running Invoke-Command and Enter-PSSession over HTTP.

However, you will now see that enabling SSL for WinRM on the client and on the server is not so difficult (although it is not as straightforward as with SSH), and you can do it all with PowerShell’s built-in cmdlets. You don’t even need the notorious winrm Windows command-line tool.

Enabling HTTPS for PowerShell Remoting

On the remote computer

The first thing we need to do is create an SSL certificate. (Note that this guide focuses on the usage of a self-signed certificate. If you have a publicly-signed certificate, things are easier and you can use Set-WSManQuickConfig -UseSSL.)

As mentioned above, since the release of PowerShell 4, we don’t require third-party tools for this purpose. The New-SelfSignedCertificate cmdlet is all we need:

$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "myHost"

It is important to pass the name of the computer that you want to manage remotely to the ‑DnsName parameter. If the computer has a DNS name, you should use the fully qualified domain name (FQDN).

If you want to, you can verify that the certificate has been stored correctly using the certificate add-in of the Microsoft Management Console (MMC). Type mmc on the Start screen and add the Certificates add-in for a computer account and the local computer. The certificate should be in the Personal\Certificates folder. The name of my test computer was “win81.”

Certificate in MMC on the remote computer

Certificate in MMC on the remote computer

We now have to export the certificate to a file because we will have to import it later on our local machine. You can do this with the MMC add-in, but we’ll do it in PowerShell:

Export-Certificate -Cert $Cert -FilePath C:\temp\cert

The file name doesn’t matter here.

We need the certificate to start the WS-Management HTTPS listener. But we should first enable PowerShell Remoting on the host:

Enable-PSRemoting -SkipNetworkProfileCheck -Force

As I’ve learned recently, -SkipNetworkProfileCheck ensures that PowerShell won’t complain if your network connection type is set to Public.

Enable-PSRemoting also starts a WS-Management listener, but only for HTTP. If you want to, you can verify this by reading the contents of the WSMan drive:

dir wsman:\localhost\listener

Listing WSMan listeners

Listing WSMan listeners

To ensure that nobody uses HTTP to connect to the computer, you can remove the HTTP listener this way:

Get-ChildItem WSMan:\Localhost\listener | Where -Property Keys -eq "Transport=HTTP" | Remove-Item -Recurse

This command removes all WSMan listeners:

Remove-Item -Path WSMan:\Localhost\listener\listener* -Recurse

Next, we add our WSMan HTTPS listener:

New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint –Force

Adding a WSMan HTTPS listener

Adding a WSMan HTTPS listener

We are using the $Cert variable that we defined before to read the Thumbprint, which allows the New-Item cmdlet to locate the certificate in our certificates store.

The last thing we have to do is configure the firewall on the host because the Enable-PSRemoting cmdlet only added rules for HTTP:

New-NetFirewallRule -DisplayName "Windows Remote Management (HTTPS-In)" -Name "Windows Remote Management (HTTPS-In)" -Profile Any -LocalPort 5986 -Protocol TCP

Notice here that we allow inbound traffic on port 5986. WinRM 1.1 (current version is 3.0) used the common HTTPS port 443. You can still use this port if the host is behind a gateway firewall that blocks port 5986:

Set-Item WSMan:\localhost\Service\EnableCompatibilityHttpsListener -Value true

Of course, you then have to open port 443 in the Windows Firewall. Note that this command won’t work if the network connection type on this machine is set to Public. In this case, you have to change the connection type to private:

Set-NetConnectionProfile -NetworkCategory Private

For security reasons, you might want to disable the firewall rule for HTTP that Enable-PSRemoting added:

Disable-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)"

Our remote machine is now ready for PowerShell Remoting via HTTPS, and we can configure our local computer.

On the local computer

Things are a bit easier here. First, you have to copy the certificate file to which we exported our certificate. You can then import the certificate with this command:

Import-Certificate -Filepath "C:\temp\cert" -CertStoreLocation "Cert:\LocalMachine\Root"

Note that we need to store the certificate in the Trusted Root Certification Authorities folder here and not in the Personal folder as we did on the remote computer. Your computer “trusts” all machines that can prove their authenticity with the help of their private keys (stored on the host) and the certificates stored here.

Certificate in MMC on the local computer

Certificate in MMC on the local computer

By the way, this is why we don’t have to add the remote machine to the TrustedHosts list. In contrast to PowerShell Remoting over HTTP, we can be sure that the remote machine is the one it claims to be, which is the main point of using HTTPS instead of HTTP.

We are now ready to enter a PowerShell session on the remote machine via HTTPS:

Enter-PSSession -ComputerName myHost -UseSSL -Credential (Get-Credential)

The crucial parameter here is -UseSSL. Of course, we still have to authenticate on the remote machine with an administrator account.

You might receive this error message:

The SSL certificate is signed by an unknown certificate authority.

In that case you can just add the the -SkipCACheck parameter. (See comments below.)

The Invoke-Command cmdlet also supports the -UseSSL parameter:

Invoke-Command -ComputerName myHost -UseSSL -ScriptBlock {Get-Process} -Credential (Get-Credential)

If your remote host doesn’t have a DNS entry, you can add its IP to the hosts file on your local computer. To do so, open an elevated Notepad and then navigate to %systemroot%\system32\drivers\etc\. Of course, you can also do it the PowerShell if you are working on an elevated console:

Add-Content $Env:SystemRoot\system32\drivers\etc\hosts "10.0.0.1 myHost"

You will have to reboot after that. I have my own private DNS server in the cloud for such cases.

Conclusion

Admittedly, the post got a bit longer than I planned. However, once you know how it works, you can complete the entire procedure to configure PowerShell Remoting for HTTPS in a couple of minutes. You just create a self-signed SSL certificate on the host and start an HTTPS listener using this certificate. Then, you create the corresponding firewall rule and export the certificate. On the local computer, you only have to import the certificate.

HTTPS doesn’t just add another encryption layer; its main purpose is to verify the authenticity of the remote machine, thereby preventing man-in-the-middle attacks. Thus, you only need HTTPS if you do PowerShell Remoting through an insecure territory. Inside your local network, with trust relationships between Active Directory domain members, WSMan over HTTP is secure enough.

avataravataravataravatar
65 Comments
  1. Avatar
    th3l0nius 4 years ago

    Thanks for the article. There is no need to only use the FQDN (or not). You can simply use multiple names with the -DnsName parameter just like this:

    $Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "myHost","myHost.full.qualified"

    The first name goes to the cn field, the rest to the Subject Alternative Name extension.

    avatar
  2. Avatar
    Eugene 4 years ago

    Hi Michael thanks a stack for this post.

    I have spend a lot of time in the past trying to use HTTP and use trusted hosts. Even if I follow instructions to the letter for using HTTP on non domain machines it almost never works.

     By using this guide it took me a few minutes and it is actually much easier to configure over HTTPS than using http. Creating an SSL is much easier than what I thought.

    • Avatar Author

      Eugene, you are welcome. I wouldn't use PowerShell remoting over HTTP outside an AD domain because it is not secure. I found it amazingly complicated to configure PowerShell remoting with HTTPS. PowerShell should do this automatically if a machine is not a domain member. SSH is still a lot more advanced here.

      avatar
      • Avatar
        Paul Bendall 4 years ago

        I agree with you @Michael, it should be, more, secure by design. Although this isn't just Microsoft's fault, how many blogs say just run winrm quickconfig without explaining any of the implications or what is going on? WinRM or WS-Man is a great feature but it is misunderstood, even the term remoting to many has undertones of remote registry access and other legacy (insecure) RPC communications. 

        SSH still appears to be the gold standard for remoting access, WinRM has certificate-based authentication, but this is just as hard to set up as HTTPS access and few bother with it. Let's not even get started with issues of double-hop authentication! Maybe this stems from MS (wrongly) assuming that all servers are in an Active Directory domain and use Kerberos. What about standalone machines in the DMZ? *nix never really had this centralised control concept (okay there was NIS)  maybe was a benefit for this kind of remote admin access and where SSH came to excel?

        Paul

        • Avatar Author

          Paul, thanks! It appears PowerShell Remoting was build for typical on-premises LANs. Outside this environment PowerShell Remoting performs poorly.

          Take implicit remoting as an example. Before, I always used PowerShell to manage Office 365. However, because I am often on another continent than Microsoft's servers, it often takes ages until all the stuff is downloaded. So I now use the web interface whenever it offers the feature I need because I am usually much faster with it.

          On the other hand, when I manage Linux boxes I really don't have to care where they are located and in what environments they are running. SSH is fast, reliable, secure, and super simple to set up. In a way, this also summarizes the difference between Windows and Linux.

  3. Avatar
    PowerMe! (Rank 3) 4 years ago

    Thank you for the article. I was stuck with winrm quickconfig -transport:HTTPs. But this was big rescue! However I had an issue with the self-signed cert as the Enter-PSSession kept complaining about the self-signed nature of the cert.

    I came up with the using a session option.

    $myhost = 'serv19'
    
    $winrmPort = '5986'
    
    if(Test-NetConnection $myhost -port $winrmPort){
    
    $sessOptions = New-PSSessionOption -SkipCACheck
    
    Enter-PSSession -ComputerName $myhost -UseSSL -Credential Administrator -SessionOption $sessOptions
    
    }
    avataravatar
    • Avatar Author

      Interesting. What was the error message when PowerShell complained about the self-signed certificate?

      • Avatar
        PowerMe! (Rank 3) 4 years ago
        Enter-PSSession : Connecting to remote server serv19 failed with the following error message : The server certificate on the destination computer (serv19:5986) has the following errors:    
        
        The SSL certificate is signed by an unknown certificate authority. For more information, see the about_Remote_Troubleshooting Help topic.
        
        At line:1 char:1
        
        + Enter-PSSession -ComputerName $myhost -Credential $cred -UseSSL
        
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
            + CategoryInfo          : InvalidArgument: (serv19:String) [Enter-PSSession], PSRemotingTransportException
        
            + FullyQualifiedErrorId : CreateRemoteRunspaceFailed
        avatar
        • Avatar Author

          I think the problem didn't exist when I wrote the article. I added a note to the article. Thanks a lot for the hint!

          avatar
    • Avatar

      Yes, the -SessionOption parameter works well for this. I prefer using it too.

  4. Avatar
    Artem 4 years ago

    Thank you for the article. i have an issue with  a execution this script on  few machines.

    PS C:\Users\user> New-Item -Path WSMan:\localhost\Listener\ -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force -Verbose
    New-Item : An unexpected error has occurred function "HttpSetServiceConfiguration". Error=31.
    
    + New-Item -Path WSMan:\localhost\Listener\ -Transport HTTPS -Address * ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [New-Item], InvalidOperationException
        + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.NewItemCommand

     

    Don't know how to solve it?

  5. Avatar
    michael bourgon 3 years ago

    THANK YOU.  One suggestion on wording, at least it would've made it easier for me:

     

    It is important to pass the name of the computer that you want to manage remotely to the ‑DnsName parameter".

    "It is important to pass the name of the computer that you want to manage remotely (aka the computer you're running this command on) to the ‑DnsName parameter".

  6. Avatar
    Marek 3 years ago

    Hi

    You mentioned that WS-Management encrypts sessions when we are in the domain but is it true also for connection inside forest between trusted domains?

    Thanks

    avatar
    • Avatar
      Leos Marek (Rank 4) 3 years ago

      There is no difference. Its still a domain communication using Kerberos. 

    • Avatar Author

      Do you want to know how AD domains communicate or do you want to know if PowerShell remoting is encrypted if you connect to a remote computer in another domain of the forest? I never tried the latter case, but I guess as long as you are authenticated in Active Directory you don't need an SSL certificate. Assuming you have the correct rights on the remote machine, you should be able to authenticate without needing a username or password.

      I suppose you tried to find Microsoft's official documentation which probably does not exist. So if you want to be sure that everything is encrypted, you can try to read the traffic with a packet sniffer. When it comes to security Microsoft is always full of surprises.

  7. Avatar
    Kantharaj 3 years ago

    Can we connect from domain machine to a workgroup machine, I am having below issue, Please suggest
    Enter-PSSession : Connecting to remote server ipaddress failed with the 
    following error message : The server certificate on the destination computer 
    (ipadress:5986) has the following errors:      
    The SSL certificate is expired. For more information, see the 
    about_Remote_Troubleshooting Help topic.
    At line:11 char:1
    + Enter-PSSession -ComputerName $myhost -UseSSL -Credential Administrat …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (ipadress:String) [Enter-P 
       SSession], PSRemotingTransportException
        + FullyQualifiedErrorId : CreateRemoteRunspaceFailed
     

  8. Avatar

    please suggest best way to remote servers using powershell. Already I'm using credentials, but I wanted to use certificate and eliminate credentials. Target servers are in different domains and different service accounts.

  9. Avatar
    Gineesh Madapparambath 2 years ago

    Indeed a great guide. thank you.

  10. Avatar
    Julien 2 years ago

    Helpful in 2021. Thank you

Leave a reply

Please enclose code in pre tags

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account