- Poll: How reliable are ChatGPT and Bing Chat? - Tue, May 23 2023
- Pip install Boto3 - Thu, Mar 24 2022
- Install Boto3 (AWS SDK for Python) in Visual Studio Code (VS Code) on Windows - Wed, Feb 23 2022
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
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
To check how your machines are configured, you can run this command:
winrm get winrm/config
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
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
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
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
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.
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:
The first name goes to the cn field, the rest to the Subject Alternative Name extension.
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.
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.
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
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.
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.
Interesting. What was the error message when PowerShell complained about the self-signed certificate?
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!
Yes, the -SessionOption parameter works well for this. I prefer using it too.
Thank you for the article. i have an issue with a execution this script on few machines.
Don't know how to solve it?
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".
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
There is no difference. Its still a domain communication using Kerberos.
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.
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
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.
Indeed a great guide. thank you.
Helpful in 2021. Thank you