How to enable winrm in windows
Part 1 — Enable WinRM on HTTP (port 5985)
This is the easy part. Run PowerShell as Administrator on the Windows Server:
# One-shot configuration: starts the service, sets it to auto-start,
# creates the HTTP listener on 5985, and opens the firewall rule.
Enable-PSRemoting -Force
That's it for HTTP. Verify:
# Should show a Transport=HTTP listener on port 5985
winrm enumerate winrm/config/Listener
# Or with PowerShell cmdlets
Get-WSManInstance -ResourceURI winrm/config/listener -Enumerate
If the host is on a "Public" network profile, Enable-PSRemoting will refuse. Either change the profile to Private/Domain, or force it:
Enable-PSRemoting -Force -SkipNetworkProfileCheck
Part 2 — Enable WinRM on HTTPS (port 5986)
HTTPS requires a certificate. You have three options depending on your environment.
Option A — Self-signed certificate (lab / quick test)
# 1) Create a self-signed cert. Use the server's real FQDN.
$fqdn = [System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName
$cert = New-SelfSignedCertificate `
-DnsName $fqdn `
-CertStoreLocation Cert:\LocalMachine\My `
-KeyExportPolicy Exportable `
-KeySpec Signature `
-KeyLength 2048 `
-KeyAlgorithm RSA `
-HashAlgorithm SHA256 `
-NotAfter (Get-Date).AddYears(5)
Write-Host "Thumbprint: $($cert.Thumbprint)"
Write-Host "FQDN: $fqdn"
# 2) Create the HTTPS listener bound to that cert
New-Item -Path WSMan:\LocalHost\Listener `
-Transport HTTPS `
-Address * `
-CertificateThumbPrint $cert.Thumbprint `
-HostName $fqdn `
-Force
# 3) Open the firewall for 5986
New-NetFirewallRule -DisplayName "WinRM HTTPS-In (TCP 5986)" `
-Direction Inbound `
-LocalPort 5986 `
-Protocol TCP `
-Action Allow `
-Profile Domain,Private
Option B — Certificate from your enterprise CA (production)
If you have an Active Directory Certificate Services CA, request a Server Authentication cert first:
# Request from AD CS using a template that allows Server Authentication
# (the template name varies — common ones are "WebServer" or "Computer")
$req = Get-Certificate `
-Template "WebServer" `
-DnsName $fqdn `
-SubjectName "CN=$fqdn" `
-CertStoreLocation Cert:\LocalMachine\My
$cert = $req.Certificate
# Then create the listener the same way as Option A, step 2+3
New-Item -Path WSMan:\LocalHost\Listener `
-Transport HTTPS `
-Address * `
-CertificateThumbPrint $cert.Thumbprint `
-HostName $fqdn `
-Force
Option C — Existing certificate (you already have one)
# Find an existing Server Auth cert for this host
$cert = Get-ChildItem Cert:\LocalMachine\My |
Where-Object {
$_.Subject -match $fqdn -and
$_.EnhancedKeyUsageList.FriendlyName -contains "Server Authentication"
} | Select-Object -First 1
# Use its thumbprint in step 2 of Option A
Part 3 — Verify both listeners
# List all listeners; you should see two — HTTP on 5985 and HTTPS on 5986
winrm enumerate winrm/config/Listener
Expected output (abbreviated):
Listener
Address = *
Transport = HTTP
Port = 5985
Enabled = true
Listener
Address = *
Transport = HTTPS
Port = 5986
Enabled = true
CertificateThumbprint = A1B2C3D4...
Test from the same server first (loopback check):
# HTTP
Test-WSMan -ComputerName localhost
# HTTPS — use -UseSSL and skip CA check if self-signed
$opt = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
Test-WSMan -ComputerName $fqdn -UseSSL -SessionOption $opt
Then test from another machine on the network:
# From a different Windows box
Test-WSMan -ComputerName dc01.corp.local
Test-WSMan -ComputerName dc01.corp.local -UseSSL -SessionOption $opt
Or from your Linux box with the Python script you already have:
python winrm_ad_test.py --host dc01.corp.local --user 'CORP\admin'
Part 4 — Hardening (recommended for production)
After both listeners work, lock things down:
# Disable unencrypted traffic (forces NTLM/Kerberos encryption or HTTPS)
Set-Item -Path WSMan:\LocalHost\Service\AllowUnencrypted -Value $false
# Disable Basic auth (use NTLM/Kerberos/CredSSP instead)
Set-Item -Path WSMan:\LocalHost\Service\Auth\Basic -Value $false
# If you want to require HTTPS only, remove the HTTP listener
Get-ChildItem WSMan:\LocalHost\Listener |
Where-Object Keys -match "Transport=HTTP$" |
Remove-Item -Recurse
# Optional: restrict who can connect (default is BUILTIN\Administrators)
Set-PSSessionConfiguration -Name Microsoft.PowerShell `
-ShowSecurityDescriptorUI
For NTLM connections from non-domain Linux clients, you may also need to add the server to TrustedHosts on the client, not the server:
# On the Windows client (not needed for Linux pywinrm clients)
Set-Item WSMan:\LocalHost\Client\TrustedHosts -Value "dc01.corp.local" -Force
Part 5 — Rolling it out at scale via GPO
For multiple servers, do it once via Group Policy instead of per-host:
Computer Configuration → Policies → Administrative Templates → Windows Components → Windows Remote Management (WinRM) → WinRM Service
- Allow remote server management through WinRM → Enabled, IPv4/IPv6 filter =
* - Allow Basic authentication → Disabled
- Allow unencrypted traffic → Disabled
And in Computer Configuration → Policies → Windows Settings → Security Settings → System Services, set Windows Remote Management (WS-Management) to Automatic.
Firewall rule via GPO: Computer Configuration → Policies → Windows Settings → Security Settings → Windows Defender Firewall with Advanced Security → Inbound Rules → New Rule → Predefined → "Windows Remote Management".
The HTTPS cert is the only piece GPO can't easily push — that needs either AD CS auto-enrollment (recommended) or a per-host script.
Common pitfalls
The most frequent issues, in order of how often I've seen them bite people: the firewall rule existing but being scoped to "Private only" while the NIC is on a "Public" profile; the cert's CN/SAN not matching the hostname clients actually use (cert says dc01 but clients connect to dc01.corp.local); the HTTPS listener pointing at a thumbprint whose cert has expired or been removed; and AllowUnencrypted=false combined with Basic auth, which leaves no working auth path. If Test-WSMan fails, check those four before anything else.
Want me to put any of this into a single bootstrap PowerShell script you can drop onto a new server?