Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AADAdministrativeUnit: SHOWSTOPPER - Removes all Members and ScopedRoleMembers during resource update when parameter is undefined #3194

Closed
Borgquite opened this issue Apr 20, 2023 · 3 comments · Fixed by #3199 or #3229
Labels
Bug Something isn't working Entra ID

Comments

@Borgquite
Copy link
Contributor

I have just had manual AU assignments for 433 users and 721 groups wiped out on my tenant, because of this behaviour in Microsoft365DSC.

Sidenote: I've now raised a 10 bugs (a couple still to be assigned the flag) and raised a number of times that (compared to other DSC modules I've used, see below) this module appears to lack sufficient unit testing, or integration testing. This bug demonstrates that point. I have no words right now, and maybe it's my fault somehow, but right now I can't think of anything more that I could have done which would have warned me about this, except for a line-by-line review of the code. I'm angry because I've trusted a module which I know is insufficiently tested, and I'm angry because the tests which should have caught this bug (which has existed for months) appear to be just... missing in action.

Details of the scenario you tried and the problem that is occurring

  • Create an AU without specifying Members or ScopedRoleMembers parameters e.g. sample configuration below. Please note that this is a perfectly normal thing to do and means I expect Microsoft365DSC to leave those parameters alone.
  • Run Start-DscConfiguration - AU is created
  • Use the Azure AD console to assign Users, Groups and Devices to the AU
  • Run Test-DscConfiguration - no changes required - so according to the Test functionality, the Set-TargetResource should NOT modify Members or ScopedRoleMembers because they are not defined - this is the correct behaviour - and apart from doing a line-by-line review of your code, this is the only safety net to ensure I'm safe to run this on a production environment.
  • Update the Description of the AU in DSC and re-apply configuration
  • MICROSOFT365DSC GOES AHEAD AND REMOVES EACH AND EVERY SINGLE MEMBER AND SCOPEDROLEMEMBER FROM THE AFFECTED ADMINISTRATIVE UNIT (see logs)

Verbose logs showing the problem

VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' =    root/Microsoft/Windows/DesiredStateConfiguration'.                                                                                                                                   
VERBOSE: An LCM method call arrived from computer COMPUTERNAME with user sid REDACTED.                                                           
VERBOSE: [COMPUTERNAME]: LCM:  [ Start  Set      ]                                                                                                                                     
VERBOSE: [COMPUTERNAME]: LCM:  [ Start  Resource ]  [[AADAdministrativeUnit]TestUnit]                                                                                                  
VERBOSE: [COMPUTERNAME]: LCM:  [ Start  Test     ]  [[AADAdministrativeUnit]TestUnit]                                                                                                  
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Testing configuration of the Azure AD Administrative Unit with Id {Test-Unit} and DisplayName    {Test-Unit}                                                                                                                                                                          
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Could not find an Azure AD Administrative Unit with Id {Test-Unit}                               
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] An Azure AD Administrative Unit with Id {12b00630-78a7-4cea-b368-04fb96c0522e} and DisplayName   {Test-Unit} was found.                                                                                                                                                               
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} MembershipType {}                                                                 
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} get Members                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} process 3 members                                                                 
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/83719198-871f-4a16-bfc0-fa1a39150c02 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 451-byte response of content type application/json                                      
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} member found: Type 'User' identity 'REDACTED1'                        
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/013dabfa-3d1c-4a13-9829-293ea1e1a153 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 1800-byte response of content type application/json                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} member found: Type 'Device' identity 'REDACTED2'                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/020dcc5d-81e9-4f72-b78c-87adf6e50235 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 1641-byte response of content type application/json                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} member found: Type 'Group' identity 'REDACTED3'                    
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} add Members to results                                                            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} get Scoped Role Members                                                           
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} process 1 scoped role members                                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} verify RoleId {c6ee7a08-a2ae-41b2-b88c-892119633d64}                              
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Found DirectoryRole 'User Administrator' with id c6ee7a08-a2ae-41b2-b88c-892119633d64            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} verify RoleMemberInfo.Id {07a0a759-225f-46cb-8470-9718b868e398}
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/07a0a759-225f-46cb-8470-9718b868e398 with  0-byte payload
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 460-byte response of content type application/json
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} @odata.Type={#microsoft.graph.user}
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} UPN = {REDACTED4}
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} scoped role member: RoleName 'User Administrator' Type 'User' Identity 'REDACTED4'                                                                                                                                                            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} add 1 ScopedRoleMembers to results                                                
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} return results                                                                    
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Current Values: ApplicationId=***                                                                ApplicationSecret=$null                                                                                                                                                              CertificateThumbprint=FF4E1EF504EFF25A8989A71BBF3D8B29D70550BB                                                                                                                       Credential=$null                                                                                                                                                                     Description=$null                                                                                                                                                                    DisplayName=Test-Unit                                                                                                                                                                Ensure=Present                                                                                                                                                                       Id=12b00630-78a7-4cea-b368-04fb96c0522e                                                                                                                                              Managedidentity=False                                                                                                                                                                Members=({Identity=REDACTED1                                                                                                                                             Type=User},{Identity=REDACTED2                                                                                                                                            Type=Device},{Identity=REDACTED3                                                                                                                                      Type=Group})                                                                                                                                                                         ScopedRoleMembers=(System.Collections.Specialized.OrderedDictionary)                                                                                                                 TenantId=***                                                                                                                                                                         Visibility=$null                                                                                                                                                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Target Values: CertificateThumbprint=FF4E1EF504EFF25A8989A71BBF3D8B29D70550BB                    Description=Test-Unit1                                                                                                                                                               DisplayName=Test-Unit                                                                                                                                                                Ensure=Present                                                                                                                                                                       Verbose=True                                                                                                                                                                         
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Test-TargetResource returned False                                                               
VERBOSE: [COMPUTERNAME]: LCM:  [ End    Test     ]  [[AADAdministrativeUnit]TestUnit]  in 11.3540 seconds.                                                                             
VERBOSE: [COMPUTERNAME]: LCM:  [ Start  Set      ]  [[AADAdministrativeUnit]TestUnit]                                                                                                  
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Could not find an Azure AD Administrative Unit with Id {Test-Unit}                               
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] An Azure AD Administrative Unit with Id {12b00630-78a7-4cea-b368-04fb96c0522e} and DisplayName   {Test-Unit} was found.                                                                                                                                                               
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} MembershipType {}                                                                 
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} get Members                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} process 3 members                                                                 
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/83719198-871f-4a16-bfc0-fa1a39150c02 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 451-byte response of content type application/json                                      
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} member found: Type 'User' identity 'REDACTED1'                        
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/013dabfa-3d1c-4a13-9829-293ea1e1a153 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 1800-byte response of content type application/json                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} member found: Type 'Device' identity 'REDACTED2'                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/020dcc5d-81e9-4f72-b78c-87adf6e50235 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 1641-byte response of content type application/json                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} member found: Type 'Group' identity 'REDACTED3'                    
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} add Members to results                                                            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} get Scoped Role Members                                                           
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} process 1 scoped role members                                                     
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} verify RoleId {c6ee7a08-a2ae-41b2-b88c-892119633d64}                              
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Found DirectoryRole 'User Administrator' with id c6ee7a08-a2ae-41b2-b88c-892119633d64            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} verify RoleMemberInfo.Id {07a0a759-225f-46cb-8470-9718b868e398}                   
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] GET https://graph.microsoft.com/v1.0/directoryobjects/07a0a759-225f-46cb-8470-9718b868e398 with  0-byte payload                                                                                                                                                                       
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] received 460-byte response of content type application/json                                      
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} @odata.Type={#microsoft.graph.user}                                               
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} UPN = {REDACTED4}                                                   
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} scoped role member: RoleName 'User Administrator' Type 'User' Identity 'REDACTED4'                                                                                                                                                            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} add 1 ScopedRoleMembers to results                                                
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} return results                                                                    
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Updating the Azure AD Administrative Unit with Id {12b00630-78a7-4cea-b368-04fb96c0522e}         
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Administrative Unit {Test-Unit} Removing member {REDACTED1}, type {User}             
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Administrative Unit {Test-Unit} Removing member {REDACTED2}, type {Device}            
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Administrative Unit {Test-Unit} Removing member {REDACTED3}, type {Group}         
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] AU {Test-Unit} Update ScopedRoleMembers: Current members: REDACTED4                
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit]                                             Desired members:
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit]                                             # compare results : False
VERBOSE: [COMPUTERNAME]:                            [[AADAdministrativeUnit]TestUnit] Removing scoped role {User Administrator} member {REDACTED4}, type {User} from Administrative Unit {Test-Unit}
VERBOSE: [COMPUTERNAME]: LCM:  [ End    Set      ]  [[AADAdministrativeUnit]TestUnit]  in 8.7490 seconds.
VERBOSE: [COMPUTERNAME]: LCM:  [ End    Resource ]  [[AADAdministrativeUnit]TestUnit]
VERBOSE: [COMPUTERNAME]: LCM:  [ End    Set      ]
VERBOSE: [COMPUTERNAME]: LCM:  [ End    Set      ]    in  20.6490 seconds.
VERBOSE: Operation 'Invoke CimMethod' complete.
VERBOSE: Time taken for configuration job to complete is 20.899 seconds

