Skip to content

Instantly share code, notes, and snippets.

@kgriffs
Last active October 17, 2017 17:49
Show Gist options
  • Save kgriffs/48e85a6025b5f2ec9961 to your computer and use it in GitHub Desktop.
Save kgriffs/48e85a6025b5f2ec9961 to your computer and use it in GitHub Desktop.
Enable WinRM (w2k8r2 or better)
# Configure a Windows host for remote management with Ansible
# -----------------------------------------------------------
#
# This script checks the current WinRM/PSRemoting configuration and makes the
# necessary changes to allow Ansible to connect, authenticate and execute
# PowerShell commands.
#
# Written by Trond Hindenes <trond@hindenes.com>
# Updated by Chris Church <cchurch@ansible.com>
# Updated by Kurt Griffiths <kurt.griffiths@rackspace.com>
#
Param (
[string]$SubjectName = $env:COMPUTERNAME,
$CreateSelfSignedCert = $true
)
Function New-LegacySelfSignedCert
{
Param (
[string]$SubjectName
)
# New-SelfSignedCertificate is hard-coded for 1 year, so follow suit
$ValidDays = 365
$name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$SubjectName", 0)
$key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
$ekuoids.Add($serverauthoid)
$ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = (Get-Date).AddDays(-1)
$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
# Return the thumbprint of the last installed cert.
Get-ChildItem "Cert:\LocalMachine\my"| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint
}
# Setup error handling.
Trap
{
$_
Exit 1
}
$ErrorActionPreference = "Stop"
# Find and start the WinRM service.
Write "Verifying WinRM service."
If (!(Get-Service "WinRM"))
{
Throw "Unable to find the WinRM service."
}
ElseIf ((Get-Service "WinRM").Status -ne "Running")
{
Write "Starting WinRM service."
Start-Service -Name "WinRM" -ErrorAction Stop
}
Else
{
Write "WinRM service is running."
}
# WinRM should be running; check that we have a PS session config.
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
{
Write "Enabling PS Remoting."
Enable-PSRemoting -Force -ErrorAction Stop
}
Else
{
Write "PS Remoting is already enabled."
}
# Make sure there is an SSL listener.
$listeners = Get-ChildItem WSMan:\localhost\Listener
If (!($listeners | Where {$_.Keys -like "TRANSPORT=HTTPS"}))
{
If (!$CreateSelfSignedCert)
{
Throw "SSL listener is not enabled. Manually enable the SSL listener and re-run this script."
}
# HTTPS-based endpoint does not exist.
If (Get-Command "New-SelfSignedCertificate" -ErrorAction SilentlyContinue)
{
$cert = New-SelfSignedCertificate -DnsName $SubjectName -CertStoreLocation "Cert:\LocalMachine\My"
$thumbprint = $cert.Thumbprint
}
Else
{
# w2k8 may not have New-SelfSignedCertificate so we have to roll our own
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName
}
# Create the hashtables of settings to be used.
$valueset = @{}
$valueset.Add('Hostname', $SubjectName)
$valueset.Add('CertificateThumbprint', $thumbprint)
$selectorset = @{}
$selectorset.Add('Transport', 'HTTPS')
$selectorset.Add('Address', '*')
Write "Enabling SSL listener."
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
}
Else
{
Write "SSL listener is already active."
}
If (($listeners | Where {$_.Keys -like "TRANSPORT=HTTP"}))
{
Write "Warning: HTTP listener is enabled. Do not use basic auth on port 5985."
# Write "Disabling plaintext listener before enabling basic auth to avoid opening an attack vector."
# $selectorset = @{}
# $selectorset.Add('Transport', 'HTTP')
# $selectorset.Add('Address', '*')
# Remove-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset
}
# Check for basic authentication.
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -eq "Basic"}
If (($basicAuthSetting.Value) -eq $false)
{
Write "Enabling basic auth support."
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
}
Else
{
Write "Basic auth is already enabled."
}
# Test a remoting connection to localhost, which should work.
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
If ($httpsResult)
{
Write "HTTPS sessions are enabled."
}
Else
{
Throw "Unable to establish an HTTP or HTTPS remoting session."
}
# Configure firewall to allow WinRM HTTPS connections. We have to use netsh because
# New-NetFirewallRule may not be available on w2k8.
$rule_name = "Windows Remote Management (HTTPS-In)"
$fwtest1 = netsh advfirewall firewall show rule name=$rule_name
$fwtest2 = netsh advfirewall firewall show rule name=$rule_name profile=any
If ($fwtest1.count -lt 5)
{
Write "Adding firewall rule to allow WinRM HTTPS."
netsh advfirewall firewall add rule profile=any name=$rule_name dir=in localport=5986 protocol=TCP action=allow
}
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
{
Write "Updating firewall rule to allow WinRM HTTPS for any profile."
netsh advfirewall firewall set rule name=$rule_name new profile=any
}
Else
{
Write "Enabling existing firewall rule to allow WinRM HTTPS."
netsh advfirewall firewall set rule name=$rule_name new enable=yes
}
Write "WinRM service has been successfully configured."
@kgriffs
Copy link
Author

kgriffs commented Sep 11, 2015

TODO: Disable HTTP listener (if one was previously configured) before enabling basic auth.

@fxfitz
Copy link

fxfitz commented Oct 2, 2015

Should we actually disable the HTTP listener? Wouldn't that have the possibility of breaking other services that may depend on it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment