PowerShell / PSDscResources

MIT License
129 stars 53 forks source link

Group: Resource failing when using 'MembersToInclude' to add members to a local group that contains a domain group #97

Open aydeisen opened 6 years ago

aydeisen commented 6 years ago

I have a DSC file with a resource hashtable configured similar to the following:

Group AdminGroupMembership {
    Ensure           = "Present"
    GroupName        = "Administrators"
    MembersToInclude = @("Member01")
}

When the DSC applies to a domain member server, it fails, even though 'Member01' was successfully added to the group.

What appears to be happening is that MembersToInclude has the resource iterating through all the members of the group to see if 'Member01' is present. Since this is a domain member server, and since PsDscRunAsCredential isn't specified, the failure is being generated when the script attempts to process the [DOMAIN]\Domain Admins group, as it doesn't have access.

The outcome I was is expecting is: since I'm only looking to validate that 'Member01' exists inside the Administrators local group, and since I'm not looking to remove any members from it, DSC would only validate that 'Member01' exists inside the Administrators local group, and it wouldn't try to resolve a domain member when it doesn't have access to Active Directory.

Is this "working as intended" or can this be resolved in a future update?

ewhitesides commented 6 years ago

I'm able to check domain members/domain groups by specifying the runas credential.
to create the credential.dat file use:

$credentials = get-credential $credentials | export-clixml powershelluser.dat

then your DSC config will look like:

$CredentialFolder = "$PSScriptRoot\credentials" $powershelljobs_svc = "$CredentialFolder\powershelluser.dat"

Configuration MyConfig { Group StandardLocalAdmins { GroupName = 'Administrators' Ensure = 'Present' MembersToInclude = @( 'LocalAdminUser', 'DOMAIN\Domain Admins' ) PsDscRunAsCredential = Import-Clixml $powershelluser } }

aydeisen commented 6 years ago

@ewhitesides: but that's the point. I have no desire to include 'DOMAIN\Domain Admins' in my DSC Configuration and, by using MembersToInclude, I'm not making my configuration overwrite the unlisted accounts in the group. So, why should I need to include PsDscRunAsCredential when there's nothing included in my DSC configuration that manipulates domain accounts. By extension, if I'm not including anything that manipulates domain accounts in my DSC configuration, why is it trying to enumerate the members of a domain group when doing so is not defined in the DSC configuration

ewhitesides commented 6 years ago

it most likely has to do with the way the group resource module was coded. it probably detects the computer is a member of a domain, and switches to requiring a domain account for verifying even the local only accounts.

In situations like this, you're best off just using the Script resource to build something on your own.

Test-Script could involve something like '$UserCheck = &net localgroup administrators' and checking if the user is in the $UserCheck variable.

Set-Script would involve a command like 'net localgroup administrators /add'

aydeisen commented 6 years ago

@ewhitesides Why would I want to use a workaround for a resource of this project when it isn't working as documented? This is a bugfix request. If the owners of this project aren't going to implement a fix, they can at least have the courtesy of reviewing the issue and marking it as such.

johlju commented 6 years ago

@aydeisen what error message are you seeing when this happens? I guess you are running the resource as SYSTEM?

I guess the problem is in Get-MembersAsPrincipalsList. I gather by this comment that this should work, but something is going on that prevents it from "Dropping down to the underyling DirectoryEntry API".

https://github.com/PowerShell/PSDscResources/blob/9f5e9e48eda63b5ff0ab5ad179173b754863c49e/DscResources/MSFT_GroupResource/MSFT_GroupResource.psm1#L1666-L1674

johlju commented 6 years ago

@aydeisen Also, could you please provide the verbose output when you get this error?

aydeisen commented 6 years ago

@johlju This is the error message:

PowerShell DSC resource MSFT_GroupResource  failed to execute Test-TargetResource functionality with error message: Exception calling ".ctor" with "2" argument(s): "The server could not be contacted." 
+ CategoryInfo          : InvalidOperation: (:) [], CimException
+ FullyQualifiedErrorId : ProviderOperationExecutionFailure
+ PSComputerName        : localhost

...and this is the verbose log for the resource (with username, hostname, and domain name replacement for company compliance reasons):

