PSRemoting to AD-less Azure Local

Table of Contents

Preface

Azure Local’s Local Identity deployment option lets you run a cluster without Active Directory: edge sites, disconnected labs, anywhere you don’t want a hard dependency on a DC. The nodes are workgroup machines, and that changes how PowerShell remoting works:

  • No Kerberos, so WinRM authenticates with NTLM.
  • With NTLM, the WinRM client only connects if you use HTTPS, or add the target to TrustedHosts.

HTTPS is the better answer: the client verifies it’s talking to the right server, and you don’t have to loosen TrustedHosts on every admin machine. And the deployment has already done half the work: each node has a server certificate in Cert:\LocalMachine\My with its FQDN as the subject. You just need a listener that uses it.

The recipe

On each node:

Enable-PSRemoting -SkipNetworkProfileCheck -Force

# the certificate the deployment created, and its exact common name
$cert = Get-ChildItem Cert:\LocalMachine\My |
    Where-Object { $_.Subject -like "*CN=$env:COMPUTERNAME*" } | Select-Object -First 1
$cn   = $cert.GetNameInfo(
    [System.Security.Cryptography.X509Certificates.X509NameType]::SimpleName, $false)

# HTTPS listener on that certificate; Hostname must be the exact CN
winrm create winrm/config/Listener?Address=*+Transport=HTTPS `
  "@{Hostname=`"$cn`";CertificateThumbprint=`"$($cert.Thumbprint)`"}"

New-NetFirewallRule -DisplayName "WinRM HTTPS (5986)" -Direction Inbound `
    -Protocol TCP -LocalPort 5986 -Action Allow

winrm enumerate winrm/config/Listener      # should show Transport = HTTPS, Port = 5986

From your admin machine:

Enter-PSSession -ComputerName <node FQDN> -UseSSL -Credential <node>\Administrator `
    -SessionOption (New-PSSessionOption -SkipCACheck -SkipRevocationCheck)
  • Connect by the FQDN (the $cn value). It has to match the certificate’s name.
  • Use a local account on the node. There’s no domain, so no DOMAIN\user.
  • -SkipCACheck and -SkipRevocationCheck are needed because your admin machine doesn’t trust whatever issued the node’s certificate, and can’t check it for revocation. To drop them, import the issuing certificate into the client’s Cert:\LocalMachine\Root.
  • No TrustedHosts change needed. HTTPS satisfies the NTLM requirement on its own.

Gotchas

“Enable-PSRemoting” fails on a Public network

The management NIC on these nodes usually lands on the Public network profile, and Enable-PSRemoting refuses to configure remoting on Public networks. -SkipNetworkProfileCheck gets past it.

You’ll also find WinRM is already running with an HTTP listener on 5985 (Source="GPO" in winrm enumerate): Azure Local sets that up by policy. That’s fine; the HTTPS listener sits alongside it.

“This command cannot be used because root path does not exist”

You’ll hit this if you build the listener through the WSMan: drive with a path like WSMan:\LocalMachine\Listener. The drive’s root is localhost, not LocalMachine: Get-ChildItem WSMan:\ shows it. Each entry at the top of the drive is a computer the drive is connected to.

That also explains the confusing follow-up. New-Item -Path WSMan:\LocalMachine doesn’t create a folder; it tells the drive to connect to a computer named “LocalMachine”. On a workgroup node that connection fails with:

The WinRM client cannot process the request. If the authentication scheme is different
from Kerberos, or the client computer is not joined to a domain, then HTTPS transport
must be used or the destination machine must be added to the TrustedHosts configuration setting.

It isn’t telling you anything about your listener; it’s trying to reach a machine that doesn’t exist. Use WSMan:\localhost\Listener, or use winrm create as in the recipe, which doesn’t go through the drive at all.

“The certificate CN and the hostname that were provided do not match”

The listener’s Hostname has to match the certificate’s common name exactly. The easy mistake:

  • The -like "*CN=$env:COMPUTERNAME*" filter is a substring match, so it correctly finds the certificate whose CN is the FQDN (AZL-N1.contoso.local).
  • But if you then pass Hostname=$env:COMPUTERNAME, you’ve given the listener the short name (AZL-N1). That doesn’t match, and WinRM rejects it.

Don’t type the name or parse $cert.Subject by hand. Read it off the certificate with GetNameInfo(SimpleName) as in the recipe, and use that same name when you connect from the client.

The winrm create quoting

The @{...} value set has to reach winrm.exe as one string, with the inner values quoted. From PowerShell that means escaping the inner double quotes with backticks (`"), exactly as in the recipe. Get it wrong and the errors look like a different problem entirely.

Connecting by IP fails the name check

The certificate is issued to the FQDN, so connecting by IP fails validation. Use the FQDN, or add -SkipCNCheck to the session options if you really must use an IP.

Takeaways

  • AD-less means NTLM, and NTLM means HTTPS (or TrustedHosts). Go with HTTPS and the certificate the deployment already gave you.
  • The WSMan: drive’s root is localhost. “Root path does not exist” plus a TrustedHosts error usually means the path is wrong, not that WinRM is broken.
  • Match the certificate name exactly, on the listener and when you connect.