ansible-collections/ansible.windows

Error during machine sid retrieval: An error (1788) occurred while enumerating the group membership. The member's SID could not be resolved.

Yannik opened this issue · 14 comments

SUMMARY

For some reason, one of my hosts (a domain controller) is producing this warning during facts gathering:
[WARNING]: Error during machine sid retrieval: An error (1788) occurred while enumerating the group membership. The member's SID could not be resolved.

I was able to reproduce this error by manually executing the code

$adminGroup = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @(
"S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value
$namespace = 'System.DirectoryServices.AccountManagement'
Add-Type -AssemblyName $namespace
$context = New-Object -TypeName "$namespace.PrincipalContext" -ArgumentList @(
[System.DirectoryServices.AccountManagement.ContextType]::Machine)
$principal = New-Object -TypeName "$namespace.GroupPrincipal" -ArgumentList $context, $adminGroup
$searcher = New-Object -TypeName "$namespace.PrincipalSearcher" -ArgumentList $principal
$groups = $searcher.FindOne()

and then trying to list $group.Members.

$adminGroup contains the string BUILTIN\Administratoren.
However, I am unable to see the members of this group, since the affected server is a domain controller, and has no local groups.

get-localgroup $adminGroup returns get-localgroup : Group BUILTIN\Administratoren was not found..

Is there any way I can fix this / list the members of this group so I can see which one is causing issues?

ISSUE TYPE
  • Bug Report
COMPONENT NAME

setup

ANSIBLE VERSION
ansible [core 2.16.3]
  config file = /builds/ansible/deployments/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /app/lib/python3.12/site-packages/ansible
  ansible collection location = /builds/ansible/deployments/vendor_collections
  executable location = /app/bin//ansible
  python version = 3.12.2 (main, Feb  7 2024, 22:13:24) [GCC 13.2.1 20231014] (/usr/local/bin/python)
  jinja version = 3.1.3
  libyaml = True
COLLECTION VERSION

Collection      Version
--------------- -------
ansible.windows 1.14.0 
CONFIGURATION
CACHE_PLUGIN_CONNECTION(/home/yannik/projects/xxx/ansible/ansible.cfg) = .ansible_facts
CACHE_PLUGIN_TIMEOUT(/home/yannik/projects/xxx/ansible/ansible.cfg) = 60
CALLBACKS_ENABLED(/home/yannik/projects/xxx/ansible/ansible.cfg) = ['ansible.posix.profile_tasks']
COLLECTIONS_PATHS(/home/yannik/projects/xxx/ansible/ansible.cfg) = ['/home/yannik/projects/xxx/ansible/vendor_collections']
CONFIG_FILE() = /home/yannik/projects/xxx/ansible/ansible.cfg
DEFAULT_FORKS(/home/yannik/projects/xxx/ansible/ansible.cfg) = 25
DEFAULT_HOST_LIST(/home/yannik/projects/xxx/ansible/ansible.cfg) = ['/home/yannik/projects/xxx/ansible/inventory']
DEFAULT_MANAGED_STR(/home/yannik/projects/xxx/ansible/ansible.cfg) = This file is managed by ansible and will be overwritten! Do not change it manually!
DEFAULT_ROLES_PATH(/home/yannik/projects/xxx/ansible/ansible.cfg) = ['/home/yannik/projects/xxx/ansible/vendor_roles']
DEFAULT_STDOUT_CALLBACK(/home/yannik/projects/xxx/ansible/ansible.cfg) = yaml
DEFAULT_TIMEOUT(/home/yannik/projects/xxx/ansible/ansible.cfg) = 120
DIFF_ALWAYS(/home/yannik/projects/xxx/ansible/ansible.cfg) = True
EDITOR(env: EDITOR) = vim
HOST_KEY_CHECKING(/home/yannik/projects/xxx/ansible/ansible.cfg) = False
INTERPRETER_PYTHON(/home/yannik/projects/xxx/ansible/ansible.cfg) = auto_silent
PAGER(env: PAGER) = less
RETRY_FILES_ENABLED(/home/yannik/projects/xxx/ansible/ansible.cfg) = False
OS / ENVIRONMENT

Target OS: windows server 2022

Are you able to try this out and see if it fails in the same way, if so what exact line is failing?

$adminGroup = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @( 
    "S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value 

$namespace = 'System.DirectoryServices.AccountManagement' 

Add-Type -AssemblyName $namespace 
$context = New-Object -TypeName "$namespace.PrincipalContext" -ArgumentList @( 
    [System.DirectoryServices.AccountManagement.ContextType]::Machine) 
$principal = New-Object -TypeName "$namespace.GroupPrincipal" -ArgumentList $context, $adminGroup 
$searcher = New-Object -TypeName "$namespace.PrincipalSearcher" -ArgumentList $principal 
$groups = $searcher.FindOne()

$groupMembers = $groups.Members.GetEnumerator()
$i = 0
while ($true) {
    try {
        if (-not $groupMembers.MoveNext()) {
            break
        }
        $g = $groupMembers.Current
        Write-Host "Group [$i] $($g.Name) - $($g.Sid)"
    }
    catch {
        Write-Host "Failed to enumerate group at ${i}: $_"
    }
    $i++
}

Do you see a group with a SID that ends with -500 in that output? Do you see the Failed to enumerate group at ... at any point?

I've been seeing this same issue for over a year now.

I ran the script @jborean93 provided. it produced no errors, and i do see an account with a SID ending with -500.

@rhophi2000 so you've been seeing the issue but the above code didn't have any problems, specifically it didn't show Failed to enumerate group at ...? If you run the code at

$adminGroup = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @(
"S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value
$namespace = 'System.DirectoryServices.AccountManagement'
Add-Type -AssemblyName $namespace
$context = New-Object -TypeName "$namespace.PrincipalContext" -ArgumentList @(
[System.DirectoryServices.AccountManagement.ContextType]::Machine)
$principal = New-Object -TypeName "$namespace.GroupPrincipal" -ArgumentList $context, $adminGroup
$searcher = New-Object -TypeName "$namespace.PrincipalSearcher" -ArgumentList $principal
$groups = $searcher.FindOne()
foreach ($user in $groups.Members) {
if ($user.Sid.Value.EndsWith("-500")) {
$machineSid = $user.Sid.AccountDomainSid.Value
break
}
}
manually do you see any problems on the affected host?

Hi all,

after quite a bit of research, I can now give you a summary of my findings:

First I tried to find out what the non-resolvable SIDs were. Turns out, you can enumerate them with ADSI:

# from setup.ps1
$adminGroup = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @(
         "S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value

$adminGroup = $adminGroup -replace '.+\\'
$group = [ADSI]"WinNT://$($env:computername)/$adminGroup"
$group.Invoke("Members") | foreach { $_.gettype().invokemember("name", 'getproperty', $null, $_, $null) }

Trying to further understand why a seemingly local group on a freshly installed DC contains unresolvable SIDs, I found out that on a DC, $adminGroup will contain the AD administrator group, not a local group. This is the case even if the AD administrators group was renamed.
As a matter of fact, this groups SID is of no use to determine the machine SID.
First of all, this AD group needs to exist (which it does by default, but it might've become deleted). Secondly, it needs to contains a user with SID ending in -500 (default AD administrator account)
Finally, this users SID always is DOMAINSID-500. Always resulting in returning the Domain SID as machine SID, which is obviously incorrect.

You can verify this by comparing ansible_machine_id to the domain SID.

It seems like the appropriate way to determine machine SID on a DC would be to use:

(Get-ADComputer $env:computername).SID

I have checked whether the Active-Directory Powershell Module is always installed on DCs, which seem to be the case, even if installing AD-Domain-Services without -IncludeManagementTools.

Looking forward to hearing your thoughts @jborean93

It seems like the appropriate way to determine machine SID on a DC would be to use:

This may be the case but using the same code on my DC returns the same SID as the AD module. Unfortunately it isn't guaranteed that the RSAT module is present so we would also have to rely on AD or the .NET classes to get the value which ends up being the code we have right now

image

We don't use ADSI directly but the .NET System.DirectoryServices is the .NET layer over the same technology so the same thing really applies there. What I don't understand is what part is unresolvable in these broken examples. The only translation we do is translating the SID S-1-5-32-544 to the group name but based on your snippet you are doing the same thing without a problem. We don't try and translate the SIDs of each group member, just checking if it ends with -500. The snippet I had in #606 (comment) seemed to not indicate there was any error when enumerating the group members as per #606 (comment). This should mean there shouldn't be a problem with the foreach loop we have as that's just a shorthand of that while loop enumeration. If you run that same code do you see any errors in the output?

This may be the case but using the same code on my DC returns the same SID as the AD module.

@jborean93 Please check your screenshot again, the $machineSid SID and Get-ADComputer SID are NOT identical. $machineSid contains the domain SID (ending in -203368311), while the Get-ADComputer output shows the machine SID (ending in -1001). I explained why $machineSid contains the domain SID in my previous comment.

What I don't understand is what part is unresolvable in these broken examples.

The SID enumeration issue is caused by the AD Administrator Group containing a deleted user as member. Iterating over the users (foreach ($user in $groups.Members)) throws the error. Removing this deleted account as a group member fixes the issue. However, this does not fix the problem of $machineSid actually containing the domain SID instead of the machine SID.

Regarding your point "Unfortunately it isn't guaranteed that the RSAT module is present [...]", I already commented earlier:

I have checked whether the Active-Directory Powershell Module is always installed on DCs, which seem to be the case, even if installing AD-Domain-Services without -IncludeManagementTools.

You wrote:

so we would also have to rely on AD or the .NET classes to get the value which ends up being the code we have right now

As far as I can see, that is not at all correct. Get-ADComputer retrieves the SID property of the computer adobject.
The current setup.ps1 code retrieves the AD administrator group and chops of the last part, which is totally different.

(I guess it should be possible to retrieve the SID property of the adobject using ADSI instead of the ActiveDirectory cmdlets, but that is just not what's happening right now)

Please check your screenshot again, the $machineSid SID and Get-ADComputer SID are NOT identical

Sorry I should have been clearer, the -1001 was the computer SID id (and should be ignored) but the prefix is the same (machine/domain SID).

The SID enumeration issue is caused by the AD Administrator Group containing a deleted user as member. Iterating over the users (foreach ($user in $groups.Members)) throws the error. Removing this deleted account as a group member fixes the issue.

That's the part I am confused about, the code I shared in #606 (comment) should handle the enumeration problem by skipping unresolvable identities. The comment after indicated that it didn't report an error like I would expect but potentially the user had an unrelated problem. If you were to run that snippet do you see something like Failed to enumerate group at ...? If not do you see the proper group names like

Group [0] Administrator - S-1-5-21-2100517712-2957671396-2033368311-500
Group [1] vagrant - S-1-5-21-2100517712-2957671396-2033368311-1000
Group [2] Enterprise Admins - S-1-5-21-2100517712-2957671396-2033368311-519
Group [3] Domain Admins - S-1-5-21-2100517712-2957671396-2033368311-512

However, this does not fix the problem of $machineSid actually containing the domain SID instead of the machine SID.

For a DC the machine SID is the domain SID. This fact is not meant to be the AD computer account SID like but the specific machine SID.

I have checked whether the Active-Directory Powershell Module is always installed on DCs, which seem to be the case, even if installing AD-Domain-Services without -IncludeManagementTools.

I've definitely installed the AD role without the RSAT tools being present. It's not something we can rely on being there.

As far as I can see, that is not at all correct. Get-ADComputer retrieves the SID property of the computer adobject.

My comment was talking about ADSI and System.DirectoryServices and not the RSAT AD module.

If you were to run that snippet do you see something like Failed to enumerate group at ...?

I cannot reproduce this at this moment because I removed the non-existant group members.

This fact is not meant to be the AD computer account SID like but the specific machine SID.

Ok, got it.

For a DC the machine SID is the domain SID.

Looking at one of my DCs, I cannot confirm this:

machine sid:

PS C:\Windows\system32> $v = Get-ItemProperty HKLM:\security\sam\domains\account -Name v
PS C:\Windows\system32> New-Object System.Security.Principal.SecurityIdentifier([Byte[]]$v.V[-24..-1],0)

BinaryLength AccountDomainSid                         Value
------------ ----------------                         -----
          24 S-1-5-21-1354245917-823686366-1199517847 S-1-5-21-1354245917-823686366-1199517847

domain sid:

PS C:\Windows\system32> (get-addomain).domainsid

BinaryLength AccountDomainSid                       Value
------------ ----------------                       -----
          24 S-1-5-21-741685862-1582030302-41348483 S-1-5-21-741685862-1582030302-41348483

I've definitely installed the AD role without the RSAT tools being present. It's not something we can rely on being there.

Yes, me too.
I am not talking about the whole RSAT tools. Just the RSAT-AD-PowerShell feature, which from my testing seems to always be installed when installing AD-Domain-Services feature.

This is confirmed by the fact that you cannot even manually uninstall RSAT-AD-Powershell on a DC:

PS C:\Users\Administrator> Remove-WindowsFeature RSAT-AD-PowerShell

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
False   Maybe          Failed         {}
Remove-WindowsFeature : A prerequisite check for the AD-Domain-Services feature failed.
1. The Active Directory domain controller needs to be demoted before the AD DS role can be removed.
At line:1 char:1
+ Remove-WindowsFeature RSAT-AD-PowerShell
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Active Directory Domain Services:ServerComponentWrapper) [Uninstall-W
   indowsFeature], Exception
    + FullyQualifiedErrorId : Alteration_PrerequisiteCheck_Failed,Microsoft.Windows.ServerManager.Commands.RemoveWindo
   wsFeatureCommand

Anyway, this does not matter too much, since I understood now that you want the local windows machine sid, and not the computer account sid in this fact.