From 30c848e74dfaed622e24dd4b5366b9838cac9f3f Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Mon, 10 Jun 2024 09:42:17 -0500 Subject: [PATCH 1/4] fix: Revert script to oringinal for 1.1.1 --- .../Test-AdministrativeAccountCompliance.ps1 | 144 +++++++----------- 1 file changed, 57 insertions(+), 87 deletions(-) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 1b22bdb..21ab959 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -1,113 +1,83 @@ function Test-AdministrativeAccountCompliance { [CmdletBinding()] - [OutputType([CISAuditResult])] param ( + # Aligned # Parameters can be added if needed ) begin { + #. .\source\Classes\CISAuditResult.ps1 $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') - $recnum = "1.1.1" } process { - try { - # Retrieve all necessary data outside the loops - $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } - $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment - $principalIds = $roleAssignments.PrincipalId | Select-Object -Unique + $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } + $adminRoleUsers = @() - # Fetch user details using filter - $userDetailsList = @{} - $licensesList = @{} + foreach ($role in $adminRoles) { + $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" - $userDetails = Get-MgUser -Filter "id in ('$($principalIds -join "','")')" -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue - foreach ($user in $userDetails) { - $userDetailsList[$user.Id] = $user - } + foreach ($assignment in $roleAssignments) { + $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue + if ($userDetails) { + $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue + $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } - # Fetch user licenses for each unique principal ID - foreach ($principalId in $principalIds) { - $licensesList[$principalId] = Get-MgUserLicenseDetail -UserId $principalId -ErrorAction SilentlyContinue - } - - $adminRoleUsers = @() - - foreach ($role in $adminRoles) { - foreach ($assignment in $roleAssignments | Where-Object { $_.RoleDefinitionId -eq $role.Id }) { - $userDetails = $userDetailsList[$assignment.PrincipalId] - if ($userDetails) { - $licenses = $licensesList[$assignment.PrincipalId] - $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } - - $adminRoleUsers += [PSCustomObject]@{ - UserName = $userDetails.UserPrincipalName - RoleName = $role.DisplayName - UserId = $userDetails.Id - HybridUser = $userDetails.OnPremisesSyncEnabled - Licenses = $licenseString - } + $adminRoleUsers += [PSCustomObject]@{ + UserName = $userDetails.UserPrincipalName + RoleName = $role.DisplayName + UserId = $userDetails.Id + HybridUser = $userDetails.OnPremisesSyncEnabled + Licenses = $licenseString } } } - - $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { - $first = $_.Group | Select-Object -First 1 - $roles = ($_.Group.RoleName -join ', ') - $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique - - $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } - } - - $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { - $_.HybridUser -or - -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) - } - - $failureReasons = $nonCompliantUsers | ForEach-Object { - $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } - $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } - "$($_.UserName)|$($_.Roles)|$accountType|$($missingLicenses -join ',')" - } - $failureReasons = $failureReasons -join "`n" - - $details = if ($nonCompliantUsers) { - "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" - } else { - "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" - } - - $failureReason = if ($nonCompliantUsers) { - "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" - } else { - "N/A" - } - - $result = $nonCompliantUsers.Count -eq 0 - $status = if ($result) { 'Pass' } else { 'Fail' } - - $params = @{ - Rec = $recnum - Result = $result - Status = $status - Details = $details - FailureReason = $failureReason - } - - $auditResult = Initialize-CISAuditResult @params } - catch { - Write-Error "An error occurred during the test: $_" - $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } - $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { + $first = $_.Group | Select-Object -First 1 + $roles = ($_.Group.RoleName -join ', ') + $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique - $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) - - $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } } + + $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { + $_.HybridUser -or + -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) + } + + $failureReasons = $nonCompliantUsers | ForEach-Object { + $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } + $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } + "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" + } + $failureReasons = $failureReasons -join "`n" + $details = if ($nonCompliantUsers) { + "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" + } + else { + "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" + } + + $result = $nonCompliantUsers.Count -eq 0 + $status = if ($result) { 'Pass' } else { 'Fail' } + $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } + + # Create the parameter splat + $params = @{ + Rec = "1.1.1" + Result = $result + Status = $status + Details = $details + FailureReason = $failureReason + } + + $auditResult = Initialize-CISAuditResult @params } + end { + # Output the result return $auditResult } } From 6ed99dbacf201c62feb7d38f4e5a2557acf5ead5 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Mon, 10 Jun 2024 09:56:42 -0500 Subject: [PATCH 2/4] fix: Comments steps --- .../Test-AdministrativeAccountCompliance.ps1 | 121 +++++++++++------- 1 file changed, 72 insertions(+), 49 deletions(-) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 21ab959..5cc38af 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -8,72 +8,95 @@ function Test-AdministrativeAccountCompliance { begin { #. .\source\Classes\CISAuditResult.ps1 $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $recnum = "1.1.1" } process { - $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } - $adminRoleUsers = @() + try { + # Retrieve all admin roles + $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } + $adminRoleUsers = @() - foreach ($role in $adminRoles) { - $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" + # Loop through each admin role to get role assignments and user details + foreach ($role in $adminRoles) { + $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" - foreach ($assignment in $roleAssignments) { - $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue - if ($userDetails) { - $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue - $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } + foreach ($assignment in $roleAssignments) { + # Get user details for each principal ID + $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue + if ($userDetails) { + # Get user license details + $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue + $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } - $adminRoleUsers += [PSCustomObject]@{ - UserName = $userDetails.UserPrincipalName - RoleName = $role.DisplayName - UserId = $userDetails.Id - HybridUser = $userDetails.OnPremisesSyncEnabled - Licenses = $licenseString + # Collect user information + $adminRoleUsers += [PSCustomObject]@{ + UserName = $userDetails.UserPrincipalName + RoleName = $role.DisplayName + UserId = $userDetails.Id + HybridUser = $userDetails.OnPremisesSyncEnabled + Licenses = $licenseString + } } } } - } - $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { - $first = $_.Group | Select-Object -First 1 - $roles = ($_.Group.RoleName -join ', ') - $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique + # Group admin role users by UserName and collect unique roles and licenses + $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { + $first = $_.Group | Select-Object -First 1 + $roles = ($_.Group.RoleName -join ', ') + $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique - $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } - } + $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } + } - $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { - $_.HybridUser -or - -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) - } + # Identify non-compliant users + $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { + # Condition A: The administrative account is not cloud-only (it is synced). + $_.HybridUser -or + # Condition B: The account is assigned a license associated with applications. + -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) + } - $failureReasons = $nonCompliantUsers | ForEach-Object { - $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } - $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } - "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" - } - $failureReasons = $failureReasons -join "`n" - $details = if ($nonCompliantUsers) { - "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" - } - else { - "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" - } + # Generate failure reasons + $failureReasons = $nonCompliantUsers | ForEach-Object { + $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } + $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } + "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" + } + $failureReasons = $failureReasons -join "`n" + $details = if ($nonCompliantUsers) { + "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" + } else { + "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" + } - $result = $nonCompliantUsers.Count -eq 0 - $status = if ($result) { 'Pass' } else { 'Fail' } - $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } + $result = $nonCompliantUsers.Count -eq 0 + $status = if ($result) { 'Pass' } else { 'Fail' } + $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } - # Create the parameter splat - $params = @{ - Rec = "1.1.1" - Result = $result - Status = $status - Details = $details - FailureReason = $failureReason + # Create the parameter splat + $params = @{ + Rec = $recnum + Result = $result + Status = $status + Details = $details + FailureReason = $failureReason + } + + $auditResult = Initialize-CISAuditResult @params } + catch { + Write-Error "An error occurred during the test: $_" - $auditResult = Initialize-CISAuditResult @params + # Handle the error and create a failure result + $testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum } + $description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" } + + $script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ }) + + $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure + } } end { From 032c951e021ee2e270d4dc0a6a4f58060c7f06eb Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Mon, 10 Jun 2024 11:55:19 -0500 Subject: [PATCH 3/4] fix: working but needs tuning --- .../Test-AdministrativeAccountCompliance.ps1 | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 5cc38af..4694d37 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -6,7 +6,11 @@ function Test-AdministrativeAccountCompliance { ) begin { - #. .\source\Classes\CISAuditResult.ps1 + # The following conditions are checked: + # Condition A: The administrative account is cloud-only (not synced). + # Condition B: The account is assigned only valid licenses (e.g., Microsoft Entra ID P1 or P2). + # Condition C: The administrative account does not have application assignments (only valid licenses are allowed). + $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') $recnum = "1.1.1" } @@ -29,13 +33,23 @@ function Test-AdministrativeAccountCompliance { $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } + # Condition A: Check if the account is cloud-only + $cloudOnlyStatus = if ($userDetails.OnPremisesSyncEnabled) { "Fail" } else { "Pass" } + + # Condition B and C: Check if the account has only valid licenses + $hasOnlyValidLicenses = ($licenses.SkuPartNumber | ForEach-Object { $validLicenses -contains $_ }) -and (($licenses.SkuPartNumber | ForEach-Object { $validLicenses -notcontains $_ }).Count -eq 0) + $validLicensesStatus = if ($hasOnlyValidLicenses) { "Pass" } else { "Fail" } + # Collect user information $adminRoleUsers += [PSCustomObject]@{ - UserName = $userDetails.UserPrincipalName - RoleName = $role.DisplayName - UserId = $userDetails.Id - HybridUser = $userDetails.OnPremisesSyncEnabled - Licenses = $licenseString + UserName = $userDetails.UserPrincipalName + RoleName = $role.DisplayName + UserId = $userDetails.Id + HybridUser = $userDetails.OnPremisesSyncEnabled + Licenses = $licenseString + CloudOnlyStatus = $cloudOnlyStatus + ValidLicensesStatus = $validLicensesStatus + ApplicationAssignmentStatus = $validLicensesStatus # Using the same status as ValidLicensesStatus for now } } } @@ -47,33 +61,29 @@ function Test-AdministrativeAccountCompliance { $roles = ($_.Group.RoleName -join ', ') $licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique - $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } } + $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } }, CloudOnlyStatus, ValidLicensesStatus, ApplicationAssignmentStatus } - # Identify non-compliant users + # Identify non-compliant users based on conditions A and B $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { - # Condition A: The administrative account is not cloud-only (it is synced). - $_.HybridUser -or - # Condition B: The account is assigned a license associated with applications. - -not ($_.Licenses -split '\|' | Where-Object { $validLicenses -contains $_ }) + $_.HybridUser -or # Fails Condition A + $_.ValidLicensesStatus -eq "Fail" # Fails Condition B } # Generate failure reasons $failureReasons = $nonCompliantUsers | ForEach-Object { - $accountType = if ($_.HybridUser) { "Hybrid" } else { "Cloud-Only" } - $missingLicenses = $validLicenses | Where-Object { $_ -notin ($_.Licenses -split '\|') } - "$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')" + "$($_.UserName)|$($_.Roles)|$($_.CloudOnlyStatus)|$($_.ValidLicensesStatus)|$($_.ApplicationAssignmentStatus)" } $failureReasons = $failureReasons -join "`n" $details = if ($nonCompliantUsers) { - "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n" + "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + $failureReasons } else { "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" } $result = $nonCompliantUsers.Count -eq 0 $status = if ($result) { 'Pass' } else { 'Fail' } - $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" } + $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | Cloud-Only Status | Valid Licenses Status | Application Assignment Status`n$failureReasons" } else { "N/A" } # Create the parameter splat $params = @{ From 1161baffad00cd599e6532d9f35f693048d778e8 Mon Sep 17 00:00:00 2001 From: DrIOS <58635327+DrIOSX@users.noreply.github.com> Date: Mon, 10 Jun 2024 12:31:22 -0500 Subject: [PATCH 4/4] fix: working and verbose confirmation included --- .../Test-AdministrativeAccountCompliance.ps1 | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/source/tests/Test-AdministrativeAccountCompliance.ps1 b/source/tests/Test-AdministrativeAccountCompliance.ps1 index 4694d37..2a1b0a8 100644 --- a/source/tests/Test-AdministrativeAccountCompliance.ps1 +++ b/source/tests/Test-AdministrativeAccountCompliance.ps1 @@ -8,27 +8,32 @@ function Test-AdministrativeAccountCompliance { begin { # The following conditions are checked: # Condition A: The administrative account is cloud-only (not synced). - # Condition B: The account is assigned only valid licenses (e.g., Microsoft Entra ID P1 or P2). - # Condition C: The administrative account does not have application assignments (only valid licenses are allowed). + # Condition B: The account is assigned a valid license (e.g., Microsoft Entra ID P1 or P2). + # Condition C: The administrative account does not have any other application assignments (only valid licenses). $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') $recnum = "1.1.1" + Write-Verbose "Starting Test-AdministrativeAccountCompliance with Rec: $recnum" } process { try { # Retrieve all admin roles + Write-Verbose "Retrieving all admin roles" $adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" } $adminRoleUsers = @() # Loop through each admin role to get role assignments and user details foreach ($role in $adminRoles) { + Write-Verbose "Processing role: $($role.DisplayName)" $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" foreach ($assignment in $roleAssignments) { + Write-Verbose "Processing role assignment for principal ID: $($assignment.PrincipalId)" # Get user details for each principal ID $userDetails = Get-MgUser -UserId $assignment.PrincipalId -Property "DisplayName, UserPrincipalName, Id, OnPremisesSyncEnabled" -ErrorAction SilentlyContinue if ($userDetails) { + Write-Verbose "Retrieved user details for: $($userDetails.UserPrincipalName)" # Get user license details $licenses = Get-MgUserLicenseDetail -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue $licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" } @@ -36,9 +41,15 @@ function Test-AdministrativeAccountCompliance { # Condition A: Check if the account is cloud-only $cloudOnlyStatus = if ($userDetails.OnPremisesSyncEnabled) { "Fail" } else { "Pass" } - # Condition B and C: Check if the account has only valid licenses - $hasOnlyValidLicenses = ($licenses.SkuPartNumber | ForEach-Object { $validLicenses -contains $_ }) -and (($licenses.SkuPartNumber | ForEach-Object { $validLicenses -notcontains $_ }).Count -eq 0) - $validLicensesStatus = if ($hasOnlyValidLicenses) { "Pass" } else { "Fail" } + # Condition B: Check if the account has valid licenses + $hasValidLicense = $licenses.SkuPartNumber | ForEach-Object { $validLicenses -contains $_ } + $validLicensesStatus = if ($hasValidLicense) { "Pass" } else { "Fail" } + + # Condition C: Check if the account has no other licenses + $hasInvalidLicense = $licenses.SkuPartNumber | ForEach-Object { $validLicenses -notcontains $_ } + $applicationAssignmentStatus = if ($hasInvalidLicense) { "Fail" } else { "Pass" } + + Write-Verbose "User: $($userDetails.UserPrincipalName), Cloud-Only: $cloudOnlyStatus, Valid Licenses: $validLicensesStatus, Other Applications Assigned: $applicationAssignmentStatus" # Collect user information $adminRoleUsers += [PSCustomObject]@{ @@ -49,13 +60,17 @@ function Test-AdministrativeAccountCompliance { Licenses = $licenseString CloudOnlyStatus = $cloudOnlyStatus ValidLicensesStatus = $validLicensesStatus - ApplicationAssignmentStatus = $validLicensesStatus # Using the same status as ValidLicensesStatus for now + ApplicationAssignmentStatus = $applicationAssignmentStatus } } + else { + Write-Verbose "No user details found for principal ID: $($assignment.PrincipalId)" + } } } # Group admin role users by UserName and collect unique roles and licenses + Write-Verbose "Grouping admin role users by UserName" $uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object { $first = $_.Group | Select-Object -First 1 $roles = ($_.Group.RoleName -join ', ') @@ -64,26 +79,31 @@ function Test-AdministrativeAccountCompliance { $first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } }, CloudOnlyStatus, ValidLicensesStatus, ApplicationAssignmentStatus } - # Identify non-compliant users based on conditions A and B + # Identify non-compliant users based on conditions A, B, and C + Write-Verbose "Identifying non-compliant users based on conditions" $nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object { $_.HybridUser -or # Fails Condition A - $_.ValidLicensesStatus -eq "Fail" # Fails Condition B + $_.ValidLicensesStatus -eq "Fail" -or # Fails Condition B + $_.ApplicationAssignmentStatus -eq "Fail" # Fails Condition C } # Generate failure reasons + Write-Verbose "Generating failure reasons for non-compliant users" $failureReasons = $nonCompliantUsers | ForEach-Object { "$($_.UserName)|$($_.Roles)|$($_.CloudOnlyStatus)|$($_.ValidLicensesStatus)|$($_.ApplicationAssignmentStatus)" } $failureReasons = $failureReasons -join "`n" - $details = if ($nonCompliantUsers) { - "Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + $failureReasons + $failureReason = if ($nonCompliantUsers) { + "Non-Compliant Accounts: $($nonCompliantUsers.Count)" } else { "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" } $result = $nonCompliantUsers.Count -eq 0 $status = if ($result) { 'Pass' } else { 'Fail' } - $failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | Cloud-Only Status | Valid Licenses Status | Application Assignment Status`n$failureReasons" } else { "N/A" } + $details = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | Cloud-Only Status | Entra ID License Status | Other Applications Assigned Status`n$failureReasons" } else { "N/A" } + + Write-Verbose "Assessment completed. Result: $status" # Create the parameter splat $params = @{