[SERVER06]: LCM:  [ Start  Resource ]  [[Group]AdminGroupMembership]
[SERVER06]: LCM:  [ Start  Test     ]  [[Group]AdminGroupMembership]
[SERVER06]:                            [[Group]AdminGroupMembership] Invoking the function Test-TargetResourceOnFullSKU for the group Administrators.
[SERVER06]:                            [[Group]AdminGroupMembership] A group with the name Administrators exists.
[SERVER06]:                            [[Group]AdminGroupMembership] Resolving Administrator as a local account.
[SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantLocalUser01 as a local account.
[SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantLocalUser02 as a local account.
[SERVER06]:                            [[Group]AdminGroupMembership] Resolving Member01 as a local account.
[SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantLocalUser03 as a local account.
[SERVER06]:                            [[Group]AdminGroupMembership] Resolving Domain Admins in the domain CONTOSO.
[SERVER06]: LCM:  [ End    Test     ]  [[Group]AdminGroupMembership]  in 46.4910 seconds.
PowerShell DSC resource MSFT_GroupResource  failed to execute Test-TargetResource functionality with error message: Exception calling ".ctor" with "2" argument(s): "The server could not be contacted." 
+ CategoryInfo          : InvalidOperation: (:) [], CimException
+ FullyQualifiedErrorId : ProviderOperationExecutionFailure
+ PSComputerName        : localhost
johlju commented 6 years ago

@aydeisen okay, so it seems that Test-TargetResource functin fails, because it seems it never start the Set-TargetResource, it ends with [ End Test ] and then the error is reported.

Questions when looking at trying to reproduce this behavior.

  1. What version of PSDscResources are you using?
  2. 'Member01' in your configuration above, is it a local account or a domain account?
  3. Is the server able to connect to the domain controller? Thought if this was member server but then is disconnected by a firewall for instance. I know the point is shouldn't need to connect, just looking for the scenario where this fails.
johlju commented 6 years ago

Tried to reproduced using

With those parameters I cannot reproduce the behavior.

Configuration

$newObjectParameters = @{
    TypeName = 'System.Management.Automation.PSCredential'
    ArgumentList = @(
        'Dummy',
        (ConvertTo-SecureString 'Password/2/(&(/' -AsPlainText -Force)
    )
}
$localDummyCredential = New-Object @newObjectParameters

User 'CreateLocalAccountDummy'
{
    Ensure   = 'Present'
    UserName = $localDummyCredential.UserName
    Password = $localDummyCredential
}

Group 'AddLocalAccountToLocalAdministratorsGroup'
{
    Ensure           = 'Present'
    GroupName        = 'Administrators'
    MembersToInclude = @($localDummyCredential.UserName)
}

Result:

VERBOSE: [SQLTEST]: LCM:  [ Start  Resource ]  [[User]CreateLocalAccountDummy]
VERBOSE: [SQLTEST]: LCM:  [ Start  Test     ]  [[User]CreateLocalAccountDummy]
VERBOSE: [SQLTEST]:                            [[User]CreateLocalAccountDummy] A user with the name Dummy does not exist.
VERBOSE: [SQLTEST]: LCM:  [ End    Test     ]  [[User]CreateLocalAccountDummy]  in 5.8920 seconds.
VERBOSE: [SQLTEST]: LCM:  [ Start  Set      ]  [[User]CreateLocalAccountDummy]
VERBOSE: [SQLTEST]:                            [[User]CreateLocalAccountDummy] Configuration of user Dummy started.
VERBOSE: [SQLTEST]:                            [[User]CreateLocalAccountDummy] User: Dummy
VERBOSE: [SQLTEST]:                            [[User]CreateLocalAccountDummy] User Dummy created successfully.
VERBOSE: [SQLTEST]:                            [[User]CreateLocalAccountDummy] Configuration of user Dummy completed successfully.
VERBOSE: [SQLTEST]: LCM:  [ End    Set      ]  [[User]CreateLocalAccountDummy]  in 3.2190 seconds.
VERBOSE: [SQLTEST]: LCM:  [ End    Resource ]  [[User]CreateLocalAccountDummy]
VERBOSE: [SQLTEST]: LCM:  [ Start  Resource ]  [[Group]AddLocalAccountToLocalAdministratorsGroup]
VERBOSE: [SQLTEST]: LCM:  [ Start  Test     ]  [[Group]AddLocalAccountToLocalAdministratorsGroup]
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Invoking the function Test-TargetResourceOnFullSKU for the group Administrators.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] A group with the name Administrators exists.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Resolving Administrator as a local account.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Resolving Domain Admins in the domain COMPANY.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Resolving Dummy as a local account.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] MembersToExclude is empty. No group member removals are needed.
VERBOSE: [SQLTEST]: LCM:  [ End    Test     ]  [[Group]AddLocalAccountToLocalAdministratorsGroup]  in 3.5160 seconds.
VERBOSE: [SQLTEST]: LCM:  [ Start  Set      ]  [[Group]AddLocalAccountToLocalAdministratorsGroup]
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Begin executing Set functionality on the group Administrators.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Performing the operation "Set" on target "Group: Administrators".
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Resolving Administrator as a local account.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Resolving Domain Admins in the domain COMPANY.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Resolving Dummy as a local account.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] MembersToExclude is empty. No group member removals are needed.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] Group Administrators properties updated successfully.
VERBOSE: [SQLTEST]:                            [[Group]AddLocalAccountToLocalAdministratorsGroup] End executing Set functionality on the group Administrators.
VERBOSE: [SQLTEST]: LCM:  [ End    Set      ]  [[Group]AddLocalAccountToLocalAdministratorsGroup]  in 2.9580 seconds.
VERBOSE: [SQLTEST]: LCM:  [ End    Resource ]  [[Group]AddLocalAccountToLocalAdministratorsGroup]
aydeisen commented 6 years ago

@johlju

What version of PSDscResources are you using?

2.8.0.0

'Member01' in your configuration above, is it a local account or a domain account?

Local Account

Is the server able to connect to the domain controller? Thought if this was member server but then is disconnected by a firewall for instance. I know the point is shouldn't need to connect, just looking for the scenario where this fails.

The server itself is a domain member server, and is able to communicate with a domain controller.

johlju commented 6 years ago

@aydeisen Is there any difference in your environment from what I used trying to reproduce this? See bullet list in my previous comment. Do you see anything else in your environment that could possibly make this behavior happen? Could you try the above code in a lab/test environment and see if that gives the same behavior?

I see the following verbose output of the Test-TargetResource function in my verbose output, but not yours.

MembersToExclude is empty. No group member removals are needed.

Would it be possible for you to add more verbose output in the code to see which row it is actually failing on?

aydeisen commented 6 years ago

@johlju There's nothing I can think of in the environment that would cause any difference. I have nine different servers with pretty vanilla builds running a mix of 2008 R2 SP1 and 2012 R2, and they're all displaying this error.

I'm not sure how I can get any more verbose without wrapping Trace-Command around it. That output came directly from executing Start-DscConfiguration -Wait -Verbose. What I put in my previous update is the entirety of the output for that DSC Resource. I assume my output doesn't have it because your output proceeds past the Domain Admins member, and mine fails at that point.