Suggested solution to the issue

Fix the member check (I suspect MSFT_AADAdministrativeUnit.psm1 lines 558 and line 619)
Find a way to remind me which of the 20-odd OUs my 433 users and 721 groups were associated with
And please, please PLEASE implement some sort of more rigorous unit/integration tests to rule out this disaster-level bug!

The DSC configuration that is used to reproduce the issue (as detailed as possible)

$Microsoft365DSCApplicationId = Get-AutomationVariable -Name 'Microsoft365DSCApplicationId'
$Microsoft365DSCCertificateThumbprint = Get-AutomationVariable -Name 'Microsoft365DSCCertificateThumbprint'
$Microsoft365DSCOrganization = Get-AutomationVariable -Name 'Microsoft365DSCOrganization'

Configuration Example
{
    Import-DscResource -ModuleName Microsoft365DSC

    node localhost
    {
        AADAdministrativeUnit 'TestUnit'
        {
            Id                            = 'Test-Unit'
            DisplayName                   = 'Test-Unit'
            Description                   = 'Test-Unit1'
            Ensure                        = 'Present'
            ApplicationId                 = $Microsoft365DSCApplicationId
            CertificateThumbprint         = $Microsoft365DSCCertificateThumbprint
            TenantId                      = $Microsoft365DSCOrganization
        }
    }
}

$cd = @{
    AllNodes = @(
        @{
            NodeName = 'localhost'
            PSDscAllowPlainTextPassword = $true
        }
    )
}

Example -ConfigurationData $cd

The operating system the target node is running

OsName : Microsoft Windows 11 Enterprise
OsOperatingSystemSKU : EnterpriseEdition
OsArchitecture : 64-bit
WindowsVersion : 2009
WindowsBuildLabEx : 22621.1.amd64fre.ni_release.220506-1250
OsLanguage : en-GB
OsMuiLanguages : {en-GB, en-US}

Version of the DSC module that was used ('dev' if using current dev branch)

1.23.412.1

P.S. I've been working with PowerShell DSC for a year and a half now. I've found, reported and sometimes been able to fix bugs throughout that time. I've never encountered a big like this. The vast majority of modules are community led and have extensive unit and integration tests against all the different permutations of parameters, per the DSC Community Testing Guidelines. This may slow down development time - but it prevents showstopper bugs like this. Please can you make this module, actively developed and led by Microsoft, a leading example of DSC 'done well' - so that your module can be trusted not to wipe out showstopping chunks of data, like it just did for me.

@andikrueger andikrueger added Bug Something isn't working Entra ID labels Apr 20, 2023
@Borgquite
Copy link
Contributor Author

Borgquite commented Apr 20, 2023

Just for testing purposes: I expected the behaviour of Members and ScopedRoleMembers values to work the same as most DSC modules:

(Undefined) - Leave as-is
Set to $null (or alternatively @() i.e. null array) - Clear all values
Set with values - Set to the contents of the array (adding/removing entries to match)

salbeck-sit added a commit to salbeck-sit/Microsoft365DSC that referenced this issue Apr 21, 2023
@salbeck-sit
Copy link
Contributor

@Borgquite I have fixed the issue in the above PR and updated unit-test so it verifies that existing members are NOT removed when Members is not specified. Same for ScopedRoleMembers

NikCharlebois added a commit that referenced this issue Apr 21, 2023
AADAdministrativeUnit - fixes #3194
@Borgquite
Copy link
Contributor Author

@salbeck-sit I've grabbed your updated code and inserted it into my existing module while we wait for the new release, and it seems to work. appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working Entra ID
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants