🎁 New User? Get 20% off your first purchase with code NEWUSER20 Register Now →
Menu

Categories

PowerShell Remoting & WinRM Hardening: A 2026 Practitioner Guide

PowerShell Remoting & WinRM Hardening: A 2026 Practitioner Guide
PowerShell Remoting and WinRM hardening - Dargslan 2026

PowerShell Remoting is the most useful and most under-audited feature in the Windows administration toolbox. It is on by default on every Windows Server since 2012 R2. It uses WinRM, which speaks HTTP on TCP 5985 out of the box, and it accepts NTLM and Kerberos. Almost every Windows incident report from the last five years mentions WinRM in the lateral-movement section. The good news is that hardening it takes a few hours and the result is durable.

This guide walks through a defensible WinRM hardening pass, ships a free PDF cheat sheet, and explains the trade-offs you will hit in production.

Why WinRM is the lateral-movement target

Once an attacker has any local admin account on any domain-joined Windows host, Enter-PSSession -ComputerName <target> works against every other host that account can reach over 5985/5986. The attack does not need malware — it uses a feature. CIS, NIST 800-171 (3.1.13) and the Microsoft Security Compliance Toolkit all expect remoting to be enabled only where required, scoped, and logged.

Audit the current listener

Start by enumerating what is actually exposed on the box:

winrm enumerate winrm/config/listener
Get-WSManInstance -ResourceURI winrm/config/service
Get-Item WSMan:\localhost\Service\Auth\*

You will usually see one HTTP listener on *:5985, no HTTPS listener, Basic auth disabled, Negotiate enabled, Kerberos enabled. That is the default and it is not safe to leave alone on Internet-reachable hosts.

Move to HTTPS only

Build an HTTPS listener bound to a server certificate (PKI or a self-signed cert that is trusted on every client) and remove the HTTP listener:

$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME `
    -CertStoreLocation Cert:\LocalMachine\My
New-Item WSMan:\localhost\Listener -Address * -Transport HTTPS `
    -CertificateThumbPrint $cert.Thumbprint -Force
Remove-Item WSMan:\localhost\Listener\Listener_HTTP_* -Recurse

HTTPS does two things: it encrypts the channel even when Kerberos is not in play, and it lets you deny TCP 5985 at the firewall without breaking the server's own management.

Authentication: kill Basic, prefer Kerberos

Basic authentication on WinRM sends credentials in clear over the channel. Disable it explicitly even if the listener is HTTPS:

Set-Item WSMan:\localhost\Service\Auth\Basic -Value $false
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $false
Set-Item WSMan:\localhost\Service\Auth\CredSSP -Value $false

Kerberos is the only authentication method that delivers mutual auth and survives a credential theft on the client. Negotiate falls back to NTLM when Kerberos cannot be used (workgroup hosts, IP-based connections), so disabling NTLM for the WinRM SPN is the next step on a domain-joined fleet.

TrustedHosts review

The TrustedHosts list is the client-side override that says "trust this server's identity even though I cannot validate it via Kerberos". It is meant for quick lab work. In production it should be empty or contain only documented exceptions:

Get-Item WSMan:\localhost\Client\TrustedHosts
# To clear:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value ''

Scope: firewall + IPSec + JEA

The default firewall rule for WinRM allows the Domain and Private profiles. Replace it with one that restricts source addresses to the management subnets (jump hosts, monitoring, MECM) and apply IPSec for transport-level identity:

Set-NetFirewallRule -Name 'WINRM-HTTPS-In-TCP' `
    -RemoteAddress 10.10.0.0/24,10.20.0.0/24 -Profile Domain

For role-restricted accounts (helpdesk, monitoring service), publish a Just Enough Administration (JEA) endpoint with a constrained role capability instead of giving them generic remoting. JEA limits the cmdlets and parameters available in the session and writes a transcript per connection.

Logging: ScriptBlock and Module

Without ScriptBlock logging there is no forensic trail of what an attacker ran inside an Enter-PSSession. Enable it via GPO or registry, plus Module logging for the modules you care about and PowerShell transcription to a write-only share:

$base = 'HKLM:\Software\Policies\Microsoft\Windows\PowerShell'
New-Item -Path "$base\ScriptBlockLogging" -Force | Out-Null
Set-ItemProperty "$base\ScriptBlockLogging" EnableScriptBlockLogging 1
New-Item -Path "$base\Transcription" -Force | Out-Null
Set-ItemProperty "$base\Transcription" EnableTranscripting 1
Set-ItemProperty "$base\Transcription" OutputDirectory '\\logs\ps'

A defensible audit checklist

  1. HTTPS listener present, HTTP listener absent (1 pt)
  2. Basic, AllowUnencrypted and CredSSP all False (1 pt)
  3. TrustedHosts empty or matches an approved list (1 pt)
  4. Firewall scope restricts WinRM to management subnets (1 pt)
  5. ScriptBlockLogging and Transcription enabled (1 pt)

5/5 = PASS, 3-4 = WARN, 0-2 = FAIL. Audit one host, prove the controls, then push the same configuration via GPO or DSC across the fleet.

Advanced hardening: certificate auth, TrustedHosts and JEA pairing

Once HTTPS, NTLM-block and firewall scoping are in place, the next layer is identity. Certificate-based WinRM authentication removes the dependency on domain credentials for service automation, and pairs naturally with Just Enough Administration so callers receive only the cmdlets they need.

Issue and bind a client certificate

On the calling host, request a client-auth certificate from your internal CA, then map it to a local user on the target server. The mapping happens on the listener side, not in Active Directory, so the target host has full control over which thumbprint is allowed in.

$cert = Get-ChildItem Cert:\LocalMachine\My |
        Where-Object EnhancedKeyUsageList -match 'Client Authentication' |
        Select-Object -First 1

New-Item -Path WSMan:\localhost\ClientCertificate `
         -Subject 'CN=svc-monitor*' `
         -URI '*' `
         -Issuer $cert.Issuer `
         -Credential (Get-Credential SVC\monitor) `
         -Force