johlju commented 6 years ago

Since this is only reproducible in your environment, you need to debug this to find the actual row that is failing. Maybe then it's possible to determine why it is happening.

On line 1241 the MembersToExclude is empty message is written out, so something happens before then.

You can debug resource by using Enable-DscDebug, see Debugging DSC resources.

Another way to debug this is to copy the psm1 file to a ps1 file, open the ps1 file in ISE for example and manually call `Test-TargetResource' with the correct paramaters and debug each step.

Or before line 1241 and after the else-if statment, add Write-Verbose -Message 'Debug1', and so on, after each row that is called. If there is a helper function that throws, then continue the process in that helper function, and so on.

aydeisen commented 6 years ago

@johlju An error is being thrown from the Remove-DisposableObject function in the Group resource. Error is Cannot convert value to type System.String. The value it's attempting to convert appears to be an empty string. The HResult is -2146233087 (0x80131501) This is the full debug for the Domain Admins group:

DEBUG: 1677+     foreach ( >>>$groupDirectoryMember in $groupDirectoryMembers)
DEBUG:     ! SET $groupDirectoryMember = 'System.__ComObject'.
DEBUG: 1680+          >>>$memberDirectoryEntry = New-Object -TypeName 'System.DirectoryServices.DirectoryEntry' `
DEBUG:     ! SET $memberDirectoryEntry = 'System.DirectoryServices.DirectoryEntry'.
DEBUG: 1682+          >>>$null = $disposables.Add($memberDirectoryEntry)
DEBUG: 1684+          >>>$memberDirectoryEntryPathParts = $memberDirectoryEntry.Path.Split('/')
DEBUG:     ! SET $memberDirectoryEntryPathParts = 'WinNT:  CONTOSO Domain Admins'.
DEBUG: 1686+         if ( >>>$memberDirectoryEntryPathParts.Count -eq 4)
DEBUG: 1689+              >>>$scope = $memberDirectoryEntryPathParts[2]
DEBUG:     ! SET $scope = 'CONTOSO'.
DEBUG: 1690+              >>>$accountName = $memberDirectoryEntryPathParts[3]
DEBUG:     ! SET $accountName = 'Domain Admins'.
DEBUG: 1711+          >>>$principalContext = Get-PrincipalContext `
DEBUG: 2054+  >>>{
DEBUG:     ! CALL function 'Get-PrincipalContext'  (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2081+      >>>$principalContext = $null
DEBUG:     ! SET $principalContext = ''.
DEBUG: 2083+     if ( >>>Test-IsLocalMachine -Scope $Scope)
DEBUG: 2083+     if ( >>>Test-IsLocalMachine -Scope $Scope)
DEBUG: 2149+  >>>{
DEBUG:     ! CALL function 'Test-IsLocalMachine'  (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2160+      >>>$localMachineScopes = @( '.', $env:computerName, 'localhost', '127.0.0.1', 'NT Authority', 'NT Service', 'BuiltIn' )
DEBUG:     ! SET $localMachineScopes = '. SERVER06 localhost 127.0.0.1 NT Autho...'.
DEBUG: 2162+     if ( >>>$localMachineScopes -icontains $Scope)
DEBUG: 2171+     if ( >>>$Scope.Contains('.'))
DEBUG: 2189+     return  >>>$false
DEBUG: 2190+  >>>}
DEBUG: 2101+     elseif ( >>>$PrincipalContextCache.ContainsKey($Scope))
DEBUG: 2105+     elseif ( >>>$null -ne $Credential)
DEBUG: 2130+          >>>$principalContext = New-Object -TypeName 'System.DirectoryServices.AccountManagement.PrincipalContext' `
DEBUG:     ! SET $principalContext = 'System.DirectoryServices.AccountManagement.P...'.
DEBUG: 2134+          >>>$null = $PrincipalContextCache.Add($Scope, $principalContext)
DEBUG: 2135+          >>>$null = $Disposables.Add($principalContext)
DEBUG: 2138+     return  >>>$principalContext
DEBUG: 2139+  >>>}
DEBUG:     ! SET $principalContext = 'System.DirectoryServices.AccountManagement.P...'.
DEBUG: 1718+         if ( >>>Test-IsLocalMachine -Scope $scope)
DEBUG: 1718+         if ( >>>Test-IsLocalMachine -Scope $scope)
DEBUG: 2149+  >>>{
DEBUG:     ! CALL function 'Test-IsLocalMachine'  (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2160+      >>>$localMachineScopes = @( '.', $env:computerName, 'localhost', '127.0.0.1', 'NT Authority', 'NT Service', 'BuiltIn' )
DEBUG:     ! SET $localMachineScopes = '. SERVER06 localhost 127.0.0.1 NT Autho...'.
DEBUG: 2162+     if ( >>>$localMachineScopes -icontains $Scope)
DEBUG: 2171+     if ( >>>$Scope.Contains('.'))
DEBUG: 2189+     return  >>>$false
DEBUG: 2190+  >>>}
DEBUG: 1723+         elseif ( >>>$null -ne $principalContext)
DEBUG: 1725+              >>>Write-Verbose -Message ($script:localizedData.ResolvingDomainAccount -f $accountName, $scope)
DEBUG: 1739+          >>>$memberSidBytes = $memberDirectoryEntry.Properties['ObjectSid'].Value
DEBUG:     ! SET $memberSidBytes = '1 5 0 0 0 0 0 5 21 0 0 0 221 41 76 245 89 223 ...'.
DEBUG: 1740+          >>>$memberSid = New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' `
DEBUG:     ! SET $memberSid = 'S-1-5-21-4115409373-4274446169-823295157-512'.
DEBUG: 1743+          >>>$principal = Resolve-SidToPrincipal -PrincipalContext $principalContext -Sid $memberSid -Scope $scope
DEBUG: 1995+  >>>{
DEBUG:     ! CALL function 'Resolve-SidToPrincipal'  (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2015+      >>>$principal = Find-Principal -PrincipalContext $PrincipalContext -IdentityValue $Sid.Value -IdentityType ([System.DirectoryServices.AccountManagement.IdentityType]::Sid)
DEBUG: 2319+  >>>{
DEBUG:     ! CALL function 'Find-Principal'  (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2336+     if ( >>>$PSBoundParameters.ContainsKey('IdentityType'))
DEBUG: 2338+         return  >>>[System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($PrincipalContext, $IdentityType, $IdentityValue)
DEBUG:     ! SET $foreach = ''.
DEBUG: 1284+          >>>Remove-DisposableObject -Disposables $disposables
DEBUG: 2554+  >>>{
DEBUG:     ! CALL function 'Remove-DisposableObject'  (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2565+     foreach ($disposable in  >>>$Disposables)
DEBUG:     ! SET $foreach = 'IEnumerator'.
DEBUG: 2565+     foreach ( >>>$disposable in $Disposables)
DEBUG:     ! SET $disposable = 'System.DirectoryServices.AccountManagement.Princip...'.
DEBUG: 2567+         if ( >>>$disposable -is [System.IDisposable])
DEBUG: 2569+              >>>$disposable.Dispose()
DEBUG: 2565+     foreach ( >>>$disposable in $Disposables)
DEBUG:     ! SET $foreach = ''.
Remove-DisposableObject : Cannot convert value to type System.String.
At C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1:1284 char:9
\+         Remove-DisposableObject -Disposables $disposables
\+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    \+ CategoryInfo          : InvalidArgument: (:) [Remove-DisposableObject], RuntimeException
    \+ FullyQualifiedErrorId : InvalidCastFromAnyTypeToString,Remove-DisposableObject

This is the Stack Trace from the error:

   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
   at System.Management.Automation.DlrScriptCommandProcessor.RunClause(Action`1 clause, Object dollarUnderbar, Object inputToProcess)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()

This is the Script Stack Trace from the error:

at Remove-DisposableObject, C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1: line 2565
at Test-TargetResourceOnFullSKU, C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1: line 1284
at Test-TargetResource, C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1: line 321
at <ScriptBlock>, <No file>: line 7
johlju commented 6 years ago

Sorry that I haven't had time to answer you for so long 😞 Thanks for the detailed debugging steps!

DEBUG: ! CALL function 'Remove-DisposableObject' (defined in file 'C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1')
DEBUG: 2565+ foreach ($disposable in >>>> $Disposables)

DEBUG: ! SET $foreach = 'IEnumerator'.
DEBUG: 2565+ foreach ( >>>> $disposable in $Disposables)

DEBUG: ! SET $disposable = 'System.DirectoryServices.AccountManagement.Princip...'.
DEBUG: 2567+ if ( >>>> $disposable -is [System.IDisposable])

DEBUG: 2569+ >>>> $disposable.Dispose()

DEBUG: 2565+ foreach ( >>>> $disposable in $Disposables)

DEBUG: ! SET $foreach = ''.
Remove-DisposableObject : Cannot convert value to type System.String.
At C:\Program Files\WindowsPowerShell\Modules\PSDscResources\2.8.0.0\DscResources\MSFT_GroupResource\MSFT_GroupResource.ps1:1284 char:9
+ Remove-DisposableObject -Disposables $disposables

It looks like the first value of $Disposables returned

SET $disposable = 'System.DirectoryServices.AccountManagement.Princip...'

But the second value returned an empty string instead of a $null value. 🤔

SET $foreach = ''.

Debug actions:

  1. Could write verbose output in the Remove-DisposableObject helper function. It would be interesting how many objects $Disposables contains $Disposables.Count , and also for each object, what type it is, i.e. $Disposables[0].GetType() .

  2. It would also be interesting for every time the $disposables is used after the array is initialized to find out where the empty string is added. https://github.com/PowerShell/PSDscResources/blob/9f5e9e48eda63b5ff0ab5ad179173b754863c49e/DscResources/MSFT_GroupResource/MSFT_GroupResource.psm1#L1118

aydeisen commented 6 years ago

@johlju: the server I was using for output isn't finding any domain controllers at the moment, so I need some time to troubleshoot and resolve that. The output (below) was run under the local admin account, and might, at the very least, answer the 'type' question.

It looks like there are four types being stored in $Disposables: From System.DirectoryServices.AccountManagement: PrincipalContext, GroupPrincipal, and UserPrincipal The fourth is 'adsi', which I assume means that both the .NET representation and the underlying ADSI object is being stored in the $Disposables variable.

It also looks like Remove-DisposableObject is processing all objects in one shot at the end.

VERBOSE: [SERVER06]: LCM:  [ Start  Resource ]  [[Group]AdminGroupMembership]
VERBOSE: [SERVER06]: LCM:  [ Start  Test     ]  [[Group]AdminGroupMembership]
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Invoking the function Test-TargetResourceOnFullSKU for the group Administrators.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] A group with the name Administrators exists.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving Administrator as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantUserAccount01 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantUserAccount02 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving Member01 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantAccount03 as a local account.
WARNING: [SERVER06]:                            [[Group]AdminGroupMembership] The group member WinNT://S-1-5-21-4115409373-4274446169-823295157-512 does not exist or cannot be resolved.
WARNING: [SERVER06]:                            [[Group]AdminGroupMembership] The group member WinNT://S-1-5-21-1004336348-1085031214-725345543-512 does not exist or cannot be resolved.
WARNING: [SERVER06]:                            [[Group]AdminGroupMembership] The group member WinNT://S-1-5-21-1004336348-1085031214-725345543-5129 does not exist or cannot be resolved.
WARNING: [SERVER06]:                            [[Group]AdminGroupMembership] The group member WinNT://S-1-5-21-1004336348-1085031214-725345543-13277 does not exist or cannot be resolved.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving ipautomckessonprod as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] MembersToExclude is empty. No group member removals are needed.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Disposable Count: 16
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.PrincipalContext
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.GroupPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] adsi
VERBOSE: [SERVER06]: LCM:  [ End    Test     ]  [[Group]AdminGroupMembership]  in 2.4270 seconds.
VERBOSE: [SERVER06]: LCM:  [ Skip   Set      ]  [[Group]AdminGroupMembership]
VERBOSE: [SERVER06]: LCM:  [ End    Resource ]  [[Group]AdminGroupMembership]
johlju commented 6 years ago

@aydeisen No worries, great if you can get it to reproduce the problem again. Would be interesting what the type is on the item that fails, and what the value is that it can't convert to string.

aydeisen commented 6 years ago

@johlju : thanks for your patience. I have a new output after correcting the server's connectivity to AD.

I forgot to reference the function to show the changes in my last posting. I've also augmented it to show the name of the disposable with the type. This is the Remove-DisposableObject function with the additional Write-Verbose parameters:

<#
    .SYNOPSIS
        Disposes of the contents of an array list containing IDisposable objects.

    .PARAMETER Disosables
        The array list of IDisposable Objects to dispose of.
#>
function Remove-DisposableObject
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNull()]
        [System.Collections.ArrayList]
        [AllowEmptyCollection()]
        $Disposables
    )
    Write-Verbose -Message "`$Disposables Count: $($Disposables.Count)"
    foreach ($disposable in $Disposables)
    {
        Write-Verbose -Message "Name: $($Disposable.Name)   Type: $($Disposable.GetType())"
        if ($disposable -is [System.IDisposable])
        {
            $disposable.Dispose()
        }
    }
}

...And this is the Verbose output:

VERBOSE: [SERVER06]: LCM:  [ Start  Resource ]  [[Group]AdminGroupMembership]
VERBOSE: [SERVER06]: LCM:  [ Start  Test     ]  [[Group]AdminGroupMembership]
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Invoking the function Test-TargetResourceOnFullSKU for the group Administrators.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] A group with the name Administrators exists.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving Administrator as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantUserAccount01 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantUserAccount02 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving Member01 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving IrrelevantUserAccount03 as a local account.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Resolving Domain Admins in the domain CONTOSO.
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] $Disposables Count: 16
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.PrincipalContext
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.GroupPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: Administrator   Type: adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: IrrelevantUserAccount01   Type: adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: IrrelevantUserAccount02   Type: adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: Member01   Type: adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: IrrelevantUserAccount03   Type: adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.UserPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: Domain Admins   Type: adsi
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name: CONTOSO   Type: System.DirectoryServices.AccountManagement.PrincipalContext
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: System.DirectoryServices.AccountManagement.GroupPrincipal
VERBOSE: [SERVER06]:                            [[Group]AdminGroupMembership] Name:    Type: adsi
VERBOSE: [SERVER06]: LCM:  [ End    Test     ]  [[Group]AdminGroupMembership]  in 64.7820 seconds.

I'm counting nine times when the principal name comes up empty: eight times for an object type in the System.DirectoryServices.AccountManagement namespace, and one time for an object of the adsi type. It appears the only disposable in the System.DirectoryServices.AccountManagement namespace to return in the domain as the principal context.

Probably unrelated to my issue, but I'm a little confused as to why the ADSI object is needed at all. I see it's coming from the Get-GroupMembersFromDirectoryEntry function in the module when the GetUnderlyingObject() method is called on the group in order to retrieve its members. However, the .NET Group Principal object already has a Members property. So why the unnecessary overhead?

That function is below for reference:

<#
    .SYNOPSIS
        Retrieves the members of a group from the underlying directory entry.

    .PARAMETER Group
        The group to retrieve the members of.
#>
function Get-GroupMembersFromDirectoryEntry
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNull()]
        [System.DirectoryServices.AccountManagement.GroupPrincipal]
        $Group
    )

    $groupDirectoryEntry = $Group.GetUnderlyingObject()
    return $groupDirectoryEntry.Invoke('Members')
}
johlju commented 6 years ago

@aydeisen I'm not seeing the error being thrown, doesn't it throw anymore?

I can see two potential reasons for using GetUnderlyingObject, first the restrictions mentioned in the Remarks section, and second, but not certain at all about this, might be that it is not cached data?

johlju commented 6 years ago

@aydeisen My bad, it throws directly after that, you just skipped that when pasting in the verbose output.

It seem it throws when there is an 'adsi' object with an empty name? Now it would be interesting to find out where it adds that item, and what that item actually is. Could it be here it adds the value (per the function you referenced).

https://github.com/PowerShell/PSDscResources/blob/9f5e9e48eda63b5ff0ab5ad179173b754863c49e/DscResources/MSFT_GroupResource/MSFT_GroupResource.psm1#L1675-L1682

A thought, grasping as straws, what if there could be an issue that Members doesn't contain all the information? 🤔 Maybe RefreshCache() is needed for the Members property, see StackOverflow article UserPrincipal GetUnderlyingObject: properties missing.

aydeisen commented 6 years ago

@johjlu: regarding the members property of the. NET object: Wouldn't using the GetMembers() method bypass the issue with the property?

johlju commented 6 years ago

@aydeisen I saw that method too. GetMembers() returns a different type PrincipalSearchResult Class, a collection of Principal Class. Maybe that could be used. But right now it is not certain that GetUnderlyingObject() is the problem?

I'm curios what member it returns from the group that yields an empty name. If there are something special about that member?

aydeisen commented 6 years ago

@johlju: sorry...I got sidetracked seeing double the number of disposables, and what appeared to be redundant objects.

I'll put a verbose statement into the function to see if I can get it to return the group that the members are being enumerated from.

Also (and I should have thought of this before), I'm going to modify the previous verbose outputs to include the SID. If the null values are coming from domain objects, then DSC wouldn't be able to read the "human readable" attributes like the name, which is what I was returning previously.

johlju commented 6 years ago

No worries, all suggestions are good 🙂 Sounds good adding the additional verbose output.

aydeisen commented 6 years ago

@johlju: I've been able to account for the null outputs for the Name property; I'm just having a little difficulty in correcting for it in the Verbose outputs.

The objects of type System.DirectoryServices.AccountManagement that are coming up with an empty are the local accounts that are members (dubbed both 'IrrelevantUserAccount0# and Member01 in previous outputs). The accounts have their sAMAccountName populated, but not the 'Name' property.

The Null output for the object of type System.DirectoryServices.AccountManagement.PrincipalContext is the local machine. The constructor being used in the Get-PrincipalContext function to get the local machine context is the one that only specifies the ContextType. Since Name isn't specified, it can't be returned.

That leaves the two objects of type System.DirectoryServices.AccountManagement.GroupPrincipal: the Administrators group and the Domain Admins group. However, I have no idea why neither are returning a property in the Name field. The Administrators group is the built-in local group, so I would assume it would have all of its properties. I expected the Domain Admins group to not return its name due to access, but its ADSI counterpart returned the name just fine. So, I have no explanation for why the Name property appears null for those two.

I'm attempting to return the sAMAccountName instead, but that was also coming up empty.

aydeisen commented 6 years ago

I've been able to replicate the issue outside the context of DSC. It looks like the machine being managed by DSC is on a slow connection with no local DC, and the connection is unstable enough that activities against the domain controller occasionally timeout.

I do think there should be a better way to go about doing this, and that there's a lot of unnecessary convolution in the Group DSC resource. However, the specific error I was getting no longer appears to be related to it.

johlju commented 6 years ago

@aydeisen If you can replicate this outside of DSC, can you find a better way of doing what the resource is doing, while keeping the intended behavior, and still handle a slow response from a domain controller? If so we could might incorporate a better method for doing this.

aydeisen commented 6 years ago

@johlju: my first thought would be to use the IsMemberOf() Method of the UserPrincipal class for the IncludeMembers and ExcludeMembers when the Group Member is identified as a local account. The method returns True/False, and act accordingly. (i.e: for IncludeMembers, the expected result is 'True' and the member should be added if the result is False; for ExcludeMembers, the expected result is 'False', and the member should be removed if the result is True

Based on the note on line 41 of the module, the ADSI object is only required due to limitations in enumerating domain members accounts. The account is already identified whether it's local or domain in the Get-MembersAsPrincipalsList function on line 1636, and the GroupPrincipal and UserPrincipal objects required for that method already exist as part of the module. So, all the components needed to use the IsMemberOf() method of the UserPrincipal already exist in the module.

The biggest problem I can see is scalability, as this method would need to be executed on each member listed. In my case, where I'm only trying to confirm a single user as a member of a group, this would work great because I only need it to run once. If we're talking about arrays of multiple members, this may be time-consuming. It would also depend on whether the savings of both not contacting the domain controller and not getting the underlying ADSI object are enough offset the additional processing of each member. This may be a non-issue if this logic can be executed concurrently on each member instead of consecutively.

aydeisen commented 6 years ago

Well, I yield on the ADSI part. The only way to add a member to a .NET Group Principal object is to call $GroupPrincipal.Members.Add(), which causes .NET to try to populate all the Group Members, and generate the connectivity error.

It does appear to be possible to add a member to a group without iterating through all the group members, using the below script as an example.

Add-Type -AssemblyName System.DirectoryServices.AccountManagement

$LocalCtx = [System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Machine)
$GroupPrincipal = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($ctx, $GroupName)
$ADSIGroup = $GroupPrincipal.GetUnderlyingObject()

ForEach ($Member in $MembersToInclude)
{
    if ($Member -match '^\w+$')
    {
        $SearchCtx = $LocalCtx
    }
    elseif ($Member -match '\w+@\w+|\w+\\\w+|CN=\w+(?=.*DC=\w+)')
    {
        $SearchCtx = [System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Domain)
    }
    else
    {
        Write-Error -Message 'Invalid Format for User Name'
    }

    $MemberPrincipal = [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($SearchCtx, $Member)

    if ($MemberPrincipal.IsMemberOf($GroupPrincipal) -eq $True)
    {
        Write-Verbose -Message "$($Member.SamAccountName) already in $($GroupPrincipal.Name)"
    }
    else
    {
        $ADSIGroup.Add($MemberPrincipal.GetUnderlyingObject().Path)
    }
}
johlju commented 6 years ago

@aydeisen what I understood was the connectivity problem you were having was in the Test-TargetResource? Test-TargetResource does not add any members. Do you have connectivity problems in the Set-TargetResource function as well? If we are discussing a new method of adding members to a group that is not related to this issue, then I suggest we move that discussion to a new issue. If this is related to this issue then let's continue the discussion here.

Have you incorporated that change above in the resource locally and the resource work as expected with the changes (no connectivity issues in the Test-TargetResurce function?)

aydeisen commented 6 years ago

@johlju: you're right; I was looking ahead of the problem in this issue again.

I'm honestly having a hard time reading this DSC Resource due to the number of functions and references to functions that are in here. Additionally, I can't figure out from the script how the Principal Context Cache works, outside of the conceptual description provided in the help at the top, so I'm not confident in my own ability to modify this particular DSC Resource for testing.

I believe the error reflected in the Group DSC Resource due to the DC communications issue is a result of getting all the members of the group, as doing so on a group with a mix of domain and local members (ex: the Administrators group, in my case) requires fetching the AD attributes of the domain members of the group (in my case, the Domain Admins group). Removing that need may solve the problem, but it may not be scalable.

So, if I'm understanding conceptually what the Test-TargetResource (FullSKU) part is doing, I'm suggesting the following:

  1. Only execute Get-MembersAsPrincipalsList at line 1127 when $PSBoundParameters.ContainsKey('Members') -eq $True
  2. In the elseif ($PSBoundParameters.ContainsKey('MembersToInclude') -or $PSBoundParameters.ContainsKey('MembersToExclude')) at line 1209, loop through each object contained in $MembersToInclude and $MembersToExclude with Find-Principal (Function at line 2318)
  3. Use the resulting Principal object to determine whether it's a member of the group or not using the IsMemberOf() method. ex:
    
    $MembersToAdd = @()
    foreach ($Member in $MembersToInclude)
    {
    $principal = Find-Principal -PrincipalContext $principalContext -IdentityValue $Member
    $MembersToAdd += $principal.IsMemberOf($group) -eq $False <#returns [System.Boolean]#>
    }

$MembersToRemove = @() foreach ($Member in $MembersToExclude) { $principal = Find-Principal -PrincipalContext $principalContext -IdentityValue $Member $MembersToRemove += $principal.IsMemberOf($group) -eq $False <#returns [System.Boolean]#> }

if ($MembersToRemove.Count -gt 0 -or $MembersToAdd.Count -gt 0) { return $false }


Since doing the above no longer requires retrieving all members of the group, it's not contacting the domain controller.  However, since each account defined in the DSC is now being processed indivually, it may increase processing time to an unacceptable level for larger arrays defined in the DSC.
johlju commented 6 years ago

Currently I am having problem deciding if this issue is an enhancement, bug, or by design. Having a stable connection to a domain controller is currently vital to this resource to be able to evaluate group membership and to be able to add domain members. So for the main issue I lean toward by design.

Also having a problem deciding if the code change you are proposing is an enhancement or is an enhancement with breaking change. 🙂 Breaking changes is not allowed in this resource module. xPSDesiredStateConfiguration allows breaking changes, which means if this is considered a breaking change you have to move this proposal to xPSDesiredStateConfiguration.

Thanks for the detailed run down in the previous comments! If I may make a summary of your proposal in your last comments. You are proposing changing the Group resource in a way that make less calls to the domain controller, both when evaluating existing members and adding members, when using MembersToIncludeand MembersToExclude, thus mitigate problems with a slow-connection to a domain controller.

I'm I correct with that summary?

If your proposal is seen as an enhancement that do not break any existing functionality, to consider this then we need to be able to make a test for this, so we need a way to reproduce this problem. Do you have a way to reproduce this problem you are having in an lab environment? I think it would also help decided if there are any breaking changes in you proposal.

aydeisen commented 6 years ago

@johlju: I can reproduce the problem for testing. No issues there.

The summary of the solution I proposed is also correct.

Out of curiosity: This project hasn't had a new release in 10 months. When are breaking changes allowed to it, and when is the next planned release?

Also, one of the chief distinctions between PSDscResource and xPSDesiredStateConfiguration was that PsDscResources "is only available for WMF 5.1" and xPSDesiredStateConfiguration " is a more recent, experimental version of the PSDesiredStateConfiguration module that ships in Windows as part of PowerShell 4.0." (i.e.: backwards compatible with WMF 4.0 and 5.0). Are these descriptions no longer correct?

johlju commented 6 years ago

Could you list the steps needed to reproduce the problem in any lab environment?

PSDscResources has new versions of the resources in the built-in PSDesiredStateConfiguration, and if installed overrides the built-in resources (except those resources that still only exist as built-in). PSDscResources is supported only on WMF 5.1. PSDscResources are direct replacement of the built-in resource thus not allowing breaking changes. New release of PSDscResources will happen if there are bug fixes or if an non-breaking enhancements is approved.

The resources in xPSDesiredStateConfiguration work side by side with PSDscResources and built-in resources. xPSDesiredStateConfiguration contains more resource that PSDscResources, and also supports WMF 5.0 and WMF 4. xPSDesiredStateConfiguration allows breaking changes, meaning this resource module can have improved functionality that does not or will not exist in PSDscResources. The resources in xPSDesiredStateConfiguration will for now stay with the prefix 'x' because otherwise they would conflict with PSDscResources if both resource modules would be installed at the same time.

Since the new naming guidelines I personally don't like to use the term 'experimental' any longer. Many resources have just not been renamed yet.

aydeisen commented 6 years ago

@johlju: thanks for the clarification.

The offending servers in my environment are connecting to their domain controller using an OpenVPN connection. I imagine creating a domain-joined VM and just configuring the Windows Firewall to block communications to the domain controller would be just as effective a test.

johlju commented 6 years ago

@aydeisen Thanks for that information! I leave this open as an enhancement and help wanted for the time being.

robbygumbers commented 5 years ago

I have managed to get the same issue and can replicate it / fix it.

My environment is a forest with one way trust. We have our main domain and then our development domain which has a one way trust to allow us to log in with our main domain credentials onto the dev environments.

On the dev domain we add domain suffixes for both domains and after adding both suffixes the group IncludeMembers will fail when trying to add groups and users belonging to our main production domain. Removing the domain suffixes from the network adapter the means it will work.

elRadish commented 3 years ago

Hello,

I just stumbled across this issue and experienced the same problem in a pretty simple setup:

I'm learning PowerShell DSC with a Vanilla Windows 10 1909 VM. No domain member, just a single machine with local users.

What I'm trying to do is creating a user and adding him to the "Users" group which fails with the same error message as shown above as long as the NT-AUTHORITY/* Users are also member of the Users group. Once I remove them, it works. It also works with all the other groups which don't contain these Domain-related accounts.

Sample code ("Benutzer" is "Users" in German)

Group AddToUsersGroup { GroupName = "Benutzer" DependsOn="[User]LocalUser" Ensure = "Present" MembersToInclude = "localuser" }

So this happens even outside any domain-related environment. Any chance to get that fixed? Workaround would be to create our own restricted group instead of using "Benutzer", but that doesn't feel very elegant.

mslattery commented 3 years ago

I too as well just stumbled across this issue, as part of an AWS Quick Start for Microsoft SQL. As part of adding a few Domain Users to the Local Administrators group the following error is returned.

PowerShell DSC resource MSFT_GroupResource failed to execute Set-TargetResource functionality with error message: Exception calling "Add" with "1" argument(s): "The network path was not found.

Did some DSC Debugging and narrowed it down to this call in MSFT_GroupResource.psm1

$Group.Members.Add($MemberAsPrincipal)

Added a try/catch/finally block and saw this is producing the exact error. In terms of AD connectivity it's all there and this node joins the domain successfully several steps before this call.

Here is the MOF part this is exciting:

instance of MSFT_GroupResource as $MSFT_GroupResource1ref { ResourceID = "[Group]Administrators"; MembersToInclude = { "naepedgov\sqlsetup", "naepedgov\sqldevsa" }; Ensure = "Present"; SourceInfo = "C:\ProgramData\Amazon\SSM\InstanceData\i-06de0b626f22cb102\document\orchestration\89f2b685-10b0-417f-8ca4-ca800cf4e1fd\downloads\Node1Config.ps1::122::9::Group"; GroupName = "Administrators"; ModuleName = "PSDscResources"; ModuleVersion = "2.12.0.0"; ConfigurationName = "WSFCNode1Config"; };

Here is the exciting verbose DSC output...

VERBOSE: [WSFCNODE1]: LCM: [ Start Set ] [[Group]Administrators] VERBOSE: [WSFCNODE1]: [[Group]Administrators] Begin executing Set functionality on the group Administrators. VERBOSE: [WSFCNODE1]: [[Group]Administrators] Performing the operation "Set" on target "Group: Administrators". VERBOSE: [WSFCNODE1]: [[Group]Administrators] Resolving Administrator as a local account. VERBOSE: [WSFCNODE1]: [[Group]Administrators] Resolving Domain Admins in the domain naepedgov. VERBOSE: [WSFCNODE1]: [[Group]Administrators] Resolving AWS Delegated Server Administrators in the domain naepedgov. VERBOSE: [WSFCNODE1]: [[Group]Administrators] Resolving naepedgov\sqlsetup with domain trust. VERBOSE: [WSFCNODE1]: [[Group]Administrators] Resolving naepedgov\sqldevsa with domain trust. VERBOSE: [WSFCNODE1]: [[Group]Administrators] MembersToExclude is empty. No group member removals are needed. VERBOSE: [WSFCNODE1]: LCM: [ End Set ] [[Group]Administrators] in 2.4250 seconds. PowerShell DSC resource MSFT_GroupResource failed to execute Set-TargetResource functionality with error message: Exception calling "Add" with "1" argument(s): "The network path was not found. "

  • CategoryInfo : InvalidOperation: (:) [], CimException
  • FullyQualifiedErrorId : ProviderOperationExecutionFailure
  • PSComputerName : localhost

VERBOSE: [WSFCNODE1]: LCM: [ End Set ] The SendConfigurationApply function did not succeed.

  • CategoryInfo : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException
  • FullyQualifiedErrorId : MI RESULT 1
  • PSComputerName : localhost

VERBOSE: Operation 'Invoke CimMethod' complete. VERBOSE: Time taken for configuration job to complete is 8.409 seconds

And Finally - A workaround that fixed it :( - but BAD!

Replaced $Group.Members.Add($MemberAsPrincipal)

With Add-LocalGroupMember -Group "Administrators" -Member "naepedgov\sqlsetup" Add-LocalGroupMember -Group "Administrators" -Member "naepedgov\sqldevsa"

Then the script worked and kept on running. :( SAD

kfsone commented 1 year ago

Just ran into this with a variant telling me that it couldn't access .ctor with 4 arguments.

The original config was

  Group UserToAdmin
  {
    GroupName        = 'Administrators'
    Ensure           = 'Present'
    MembersToInclude = @( $LocalUser.UserName )
    DependsOn        = '[User]LocalAdmin', '[User]LocalUser'
    Credential= $AdminUser
  }

Changing it to the following fixed it:

    Group UserToAdmin
    {
      GroupName        = 'Administrators'
      Ensure           = 'Present'
      MembersToInclude = @( $LocalUser.UserName, $AdminUser.UserName )
      DependsOn        = '[User]LocalAdmin', '[User]LocalUser'
      PsDscRunAsCredential = $AdminUser
    }