How to Enable and Configure WinRM for Remote Management on Windows Server 2022
Windows Remote Management (WinRM) is the Microsoft implementation of the WS-Management protocol, a SOAP-based protocol for remote hardware and software management. WinRM is the transport layer that powers PowerShell Remoting, allowing you to run commands on remote machines via Invoke-Command, Enter-PSSession, and other remoting cmdlets. Understanding how to configure WinRM correctly — including listeners, authentication, HTTPS setup, and firewall rules — is fundamental to managing Windows Server 2022 at scale.
How WinRM Works
WinRM runs as a Windows service (WinRM service / Windows Remote Management) and listens on HTTP (port 5985) or HTTPS (port 5986) by default. When you connect to a remote machine, your local WinRM client sends requests to the remote WinRM listener, which executes commands and returns results. The WinRM service acts as both a server (receiving connections from remote management tools) and a client (making connections when you use remoting cmdlets).
PowerShell Remoting is the most common use of WinRM, but other tools also use it: Server Manager can manage remote servers through WinRM, CIM/WMI sessions over WSMAN use WinRM, and Desired State Configuration (DSC) uses WinRM for push deployments.
Enabling WinRM with Enable-PSRemoting
Enable-PSRemoting is the simplest way to enable WinRM and configure PowerShell Remoting in one step. It starts the WinRM service, sets it to automatic startup, creates a default HTTP listener, and configures the firewall rule — all in a single command.
# Enable WinRM and PowerShell Remoting (run as administrator)
Enable-PSRemoting -Force
# If on a non-domain machine (public network profile), use:
Enable-PSRemoting -SkipNetworkProfileCheck -Force
# Verify WinRM service is running
Get-Service -Name WinRM
# Check the startup type
(Get-Service -Name WinRM).StartType
The -Force flag suppresses confirmation prompts. The -SkipNetworkProfileCheck flag is needed when the network connection type is set to Public rather than Private or Domain, as WinRM will not configure itself on Public networks by default.
Using winrm quickconfig
The winrm quickconfig command-line tool performs similar configuration to Enable-PSRemoting but is available in both Command Prompt and PowerShell. It is the lower-level tool that Enable-PSRemoting calls internally.
# Run winrm quickconfig (accepts changes automatically with -quiet)
winrm quickconfig -quiet
# Check WinRM configuration
winrm get winrm/config
# Check just the service configuration
winrm get winrm/config/service
# Check just the client configuration
winrm get winrm/config/client
The output of winrm get winrm/config shows every configurable setting including MaxTimeoutms, MaxBatchItems, authentication methods, TrustedHosts, and AllowUnencrypted settings. Review this output to understand the current state before making changes.
Listing and Managing WinRM Listeners
A WinRM listener is a network endpoint that WinRM listens on. You can have multiple listeners — one for HTTP, one for HTTPS, or listeners bound to specific IP addresses. Use winrm enumerate to view current listeners.
# List all configured WinRM listeners
winrm enumerate winrm/config/listener
# Using PowerShell (alternative)
Get-WSManInstance -ResourceURI winrm/config/listener -Enumerate
# List just HTTP listeners
Get-WSManInstance -ResourceURI winrm/config/listener -Enumerate |
Where-Object { $_.Transport -eq "HTTP" }
# Delete the default HTTP listener
winrm delete winrm/config/listener?Address=*+Transport=HTTP
# Create a new HTTP listener manually
winrm create winrm/config/listener?Address=*+Transport=HTTP
# Create an HTTP listener bound to a specific IP
winrm create winrm/config/listener?Address=IP:192.168.1.100+Transport=HTTP
Setting Up an HTTPS Listener
HTTP WinRM traffic is still encrypted (via Kerberos or NTLM), but HTTPS provides an additional layer of transport encryption and is required for connections where Kerberos is not available (workgroup machines, cross-domain scenarios, or when using certificate authentication). Setting up HTTPS requires a valid SSL certificate with the server’s hostname in the Subject or Subject Alternative Name.
# First, find a suitable certificate in the local machine store
# The certificate must have the server FQDN in the CN or SAN
Get-ChildItem -Path Cert:LocalMachineMy |
Select-Object Subject, Thumbprint, NotAfter
# For testing, create a self-signed certificate (not for production)
$Cert = New-SelfSignedCertificate `
-DnsName "WEB-SRV-01.yourdomain.com" `
-CertStoreLocation "Cert:LocalMachineMy" `
-KeyUsage DigitalSignature, KeyEncipherment `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
$Thumbprint = $Cert.Thumbprint
Write-Host "Certificate thumbprint: $Thumbprint"
# Create the HTTPS WinRM listener using the certificate thumbprint
New-WSManInstance -ResourceURI winrm/config/listener `
-SelectorSet @{Address="*"; Transport="HTTPS"} `
-ValueSet @{Hostname="WEB-SRV-01.yourdomain.com"; CertificateThumbprint=$Thumbprint}
# Or using winrm command
winrm create winrm/config/listener?Address=*+Transport=HTTPS `
"@{Hostname=`"WEB-SRV-01.yourdomain.com`"; CertificateThumbprint=`"$Thumbprint`"}"
# Add firewall rule for WinRM HTTPS (port 5986)
New-NetFirewallRule -DisplayName "WinRM HTTPS" `
-Direction Inbound -Protocol TCP -LocalPort 5986 `
-Action Allow -Profile Domain,Private
# Verify the HTTPS listener was created
winrm enumerate winrm/config/listener
Configuring TrustedHosts
On non-domain machines or when connecting to machines in a different domain without mutual authentication, WinRM will refuse connections by default because it cannot verify the remote machine’s identity. The TrustedHosts list tells the local WinRM client to trust specific remote machines even without certificate verification. This is a client-side setting on the machine initiating the connection.
# Check current TrustedHosts value
Get-Item WSMan:localhostClientTrustedHosts
# Add a single host to TrustedHosts
Set-Item WSMan:localhostClientTrustedHosts -Value "192.168.1.100" -Force
# Add multiple hosts (comma-separated)
Set-Item WSMan:localhostClientTrustedHosts -Value "192.168.1.100,192.168.1.101,WEB-SRV-01" -Force
# Append a new host without overwriting existing ones
$existing = (Get-Item WSMan:localhostClientTrustedHosts).Value
Set-Item WSMan:localhostClientTrustedHosts -Value "$existing,192.168.1.102" -Force
# Trust ALL machines (use only in isolated lab environments — security risk)
Set-Item WSMan:localhostClientTrustedHosts -Value "*" -Force
# Clear TrustedHosts
Clear-Item WSMan:localhostClientTrustedHosts
# Using winrm command instead of PowerShell
winrm set winrm/config/client "@{TrustedHosts=`"192.168.1.100,WEB-SRV-01`"}"
Testing WinRM with Test-WSMan
Test-WSMan verifies that WinRM is running and accessible on a target machine. It is the first diagnostic tool to use when troubleshooting remoting issues.
# Test WinRM on the local machine
Test-WSMan
# Test WinRM on a remote machine
Test-WSMan -ComputerName "WEB-SRV-02"
# Test with explicit credentials (for workgroup or cross-domain)
Test-WSMan -ComputerName "192.168.1.100" -Credential (Get-Credential)
# Test HTTPS listener specifically (port 5986)
Test-WSMan -ComputerName "WEB-SRV-02" -UseSSL
# If successful, the output shows the WinRM schema version and product version
# If it fails, you get a connection error indicating the specific problem
Running Remote Commands with Invoke-Command
Invoke-Command is the primary cmdlet for executing commands on remote machines through WinRM. It supports single machines, arrays of machines, and existing PSSession objects.
# Run a simple command on one remote machine
Invoke-Command -ComputerName "WEB-SRV-02" -ScriptBlock { hostname }
# Run on multiple machines simultaneously
$Servers = @("WEB-SRV-01", "WEB-SRV-02", "DB-SRV-01")
Invoke-Command -ComputerName $Servers -ScriptBlock { Get-Service W3SVC }
# Pass variables to the remote script block using $Using:
$ServiceName = "W3SVC"
Invoke-Command -ComputerName "WEB-SRV-02" -ScriptBlock {
Get-Service -Name $Using:ServiceName
}
# Run with alternate credentials
$Creds = Get-Credential -Message "Enter admin credentials for WEB-SRV-02"
Invoke-Command -ComputerName "WEB-SRV-02" -Credential $Creds -ScriptBlock {
Get-ComputerInfo -Property CsName, OsName
}
# Run a local script file on a remote machine
Invoke-Command -ComputerName "WEB-SRV-02" -FilePath "C:Scriptsconfigure-iis.ps1"
# Run on machines using HTTPS transport
Invoke-Command -ComputerName "WEB-SRV-02" -UseSSL -ScriptBlock { ipconfig }
Interactive Remote Sessions with Enter-PSSession
Enter-PSSession opens an interactive PowerShell session on a remote machine, similar to SSH. All commands you type are executed on the remote machine until you exit the session. The prompt changes to indicate you are in a remote session.
# Open an interactive remote session
Enter-PSSession -ComputerName "WEB-SRV-02"
# The prompt changes to: [WEB-SRV-02]: PS C:UsersAdministratorDocuments>
# Run commands as normal — they execute on the remote machine
Get-Service | Where-Object { $_.Status -eq "Stopped" }
Get-EventLog -LogName System -Newest 10 -EntryType Error
# Exit the remote session
Exit-PSSession
# Connect with alternate credentials
Enter-PSSession -ComputerName "WEB-SRV-02" -Credential (Get-Credential)
# Connect via IP address (requires TrustedHosts or HTTPS)
Enter-PSSession -ComputerName "192.168.1.100" -Credential (Get-Credential)
# Persistent sessions (PSSessions) — create once, reuse multiple times
$Session = New-PSSession -ComputerName "WEB-SRV-02"
Invoke-Command -Session $Session -ScriptBlock { Get-Service }
Enter-PSSession -Session $Session
# Clean up
Remove-PSSession -Session $Session
Firewall Rules for WinRM
WinRM requires inbound firewall rules on the target server. The rules are created automatically by Enable-PSRemoting, but you may need to review or manually create them in environments with strict firewall policies.
# View existing WinRM firewall rules
Get-NetFirewallRule | Where-Object { $_.DisplayName -like "*Windows Remote Management*" } |
Select-Object DisplayName, Enabled, Direction, Action
# Enable built-in WinRM rules (re-enable if accidentally disabled)
Enable-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)"
Enable-NetFirewallRule -DisplayName "Windows Remote Management (HTTPS-In)"
# Create a custom rule for WinRM HTTP (port 5985) — restrict source IP for security
New-NetFirewallRule -DisplayName "WinRM HTTP - Admin Only" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 5985 `
-RemoteAddress "192.168.1.0/24" `
-Action Allow `
-Profile Domain,Private
# Create a custom rule for WinRM HTTPS (port 5986)
New-NetFirewallRule -DisplayName "WinRM HTTPS - Admin Only" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 5986 `
-RemoteAddress "192.168.1.0/24" `
-Action Allow `
-Profile Domain,Private
# Block WinRM on Public profile (security hardening)
New-NetFirewallRule -DisplayName "Block WinRM Public" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 5985,5986 `
-Action Block `
-Profile Public
WinRM Service Configuration
The WinRM service has configurable settings for timeouts, maximum connections, and authentication. Use the WSMan PowerShell drive to view and modify these settings.
# Browse WinRM configuration via the WSMan: drive
Set-Location WSMan:localhost
Get-ChildItem
# Set the maximum number of concurrent shells per user
Set-Item WSMan:localhostShellMaxShellsPerUser -Value 30
# Set maximum memory per shell (in MB)
Set-Item WSMan:localhostShellMaxMemoryPerShellMB -Value 1024
# Set maximum idle timeout for shells (in ms) — 60 minutes
Set-Item WSMan:localhostShellIdleTimeOut -Value 3600000
# Set maximum time for a WinRM operation (in ms)
Set-Item WSMan:localhostServiceMaxTimeoutms -Value 60000
# Enable Basic authentication (disabled by default — use only with HTTPS)
Set-Item WSMan:localhostServiceAuthBasic -Value $true
# Disable unencrypted traffic (enforce encryption — leave this on)
Set-Item WSMan:localhostServiceAllowUnencrypted -Value $false
# Verify service settings
Get-Item WSMan:localhostService*
Troubleshooting WinRM
WinRM connection failures often fall into a few common categories: the service is not running, the firewall is blocking the connection, the machine is not in TrustedHosts, or authentication is failing. Here is a systematic troubleshooting approach:
# Step 1: Verify WinRM service is running on the TARGET machine
Get-Service -Name WinRM
# If stopped:
Start-Service -Name WinRM
Set-Service -Name WinRM -StartupType Automatic
# Step 2: Verify listener is active
winrm enumerate winrm/config/listener
# Step 3: Test connectivity from the source machine
Test-NetConnection -ComputerName "WEB-SRV-02" -Port 5985
Test-NetConnection -ComputerName "WEB-SRV-02" -Port 5986
# Step 4: Check TrustedHosts (run on the SOURCE machine)
Get-Item WSMan:localhostClientTrustedHosts
# Step 5: Check WinRM with diagnostic output
$Error.Clear()
Test-WSMan -ComputerName "WEB-SRV-02" -ErrorAction SilentlyContinue
If ($Error) { $Error[0].Exception.Message }
# Step 6: Check Windows Firewall on the TARGET
Get-NetFirewallRule -DisplayName "*Remote Management*" |
Select-Object DisplayName, Enabled, Direction
# Step 7: Test with explicit credentials
Invoke-Command -ComputerName "WEB-SRV-02" `
-Credential (Get-Credential) `
-ScriptBlock { hostname } `
-ErrorAction Stop
# Step 8: View WinRM event log for errors on the TARGET
Get-WinEvent -LogName "Microsoft-Windows-WinRM/Operational" -MaxEvents 20 |
Where-Object { $_.LevelDisplayName -ne "Information" } |
Select-Object TimeCreated, LevelDisplayName, Message
# Step 9: Re-run quickconfig to reset to defaults
winrm quickconfig -quiet
# Step 10: If all else fails, reset WinRM completely
winrm invoke Restore winrm/config '@{}'
Securing WinRM in Production
Default WinRM over HTTP is acceptable on trusted domain networks with Kerberos authentication, but for higher-security environments, apply these hardening steps:
# Disable HTTP listener (force HTTPS only)
# First ensure HTTPS listener is working, then remove HTTP
winrm delete winrm/config/listener?Address=*+Transport=HTTP
# Disable basic and digest authentication (use Kerberos or certificate only)
Set-Item WSMan:localhostServiceAuthBasic -Value $false
Set-Item WSMan:localhostServiceAuthDigest -Value $false
Set-Item WSMan:localhostServiceAuthKerberos -Value $true
Set-Item WSMan:localhostServiceAuthCertificate -Value $true
# Disable unencrypted traffic
Set-Item WSMan:localhostServiceAllowUnencrypted -Value $false
# Restrict WinRM to specific source IPs using firewall
$AdminSubnet = "192.168.1.0/24"
New-NetFirewallRule -DisplayName "WinRM - Restricted" `
-Direction Inbound -Protocol TCP -LocalPort 5985,5986 `
-RemoteAddress $AdminSubnet -Action Allow -Profile Domain,Private
# Block all other WinRM access
New-NetFirewallRule -DisplayName "WinRM - Block All Others" `
-Direction Inbound -Protocol TCP -LocalPort 5985,5986 `
-Action Block -Profile Domain,Private
# Verify final authentication configuration
Get-Item WSMan:localhostServiceAuth*
WinRM is a powerful and essential component of Windows Server 2022 management. With the HTTP or HTTPS listeners correctly configured, TrustedHosts set appropriately for your environment, firewall rules restricting access to management subnets, and PowerShell remoting verified with Test-WSMan, you have the foundation for scalable, scripted server management. Combine WinRM with Invoke-Command for batch operations across your server fleet and Enter-PSSession for interactive troubleshooting on any server in your environment.