The caller then connects with -CertificateThumbprint instead of -Credential. There is no password on the wire, no Kerberos ticket, and the cert can be rotated without touching AD.

TrustedHosts is not a firewall

TrustedHosts tells the client which servers are allowed to receive its credentials over a non-Kerberos connection. It is not a server-side allow-list. Many teams confuse the two and add * to TrustedHosts in a panic, which means every workstation will happily send NTLM hashes to any host on the network.

# Read current TrustedHosts
Get-Item WSMan:\localhost\Client\TrustedHosts

# Scope to a single management subnet, do NOT use *
Set-Item WSMan:\localhost\Client\TrustedHosts `
         -Value '10.20.30.*' -Force

If you ever see TrustedHosts = * in a production audit, treat it as a finding and document it. The fix is almost always to deploy a CA-issued cert on the target so Kerberos or HTTPS-with-cert-validation can take over.

Combine with JEA for blast-radius control

Hardened transport is half the story. The other half is what the caller can run after they connect. A JEA endpoint with a constrained role capability file means a compromised service account cannot spawn cmd.exe, drop a binary, or pivot. See the dedicated JEA tutorial in the related reading section.

Common pitfalls

  • Self-signed certs in production. They work for the demo, fail every audit, and break clients that validate the chain. Always issue from your internal CA so renewal and revocation are managed.
  • Forgetting the firewall scope after enabling HTTPS. Removing the HTTP listener does not remove the HTTP firewall rule. Disable Windows Remote Management (HTTP-In) explicitly.
  • Group Policy overwriting your hardening. If a domain-level GPO re-enables Basic auth or AllowUnencrypted, every reboot resets your work. Audit GPO with gpresult /h before you ship the config to a fleet.
  • Assuming Kerberos always wins. Cross-forest, workgroup or DMZ scenarios fall back to NTLM. If you have not blocked NTLM at the listener, you have not actually blocked NTLM.
  • No monitoring. Hardened or not, you need Microsoft-Windows-WinRM/Operational shipped to your SIEM. The hardening tells you what should not happen; the logs prove what actually happened.

FAQ

Will disabling HTTP break existing automation?

Only if the automation is hard-coded to port 5985. Most modern callers (Invoke-Command, Ansible's winrm connection plugin, Microsoft DSC) accept -UseSSL or an equivalent flag.

Do I need a public PKI cert for HTTPS WinRM?

No. An internal CA (Active Directory Certificate Services) is the right choice. The clients trust the AD root, the cert is auto-renewed, and you avoid public-CA cost and exposure.

Is JEA worth the effort for a small team?

Yes for any account that should not be a full admin — service accounts, helpdesk, monitoring. The effort is a one-time role capability file per use case.

What about SSH-based PowerShell Remoting?

It works, it is supported on Windows Server 2019+, and it is a good answer for cross-platform automation. The hardening posture is then SSH posture (key-only auth, restricted users) instead of WinRM posture.

How do I roll this out to 200 servers without breaking everything?

Pilot on five hosts for a week, then push the config via Desired State Configuration or a signed startup script. Do not use a single Group Policy that flips every setting at once — split into two GPOs (transport hardening, then auth hardening) so you can roll one back if monitoring lights up.

Does PowerShell 7 change any of this?

The protocol is the same. PowerShell 7 adds SSH-based remoting as a parallel option, but WinRM is still the default for Windows-to-Windows. Your hardening rules apply unchanged.

What is the right log retention for WinRM?

At minimum 90 days hot in the SIEM and 12 months cold. Most lateral-movement investigations look back 60–90 days, and audit standards (ISO 27001, SOC 2) typically require a year.

Can I block PowerShell Remoting entirely and use something else?

Technically yes — SSH, RDP with Remote PowerShell over a bastion, or agent-based tooling like Ansible-with-WinRM-disabled. In practice WinRM is the most efficient transport for native Windows automation and the right answer is usually to harden it, not replace it.

Related Dargslan resources

Share this article:
Dargslan Editorial Team (Dargslan)
About the Author

Dargslan Editorial Team (Dargslan)

Collective of Software Developers, System Administrators, DevOps Engineers, and IT Authors

Dargslan is an independent technology publishing collective formed by experienced software developers, system administrators, and IT specialists.

The Dargslan editorial team works collaboratively to create practical, hands-on technology books focused on real-world use cases. Each publication is developed, reviewed, and...

Programming Languages Linux Administration Web Development Cybersecurity Networking

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.