Issue with PowerShell Remote Endpoints after a Windows 10 Upgrade

  • Context:

I’ve tested recently an upgrade to the latest branch 1803 (aka Spring Creators Update / RS4) of a Windows 10 Enterprise x64 that had a custom remote endpoint configuration.

  • Issue:

Everything was still there. It was still registered, its ACL still set… except that it doesn’t work.
If you attempt to create a new PSSession or use Enter-PSSession or Invoke-Command, it failed with the same error message:

New-PSSession : [localhost] Connecting to remote server localhost failed with the following error message : The WS-Management service cannot process the operation. An attempt to create a virtual account failed. Ensure that WinRM service is running as Local System and that it has TCB privilege enabled. For more information, see the about_Remote_Troubleshooting Help topic.

TCB means Trusted Computing Base. The WinRM service seems to have lost its (SeTcbPrivilege) ability to Act as part of the operating system and cannot create the virtual account used by the remote endpoint.

If I check the services on a 1709, I’ve:

If I check the services on a 1709 upgraded to a 1803, I’ve:

  • Solution 1:

Unregister and register

  • Solution 2:

There are two ways to restore the TCB privilege: either using sc.exe or by setting the RequiredPrivileges REG_MULTI_SZ value in the registry.

# using sc.exe to restore privilege
sc.exe privs WinRM SeAssignPrimaryTokenPrivilege/SeAuditPrivilege/SeChangeNotifyPrivilege/SeCreateGlobalPrivilege/SeImpersonatePrivilege/SeTcbPrivilege
# or directly setting the value in the registry
$HT = @{
 Path = 'HKLM:\SYSTEM\CurrentControlSet\Services\WinRM'
 Name = 'RequiredPrivileges'
 Value = @(
  'SeAssignPrimaryTokenPrivilege',
  'SeAuditPrivilege',
  'SeChangeNotifyPrivilege',
  'SeCreateGlobalPrivilege',
  'SeImpersonatePrivilege',
  'SeTcbPrivilege'
 )
}
Set-ItemProperty -Type MultiString @HT -Force

# Restore the local system account
Get-CimInstance -ClassName Win32_Service -Filter "Name='WinRM'"| 
Invoke-CimMethod -MethodName Change -Arguments @{StartName='LocalSystem'}

# Apply changes
Restart-Service -Name WinRM
  • Misc.:

Can you notice any other difference left by the upgrade?

The DisplayName was changed and the ServiceType was changed from 0x10 (it has its own process) to 0x20 (it’s a shared process).
Don’t ask me why the upgrade changed these settings? 🙄 I have no idea.

Bonus: Solution 1 is better than solution 2 because it also fixes the service type.

Detect and correct orphaned ‘adminCount=1’ in Active Directory

I recently needed to detect and correct orphaned ‘adminCount=1’ in Active Directory.
I googled that old problem and found the following code: https://gist.github.com/webash/b34c5a422288827ff4e53318e34c6923

I loved his honesty and the fact that he respected the best practice of adding a note where he has acquired the code.
The help also references a blog post on technet.

I don’t like to reinvent the wheel and I couldn’t resist fixing the code anyway.

#Requires -Version 3.0
#Requires -Module ActiveDirectory
Function Get-OrphanAdminSdHolderUser {
[CmdletBinding()]
Param()
Begin {}
Process {
}
End {
$UsersInAdminGroups = (Get-ADGroup -LDAPFilter '(adminCount=1)') |
ForEach-Object {
# Get all users from all admin groups recursively
Get-ADGroupMember $_ -Recursive | Where-Object {$_.ObjectClass -eq 'User'}
# ...then sort them by distinguishedName to ensure accurate -Unique results (because some users might be in multiple protected groups)
} | Sort-Object distinguishedname | Select-Object -Unique
#Get List of Admin Users (Past and Present) = $UsersFlaggedAsAdmin
#Compare $UsersFlaggedAsAdmin to $Admins and place in appropriate hash table
Get-ADUser -LDAPFilter '(adminCount=1)' |
ForEach-Object {
If ($_.samAccountName -notin $UsersInAdminGroups.samAccountName) {
Write-Verbose -Message ("ORPHAN`t`t{0}" -f $_.samAccountName)
$_
} else {
Write-Verbose -Message ("STILL ADMIN`t{0}" -f $_.samAccountName)
}
}
}
<#
.SYNOPSIS
Detects Orphaned SD Admin users
.DESCRIPTION
Get all users that are members of protected groups within AD and compares membership with users
that have the AD Attribute AdminCount=1 set. If the user has the AdminCount=1 enabled but is
not a member of a protected group then the user is considered an orphaned admin user.
#>
}
Function Clear-OrphanAdminSdHolderUser {
[CmdletBinding(SupportsShouldProcess,ConfirmImpact='High')]
Param(
[parameter(Mandatory,ValueFromPipeline)]
[Microsoft.ActiveDirectory.Management.ADPrincipal[]]$OrphanUser
)
Begin {}
Process {
$OrphanUser |
Where-Object { $_.SamAccountName -ne 'krbtgt' } |
ForEach-Object {
$user = $_
if ($pscmdlet.ShouldProcess($_,'Clear AdminCount and reset permissions inheritance')) {
try {
$user | Set-ADUser -Clear {AdminCount} -ErrorAction Stop
Write-Verbose -Message ('Clearing AdminCount for {0}' -f $user.SamAccountName)
} catch {
Write-Warning -Message "Failed to clear admincount property for $($user.SamAccountName) because $($_.Exception.Message)"
}
try {
$Acl = Get-ACL -Path ('AD:\{0}' -f $user.DistinguishedName) -ErrorAction Stop
If ($Acl.AreAccessRulesProtected) {
$Acl.SetAccessRuleProtection($False, $True)
Set-ACL -AclObject $ACL -Path ('AD:\{0}' -f $user.DistinguishedName) -ErrorAction Stop
Write-Verbose -Message ('Enabling Inheritence for {0}' -f $user.SamAccountName)
} else {
Write-Verbose -Message ('Inheritence already set for {0}' -f $user.SamAccountName)
}
} catch {
Write-Warning -Message "Failed to enable inheritence for $($user.SamAccountName) because $($_.Exception.Message)"
}
}
}
}
End {}
<#
.SYNOPSIS
Resets admin count attribute and enables inheritable permissions on AD user
.DESCRIPTION
The AdminCount attributed is cleared and inheritable permissions are reset
.PARAMETER OrphanUser
A list or array of ADUser objects
.EXAMPLE
Get-OrphanAdminSdHolderUser| Select -First 1 | Clear-OrphanAdminSdHolderUser -WhatIf
.EXAMPLE
Get-OrphanAdminSdHolderUser | Clear-OrphanAdminSdHolderUser
#>
}