Entra ID & Intune Cloud Security Audit Scripts
Essential PowerShell automation scripts utilizing the official Microsoft.Graph and Microsoft.Graph.DeviceManagement modules for cloud identity hygiene, privilege escalation detection, and Intune compliance auditing.
๐ 1. Privileged Role & PIM Assignment Audit
Section titled โ๐ 1. Privileged Role & PIM Assignment AuditโAudits all active and eligible assignments to Tier-0 Entra ID administrative roles (Global Administrator, Privileged Role Administrator, Security Administrator, Intune Administrator).
# Connect to Microsoft GraphConnect-MgGraph -Scopes "RoleManagement.Read.Directory", "User.Read.All"
$targetRoles = @( "Global Administrator", "Privileged Role Administrator", "Security Administrator", "Intune Administrator", "Authentication Administrator", "Cloud Application Administrator")
$auditReport = foreach ($roleName in $targetRoles) { $roleDef = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq '$roleName'" if ($roleDef) { Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($roleDef.Id)'" -ExpandProperty "principal" | ForEach-Object { [PSCustomObject]@{ RoleName = $roleName PrincipalType = $_.Principal.AdditionalProperties["@odata.type"] -replace '#microsoft.graph.', '' DisplayName = $_.Principal.AdditionalProperties["displayName"] UserPrincipal = $_.Principal.AdditionalProperties["userPrincipalName"] AppId = $_.Principal.AdditionalProperties["appId"] AssignmentId = $_.Id } } }}
$auditReport | Sort-Object RoleName, DisplayName | Format-Table -AutoSize๐ฑ 2. High-Risk App Registrations & Over-Permissioned Service Principals
Section titled โ๐ฑ 2. High-Risk App Registrations & Over-Permissioned Service PrincipalsโIdentifies Enterprise Applications and Service Principals possessing sensitive Microsoft Graph Application permissions (daemon rights that bypass user MFA and access tenant-wide data):
# Hunt for apps with tenant-wide administrative Graph API permissions$dangerousScopes = @( "Application.ReadWrite.All", "RoleManagement.ReadWrite.Directory", "Mail.ReadWrite", "Mail.ReadWrite.Shared", "Files.ReadWrite.All", "Directory.ReadWrite.All", "User.ReadWrite.All")
Get-MgServicePrincipal -All | ForEach-Object { $sp = $_ $appRoles = $sp.AppRoleAssignments | Where-Object { $_.ResourceDisplayName -eq "Microsoft Graph" }
foreach ($role in $appRoles) { # Match role IDs to permission names [PSCustomObject]@{ AppDisplayName = $sp.DisplayName AppId = $sp.AppId Publisher = $sp.PublisherName PrincipalId = $sp.Id } }}๐ 3. Expiring & Long-Lived Service Principal Secrets
Section titled โ๐ 3. Expiring & Long-Lived Service Principal SecretsโAudits client secrets and certificates configured on App Registrations, identifying keys valid for over 2 years or already expired:
# Audit credential hygiene on App RegistrationsGet-MgApplication -All | ForEach-Object { $app = $_
# Check Password Secrets foreach ($secret in $app.PasswordCredentials) { [PSCustomObject]@{ AppName = $app.DisplayName AppId = $app.AppId Type = "ClientSecret" KeyName = $secret.DisplayName CreatedDate = $secret.StartDateTime ExpiryDate = $secret.EndDateTime IsExpired = ($secret.EndDateTime -lt (Get-Date)) } }
# Check Certificates foreach ($cert in $app.KeyCredentials) { [PSCustomObject]@{ AppName = $app.DisplayName AppId = $app.AppId Type = "Certificate" KeyName = $cert.DisplayName CreatedDate = $cert.StartDateTime ExpiryDate = $cert.EndDateTime IsExpired = ($cert.EndDateTime -lt (Get-Date)) } }} | Format-Table -AutoSize๐ป 4. Intune Device Compliance Audit (Windows & macOS)
Section titled โ๐ป 4. Intune Device Compliance Audit (Windows & macOS)โScans the managed endpoint fleet in Microsoft Intune, highlighting non-compliant, jailbroken, or unmanaged devices:
# Connect to Microsoft Graph Device Management# Connect-MgGraph -Scopes "DeviceManagementManagedDevices.Read.All"
Get-MgDeviceManagementManagedDevice -All | Select-Object DeviceName, OperatingSystem, OSVersion, ComplianceState, JailBroken, ManagementAgent, UserPrincipalName, LastSyncDateTime | Where-Object { $_.ComplianceState -ne "compliant" } | Sort-Object OperatingSystem, DeviceName | Format-Table -AutoSize๐ค 5. Stale Guest Accounts & Inactive Cloud Users
Section titled โ๐ค 5. Stale Guest Accounts & Inactive Cloud UsersโLocates external guest accounts (#EXT#) and internal users who have not authenticated in over 90 days:
# Find inactive cloud users and stale guest collaborators$cutoffDate = (Get-Date).AddDays(-90)
Get-MgUser -All -Property DisplayName, UserPrincipalName, UserType, AccountEnabled, SignInActivity | ForEach-Object { $lastSign = $_.SignInActivity.LastSignInDateTime
if ($_.AccountEnabled -eq $true -and ($lastSign -lt $cutoffDate -or $null -eq $lastSign)) { [PSCustomObject]@{ DisplayName = $_.DisplayName UPN = $_.UserPrincipalName UserType = $_.UserType LastSignIn = $lastSign DaysIdle = if ($lastSign) { ( (Get-Date) - $lastSign ).Days } else { "Never" } } }} | Sort-Object DaysIdle -Descending | Format-Table -AutoSize๐ก๏ธ 6. User Authentication Methods Audit (Phishing-Resistant MFA)
Section titled โ๐ก๏ธ 6. User Authentication Methods Audit (Phishing-Resistant MFA)โAudits which users have registered hardware-bound phishing-resistant credentials (FIDO2 keys, Windows Hello for Business) vs. legacy methods:
# Audit MFA method adoption across all enabled usersGet-MgUser -All -Property Id, DisplayName, UserPrincipalName -Filter "accountEnabled eq true" | ForEach-Object { $methods = Get-MgUserAuthenticationMethod -UserId $_.Id $methodTypes = $methods.AdditionalProperties["@odata.type"] -replace '#microsoft.graph.', ''
[PSCustomObject]@{ DisplayName = $_.DisplayName UPN = $_.UserPrincipalName HasFIDO2 = ($methodTypes -contains "fido2AuthenticationMethod") HasWindowsHello = ($methodTypes -contains "windowsHelloForBusinessAuthenticationMethod") HasAuthenticator = ($methodTypes -contains "microsoftAuthenticatorAuthenticationMethod") HasPhoneSMS = ($methodTypes -contains "phoneAuthenticationMethod") }} | Format-Table -AutoSize