diff --git a/source/Private/Get-CISMgOutput.ps1 b/source/Private/Get-CISMgOutput.ps1 index 0c03340..87459c1 100644 --- a/source/Private/Get-CISMgOutput.ps1 +++ b/source/Private/Get-CISMgOutput.ps1 @@ -58,10 +58,6 @@ function Get-CISMgOutput { return $AdminRoleAssignmentsAndUsers } } - '1.1.4' { - # 1.1.4 - MicrosoftGraphPlaceholder - # Placeholder for Test-AdminAccountLicenses - } '1.1.3' { # Test-GlobalAdminsCount # Step: Retrieve global admin role @@ -70,6 +66,32 @@ function Get-CISMgOutput { $globalAdmins = Get-MgDirectoryRoleMember -DirectoryRoleId $globalAdminRole.Id return $globalAdmins } + '1.1.4' { + # 1.1.4 - MicrosoftGraphPlaceholder + $DirectoryRoles = Get-MgDirectoryRole + # Get privileged role IDs + $PrivilegedRoles = $DirectoryRoles | + Where-Object { $_.DisplayName -like '*Administrator*' -or $_.DisplayName -eq 'Global Reader' } + # Get the members of these various roles + $RoleMembers = $PrivilegedRoles | ForEach-Object { Get-MgDirectoryRoleMember -DirectoryRoleId $_.Id } | + Select-Object Id -Unique + # Retrieve details about the members in these roles + $PrivilegedUsers = $RoleMembers | ForEach-Object { + Get-MgUser -UserId $_.Id -Property UserPrincipalName, DisplayName, Id + } + $Report = [System.Collections.Generic.List[Object]]::new() + foreach ($Admin in $PrivilegedUsers) { + $License = $null + $License = (Get-MgUserLicenseDetail -UserId $Admin.id).SkuPartNumber -join ', ' + $Object = [pscustomobject][ordered]@{ + DisplayName = $Admin.DisplayName + UserPrincipalName = $Admin.UserPrincipalName + License = $License + } + $Report.Add($Object) + } + return $Report + } '1.2.1' { # Test-ManagedApprovedPublicGroups $allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq 'Public' } | Select-Object DisplayName, Visibility diff --git a/source/tests/Test-AdminAccountLicenses.ps1 b/source/tests/Test-AdminAccountLicenses.ps1 new file mode 100644 index 0000000..71822bf --- /dev/null +++ b/source/tests/Test-AdminAccountLicenses.ps1 @@ -0,0 +1,55 @@ +function Test-AdminAccountLicenses { + [CmdletBinding()] + param () + begin { + # The following conditions are checked: + # Condition A: The administrative account is cloud-only (not synced). + # 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.4" + Write-Verbose "Starting Test-AdministrativeAccountCompliance with Rec: $RecNum" + } + process { + try { + # Retrieve admin roles, assignments, and user details including licenses + Write-Verbose "Retrieving admin roles, assignments, and user details including licenses" + $Report = Get-CISMgOutput -Rec $RecNum + $NonCompliantUsers = $Report | Where-Object {$_.License -notin $validLicenses} + # Generate failure reasons + Write-Verbose "Generating failure reasons for non-compliant users" + $failureReasons = $nonCompliantUsers | ForEach-Object { + "$($_.DisplayName)|$($_.UserPrincipalName)|$(if ($_.License) {$_.License}else{"No licenses found"})" + } + $failureReasons = $failureReasons -join "`n" + $failureReason = if ($nonCompliantUsers) { + "Non-Compliant Accounts without only a singular P1 or P2 license and no others: $($nonCompliantUsers.Count)" + } + else { + "Compliant Accounts: $($uniqueAdminRoleUsers.Count)" + } + $result = $nonCompliantUsers.Count -eq 0 + $status = if ($result) { 'Pass' } else { 'Fail' } + $details = if ($nonCompliantUsers) { "DisplayName | UserPrincipalName | License`n$failureReasons" } else { "N/A" } + Write-Verbose "Assessment completed. Result: $status" + # Create the parameter splat + $params = @{ + Rec = $RecNum + Result = $result + Status = $status + Details = $details + FailureReason = $failureReason + } + $auditResult = Initialize-CISAuditResult @params + } + catch { + $LastError = $_ + $auditResult = Get-TestError -LastError $LastError -RecNum $RecNum + } + } + end { + # Output the result + return $auditResult + } +} + # $validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') \ No newline at end of file