Remote Powershell Quest
Our goal is to:
- open from a machine (the client)
- a Powershell session on a remote machine (the server)
- using certificates
- over a SSL connection
On any Windows machine
Create a self signed certificate
This certificate will have a private and a public key.
We’ll pair the public key on the server to a local user.
# Set infos for the certificate
$certuser = "leopardb"
$certuserUPN = "leopardb@mail.cool"
# Instead of generating a file, the cert will be added to the
# Current User folder in the certificate store
$cert = New-SelfSignedCertificate `
-Type Custom `
-Subject "CN=$certuser" `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2","2.5.29.17={text}upn=$certuserUPN") `
-KeyUsage DigitalSignature `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My"
PS C:\Windows\system32> Get-ChildItem -Path cert:\CurrentUser\My
PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My
Thumbprint Subject
---------- -------
85F7C77B16893A5502B387A3B4DCEE313DA3CA6E CN=leopardb
Export the keys
We export the certificate in three different forms:
- PEM (only public key)
- PFX (PKCS #12 contains private and public key)
- CER (contains the public key)
# We set the filenames for the certificate
$certuser = "leopardb"
$output_path = "C:\temp"
# Export the public key
$pem_output = @()
$pem_output += "-----BEGIN CERTIFICATE-----"
$pem_output += [System.Convert]::ToBase64String($cert.RawData) -replace ".{64}", "$&`n"
$pem_output += "-----END CERTIFICATE-----"
[System.IO.File]::WriteAllLines("$output_path\$certuser.pem", $pem_output)
# Export the private key in a PFX file will be converted to private pem with openssl
[System.IO.File]::WriteAllBytes("$output_path\$certuser.pfx", $cert.Export("Pfx"))
# Export the public key in .cer format for logging on other windows machines
Export-Certificate -Cert $cert -FilePath "$output_path\$certuser.cer" -Type Cert
On the server
The following steps must be done with administrator privileges.
First, we enable remote access:
PS C:\Windows\system32> Enable-PSRemoting
WinRM has been updated to receive requests.
WinRM service type changed successfully.
WinRM service started.
WinRM has been updated for remote management.
WinRM firewall exception enabled.
Configured LocalAccountTokenFilterPolicy to grant administrative rights remotely to local users.
Then we allow certificate authentication:
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
We open the firewall for incoming WinRM connections
netsh advfirewall firewall add rule name="WinRM-HTTPS" dir=in localport=5986 protocol=TCP action=allow
We create a HTTPS listener with a another self-signed certificate
$computername = ([System.Net.Dns]::GetHostByName(($env:computerName)).Hostname)
$c = New-SelfSignedCertificate `
-DnsName $computername `
-CertStoreLocation cert:\LocalMachine\My `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"$computername`";CertificateThumbprint=`"$($c.ThumbPrint)`"}"
Certificates
If we are using user authentication, the public key of the certificate we are using to connect to the server must be saved in the LocalMachine\TrustedPeople
store.
If we are using server authentication, the public key of the certificate we are using to connect to the server must be saved in the LocalMachine\TrustedDevices
store.
Also, if our certificate is self-signed, the server must trust it, therefore it must also be present in the LocalMachine\Root
store.
So we install our self-signed certificate on the machine:
Import-Certificate -FilePath "C:\cert.cer" -CertStoreLocation cert:\LocalMachine\root
Import-Certificate -FilePath "C:\cert.cer" -CertStoreLocation cert:\LocalMachine\TrustedPeople
At last, we map the imported certificate to a local user:
$certuser = "leopardb"
$certuserUPN = "leopardb@mail.cool"
$localuser = "leo"
$thumbprint = (Get-ChildItem cert:\LocalMachine\TrustedPeople | Where-Object {$_.Subject -match $certuser}).Thumbprint
New-Item -Path WSMan:\localhost\ClientCertificate `
-Subject $certuserUPN `
-URI * `
-Issuer $thumbprint `
-Credential (Get-Credential $localuser) `
-Force
Connect from a client
When using certificates for WinRM authentication, the certificate must include the private key and must be put:
- In the
CurrentUser\My
store if it’s a user certificate - In the
LocalMachine\My
store if it’s a server certificate
To connect with the certificate (SSL)
$remotecomputer = "DESKTOP-AA7J9T7.leodom.local"
$certusername = "leopardb"
$thumbprint = (Get-ChildItem cert:\CurrentUser\My | Where-Object {$_.Subject -match $certusername}).Thumbprint
$SessionOptions = New-PSSessionOption –SkipCACheck –SkipCNCheck
Enter-PSSession `
-ComputerName $remotecomputer `
-SessionOption $SessionOptions `
-UseSSL `
-CertificateThumbprint $thumbprint
To connect directly with credentials (SSL)
$remotecomputer = "DESKTOP-AA7J9T7.leodom.local"
$remoteuser = "toto"
$SessionOptions = New-PSSessionOption –SkipCACheck –SkipCNCheck
Enter-PSSession `
-ComputerName $remotecomputer `
-SessionOption $SessionOptions `
-UseSSL `
-Credential (Get-Credential $remotecomputer\$remoteuser)
To connect directly with credentials
$remotecomputer = "DESKTOP-AA7J9T7.leodom.local"
$remoteuser = "toto"
Enter-PSSession `
-ComputerName $remotecomputer `
-Credential (Get-Credential $remotecomputer\$remoteuser)
Scripts
Open command prompt as admin and run:
powershell.exe -noprofile -executionpolicy bypass -file \\path\to\SetRemotePSWithCert.ps1
SetRemotePSWithCert.ps1:
# Variables for the script
$computername = ([System.Net.Dns]::GetHostByName(($env:computerName)).Hostname)
$certpath = "\\folder\where\the\cert\is"
$certuser = "leopardb"
$certuserUPN = "leopardb@mail.cool"
$localuser = "toto"
# Sadly this one is required
Enable-PSRemoting -SkipNetworkProfileCheck -Force
# Create Server Auth certificate
$c = New-SelfSignedCertificate `
-DnsName $computername `
-CertStoreLocation cert:\LocalMachine\My `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
# Create a WinRM HTTPS listener
winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"$computername`";CertificateThumbprint=`"$($c.ThumbPrint)`"}"
# Create a firewall rule to allow incoming HTTPS WinRM connections
netsh advfirewall firewall add rule name="WinRM-HTTPS" dir=in localport=5986 protocol=TCP action=allow
# Allow Certificate authentication (default is disabled)
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
# Import the certificate
Import-Certificate -FilePath "$certpath\$certuser.cer" -CertStoreLocation cert:\LocalMachine\root
Import-Certificate -FilePath "$certpath\$certuser.cer" -CertStoreLocation cert:\LocalMachine\TrustedPeople
# Map the certificate identified by $username to the local user $localuser
$thumbprint = (Get-ChildItem cert:\LocalMachine\TrustedPeople | Where-Object {$_.Subject -match $certuser}).Thumbprint
New-Item -Path WSMan:\localhost\ClientCertificate `
-Subject $certuserUPN `
-URI * `
-Issuer $thumbprint `
-Credential (Get-Credential $localuser) `
-Force
When not in a domain
In a domain
Create GPOs using gpmc.msc
WinRM
Computer Configuration
Policies – Windows Settings – Security Settings – Windows Firewall with Advanced Security – Inbound Rules
Add predefined rule : “Windows Remote Management (HTTP-In)” for Domain,Private (can remove private afterwards)
Policies – Administrative Templates – Windows Components – Windows Remote Management (WinRM) – WinRM Service
“Allow remote server management through WinRM” Enabled, IPv4 Filter: *
if not a * wildcard, then it must be a range even if it’s a single address (ex: 192.168.2.51-192.168.2.51)
this is the Server’s IPs where the Service is listening ! Not the clients ! This filtering is made by the firewall
Preferences – Control Panel Settings – Services
New service
– Startup: Automatic
– Service name: WinRM
– Service action: Start service
WMI
Policies – Windows Settings – Security Settings – Windows Firewall with Advanced Security – Inbound Rules
– Add predefined rule : “Remote Scheduled Tasks Management”
– Add predefined rule : “Windows Management Instrumentation (WMI)”
SNMP
Firewall
Service
Description
Connect from the DC
Enter-PSSession -Computername DESKTOP-AA7J9T7.leodom.local