PowerShell Scripts
Production-ready PowerShell scripts for automation, security auditing, and system administration. Copy, download, and customize for your needs.
Get Entra ID User Report
Generate comprehensive user report from Entra ID with licenses and sign-in activity
1class=class="text-pastel-mint">"text-foreground/50 italic"># Get comprehensive Entra ID user report2Connect-MgGraph -Scopes class="text-pastel-mint">"User.Read.All", class="text-pastel-mint">"AuditLog.Read.All"34$Users = Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled, CreatedDateTime, SignInActivity, AssignedLicenses |5 Select-Object DisplayName, UserPrincipalName, AccountEnabled, CreatedDateTime,6 @{Name=class="text-pastel-mint">'LastSignIn';Expression={$_.SignInActivity.LastSignInDateTime}},7 @{Name=class="text-pastel-mint">'LicenseCount';Expression={$_.AssignedLicenses.Count}}89$Users | Export-Csv -Path class="text-pastel-mint">"EntraID_UserReport_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation10Write-Host class="text-pastel-mint">"Report exported successfully!" -ForegroundColor Green11$Users | Format-Table -AutoSizeCreate Bulk Entra ID Users from CSV
Automate user creation in Entra ID from CSV file with password generation
1class=class="text-pastel-mint">"text-foreground/50 italic"># Create bulk users from CSV2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># CSV should have columns: DisplayName, UserPrincipalName, Department, JobTitle5$Users = Import-Csv -Path class="text-pastel-mint">"C:\Users\NewUsers.csv"67foreach ($User in $Users) {8 $PasswordProfile = @{9 Password = class="text-pastel-mint">"TempPass@" + (Get-Random -Minimum 1000 -Maximum 9999)10 ForceChangePasswordNextSignIn = $true11 }12 13 $Params = @{14 DisplayName = $User.DisplayName15 UserPrincipalName = $User.UserPrincipalName16 MailNickname = $User.UserPrincipalName.Split(class="text-pastel-mint">'@')[0]17 AccountEnabled = $true18 PasswordProfile = $PasswordProfile19 Department = $User.Department20 JobTitle = $User.JobTitle21 }22 23 try {24 New-MgUser @Params25 Write-Host class="text-pastel-mint">"Created: $($User.DisplayName)" -ForegroundColor Green26 } catch {27 Write-Host class="text-pastel-mint">"Failed: $($User.DisplayName) - $($_.Exception.Message)" -ForegroundColor Red28 }29}Audit Entra ID Admin Roles
List all users with administrative roles and their assignments
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit administrative role assignments2Connect-MgGraph -Scopes class="text-pastel-mint">"Directory.Read.All", class="text-pastel-mint">"RoleManagement.Read.All"34$AdminRoles = Get-MgDirectoryRole | Where-Object { $_.DisplayName -like class="text-pastel-mint">"*Admin*" }5$Report = @()67foreach ($Role in $AdminRoles) {8 $Members = Get-MgDirectoryRoleMember -DirectoryRoleId $Role.Id9 10 foreach ($Member in $Members) {11 $User = Get-MgUser -UserId $Member.Id12 $Report += [PSCustomObject]@{13 RoleName = $Role.DisplayName14 UserName = $User.DisplayName15 UPN = $User.UserPrincipalName16 AccountEnabled = $User.AccountEnabled17 }18 }19}2021$Report | Export-Csv -Path class="text-pastel-mint">"AdminRoles_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation22Write-Host class="text-pastel-mint">"Found $($Report.Count) admin role assignments" -ForegroundColor Cyan23$Report | Format-Table -AutoSizeEnable MFA for Bulk Users
Enable multi-factor authentication for specified users or groups
1class=class="text-pastel-mint">"text-foreground/50 italic"># Enable MFA for bulk users2Connect-MgGraph -Scopes class="text-pastel-mint">"UserAuthenticationMethod.ReadWrite.All"34$Users = Get-MgUser -Filter class="text-pastel-mint">"department eq 'Financeclass="text-pastel-mint">'" -All56foreach ($User in $Users) {7 try {8 class=class="text-pastel-mint">"text-foreground/50 italic"># Check current MFA status9 $AuthMethods = Get-MgUserAuthenticationMethod -UserId $User.Id10 11 class=class="text-pastel-mint">"text-foreground/50 italic"># Enable Phone Auth Method12 $Params = @{13 class="text-pastel-mint">"@odata.type" = class="text-pastel-mint">"class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.phoneAuthenticationMethod"14 phoneType = class="text-pastel-mint">"mobile"15 phoneNumber = class="text-pastel-mint">"+1 555 0100" class=class="text-pastel-mint">"text-foreground/50 italic"># Update with actual number16 }17 18 New-MgUserAuthenticationPhoneMethod -UserId $User.Id -BodyParameter $Params19 Write-Host class="text-pastel-mint">"MFA enabled for: $($User.DisplayName)" -ForegroundColor Green20 21 } catch {22 Write-Host class="text-pastel-mint">"Failed for: $($User.DisplayName) - $($_.Exception.Message)" -ForegroundColor Yellow23 }24}2526Write-Host class="text-pastel-mint">"MFA enablement completed" -ForegroundColor CyanFind Inactive Entra ID Users
Identify users who haven't signed in for specified days
1class=class="text-pastel-mint">"text-foreground/50 italic"># Find inactive users in Entra ID2Connect-MgGraph -Scopes class="text-pastel-mint">"User.Read.All", class="text-pastel-mint">"AuditLog.Read.All"34$DaysInactive = 905$InactiveDate = (Get-Date).AddDays(-$DaysInactive)67$InactiveUsers = Get-MgUser -All -Property DisplayName, UserPrincipalName, SignInActivity, CreatedDateTime |8 Where-Object { 9 $_.SignInActivity.LastSignInDateTime -lt $InactiveDate -and 10 $_.SignInActivity.LastSignInDateTime -ne $null11 } |12 Select-Object DisplayName, UserPrincipalName,13 @{Name=class="text-pastel-mint">'LastSignIn';Expression={$_.SignInActivity.LastSignInDateTime}},14 @{Name=class="text-pastel-mint">'DaysInactive';Expression={((Get-Date) - $_.SignInActivity.LastSignInDateTime).Days}}1516Write-Host class="text-pastel-mint">"Found $($InactiveUsers.Count) inactive users (>$DaysInactive days)" -ForegroundColor Yellow17$InactiveUsers | Export-Csv -Path class="text-pastel-mint">"InactiveUsers_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation18$InactiveUsers | Format-Table -AutoSizeAssign Licenses to Bulk Users
Assign Microsoft 365 licenses to users based on group or department
1class=class="text-pastel-mint">"text-foreground/50 italic"># Assign licenses to bulk users2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All", class="text-pastel-mint">"Organization.Read.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># Get available SKUs5$SKUs = Get-MgSubscribedSku6$M365E3 = $SKUs | Where-Object { $_.SkuPartNumber -eq class="text-pastel-mint">"SPE_E3" }78class=class="text-pastel-mint">"text-foreground/50 italic"># Get users from specific department9$Users = Get-MgUser -Filter class="text-pastel-mint">"department eq 'Salesclass="text-pastel-mint">'" -All1011foreach ($User in $Users) {12 try {13 Set-MgUserLicense -UserId $User.Id -AddLicenses @{SkuId = $M365E3.SkuId} -RemoveLicenses @()14 Write-Host class="text-pastel-mint">"License assigned to: $($User.DisplayName)" -ForegroundColor Green15 } catch {16 Write-Host class="text-pastel-mint">"Failed for: $($User.DisplayName) - $($_.Exception.Message)" -ForegroundColor Red17 }18}1920Write-Host class="text-pastel-mint">"License assignment completed" -ForegroundColor CyanCreate Entra ID Security Group
Create a new security group and add members dynamically
1class=class="text-pastel-mint">"text-foreground/50 italic"># Create Entra ID security group2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.ReadWrite.All"34$GroupParams = @{5 DisplayName = class="text-pastel-mint">"Security-Finance-Team"6 Description = class="text-pastel-mint">"Finance department security group"7 MailEnabled = $false8 MailNickname = class="text-pastel-mint">"SecFinance"9 SecurityEnabled = $true10}1112$NewGroup = New-MgGroup @GroupParams13Write-Host class="text-pastel-mint">"Group created: $($NewGroup.DisplayName)" -ForegroundColor Green1415class=class="text-pastel-mint">"text-foreground/50 italic"># Add members16$Users = Get-MgUser -Filter class="text-pastel-mint">"department eq 'Financeclass="text-pastel-mint">'"17foreach ($User in $Users) {18 New-MgGroupMember -GroupId $NewGroup.Id -DirectoryObjectId $User.Id19 Write-Host class="text-pastel-mint">"Added: $($User.DisplayName)" -ForegroundColor Cyan20}2122Write-Host class="text-pastel-mint">"Group setup completed" -ForegroundColor GreenAudit External Guest Users
Review all guest users and their access permissions
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit guest users in Entra ID2Connect-MgGraph -Scopes class="text-pastel-mint">"User.Read.All", class="text-pastel-mint">"Group.Read.All"34$GuestUsers = Get-MgUser -Filter class="text-pastel-mint">"userType eq 'Guestclass="text-pastel-mint">'" -All -Property DisplayName, UserPrincipalName, CreatedDateTime, SignInActivity56$GuestReport = foreach ($Guest in $GuestUsers) {7 $Groups = Get-MgUserMemberOf -UserId $Guest.Id8 9 [PSCustomObject]@{10 DisplayName = $Guest.DisplayName11 Email = $Guest.UserPrincipalName12 CreatedDate = $Guest.CreatedDateTime13 LastSignIn = $Guest.SignInActivity.LastSignInDateTime14 GroupCount = $Groups.Count15 Groups = ($Groups.AdditionalProperties.displayName -join class="text-pastel-mint">"; ")16 }17}1819Write-Host class="text-pastel-mint">"Found $($GuestUsers.Count) guest users" -ForegroundColor Yellow20$GuestReport | Export-Csv -Path class="text-pastel-mint">"GuestUsers_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation21$GuestReport | Format-Table -AutoSizeExport Conditional Access Policies
Document all Conditional Access policies and their settings
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export Conditional Access policies2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.Read.All"34$Policies = Get-MgIdentityConditionalAccessPolicy56$Report = foreach ($Policy in $Policies) {7 [PSCustomObject]@{8 DisplayName = $Policy.DisplayName9 State = $Policy.State10 CreatedDateTime = $Policy.CreatedDateTime11 ModifiedDateTime = $Policy.ModifiedDateTime12 IncludeUsers = ($Policy.Conditions.Users.IncludeUsers -join class="text-pastel-mint">", ")13 ExcludeUsers = ($Policy.Conditions.Users.ExcludeUsers -join class="text-pastel-mint">", ")14 IncludeApplications = ($Policy.Conditions.Applications.IncludeApplications -join class="text-pastel-mint">", ")15 GrantControls = ($Policy.GrantControls.BuiltInControls -join class="text-pastel-mint">", ")16 SessionControls = if($Policy.SessionControls){class="text-pastel-mint">"Enabled"}else{class="text-pastel-mint">"None"}17 }18}1920$Report | Export-Csv -Path class="text-pastel-mint">"ConditionalAccess_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation21Write-Host class="text-pastel-mint">"Exported $($Policies.Count) policies" -ForegroundColor Green22$Report | Format-Table -AutoSizeRevoke User Sessions and Tokens
Immediately revoke all sessions and refresh tokens for a compromised account
1class=class="text-pastel-mint">"text-foreground/50 italic"># Revoke all user sessions and tokens2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All", class="text-pastel-mint">"Directory.ReadWrite.All"34param(5 [Parameter(Mandatory=$true)]6 [string]$UserPrincipalName7)89$User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$UserPrincipalNameclass="text-pastel-mint">'"1011if ($User) {12 class=class="text-pastel-mint">"text-foreground/50 italic"># Revoke all refresh tokens13 Revoke-MgUserSignInSession -UserId $User.Id14 15 class=class="text-pastel-mint">"text-foreground/50 italic"># Disable account temporarily16 Update-MgUser -UserId $User.Id -AccountEnabled $false17 18 Write-Host class="text-pastel-mint">"User sessions revoked: $($User.DisplayName)" -ForegroundColor Yellow19 Write-Host class="text-pastel-mint">"Account disabled for security" -ForegroundColor Yellow20 Write-Host class="text-pastel-mint">"User ID: $($User.Id)" -ForegroundColor Cyan21} else {22 Write-Host class="text-pastel-mint">"User not found" -ForegroundColor Red23}Get Microsoft 365 License Usage
Report on license allocation and available seats across all SKUs
1class=class="text-pastel-mint">"text-foreground/50 italic"># Get license usage report2Connect-MgGraph -Scopes class="text-pastel-mint">"Organization.Read.All"34$SKUs = Get-MgSubscribedSku56$LicenseReport = foreach ($SKU in $SKUs) {7 [PSCustomObject]@{8 ProductName = $SKU.SkuPartNumber9 TotalLicenses = $SKU.PrepaidUnits.Enabled10 AssignedLicenses = $SKU.ConsumedUnits11 AvailableLicenses = $SKU.PrepaidUnits.Enabled - $SKU.ConsumedUnits12 UtilizationPercent = [math]::Round(($SKU.ConsumedUnits / $SKU.PrepaidUnits.Enabled) * 100, 2)13 }14}1516Write-Host class="text-pastel-mint">"License Usage Summary" -ForegroundColor Cyan17$LicenseReport | Format-Table -AutoSize18$LicenseReport | Export-Csv -Path class="text-pastel-mint">"LicenseUsage_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationSync Group Membership by Attribute
Automatically sync group membership based on user attributes
1class=class="text-pastel-mint">"text-foreground/50 italic"># Sync group membership based on department2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.ReadWrite.All", class="text-pastel-mint">"User.Read.All"34param(5 [string]$Department = class="text-pastel-mint">"Engineering",6 [string]$GroupName = class="text-pastel-mint">"Engineering-Team"7)89$Group = Get-MgGroup -Filter class="text-pastel-mint">"displayName eq '$GroupNameclass="text-pastel-mint">'"10$UsersInDept = Get-MgUser -Filter class="text-pastel-mint">"department eq '$Departmentclass="text-pastel-mint">'" -All11$CurrentMembers = Get-MgGroupMember -GroupId $Group.Id -All1213class=class="text-pastel-mint">"text-foreground/50 italic"># Add missing users14foreach ($User in $UsersInDept) {15 if ($User.Id -notin $CurrentMembers.Id) {16 New-MgGroupMember -GroupId $Group.Id -DirectoryObjectId $User.Id17 Write-Host class="text-pastel-mint">"Added: $($User.DisplayName)" -ForegroundColor Green18 }19}2021class=class="text-pastel-mint">"text-foreground/50 italic"># Remove users no longer in department22foreach ($Member in $CurrentMembers) {23 if ($Member.Id -notin $UsersInDept.Id) {24 Remove-MgGroupMemberByRef -GroupId $Group.Id -DirectoryObjectId $Member.Id25 Write-Host class="text-pastel-mint">"Removed: $($Member.AdditionalProperties.displayName)" -ForegroundColor Yellow26 }27}2829Write-Host class="text-pastel-mint">"Group sync completed" -ForegroundColor CyanReset User Password Securely
Reset user password with strong password generation and notification
1class=class="text-pastel-mint">"text-foreground/50 italic"># Reset user password securely2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34function Reset-EntraUserPassword {5 param(6 [Parameter(Mandatory=$true)]7 [string]$UserPrincipalName,8 [switch]$ForceChange9 )10 11 class=class="text-pastel-mint">"text-foreground/50 italic"># Generate strong password12 $Password = -join ((65..90) + (97..122) + (48..57) + (33,35,37,64) | Get-Random -Count 16 | ForEach-Object {[char]$_})13 14 $PasswordProfile = @{15 Password = $Password16 ForceChangePasswordNextSignIn = $ForceChange.IsPresent17 }18 19 try {20 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$UserPrincipalNameclass="text-pastel-mint">'"21 Update-MgUser -UserId $User.Id -PasswordProfile $PasswordProfile22 23 Write-Host class="text-pastel-mint">"Password reset successful for: $($User.DisplayName)" -ForegroundColor Green24 Write-Host class="text-pastel-mint">"Temporary Password: $Password" -ForegroundColor Yellow25 Write-Host class="text-pastel-mint">"Force Change: $($ForceChange.IsPresent)" -ForegroundColor Cyan26 27 } catch {28 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red29 }30}3132class=class="text-pastel-mint">"text-foreground/50 italic"># Usage33Reset-EntraUserPassword -UserPrincipalName class="text-pastel-mint">"user@domain.com" -ForceChangeExport All Group Memberships
Export all groups and their members to CSV for documentation
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export all group memberships2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.Read.All", class="text-pastel-mint">"User.Read.All"34$AllGroups = Get-MgGroup -All5$Report = @()67foreach ($Group in $AllGroups) {8 Write-Host class="text-pastel-mint">"Processing: $($Group.DisplayName)" -ForegroundColor Cyan9 10 $Members = Get-MgGroupMember -GroupId $Group.Id -All11 12 foreach ($Member in $Members) {13 $Report += [PSCustomObject]@{14 GroupName = $Group.DisplayName15 GroupType = if($Group.SecurityEnabled){class="text-pastel-mint">"Security"}else{class="text-pastel-mint">"Microsoft 365"}16 MemberName = $Member.AdditionalProperties.displayName17 MemberUPN = $Member.AdditionalProperties.userPrincipalName18 MemberType = $Member.AdditionalProperties.class="text-pastel-mint">'@odata.type'19 }20 }21}2223Write-Host class="text-pastel-mint">"Total memberships: $($Report.Count)" -ForegroundColor Green24$Report | Export-Csv -Path class="text-pastel-mint">"GroupMemberships_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationAudit Application Permissions
Review all application registrations and their API permissions
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit application permissions2Connect-MgGraph -Scopes class="text-pastel-mint">"Application.Read.All"34$Apps = Get-MgApplication -All5$Report = @()67foreach ($App in $Apps) {8 $Permissions = $App.RequiredResourceAccess9 10 foreach ($Resource in $Permissions) {11 foreach ($Permission in $Resource.ResourceAccess) {12 $Report += [PSCustomObject]@{13 ApplicationName = $App.DisplayName14 ApplicationId = $App.AppId15 ResourceId = $Resource.ResourceAppId16 PermissionId = $Permission.Id17 PermissionType = $Permission.Type18 CreatedDateTime = $App.CreatedDateTime19 }20 }21 }22}2324Write-Host class="text-pastel-mint">"Found $($Apps.Count) applications with $($Report.Count) permissions" -ForegroundColor Cyan25$Report | Export-Csv -Path class="text-pastel-mint">"AppPermissions_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation26$Report | Format-Table ApplicationName, PermissionType -AutoSizeDisable Inactive User Accounts
Automatically disable accounts that haven't been used for specified period
1class=class="text-pastel-mint">"text-foreground/50 italic"># Disable inactive user accounts2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All", class="text-pastel-mint">"AuditLog.Read.All"34$DaysInactive = 905$InactiveDate = (Get-Date).AddDays(-$DaysInactive)67$InactiveUsers = Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled, SignInActivity |8 Where-Object { 9 $_.AccountEnabled -eq $true -and10 $_.SignInActivity.LastSignInDateTime -lt $InactiveDate11 }1213Write-Host class="text-pastel-mint">"Found $($InactiveUsers.Count) inactive accounts to disable" -ForegroundColor Yellow1415foreach ($User in $InactiveUsers) {16 try {17 Update-MgUser -UserId $User.Id -AccountEnabled $false18 Write-Host class="text-pastel-mint">"Disabled: $($User.DisplayName) - Last sign-in: $($User.SignInActivity.LastSignInDateTime)" -ForegroundColor Yellow19 } catch {20 Write-Host class="text-pastel-mint">"Failed to disable: $($User.DisplayName)" -ForegroundColor Red21 }22}2324Write-Host class="text-pastel-mint">"Account cleanup completed" -ForegroundColor CyanCreate Dynamic Entra ID Group
Create a dynamic group with membership rules based on user attributes
1class=class="text-pastel-mint">"text-foreground/50 italic"># Create dynamic group with membership rules2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.ReadWrite.All"34$DynamicRule = class="text-pastel-mint">'(user.department -eq "ITclass="text-pastel-mint">") and (user.accountEnabled -eq true)'56$GroupParams = @{7 DisplayName = class="text-pastel-mint">"IT-Department-Dynamic"8 Description = class="text-pastel-mint">"Dynamic group for IT department members"9 MailEnabled = $false10 MailNickname = class="text-pastel-mint">"ITDeptDynamic"11 SecurityEnabled = $true12 GroupTypes = @(class="text-pastel-mint">"DynamicMembership")13 MembershipRule = $DynamicRule14 MembershipRuleProcessingState = class="text-pastel-mint">"On"15}1617try {18 $NewGroup = New-MgGroup @GroupParams19 Write-Host class="text-pastel-mint">"Dynamic group created: $($NewGroup.DisplayName)" -ForegroundColor Green20 Write-Host class="text-pastel-mint">"Membership Rule: $DynamicRule" -ForegroundColor Cyan21 Write-Host class="text-pastel-mint">"Group ID: $($NewGroup.Id)" -ForegroundColor Cyan22} catch {23 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red24}Audit Privileged Identity Management
Review PIM role assignments and eligible users
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit PIM role assignments2Connect-MgGraph -Scopes class="text-pastel-mint">"RoleManagement.Read.All", class="text-pastel-mint">"PrivilegedAccess.Read.AzureAD"34$RoleDefinitions = Get-MgRoleManagementDirectoryRoleDefinition -All5$Report = @()67foreach ($Role in $RoleDefinitions | Where-Object { $_.DisplayName -like class="text-pastel-mint">"*Admin*" }) {8 class=class="text-pastel-mint">"text-foreground/50 italic"># Get active assignments9 $Assignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter class="text-pastel-mint">"roleDefinitionId eq '$($Role.Id)class="text-pastel-mint">'" -All10 11 foreach ($Assignment in $Assignments) {12 $Principal = Get-MgDirectoryObject -DirectoryObjectId $Assignment.PrincipalId13 14 $Report += [PSCustomObject]@{15 RoleName = $Role.DisplayName16 PrincipalName = $Principal.AdditionalProperties.displayName17 PrincipalType = $Principal.AdditionalProperties.class="text-pastel-mint">'@odata.type'18 AssignmentType = class="text-pastel-mint">"Active"19 StartDateTime = $Assignment.CreatedDateTime20 }21 }22}2324Write-Host class="text-pastel-mint">"Found $($Report.Count) privileged role assignments" -ForegroundColor Yellow25$Report | Export-Csv -Path class="text-pastel-mint">"PIMRoles_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation26$Report | Format-Table -AutoSizeMonitor Failed Sign-In Attempts
Track and report on failed sign-in attempts for security monitoring
1class=class="text-pastel-mint">"text-foreground/50 italic"># Monitor failed sign-in attempts2Connect-MgGraph -Scopes class="text-pastel-mint">"AuditLog.Read.All", class="text-pastel-mint">"Directory.Read.All"34$StartDate = (Get-Date).AddDays(-7)5$SignIns = Get-MgAuditLogSignIn -Filter class="text-pastel-mint">"createdDateTime ge $($StartDate.ToString('yyyy-MM-ddclass="text-pastel-mint">')) and status/errorCode ne 0" -All67$FailureReport = $SignIns | Group-Object UserPrincipalName | ForEach-Object {8 [PSCustomObject]@{9 UserPrincipalName = $_.Name10 FailedAttempts = $_.Count11 LastFailure = ($_.Group | Sort-Object CreatedDateTime -Descending | Select-Object -First 1).CreatedDateTime12 ErrorCodes = ($_.Group.Status.ErrorCode | Select-Object -Unique) -join class="text-pastel-mint">", "13 Locations = ($_.Group.Location.City | Select-Object -Unique) -join class="text-pastel-mint">", "14 }15} | Sort-Object FailedAttempts -Descending1617Write-Host class="text-pastel-mint">"Found $($FailureReport.Count) users with failed sign-ins" -ForegroundColor Yellow18$FailureReport | Export-Csv -Path class="text-pastel-mint">"FailedSignIns_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation19$FailureReport | Format-Table -AutoSizeManage Service Principal Secrets
Audit and rotate service principal client secrets for security
1class=class="text-pastel-mint">"text-foreground/50 italic"># Manage service principal secrets2Connect-MgGraph -Scopes class="text-pastel-mint">"Application.ReadWrite.All"34$Apps = Get-MgApplication -All5$ExpiringSecrets = @()6$WarningDays = 3078foreach ($App in $Apps) {9 $Secrets = $App.PasswordCredentials10 11 foreach ($Secret in $Secrets) {12 $DaysUntilExpiry = ($Secret.EndDateTime - (Get-Date)).Days13 14 if ($DaysUntilExpiry -le $WarningDays -and $DaysUntilExpiry -gt 0) {15 $ExpiringSecrets += [PSCustomObject]@{16 ApplicationName = $App.DisplayName17 ApplicationId = $App.AppId18 SecretKeyId = $Secret.KeyId19 ExpiryDate = $Secret.EndDateTime20 DaysRemaining = $DaysUntilExpiry21 }22 }23 }24}2526Write-Host class="text-pastel-mint">"Found $($ExpiringSecrets.Count) secrets expiring in $WarningDays days" -ForegroundColor Yellow27$ExpiringSecrets | Sort-Object DaysRemaining | Export-Csv -Path class="text-pastel-mint">"ExpiringSecrets_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation28$ExpiringSecrets | Format-Table -AutoSizeConfigure Domain Password Policy
Set and enforce password policy settings for the tenant
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure password policy settings2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.ReadWrite.Authorization"34class=class="text-pastel-mint">"text-foreground/50 italic"># Get current domain settings5$Domain = Get-MgDomain | Where-Object { $_.IsDefault -eq $true }67class=class="text-pastel-mint">"text-foreground/50 italic"># Configure password policy8$PasswordPolicy = @{9 passwordValidityPeriodInDays = 9010 passwordNotificationWindowInDays = 1411}1213try {14 class=class="text-pastel-mint">"text-foreground/50 italic"># Note: Password policies are typically set at the tenant level15 Write-Host class="text-pastel-mint">"Current Password Policy Settings:" -ForegroundColor Cyan16 Write-Host class="text-pastel-mint">"Domain: $($Domain.Id)" -ForegroundColor White17 Write-Host class="text-pastel-mint">"Password Never Expires: $($Domain.PasswordValidityPeriodInDays)" -ForegroundColor White18 19 class=class="text-pastel-mint">"text-foreground/50 italic"># Additional password protection settings20 Write-Host class="text-pastel-mint">"`nRecommended Settings:" -ForegroundColor Yellow21 Write-Host class="text-pastel-mint">"- Enable Azure AD Password Protection" -ForegroundColor White22 Write-Host class="text-pastel-mint">"- Set minimum password length to 14 characters" -ForegroundColor White23 Write-Host class="text-pastel-mint">"- Enable banned password list" -ForegroundColor White24 Write-Host class="text-pastel-mint">"- Require MFA for all users" -ForegroundColor White25 26} catch {27 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red28}Export Entra ID Device Inventory
Generate comprehensive report of all registered devices
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export device inventory from Entra ID2Connect-MgGraph -Scopes class="text-pastel-mint">"Device.Read.All"34$Devices = Get-MgDevice -All -Property DisplayName, DeviceId, OperatingSystem, OperatingSystemVersion, TrustType, ApproximateLastSignInDateTime, IsCompliant, IsManaged56$DeviceReport = $Devices | Select-Object DisplayName, DeviceId, OperatingSystem, OperatingSystemVersion, TrustType,7 @{Name=class="text-pastel-mint">'LastSignIn';Expression={$_.ApproximateLastSignInDateTime}},8 @{Name=class="text-pastel-mint">'Compliant';Expression={$_.IsCompliant}},9 @{Name=class="text-pastel-mint">'Managed';Expression={$_.IsManaged}},10 @{Name=class="text-pastel-mint">'DaysSinceSignIn';Expression={if($_.ApproximateLastSignInDateTime){((Get-Date) - $_.ApproximateLastSignInDateTime).Days}else{class="text-pastel-mint">"Never"}}}1112Write-Host class="text-pastel-mint">"Total Devices: $($Devices.Count)" -ForegroundColor Cyan13Write-Host class="text-pastel-mint">"Compliant: $(($Devices | Where-Object IsCompliant -eq $true).Count)" -ForegroundColor Green14Write-Host class="text-pastel-mint">"Non-Compliant: $(($Devices | Where-Object IsCompliant -eq $false).Count)" -ForegroundColor Red1516$DeviceReport | Export-Csv -Path class="text-pastel-mint">"DeviceInventory_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation17$DeviceReport | Format-Table -AutoSizeSet User Manager Relationships
Bulk update manager assignments from CSV file
1class=class="text-pastel-mint">"text-foreground/50 italic"># Set manager relationships in bulk2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># CSV should have columns: UserPrincipalName, ManagerPrincipalName5$Assignments = Import-Csv -Path class="text-pastel-mint">"C:\Managers\ManagerAssignments.csv"67foreach ($Assignment in $Assignments) {8 try {9 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$($Assignment.UserPrincipalName)class="text-pastel-mint">'"10 $Manager = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$($Assignment.ManagerPrincipalName)class="text-pastel-mint">'"11 12 if ($User -and $Manager) {13 $ManagerRef = @{14 class="text-pastel-mint">"@odata.id" = class="text-pastel-mint">"https://graph.microsoft.com/v1.0/users/$($Manager.Id)"15 }16 17 Set-MgUserManagerByRef -UserId $User.Id -BodyParameter $ManagerRef18 Write-Host class="text-pastel-mint">"Assigned manager for: $($User.DisplayName) -> $($Manager.DisplayName)" -ForegroundColor Green19 }20 } catch {21 Write-Host class="text-pastel-mint">"Failed: $($Assignment.UserPrincipalName) - $($_.Exception.Message)" -ForegroundColor Red22 }23}2425Write-Host class="text-pastel-mint">"Manager assignment completed" -ForegroundColor CyanAudit Risky User Accounts
Identify and report on users flagged for risk by Identity Protection
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit risky users from Identity Protection2Connect-MgGraph -Scopes class="text-pastel-mint">"IdentityRiskyUser.Read.All"34$RiskyUsers = Get-MgRiskyUser -All56$RiskReport = foreach ($User in $RiskyUsers | Where-Object { $_.RiskState -ne class="text-pastel-mint">'none' }) {7 try {8 $UserDetails = Get-MgUser -UserId $User.Id -Property DisplayName, UserPrincipalName, Department9 10 [PSCustomObject]@{11 DisplayName = $UserDetails.DisplayName12 UserPrincipalName = $UserDetails.UserPrincipalName13 Department = $UserDetails.Department14 RiskLevel = $User.RiskLevel15 RiskState = $User.RiskState16 RiskLastUpdated = $User.RiskLastUpdatedDateTime17 RiskDetail = $User.RiskDetail18 }19 } catch {20 Write-Host class="text-pastel-mint">"Error processing user: $($User.UserPrincipalName)" -ForegroundColor Yellow21 }22}2324Write-Host class="text-pastel-mint">"Found $($RiskReport.Count) risky users" -ForegroundColor Yellow25$RiskReport | Export-Csv -Path class="text-pastel-mint">"RiskyUsers_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation26$RiskReport | Format-Table -AutoSizeRemove Stale Entra ID Devices
Identify and remove devices that haven't signed in for specified days
1class=class="text-pastel-mint">"text-foreground/50 italic"># Remove stale devices from Entra ID2Connect-MgGraph -Scopes class="text-pastel-mint">"Device.ReadWrite.All"34$DaysInactive = 905$InactiveDate = (Get-Date).AddDays(-$DaysInactive)67$StaleDevices = Get-MgDevice -All | Where-Object {8 $_.ApproximateLastSignInDateTime -lt $InactiveDate -and9 $_.ApproximateLastSignInDateTime -ne $null10}1112Write-Host class="text-pastel-mint">"Found $($StaleDevices.Count) stale devices (>$DaysInactive days inactive)" -ForegroundColor Yellow1314foreach ($Device in $StaleDevices) {15 $DaysInactive = ((Get-Date) - $Device.ApproximateLastSignInDateTime).Days16 17 Write-Host class="text-pastel-mint">"Device: $($Device.DisplayName) - Last Sign-In: $($Device.ApproximateLastSignInDateTime) ($DaysInactive days)" -ForegroundColor Cyan18 19 class=class="text-pastel-mint">"text-foreground/50 italic"># Uncomment to actually delete devices20 class=class="text-pastel-mint">"text-foreground/50 italic"># Remove-MgDevice -DeviceId $Device.Id21 class=class="text-pastel-mint">"text-foreground/50 italic"># Write-Host class="text-pastel-mint">"Removed: $($Device.DisplayName)" -ForegroundColor Red22}2324Write-Host class="text-pastel-mint">"`nReview complete. Uncomment removal code to delete devices." -ForegroundColor YellowCreate Application Registration
Register new application with API permissions and secrets
1class=class="text-pastel-mint">"text-foreground/50 italic"># Create new application registration2Connect-MgGraph -Scopes class="text-pastel-mint">"Application.ReadWrite.All"34$AppName = class="text-pastel-mint">"MyCustomApplication"56class=class="text-pastel-mint">"text-foreground/50 italic"># Define required API permissions7$RequiredResourceAccess = @{8 ResourceAppId = class="text-pastel-mint">"00000003-0000-0000-c000-000000000000" class=class="text-pastel-mint">"text-foreground/50 italic"># Microsoft Graph9 ResourceAccess = @(10 @{11 Id = class="text-pastel-mint">"e1fe6dd8-ba31-4d61-89e7-88639da4683d" class=class="text-pastel-mint">"text-foreground/50 italic"># User.Read12 Type = class="text-pastel-mint">"Scope"13 },14 @{15 Id = class="text-pastel-mint">"df021288-bdef-4463-88db-98f22de89214" class=class="text-pastel-mint">"text-foreground/50 italic"># User.Read.All16 Type = class="text-pastel-mint">"Role"17 }18 )19}2021$AppParams = @{22 DisplayName = $AppName23 SignInAudience = class="text-pastel-mint">"AzureADMyOrg"24 RequiredResourceAccess = @($RequiredResourceAccess)25}2627try {28 $App = New-MgApplication @AppParams29 Write-Host class="text-pastel-mint">"Application created: $($App.DisplayName)" -ForegroundColor Green30 Write-Host class="text-pastel-mint">"Application ID: $($App.AppId)" -ForegroundColor Cyan31 Write-Host class="text-pastel-mint">"Object ID: $($App.Id)" -ForegroundColor Cyan32 33 class=class="text-pastel-mint">"text-foreground/50 italic"># Create client secret34 $SecretParams = @{35 PasswordCredential = @{36 DisplayName = class="text-pastel-mint">"Auto-generated secret"37 }38 }39 $Secret = Add-MgApplicationPassword -ApplicationId $App.Id -BodyParameter $SecretParams40 Write-Host class="text-pastel-mint">"Client Secret: $($Secret.SecretText)" -ForegroundColor Yellow41 Write-Host class="text-pastel-mint">"Secret Expiry: $($Secret.EndDateTime)" -ForegroundColor Yellow42 43} catch {44 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red45}Export Sign-In Logs with Analytics
Export and analyze sign-in logs for security and compliance reporting
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export and analyze sign-in logs2Connect-MgGraph -Scopes class="text-pastel-mint">"AuditLog.Read.All", class="text-pastel-mint">"Directory.Read.All"34$StartDate = (Get-Date).AddDays(-30)5$SignIns = Get-MgAuditLogSignIn -Filter class="text-pastel-mint">"createdDateTime ge $($StartDate.ToString('yyyy-MM-ddclass="text-pastel-mint">'))" -All67Write-Host class="text-pastel-mint">"Processing $($SignIns.Count) sign-in events..." -ForegroundColor Cyan89$SignInReport = $SignIns | Select-Object @{Name=class="text-pastel-mint">'User';Expression={$_.UserPrincipalName}},10 @{Name=class="text-pastel-mint">'DateTime';Expression={$_.CreatedDateTime}},11 @{Name=class="text-pastel-mint">'Status';Expression={if($_.Status.ErrorCode -eq 0){class="text-pastel-mint">"Success"}else{class="text-pastel-mint">"Failed"}}},12 @{Name=class="text-pastel-mint">'ErrorCode';Expression={$_.Status.ErrorCode}},13 @{Name=class="text-pastel-mint">'Application';Expression={$_.AppDisplayName}},14 @{Name=class="text-pastel-mint">'IPAddress';Expression={$_.IPAddress}},15 @{Name=class="text-pastel-mint">'City';Expression={$_.Location.City}},16 @{Name=class="text-pastel-mint">'Country';Expression={$_.Location.CountryOrRegion}},17 @{Name=class="text-pastel-mint">'DeviceOS';Expression={$_.DeviceDetail.OperatingSystem}}1819class=class="text-pastel-mint">"text-foreground/50 italic"># Generate statistics20$TotalSignIns = $SignInReport.Count21$SuccessfulSignIns = ($SignInReport | Where-Object Status -eq class="text-pastel-mint">"Success").Count22$FailedSignIns = ($SignInReport | Where-Object Status -eq class="text-pastel-mint">"Failed").Count2324Write-Host class="text-pastel-mint">"`nSign-In Statistics:" -ForegroundColor Green25Write-Host class="text-pastel-mint">"Total: $TotalSignIns" -ForegroundColor White26Write-Host class="text-pastel-mint">"Successful: $SuccessfulSignIns" -ForegroundColor Green27Write-Host class="text-pastel-mint">"Failed: $FailedSignIns" -ForegroundColor Red2829$SignInReport | Export-Csv -Path class="text-pastel-mint">"SignInLogs_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationConfigure Guest User Access Settings
Manage external collaboration settings and guest user permissions
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure guest user access settings2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.ReadWrite.Authorization"34class=class="text-pastel-mint">"text-foreground/50 italic"># Get current authorization policy5$AuthPolicy = Get-MgPolicyAuthorizationPolicy67Write-Host class="text-pastel-mint">"Current Guest User Access Settings:" -ForegroundColor Cyan8Write-Host class="text-pastel-mint">"Allow Invitations From: $($AuthPolicy.AllowInvitesFrom)" -ForegroundColor White9Write-Host class="text-pastel-mint">"Guest User Role: $($AuthPolicy.GuestUserRoleId)" -ForegroundColor White1011class=class="text-pastel-mint">"text-foreground/50 italic"># Update guest user settings (example)12$UpdateParams = @{13 AllowInvitesFrom = class="text-pastel-mint">"adminsAndGuestInviters" class=class="text-pastel-mint">"text-foreground/50 italic"># Options: none, adminsAndGuestInviters, adminsGuestInvitersAndAllMembers, everyone14 AllowedToSignUpEmailBasedSubscriptions = $false15 AllowedToUseSspr = $false16 AllowEmailVerifiedUsersToJoinOrganization = $false17 BlockMsolPowerShell = $true18}1920try {21 Update-MgPolicyAuthorizationPolicy -AuthorizationPolicyId $AuthPolicy.Id -BodyParameter $UpdateParams22 Write-Host class="text-pastel-mint">"`nGuest access settings updated successfully" -ForegroundColor Green23} catch {24 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red25}2627class=class="text-pastel-mint">"text-foreground/50 italic"># List current guest users28$Guests = Get-MgUser -Filter class="text-pastel-mint">"userType eq 'Guestclass="text-pastel-mint">'" -All29Write-Host class="text-pastel-mint">"`nTotal Guest Users: $($Guests.Count)" -ForegroundColor YellowAudit MFA Registration Status
Check MFA registration status for all users and identify gaps
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit MFA registration status2Connect-MgGraph -Scopes class="text-pastel-mint">"UserAuthenticationMethod.Read.All", class="text-pastel-mint">"User.Read.All"34$Users = Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled5$MFAReport = @()67foreach ($User in $Users | Where-Object AccountEnabled -eq $true) {8 try {9 $AuthMethods = Get-MgUserAuthenticationMethod -UserId $User.Id10 11 $HasMFA = $AuthMethods.AdditionalProperties.class="text-pastel-mint">'@odata.type' -contains class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.phoneAuthenticationMethod' -or12 $AuthMethods.AdditionalProperties.class="text-pastel-mint">'@odata.type' -contains class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.microsoftAuthenticatorAuthenticationMethod'13 14 $MFAReport += [PSCustomObject]@{15 DisplayName = $User.DisplayName16 UserPrincipalName = $User.UserPrincipalName17 MFAEnabled = $HasMFA18 AuthMethodCount = $AuthMethods.Count19 Methods = ($AuthMethods.AdditionalProperties.class="text-pastel-mint">'@odata.type' -replace class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.', class="text-pastel-mint">'') -join class="text-pastel-mint">", "20 }21 } catch {22 Write-Host class="text-pastel-mint">"Error processing: $($User.UserPrincipalName)" -ForegroundColor Yellow23 }24}2526$MFAEnabled = ($MFAReport | Where-Object MFAEnabled -eq $true).Count27$MFADisabled = ($MFAReport | Where-Object MFAEnabled -eq $false).Count2829Write-Host class="text-pastel-mint">"MFA Status Summary:" -ForegroundColor Cyan30Write-Host class="text-pastel-mint">"Enabled: $MFAEnabled" -ForegroundColor Green31Write-Host class="text-pastel-mint">"Not Enabled: $MFADisabled" -ForegroundColor Red3233$MFAReport | Export-Csv -Path class="text-pastel-mint">"MFAStatus_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationSync User Attributes from CSV
Bulk update user properties like department, title, and location
1class=class="text-pastel-mint">"text-foreground/50 italic"># Bulk update user attributes from CSV2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># CSV should have: UserPrincipalName, Department, JobTitle, OfficeLocation, MobilePhone5$Updates = Import-Csv -Path class="text-pastel-mint">"C:\Updates\UserAttributes.csv"67foreach ($Update in $Updates) {8 try {9 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$($Update.UserPrincipalName)class="text-pastel-mint">'"10 11 if ($User) {12 $UpdateParams = @{}13 14 if ($Update.Department) { $UpdateParams[class="text-pastel-mint">'Department'] = $Update.Department }15 if ($Update.JobTitle) { $UpdateParams[class="text-pastel-mint">'JobTitle'] = $Update.JobTitle }16 if ($Update.OfficeLocation) { $UpdateParams[class="text-pastel-mint">'OfficeLocation'] = $Update.OfficeLocation }17 if ($Update.MobilePhone) { $UpdateParams[class="text-pastel-mint">'MobilePhone'] = $Update.MobilePhone }18 19 Update-MgUser -UserId $User.Id @UpdateParams20 Write-Host class="text-pastel-mint">"Updated: $($User.DisplayName)" -ForegroundColor Green21 } else {22 Write-Host class="text-pastel-mint">"User not found: $($Update.UserPrincipalName)" -ForegroundColor Yellow23 }24 } catch {25 Write-Host class="text-pastel-mint">"Error updating $($Update.UserPrincipalName): $($_.Exception.Message)" -ForegroundColor Red26 }27}2829Write-Host class="text-pastel-mint">"Attribute sync completed" -ForegroundColor CyanExport RBAC Role Assignments
Generate comprehensive report of all RBAC role assignments
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export all RBAC role assignments2Connect-MgGraph -Scopes class="text-pastel-mint">"RoleManagement.Read.Directory", class="text-pastel-mint">"Directory.Read.All"34$RoleDefinitions = Get-MgRoleManagementDirectoryRoleDefinition -All5$Report = @()67foreach ($Role in $RoleDefinitions) {8 Write-Host class="text-pastel-mint">"Processing: $($Role.DisplayName)" -ForegroundColor Cyan9 10 $Assignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter class="text-pastel-mint">"roleDefinitionId eq '$($Role.Id)class="text-pastel-mint">'" -All11 12 foreach ($Assignment in $Assignments) {13 try {14 $Principal = Get-MgDirectoryObject -DirectoryObjectId $Assignment.PrincipalId15 16 $Report += [PSCustomObject]@{17 RoleName = $Role.DisplayName18 RoleDescription = $Role.Description19 PrincipalName = $Principal.AdditionalProperties.displayName20 PrincipalType = $Principal.AdditionalProperties.class="text-pastel-mint">'@odata.type' -replace class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.', class="text-pastel-mint">''21 PrincipalId = $Assignment.PrincipalId22 AssignedDate = $Assignment.CreatedDateTime23 DirectoryScopeId = $Assignment.DirectoryScopeId24 }25 } catch {26 Write-Host class="text-pastel-mint">"Error processing assignment: $($Assignment.Id)" -ForegroundColor Yellow27 }28 }29}3031Write-Host class="text-pastel-mint">"Total assignments: $($Report.Count)" -ForegroundColor Green32$Report | Export-Csv -Path class="text-pastel-mint">"RBACAssignments_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation33$Report | Format-Table RoleName, PrincipalName, PrincipalType -AutoSizeMonitor OAuth Consent Grants
Audit OAuth2 permission grants and identify potential security risks
1class=class="text-pastel-mint">"text-foreground/50 italic"># Monitor OAuth consent grants2Connect-MgGraph -Scopes class="text-pastel-mint">"Directory.Read.All", class="text-pastel-mint">"DelegatedPermissionGrant.ReadWrite.All"34$ConsentGrants = Get-MgOauth2PermissionGrant -All5$Report = @()67foreach ($Grant in $ConsentGrants) {8 try {9 $ServicePrincipal = Get-MgServicePrincipal -ServicePrincipalId $Grant.ClientId10 $Principal = if ($Grant.PrincipalId) { Get-MgUser -UserId $Grant.PrincipalId } else { $null }11 12 $Report += [PSCustomObject]@{13 ApplicationName = $ServicePrincipal.DisplayName14 ApplicationId = $ServicePrincipal.AppId15 ConsentType = $Grant.ConsentType16 PrincipalName = if ($Principal) { $Principal.DisplayName } else { class="text-pastel-mint">"All Users" }17 Scope = $Grant.Scope18 ExpiryTime = $Grant.ExpiryTime19 StartTime = $Grant.StartTime20 }21 } catch {22 Write-Host class="text-pastel-mint">"Error processing grant: $($Grant.Id)" -ForegroundColor Yellow23 }24}2526class=class="text-pastel-mint">"text-foreground/50 italic"># Identify high-risk permissions27$HighRiskScopes = class="text-pastel-mint">"Mail.Read", class="text-pastel-mint">"Files.ReadWrite", class="text-pastel-mint">"User.ReadWrite.All"28$RiskyGrants = $Report | Where-Object { 29 $Scope = $_.Scope30 $HighRiskScopes | Where-Object { $Scope -like class="text-pastel-mint">"*$_*" }31}3233Write-Host class="text-pastel-mint">"Total consent grants: $($Report.Count)" -ForegroundColor Cyan34Write-Host class="text-pastel-mint">"High-risk grants: $($RiskyGrants.Count)" -ForegroundColor Yellow3536$Report | Export-Csv -Path class="text-pastel-mint">"ConsentGrants_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationManage Deleted Users Recycle Bin
Review and permanently delete or restore users from recycle bin
1class=class="text-pastel-mint">"text-foreground/50 italic"># Manage deleted users in recycle bin2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># Get deleted users (in recycle bin)5$DeletedUsers = Get-MgDirectoryDeletedItem -DirectoryObjectId microsoft.graph.user -All67Write-Host class="text-pastel-mint">"Found $($DeletedUsers.Count) deleted users in recycle bin" -ForegroundColor Yellow89$DeletedReport = $DeletedUsers | ForEach-Object {10 [PSCustomObject]@{11 DisplayName = $_.AdditionalProperties.displayName12 UserPrincipalName = $_.AdditionalProperties.userPrincipalName13 DeletedDateTime = $_.DeletedDateTime14 DaysInRecycleBin = ((Get-Date) - $_.DeletedDateTime).Days15 Id = $_.Id16 }17}1819$DeletedReport | Sort-Object DaysInRecycleBin -Descending | Format-Table -AutoSize2021class=class="text-pastel-mint">"text-foreground/50 italic"># Restore a user (example)22class=class="text-pastel-mint">"text-foreground/50 italic"># Restore-MgDirectoryDeletedItem -DirectoryObjectId class="text-pastel-mint">"user-id-here"2324class=class="text-pastel-mint">"text-foreground/50 italic"># Permanently delete a user (example)25class=class="text-pastel-mint">"text-foreground/50 italic"># Remove-MgDirectoryDeletedItem -DirectoryObjectId class="text-pastel-mint">"user-id-here"2627Write-Host class="text-pastel-mint">"`nUsers will be auto-deleted after 30 days" -ForegroundColor Cyan28$DeletedReport | Export-Csv -Path class="text-pastel-mint">"DeletedUsers_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationAudit All Directory Role Assignments
Comprehensive audit of directory roles and their members
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit directory role assignments2Connect-MgGraph -Scopes class="text-pastel-mint">"Directory.Read.All", class="text-pastel-mint">"RoleManagement.Read.All"34$DirectoryRoles = Get-MgDirectoryRole -All5$RoleReport = @()67foreach ($Role in $DirectoryRoles) {8 Write-Host class="text-pastel-mint">"Processing: $($Role.DisplayName)" -ForegroundColor Cyan9 10 $Members = Get-MgDirectoryRoleMember -DirectoryRoleId $Role.Id -All11 12 if ($Members.Count -eq 0) {13 $RoleReport += [PSCustomObject]@{14 RoleName = $Role.DisplayName15 RoleDescription = $Role.Description16 MemberName = class="text-pastel-mint">"No members"17 MemberType = class="text-pastel-mint">"N/A"18 MemberUPN = class="text-pastel-mint">"N/A"19 }20 } else {21 foreach ($Member in $Members) {22 $RoleReport += [PSCustomObject]@{23 RoleName = $Role.DisplayName24 RoleDescription = $Role.Description25 MemberName = $Member.AdditionalProperties.displayName26 MemberType = $Member.AdditionalProperties.class="text-pastel-mint">'@odata.type' -replace class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.', class="text-pastel-mint">''27 MemberUPN = $Member.AdditionalProperties.userPrincipalName28 }29 }30 }31}3233Write-Host class="text-pastel-mint">"`nTotal roles: $($DirectoryRoles.Count)" -ForegroundColor Green34Write-Host class="text-pastel-mint">"Total assignments: $(($RoleReport | Where-Object MemberName -ne 'No membersclass="text-pastel-mint">').Count)" -ForegroundColor Green3536$RoleReport | Export-Csv -Path class="text-pastel-mint">"DirectoryRoles_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation37$RoleReport | Format-Table RoleName, MemberName, MemberType -AutoSizeEnforce Group Naming Policy
Validate and enforce naming conventions for Entra ID groups
1class=class="text-pastel-mint">"text-foreground/50 italic"># Enforce group naming policy2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.Read.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># Define naming convention: [Type]-[Department]-[Purpose]5$NamingPattern = class="text-pastel-mint">"^(Security|M365|Distribution)-(IT|HR|Finance|Sales|Marketing)-[A-Za-z0-9]+$"67$AllGroups = Get-MgGroup -All8$NonCompliantGroups = @()910foreach ($Group in $AllGroups) {11 if ($Group.DisplayName -notmatch $NamingPattern) {12 $NonCompliantGroups += [PSCustomObject]@{13 GroupName = $Group.DisplayName14 GroupId = $Group.Id15 GroupType = if ($Group.SecurityEnabled) { class="text-pastel-mint">"Security" } else { class="text-pastel-mint">"Microsoft 365" }16 CreatedDateTime = $Group.CreatedDateTime17 ExpectedFormat = class="text-pastel-mint">"[Type]-[Department]-[Purpose]"18 }19 }20}2122Write-Host class="text-pastel-mint">"Total Groups: $($AllGroups.Count)" -ForegroundColor Cyan23Write-Host class="text-pastel-mint">"Compliant: $(($AllGroups.Count - $NonCompliantGroups.Count))" -ForegroundColor Green24Write-Host class="text-pastel-mint">"Non-Compliant: $($NonCompliantGroups.Count)" -ForegroundColor Red2526if ($NonCompliantGroups.Count -gt 0) {27 Write-Host class="text-pastel-mint">"`nNon-Compliant Groups:" -ForegroundColor Yellow28 $NonCompliantGroups | Format-Table GroupName, GroupType, ExpectedFormat -AutoSize29 $NonCompliantGroups | Export-Csv -Path class="text-pastel-mint">"NonCompliantGroups_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation30}Monitor Privileged Access Usage
Track usage of privileged roles and generate compliance reports
1class=class="text-pastel-mint">"text-foreground/50 italic"># Monitor privileged access usage2Connect-MgGraph -Scopes class="text-pastel-mint">"AuditLog.Read.All", class="text-pastel-mint">"Directory.Read.All", class="text-pastel-mint">"RoleManagement.Read.All"34$StartDate = (Get-Date).AddDays(-7)5$PrivilegedRoles = Get-MgDirectoryRole | Where-Object { $_.DisplayName -like class="text-pastel-mint">"*Admin*" }6$Report = @()78foreach ($Role in $PrivilegedRoles) {9 $Members = Get-MgDirectoryRoleMember -DirectoryRoleId $Role.Id10 11 foreach ($Member in $Members) {12 try {13 $User = Get-MgUser -UserId $Member.Id -Property DisplayName, UserPrincipalName, SignInActivity14 15 class=class="text-pastel-mint">"text-foreground/50 italic"># Get audit logs for this user16 $AuditLogs = Get-MgAuditLogSignIn -Filter class="text-pastel-mint">"userId eq '$($User.Id)class="text-pastel-mint">' and createdDateTime ge $($StartDate.ToString('yyyy-MM-ddclass="text-pastel-mint">'))" -Top 5017 18 $Report += [PSCustomObject]@{19 RoleName = $Role.DisplayName20 UserName = $User.DisplayName21 UserPrincipalName = $User.UserPrincipalName22 LastSignIn = $User.SignInActivity.LastSignInDateTime23 SignInCount = $AuditLogs.Count24 LastActivity = if ($AuditLogs) { ($AuditLogs | Sort-Object CreatedDateTime -Descending | Select-Object -First 1).CreatedDateTime } else { class="text-pastel-mint">"No activity" }25 }26 } catch {27 Write-Host class="text-pastel-mint">"Error processing user: $($Member.Id)" -ForegroundColor Yellow28 }29 }30}3132Write-Host class="text-pastel-mint">"Privileged Access Report (Last 7 Days)" -ForegroundColor Cyan33$Report | Export-Csv -Path class="text-pastel-mint">"PrivilegedAccess_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation34$Report | Format-Table -AutoSizeConfigure External Identity Settings
Manage B2B collaboration and external identity provider settings
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure external identity settings2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.ReadWrite.CrossTenantAccess", class="text-pastel-mint">"Policy.Read.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># Get current cross-tenant access settings5$CrossTenantPolicy = Get-MgPolicyCrossTenantAccessPolicyDefault67Write-Host class="text-pastel-mint">"Current External Identity Settings:" -ForegroundColor Cyan8Write-Host class="text-pastel-mint">"Inbound Trust:" -ForegroundColor Yellow9Write-Host class="text-pastel-mint">" MFA Trusted: $($CrossTenantPolicy.InboundTrust.IsMfaAccepted)" -ForegroundColor White10Write-Host class="text-pastel-mint">" Compliant Device Trusted: $($CrossTenantPolicy.InboundTrust.IsCompliantDeviceAccepted)" -ForegroundColor White11Write-Host class="text-pastel-mint">" Hybrid Azure AD Joined Trusted: $($CrossTenantPolicy.InboundTrust.IsHybridAzureADJoinedDeviceAccepted)" -ForegroundColor White1213class=class="text-pastel-mint">"text-foreground/50 italic"># Update settings (example)14$UpdateParams = @{15 InboundTrust = @{16 IsMfaAccepted = $true17 IsCompliantDeviceAccepted = $true18 IsHybridAzureADJoinedDeviceAccepted = $true19 }20}2122try {23 Update-MgPolicyCrossTenantAccessPolicyDefault -BodyParameter $UpdateParams24 Write-Host class="text-pastel-mint">"`nExternal identity settings updated successfully" -ForegroundColor Green25} catch {26 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red27}2829class=class="text-pastel-mint">"text-foreground/50 italic"># List external collaboration restrictions30Write-Host class="text-pastel-mint">"`nB2B Collaboration Status:" -ForegroundColor Cyan31Write-Host class="text-pastel-mint">"Guest users can be invited and can collaborate" -ForegroundColor GreenTrack License Assignment Changes
Monitor and report license assignment changes over time
1class=class="text-pastel-mint">"text-foreground/50 italic"># Track license assignment changes2Connect-MgGraph -Scopes class="text-pastel-mint">"AuditLog.Read.All", class="text-pastel-mint">"Directory.Read.All"34$StartDate = (Get-Date).AddDays(-30)56class=class="text-pastel-mint">"text-foreground/50 italic"># Get audit logs for license changes7$AuditLogs = Get-MgAuditLogDirectoryAudit -Filter class="text-pastel-mint">"activityDateTime ge $($StartDate.ToString('yyyy-MM-ddclass="text-pastel-mint">')) and category eq 'UserManagementclass="text-pastel-mint">'" -All89$LicenseChanges = $AuditLogs | Where-Object { 10 $_.TargetResources.ModifiedProperties.DisplayName -contains class="text-pastel-mint">"AssignedLicense"11}1213$Report = foreach ($Log in $LicenseChanges) {14 [PSCustomObject]@{15 DateTime = $Log.ActivityDateTime16 Activity = $Log.ActivityDisplayName17 InitiatedBy = $Log.InitiatedBy.User.UserPrincipalName18 TargetUser = $Log.TargetResources[0].UserPrincipalName19 TargetUserName = $Log.TargetResources[0].DisplayName20 Result = $Log.Result21 }22}2324Write-Host class="text-pastel-mint">"License Changes (Last 30 Days)" -ForegroundColor Cyan25Write-Host class="text-pastel-mint">"Total Changes: $($Report.Count)" -ForegroundColor Yellow2627$Report | Sort-Object DateTime -Descending | Format-Table -AutoSize28$Report | Export-Csv -Path class="text-pastel-mint">"LicenseChanges_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationValidate User Profile Data Quality
Check for incomplete or missing user profile information
1class=class="text-pastel-mint">"text-foreground/50 italic"># Validate user profile data quality2Connect-MgGraph -Scopes class="text-pastel-mint">"User.Read.All"34$Users = Get-MgUser -All -Property DisplayName, UserPrincipalName, Department, JobTitle, MobilePhone, OfficeLocation, Manager56$IncompleteProfiles = $Users | Where-Object {7 -not $_.Department -or8 -not $_.JobTitle -or9 -not $_.MobilePhone -or10 -not $_.OfficeLocation11} | Select-Object DisplayName, UserPrincipalName,12 @{Name=class="text-pastel-mint">'MissingDepartment';Expression={-not $_.Department}},13 @{Name=class="text-pastel-mint">'MissingJobTitle';Expression={-not $_.JobTitle}},14 @{Name=class="text-pastel-mint">'MissingMobilePhone';Expression={-not $_.MobilePhone}},15 @{Name=class="text-pastel-mint">'MissingOfficeLocation';Expression={-not $_.OfficeLocation}},16 @{Name=class="text-pastel-mint">'MissingFieldCount';Expression={17 $count = 018 if (-not $_.Department) { $count++ }19 if (-not $_.JobTitle) { $count++ }20 if (-not $_.MobilePhone) { $count++ }21 if (-not $_.OfficeLocation) { $count++ }22 $count23 }}2425Write-Host class="text-pastel-mint">"Data Quality Report:" -ForegroundColor Cyan26Write-Host class="text-pastel-mint">"Total Users: $($Users.Count)" -ForegroundColor White27Write-Host class="text-pastel-mint">"Incomplete Profiles: $($IncompleteProfiles.Count)" -ForegroundColor Yellow28Write-Host class="text-pastel-mint">"Complete Profiles: $(($Users.Count - $IncompleteProfiles.Count))" -ForegroundColor Green2930$IncompleteProfiles | Sort-Object MissingFieldCount -Descending | Export-Csv -Path class="text-pastel-mint">"IncompleteProfiles_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation31$IncompleteProfiles | Format-Table -AutoSizeConfigure Emergency Access Accounts
Set up and monitor break-glass emergency access accounts
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure emergency access (break-glass) accounts2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All", class="text-pastel-mint">"RoleManagement.ReadWrite.Directory"34class=class="text-pastel-mint">"text-foreground/50 italic"># Emergency access account configuration5$EmergencyAccounts = @(6 class="text-pastel-mint">"emergencyaccess1@yourdomain.com",7 class="text-pastel-mint">"emergencyaccess2@yourdomain.com"8)910Write-Host class="text-pastel-mint">"Emergency Access Account Configuration" -ForegroundColor Cyan1112foreach ($AccountUPN in $EmergencyAccounts) {13 try {14 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$AccountUPNclass="text-pastel-mint">'"15 16 if ($User) {17 class=class="text-pastel-mint">"text-foreground/50 italic"># Verify account settings18 Write-Host class="text-pastel-mint">"`nAccount: $($User.DisplayName)" -ForegroundColor Yellow19 Write-Host class="text-pastel-mint">" Enabled: $($User.AccountEnabled)" -ForegroundColor White20 Write-Host class="text-pastel-mint">" Password Never Expires: Check manually" -ForegroundColor White21 22 class=class="text-pastel-mint">"text-foreground/50 italic"># Check role assignments23 $Roles = Get-MgUserMemberOf -UserId $User.Id | Where-Object { 24 $_.AdditionalProperties.class="text-pastel-mint">'@odata.type' -eq class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.directoryRole'25 }26 27 Write-Host class="text-pastel-mint">" Assigned Roles: $($Roles.Count)" -ForegroundColor White28 $Roles | ForEach-Object { Write-Host class="text-pastel-mint">" - $($_.AdditionalProperties.displayName)" -ForegroundColor Cyan }29 30 class=class="text-pastel-mint">"text-foreground/50 italic"># Check last sign-in31 $SignIn = $User.SignInActivity.LastSignInDateTime32 if ($SignIn) {33 $DaysSinceSignIn = ((Get-Date) - $SignIn).Days34 Write-Host class="text-pastel-mint">" Last Sign-In: $SignIn ($DaysSinceSignIn days ago)" -ForegroundColor $(if ($DaysSinceSignIn -lt 90) { class="text-pastel-mint">'Red' } else { class="text-pastel-mint">'Green' })35 }36 }37 } catch {38 Write-Host class="text-pastel-mint">"Error checking $AccountUPN : $($_.Exception.Message)" -ForegroundColor Red39 }40}4142Write-Host class="text-pastel-mint">"`nBest Practices:" -ForegroundColor Green43Write-Host class="text-pastel-mint">"- Store credentials in secure physical location" -ForegroundColor White44Write-Host class="text-pastel-mint">"- Exclude from MFA requirements" -ForegroundColor White45Write-Host class="text-pastel-mint">"- Exclude from Conditional Access policies" -ForegroundColor White46Write-Host class="text-pastel-mint">"- Monitor for any usage" -ForegroundColor WhiteExport Detailed User License Report
Generate detailed report of license assignments per user
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export detailed user license report2Connect-MgGraph -Scopes class="text-pastel-mint">"User.Read.All", class="text-pastel-mint">"Organization.Read.All"34$Users = Get-MgUser -All -Property DisplayName, UserPrincipalName, AssignedLicenses, Department, AccountEnabled5$SKUs = Get-MgSubscribedSku6$Report = @()78foreach ($User in $Users) {9 if ($User.AssignedLicenses.Count -gt 0) {10 foreach ($License in $User.AssignedLicenses) {11 $SKU = $SKUs | Where-Object { $_.SkuId -eq $License.SkuId }12 13 $Report += [PSCustomObject]@{14 DisplayName = $User.DisplayName15 UserPrincipalName = $User.UserPrincipalName16 Department = $User.Department17 AccountEnabled = $User.AccountEnabled18 LicenseName = $SKU.SkuPartNumber19 LicenseId = $License.SkuId20 DisabledPlans = $License.DisabledPlans.Count21 }22 }23 } else {24 $Report += [PSCustomObject]@{25 DisplayName = $User.DisplayName26 UserPrincipalName = $User.UserPrincipalName27 Department = $User.Department28 AccountEnabled = $User.AccountEnabled29 LicenseName = class="text-pastel-mint">"No License"30 LicenseId = class="text-pastel-mint">"N/A"31 DisabledPlans = 032 }33 }34}3536Write-Host class="text-pastel-mint">"User License Report" -ForegroundColor Cyan37Write-Host class="text-pastel-mint">"Total Users: $($Users.Count)" -ForegroundColor White38Write-Host class="text-pastel-mint">"Licensed Users: $(($Report | Where-Object LicenseName -ne 'No Licenseclass="text-pastel-mint">' | Select-Object -Unique UserPrincipalName).Count)" -ForegroundColor Green39Write-Host class="text-pastel-mint">"Unlicensed Users: $(($Report | Where-Object LicenseName -eq 'No Licenseclass="text-pastel-mint">').Count)" -ForegroundColor Yellow4041$Report | Export-Csv -Path class="text-pastel-mint">"UserLicenses_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationAudit Conditional Access Policy Usage
Analyze which Conditional Access policies are being triggered
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit Conditional Access policy usage2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.Read.All", class="text-pastel-mint">"AuditLog.Read.All"34$StartDate = (Get-Date).AddDays(-7)5$SignIns = Get-MgAuditLogSignIn -Filter class="text-pastel-mint">"createdDateTime ge $($StartDate.ToString('yyyy-MM-ddclass="text-pastel-mint">'))" -Top 100067class=class="text-pastel-mint">"text-foreground/50 italic"># Analyze CA policy results8$CAResults = $SignIns | Where-Object { $_.ConditionalAccessStatus -ne class="text-pastel-mint">'notApplied' } | 9 Select-Object -ExpandProperty AppliedConditionalAccessPolicies1011$PolicyStats = $CAResults | Group-Object DisplayName | ForEach-Object {12 [PSCustomObject]@{13 PolicyName = $_.Name14 TimesApplied = $_.Count15 SuccessCount = ($_.Group | Where-Object Result -eq class="text-pastel-mint">'success').Count16 FailureCount = ($_.Group | Where-Object Result -eq class="text-pastel-mint">'failure').Count17 NotAppliedCount = ($_.Group | Where-Object Result -eq class="text-pastel-mint">'notApplied').Count18 }19} | Sort-Object TimesApplied -Descending2021Write-Host class="text-pastel-mint">"Conditional Access Policy Usage (Last 7 Days)" -ForegroundColor Cyan22Write-Host class="text-pastel-mint">"Total Sign-Ins Analyzed: $($SignIns.Count)" -ForegroundColor White23Write-Host class="text-pastel-mint">"Sign-Ins with CA Applied: $(($SignIns | Where-Object ConditionalAccessStatus -ne 'notAppliedclass="text-pastel-mint">').Count)" -ForegroundColor Yellow2425$PolicyStats | Format-Table -AutoSize26$PolicyStats | Export-Csv -Path class="text-pastel-mint">"CAPolicyUsage_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationBulk Disable User Accounts
Disable multiple user accounts from CSV for offboarding
1class=class="text-pastel-mint">"text-foreground/50 italic"># Bulk disable user accounts2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34class=class="text-pastel-mint">"text-foreground/50 italic"># CSV should have column: UserPrincipalName5$UsersToDisable = Import-Csv -Path class="text-pastel-mint">"C:\Offboarding\UsersToDisable.csv"67Write-Host class="text-pastel-mint">"Processing $($UsersToDisable.Count) users for disabling..." -ForegroundColor Yellow89foreach ($Item in $UsersToDisable) {10 try {11 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$($Item.UserPrincipalName)class="text-pastel-mint">'"12 13 if ($User) {14 if ($User.AccountEnabled -eq $true) {15 Update-MgUser -UserId $User.Id -AccountEnabled $false16 17 class=class="text-pastel-mint">"text-foreground/50 italic"># Revoke sessions18 Revoke-MgUserSignInSession -UserId $User.Id19 20 Write-Host class="text-pastel-mint">"Disabled: $($User.DisplayName) - Sessions revoked" -ForegroundColor Yellow21 } else {22 Write-Host class="text-pastel-mint">"Already disabled: $($User.DisplayName)" -ForegroundColor Cyan23 }24 } else {25 Write-Host class="text-pastel-mint">"User not found: $($Item.UserPrincipalName)" -ForegroundColor Red26 }27 } catch {28 Write-Host class="text-pastel-mint">"Error disabling $($Item.UserPrincipalName): $($_.Exception.Message)" -ForegroundColor Red29 }30}3132Write-Host class="text-pastel-mint">"`nBulk disable operation completed" -ForegroundColor GreenManage Dynamic Group Rules
Create and test dynamic membership rules for groups
1class=class="text-pastel-mint">"text-foreground/50 italic"># Manage dynamic group membership rules2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.ReadWrite.All", class="text-pastel-mint">"User.Read.All"34function Test-DynamicGroupRule {5 param(6 [string]$MembershipRule7 )8 9 Write-Host class="text-pastel-mint">"`nTesting rule: $MembershipRule" -ForegroundColor Cyan10 11 class=class="text-pastel-mint">"text-foreground/50 italic"># Sample test: Get users that would match12 class=class="text-pastel-mint">"text-foreground/50 italic"># Note: Actual validation requires implementing rule parser13 Write-Host class="text-pastel-mint">"Rule syntax appears valid" -ForegroundColor Green14 return $true15}1617class=class="text-pastel-mint">"text-foreground/50 italic"># Common dynamic group rule examples18$RuleExamples = @(19 @{20 Name = class="text-pastel-mint">"All IT Department Users"21 Rule = class="text-pastel-mint">'(user.department -eq "ITclass="text-pastel-mint">") and (user.accountEnabled -eq true)'22 },23 @{24 Name = class="text-pastel-mint">"Managers Only"25 Rule = class="text-pastel-mint">'(user.jobTitle -contains "Managerclass="text-pastel-mint">") and (user.accountEnabled -eq true)'26 },27 @{28 Name = class="text-pastel-mint">"Sales Team with Licenses"29 Rule = class="text-pastel-mint">'(user.department -eq "Salesclass="text-pastel-mint">") and (user.assignedLicenses -any (assignedLicenses/any(s:s/skuId -eq "license-guidclass="text-pastel-mint">")))'30 },31 @{32 Name = class="text-pastel-mint">"Users in Specific Location"33 Rule = class="text-pastel-mint">'(user.country -eq "United Statesclass="text-pastel-mint">") and (user.usageLocation -eq "USclass="text-pastel-mint">")'34 }35)3637Write-Host class="text-pastel-mint">"Dynamic Group Rule Examples:" -ForegroundColor Cyan3839foreach ($Example in $RuleExamples) {40 Write-Host class="text-pastel-mint">"`n$($Example.Name):" -ForegroundColor Yellow41 Write-Host class="text-pastel-mint">" $($Example.Rule)" -ForegroundColor White42 Test-DynamicGroupRule -MembershipRule $Example.Rule43}4445Write-Host class="text-pastel-mint">"`nUse these rules when creating dynamic groups with New-MgGroup" -ForegroundColor GreenExport User Authentication Methods
Report on all authentication methods registered by users
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export user authentication methods2Connect-MgGraph -Scopes class="text-pastel-mint">"UserAuthenticationMethod.Read.All", class="text-pastel-mint">"User.Read.All"34$Users = Get-MgUser -All -Property DisplayName, UserPrincipalName | Select-Object -First 1005$Report = @()67foreach ($User in $Users) {8 try {9 $AuthMethods = Get-MgUserAuthenticationMethod -UserId $User.Id10 11 $Methods = @{12 Password = $false13 Phone = $false14 Email = $false15 Authenticator = $false16 FIDO2 = $false17 WindowsHello = $false18 }19 20 foreach ($Method in $AuthMethods) {21 $MethodType = $Method.AdditionalProperties.class="text-pastel-mint">'@odata.type'22 23 switch -Wildcard ($MethodType) {24 class="text-pastel-mint">'*password*' { $Methods.Password = $true }25 class="text-pastel-mint">'*phone*' { $Methods.Phone = $true }26 class="text-pastel-mint">'*email*' { $Methods.Email = $true }27 class="text-pastel-mint">'*microsoftAuthenticator*' { $Methods.Authenticator = $true }28 class="text-pastel-mint">'*fido2*' { $Methods.FIDO2 = $true }29 class="text-pastel-mint">'*windowsHello*' { $Methods.WindowsHello = $true }30 }31 }32 33 $Report += [PSCustomObject]@{34 DisplayName = $User.DisplayName35 UserPrincipalName = $User.UserPrincipalName36 TotalMethods = $AuthMethods.Count37 Password = $Methods.Password38 Phone = $Methods.Phone39 Email = $Methods.Email40 Authenticator = $Methods.Authenticator41 FIDO2 = $Methods.FIDO242 WindowsHello = $Methods.WindowsHello43 }44 } catch {45 Write-Host class="text-pastel-mint">"Error processing: $($User.UserPrincipalName)" -ForegroundColor Yellow46 }47}4849$Report | Export-Csv -Path class="text-pastel-mint">"AuthMethods_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation50Write-Host class="text-pastel-mint">"Authentication methods exported for $($Report.Count) users" -ForegroundColor Green51$Report | Format-Table -AutoSizeMonitor Administrative Activity
Track all administrative actions in Entra ID
1class=class="text-pastel-mint">"text-foreground/50 italic"># Monitor administrative activity2Connect-MgGraph -Scopes class="text-pastel-mint">"AuditLog.Read.All", class="text-pastel-mint">"Directory.Read.All"34$StartDate = (Get-Date).AddDays(-7)5$AdminActivities = Get-MgAuditLogDirectoryAudit -Filter class="text-pastel-mint">"activityDateTime ge $($StartDate.ToString('yyyy-MM-ddclass="text-pastel-mint">'))" -All67class=class="text-pastel-mint">"text-foreground/50 italic"># Focus on high-privilege activities8$CriticalActivities = @(9 class="text-pastel-mint">"Add member to role",10 class="text-pastel-mint">"Remove member from role",11 class="text-pastel-mint">"Update user",12 class="text-pastel-mint">"Delete user",13 class="text-pastel-mint">"Reset user password",14 class="text-pastel-mint">"Add service principal",15 class="text-pastel-mint">"Update policy"16)1718$Report = $AdminActivities | Where-Object { 19 $_.ActivityDisplayName -in $CriticalActivities 20} | ForEach-Object {21 [PSCustomObject]@{22 DateTime = $_.ActivityDateTime23 Activity = $_.ActivityDisplayName24 InitiatedBy = $_.InitiatedBy.User.UserPrincipalName25 TargetResource = $_.TargetResources[0].DisplayName26 Result = $_.Result27 Category = $_.Category28 }29} | Sort-Object DateTime -Descending3031Write-Host class="text-pastel-mint">"Administrative Activity Report (Last 7 Days)" -ForegroundColor Cyan32Write-Host class="text-pastel-mint">"Total Admin Actions: $($Report.Count)" -ForegroundColor Yellow3334class=class="text-pastel-mint">"text-foreground/50 italic"># Group by initiator35$ByAdmin = $Report | Group-Object InitiatedBy | Sort-Object Count -Descending3637Write-Host class="text-pastel-mint">"`nTop Administrators by Activity:" -ForegroundColor Yellow38$ByAdmin | Select-Object Name, Count | Format-Table -AutoSize3940$Report | Export-Csv -Path class="text-pastel-mint">"AdminActivity_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformationConfigure Guest User Restrictions
Set granular permissions for guest user access
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure guest user restrictions2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.ReadWrite.Authorization"34class=class="text-pastel-mint">"text-foreground/50 italic"># Get current authorization policy5$AuthPolicy = Get-MgPolicyAuthorizationPolicy67Write-Host class="text-pastel-mint">"Current Guest User Restrictions:" -ForegroundColor Cyan8Write-Host class="text-pastel-mint">"Guest User Role: $($AuthPolicy.GuestUserRoleId)" -ForegroundColor White9Write-Host class="text-pastel-mint">"Allow Invitations From: $($AuthPolicy.AllowInvitesFrom)" -ForegroundColor White10Write-Host class="text-pastel-mint">"Block MSOL PowerShell: $($AuthPolicy.BlockMsolPowerShell)" -ForegroundColor White1112class=class="text-pastel-mint">"text-foreground/50 italic"># Configure restrictive guest settings13$GuestRestrictions = @{14 class=class="text-pastel-mint">"text-foreground/50 italic"># Most restrictive: Guest users have limited access to properties and memberships15 GuestUserRoleId = class="text-pastel-mint">"10dae51f-b6af-4016-8d66-8c2a99b929b3"16 17 class=class="text-pastel-mint">"text-foreground/50 italic"># Only admins can invite18 AllowInvitesFrom = class="text-pastel-mint">"adminsAndGuestInviters"19 20 class=class="text-pastel-mint">"text-foreground/50 italic"># Disable MSOL PowerShell for guests21 BlockMsolPowerShell = $true22 23 class=class="text-pastel-mint">"text-foreground/50 italic"># Prevent guest users from creating tenants24 DefaultUserRolePermissions = @{25 AllowedToCreateApps = $false26 AllowedToCreateSecurityGroups = $false27 AllowedToReadOtherUsers = $true28 }29}3031try {32 Write-Host class="text-pastel-mint">"`nApplying guest user restrictions..." -ForegroundColor Yellow33 Update-MgPolicyAuthorizationPolicy -AuthorizationPolicyId $AuthPolicy.Id -BodyParameter $GuestRestrictions34 Write-Host class="text-pastel-mint">"Guest restrictions updated successfully" -ForegroundColor Green35 36 Write-Host class="text-pastel-mint">"`nRecommended Additional Steps:" -ForegroundColor Cyan37 Write-Host class="text-pastel-mint">"1. Enable guest access reviews" -ForegroundColor White38 Write-Host class="text-pastel-mint">"2. Set guest invite restrictions in Azure Portal" -ForegroundColor White39 Write-Host class="text-pastel-mint">"3. Configure external collaboration settings" -ForegroundColor White40 41} catch {42 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red43}Export Group Ownership Report
List all groups and their designated owners
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export group ownership report2Connect-MgGraph -Scopes class="text-pastel-mint">"Group.Read.All", class="text-pastel-mint">"User.Read.All"34$Groups = Get-MgGroup -All5$Report = @()67foreach ($Group in $Groups) {8 $Owners = Get-MgGroupOwner -GroupId $Group.Id9 10 if ($Owners.Count -eq 0) {11 $Report += [PSCustomObject]@{12 GroupName = $Group.DisplayName13 GroupType = if ($Group.SecurityEnabled) { class="text-pastel-mint">"Security" } else { class="text-pastel-mint">"Microsoft 365" }14 OwnerName = class="text-pastel-mint">"No Owner"15 OwnerUPN = class="text-pastel-mint">"N/A"16 MemberCount = (Get-MgGroupMember -GroupId $Group.Id -All).Count17 }18 } else {19 foreach ($Owner in $Owners) {20 $Report += [PSCustomObject]@{21 GroupName = $Group.DisplayName22 GroupType = if ($Group.SecurityEnabled) { class="text-pastel-mint">"Security" } else { class="text-pastel-mint">"Microsoft 365" }23 OwnerName = $Owner.AdditionalProperties.displayName24 OwnerUPN = $Owner.AdditionalProperties.userPrincipalName25 MemberCount = (Get-MgGroupMember -GroupId $Group.Id -All).Count26 }27 }28 }29}3031$NoOwner = ($Report | Where-Object OwnerName -eq class="text-pastel-mint">"No Owner").Count3233Write-Host class="text-pastel-mint">"Group Ownership Report" -ForegroundColor Cyan34Write-Host class="text-pastel-mint">"Total Groups: $($Groups.Count)" -ForegroundColor White35Write-Host class="text-pastel-mint">"Groups Without Owners: $NoOwner" -ForegroundColor Yellow3637$Report | Export-Csv -Path class="text-pastel-mint">"GroupOwners_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation38$Report | Format-Table GroupName, GroupType, OwnerName -AutoSizeAudit User Consent Permissions
Review permissions users have consented to for applications
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit user consent permissions2Connect-MgGraph -Scopes class="text-pastel-mint">"DelegatedPermissionGrant.Read.All", class="text-pastel-mint">"User.Read.All", class="text-pastel-mint">"Application.Read.All"34$ConsentGrants = Get-MgOauth2PermissionGrant -All5$Report = @()67foreach ($Grant in $ConsentGrants | Where-Object { $_.ConsentType -eq class="text-pastel-mint">'Principal' }) {8 try {9 $User = Get-MgUser -UserId $Grant.PrincipalId -Property DisplayName, UserPrincipalName10 $ServicePrincipal = Get-MgServicePrincipal -ServicePrincipalId $Grant.ClientId11 12 $Report += [PSCustomObject]@{13 UserName = $User.DisplayName14 UserPrincipalName = $User.UserPrincipalName15 ApplicationName = $ServicePrincipal.DisplayName16 ApplicationId = $ServicePrincipal.AppId17 Permissions = $Grant.Scope18 ConsentDate = $Grant.StartTime19 ExpiryDate = $Grant.ExpiryTime20 }21 } catch {22 Write-Host class="text-pastel-mint">"Error processing grant: $($Grant.Id)" -ForegroundColor Yellow23 }24}2526class=class="text-pastel-mint">"text-foreground/50 italic"># Identify risky consents27$RiskyKeywords = @(class="text-pastel-mint">"Mail.Read", class="text-pastel-mint">"Files.ReadWrite", class="text-pastel-mint">"Mail.Send", class="text-pastel-mint">"Contacts.Read", class="text-pastel-mint">"Calendars.Read")28$RiskyConsents = $Report | Where-Object {29 $Permissions = $_.Permissions30 $RiskyKeywords | Where-Object { $Permissions -like class="text-pastel-mint">"*$_*" }31}3233Write-Host class="text-pastel-mint">"User Consent Audit" -ForegroundColor Cyan34Write-Host class="text-pastel-mint">"Total User Consents: $($Report.Count)" -ForegroundColor White35Write-Host class="text-pastel-mint">"Risky Consents: $($RiskyConsents.Count)" -ForegroundColor Yellow3637$Report | Export-Csv -Path class="text-pastel-mint">"UserConsents_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation38$RiskyConsents | Format-Table UserName, ApplicationName, Permissions -AutoSizeManage Temporary Access Pass
Create temporary access passes for passwordless authentication
1class=class="text-pastel-mint">"text-foreground/50 italic"># Manage Temporary Access Pass (TAP)2Connect-MgGraph -Scopes class="text-pastel-mint">"UserAuthenticationMethod.ReadWrite.All"34function New-TemporaryAccessPass {5 param(6 [Parameter(Mandatory=$true)]7 [string]$UserPrincipalName,8 [int]$LifetimeInMinutes = 60,9 [switch]$OneTimeUse10 )11 12 try {13 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$UserPrincipalNameclass="text-pastel-mint">'"14 15 $TapParams = @{16 class="text-pastel-mint">"@odata.type" = class="text-pastel-mint">"class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.temporaryAccessPassAuthenticationMethod"17 lifetimeInMinutes = $LifetimeInMinutes18 isUsableOnce = $OneTimeUse.IsPresent19 }20 21 $TAP = New-MgUserAuthenticationTemporaryAccessPassMethod -UserId $User.Id -BodyParameter $TapParams22 23 Write-Host class="text-pastel-mint">"Temporary Access Pass Created" -ForegroundColor Green24 Write-Host class="text-pastel-mint">"User: $($User.DisplayName)" -ForegroundColor Cyan25 Write-Host class="text-pastel-mint">"TAP: $($TAP.TemporaryAccessPass)" -ForegroundColor Yellow26 Write-Host class="text-pastel-mint">"Valid for: $LifetimeInMinutes minutes" -ForegroundColor White27 Write-Host class="text-pastel-mint">"One-time use: $($OneTimeUse.IsPresent)" -ForegroundColor White28 Write-Host class="text-pastel-mint">"Start Time: $($TAP.StartDateTime)" -ForegroundColor White29 30 return $TAP31 } catch {32 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red33 }34}3536class=class="text-pastel-mint">"text-foreground/50 italic"># Example usage37class=class="text-pastel-mint">"text-foreground/50 italic"># New-TemporaryAccessPass -UserPrincipalName class="text-pastel-mint">"user@domain.com" -LifetimeInMinutes 480 -OneTimeUse3839Write-Host class="text-pastel-mint">"Use New-TemporaryAccessPass function to create TAPs" -ForegroundColor Cyan40Write-Host class="text-pastel-mint">"Example: New-TemporaryAccessPass -UserPrincipalName 'user@domain.comclass="text-pastel-mint">' -LifetimeInMinutes 60" -ForegroundColor YellowGenerate Compliance Audit Report
Comprehensive compliance report for auditing and governance
1class=class="text-pastel-mint">"text-foreground/50 italic"># Generate comprehensive compliance report2Connect-MgGraph -Scopes class="text-pastel-mint">"User.Read.All", class="text-pastel-mint">"Group.Read.All", class="text-pastel-mint">"RoleManagement.Read.All", class="text-pastel-mint">"AuditLog.Read.All"34$ReportDate = Get-Date -Format class="text-pastel-mint">"yyyyMMdd_HHmmss"5$OutputPath = class="text-pastel-mint">"C:\ComplianceReports\Compliance_$ReportDate"6New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null78Write-Host class="text-pastel-mint">"Generating Comprehensive Compliance Report..." -ForegroundColor Cyan910class=class="text-pastel-mint">"text-foreground/50 italic"># 1. User Account Status11Write-Host class="text-pastel-mint">"[1/6] Collecting user data..." -ForegroundColor Yellow12$Users = Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled, CreatedDateTime, SignInActivity13$Users | Export-Csv -Path class="text-pastel-mint">"$OutputPath\Users.csv" -NoTypeInformation1415class=class="text-pastel-mint">"text-foreground/50 italic"># 2. Admin Role Assignments16Write-Host class="text-pastel-mint">"[2/6] Collecting admin roles..." -ForegroundColor Yellow17$AdminRoles = Get-MgDirectoryRole | Where-Object { $_.DisplayName -like class="text-pastel-mint">"*Admin*" }18$AdminReport = foreach ($Role in $AdminRoles) {19 $Members = Get-MgDirectoryRoleMember -DirectoryRoleId $Role.Id20 foreach ($Member in $Members) {21 [PSCustomObject]@{22 Role = $Role.DisplayName23 Member = $Member.AdditionalProperties.displayName24 MemberUPN = $Member.AdditionalProperties.userPrincipalName25 }26 }27}28$AdminReport | Export-Csv -Path class="text-pastel-mint">"$OutputPath\AdminRoles.csv" -NoTypeInformation2930class=class="text-pastel-mint">"text-foreground/50 italic"># 3. Guest Users31Write-Host class="text-pastel-mint">"[3/6] Collecting guest users..." -ForegroundColor Yellow32$Guests = Get-MgUser -Filter class="text-pastel-mint">"userType eq 'Guestclass="text-pastel-mint">'" -All33$Guests | Export-Csv -Path class="text-pastel-mint">"$OutputPath\GuestUsers.csv" -NoTypeInformation3435class=class="text-pastel-mint">"text-foreground/50 italic"># 4. Inactive Accounts36Write-Host class="text-pastel-mint">"[4/6] Identifying inactive accounts..." -ForegroundColor Yellow37$InactiveDate = (Get-Date).AddDays(-90)38$Inactive = $Users | Where-Object { $_.SignInActivity.LastSignInDateTime -lt $InactiveDate }39$Inactive | Export-Csv -Path class="text-pastel-mint">"$OutputPath\InactiveUsers.csv" -NoTypeInformation4041class=class="text-pastel-mint">"text-foreground/50 italic"># 5. License Usage42Write-Host class="text-pastel-mint">"[5/6] Collecting license data..." -ForegroundColor Yellow43$Licenses = Get-MgSubscribedSku44$Licenses | Select-Object SkuPartNumber, ConsumedUnits, @{N=class="text-pastel-mint">'Available';E={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}} | Export-Csv -Path class="text-pastel-mint">"$OutputPath\Licenses.csv" -NoTypeInformation4546class=class="text-pastel-mint">"text-foreground/50 italic"># 6. Security Groups47Write-Host class="text-pastel-mint">"[6/6] Collecting security groups..." -ForegroundColor Yellow48$Groups = Get-MgGroup -Filter class="text-pastel-mint">"securityEnabled eq true" -All49$Groups | Export-Csv -Path class="text-pastel-mint">"$OutputPath\SecurityGroups.csv" -NoTypeInformation5051class=class="text-pastel-mint">"text-foreground/50 italic"># Summary52Write-Host class="text-pastel-mint">"`nCompliance Report Summary:" -ForegroundColor Green53Write-Host class="text-pastel-mint">"Total Users: $($Users.Count)" -ForegroundColor White54Write-Host class="text-pastel-mint">"Guest Users: $($Guests.Count)" -ForegroundColor White55Write-Host class="text-pastel-mint">"Inactive Users: $($Inactive.Count)" -ForegroundColor Yellow56Write-Host class="text-pastel-mint">"Admin Assignments: $($AdminReport.Count)" -ForegroundColor White57Write-Host class="text-pastel-mint">"Security Groups: $($Groups.Count)" -ForegroundColor White58Write-Host class="text-pastel-mint">"`nReports saved to: $OutputPath" -ForegroundColor CyanConfigure Identity Governance Settings
Set up access reviews and entitlement management
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure Identity Governance settings2Connect-MgGraph -Scopes class="text-pastel-mint">"AccessReview.ReadWrite.All", class="text-pastel-mint">"EntitlementManagement.ReadWrite.All"34Write-Host class="text-pastel-mint">"Identity Governance Configuration" -ForegroundColor Cyan56class=class="text-pastel-mint">"text-foreground/50 italic"># Check for access review capability7try {8 Write-Host class="text-pastel-mint">"`nAccess Review Settings:" -ForegroundColor Yellow9 10 class=class="text-pastel-mint">"text-foreground/50 italic"># Note: Access reviews require Azure AD Premium P211 Write-Host class="text-pastel-mint">"To create an access review:" -ForegroundColor White12 Write-Host class="text-pastel-mint">"1. Define scope (group, application, or role)" -ForegroundColor White13 Write-Host class="text-pastel-mint">"2. Set review frequency (one-time, weekly, monthly, quarterly)" -ForegroundColor White14 Write-Host class="text-pastel-mint">"3. Assign reviewers (members, owners, or managers)" -ForegroundColor White15 Write-Host class="text-pastel-mint">"4. Configure auto-apply results" -ForegroundColor White16 17 Write-Host class="text-pastel-mint">"`nEntitlement Management:" -ForegroundColor Yellow18 Write-Host class="text-pastel-mint">"Create access packages to bundle resources" -ForegroundColor White19 Write-Host class="text-pastel-mint">"Define policies for who can request access" -ForegroundColor White20 Write-Host class="text-pastel-mint">"Set approval workflows" -ForegroundColor White21 Write-Host class="text-pastel-mint">"Configure automatic assignment and expiration" -ForegroundColor White22 23 Write-Host class="text-pastel-mint">"`nBest Practices:" -ForegroundColor Green24 Write-Host class="text-pastel-mint">"- Review admin roles quarterly" -ForegroundColor White25 Write-Host class="text-pastel-mint">"- Review guest access monthly" -ForegroundColor White26 Write-Host class="text-pastel-mint">"- Use access packages for temporary access" -ForegroundColor White27 Write-Host class="text-pastel-mint">"- Enable auto-removal for denied access" -ForegroundColor White28 Write-Host class="text-pastel-mint">"- Maintain audit logs for compliance" -ForegroundColor White29 30} catch {31 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red32 Write-Host class="text-pastel-mint">"Note: Identity Governance requires Azure AD Premium P2" -ForegroundColor Yellow33}Monitor Risky Sign-In Detections
Track and report on risky sign-in events from Identity Protection
1class=class="text-pastel-mint">"text-foreground/50 italic"># Monitor risky sign-in detections2Connect-MgGraph -Scopes class="text-pastel-mint">"IdentityRiskyUser.Read.All", class="text-pastel-mint">"IdentityRiskEvent.Read.All"34$StartDate = (Get-Date).AddDays(-30)56try {7 class=class="text-pastel-mint">"text-foreground/50 italic"># Get risky sign-ins8 $RiskySignIns = Get-MgRiskyUser -All | Where-Object { $_.RiskState -ne class="text-pastel-mint">'none' }9 10 $Report = foreach ($RiskyUser in $RiskySignIns) {11 try {12 $User = Get-MgUser -UserId $RiskyUser.Id -Property DisplayName, UserPrincipalName, Department13 14 [PSCustomObject]@{15 UserName = $User.DisplayName16 UserPrincipalName = $User.UserPrincipalName17 Department = $User.Department18 RiskLevel = $RiskyUser.RiskLevel19 RiskState = $RiskyUser.RiskState20 RiskDetail = $RiskyUser.RiskDetail21 LastUpdated = $RiskyUser.RiskLastUpdatedDateTime22 }23 } catch {24 Write-Host class="text-pastel-mint">"Error processing user: $($RiskyUser.Id)" -ForegroundColor Yellow25 }26 }27 28 class=class="text-pastel-mint">"text-foreground/50 italic"># Categorize by risk level29 $HighRisk = ($Report | Where-Object RiskLevel -eq class="text-pastel-mint">'high').Count30 $MediumRisk = ($Report | Where-Object RiskLevel -eq class="text-pastel-mint">'medium').Count31 $LowRisk = ($Report | Where-Object RiskLevel -eq class="text-pastel-mint">'low').Count32 33 Write-Host class="text-pastel-mint">"Risky Sign-In Report" -ForegroundColor Cyan34 Write-Host class="text-pastel-mint">"High Risk: $HighRisk" -ForegroundColor Red35 Write-Host class="text-pastel-mint">"Medium Risk: $MediumRisk" -ForegroundColor Yellow36 Write-Host class="text-pastel-mint">"Low Risk: $LowRisk" -ForegroundColor Green37 38 $Report | Sort-Object RiskLevel -Descending | Export-Csv -Path class="text-pastel-mint">"RiskySignIns_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation39 $Report | Format-Table -AutoSize40 41} catch {42 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red43 Write-Host class="text-pastel-mint">"Note: Risk detection requires Azure AD Premium P2" -ForegroundColor Yellow44}Configure Security Defaults Settings
Enable or disable security defaults for baseline protection
1class=class="text-pastel-mint">"text-foreground/50 italic"># Configure Security Defaults2Connect-MgGraph -Scopes class="text-pastel-mint">"Policy.ReadWrite.ConditionalAccess", class="text-pastel-mint">"Policy.Read.All"34try {5 class=class="text-pastel-mint">"text-foreground/50 italic"># Get current security defaults status6 $SecurityDefaults = Get-MgPolicyIdentitySecurityDefaultEnforcementPolicy7 8 Write-Host class="text-pastel-mint">"Security Defaults Configuration" -ForegroundColor Cyan9 Write-Host class="text-pastel-mint">"Current Status: $($SecurityDefaults.IsEnabled)" -ForegroundColor $(if($SecurityDefaults.IsEnabled){class="text-pastel-mint">'Green'}else{class="text-pastel-mint">'Yellow'})10 11 Write-Host class="text-pastel-mint">"`nSecurity Defaults Include:" -ForegroundColor Yellow12 Write-Host class="text-pastel-mint">"- Require MFA for administrators" -ForegroundColor White13 Write-Host class="text-pastel-mint">"- Require MFA for users when necessary" -ForegroundColor White14 Write-Host class="text-pastel-mint">"- Block legacy authentication protocols" -ForegroundColor White15 Write-Host class="text-pastel-mint">"- Protect privileged activities (Azure Portal access)" -ForegroundColor White16 Write-Host class="text-pastel-mint">"- Require users to register for MFA" -ForegroundColor White17 18 class=class="text-pastel-mint">"text-foreground/50 italic"># To enable security defaults19 class=class="text-pastel-mint">"text-foreground/50 italic"># Update-MgPolicyIdentitySecurityDefaultEnforcementPolicy -IsEnabled $true20 21 class=class="text-pastel-mint">"text-foreground/50 italic"># To disable security defaults (needed for Conditional Access)22 class=class="text-pastel-mint">"text-foreground/50 italic"># Update-MgPolicyIdentitySecurityDefaultEnforcementPolicy -IsEnabled $false23 24 Write-Host class="text-pastel-mint">"`nNote: Security Defaults and Conditional Access are mutually exclusive" -ForegroundColor Yellow25 Write-Host class="text-pastel-mint">"Disable Security Defaults before implementing CA policies" -ForegroundColor Yellow26 27} catch {28 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red29}Export Application Role Assignments
Report on app role assignments for enterprise applications
1class=class="text-pastel-mint">"text-foreground/50 italic"># Export application role assignments2Connect-MgGraph -Scopes class="text-pastel-mint">"Application.Read.All", class="text-pastel-mint">"Directory.Read.All"34$ServicePrincipals = Get-MgServicePrincipal -All5$Report = @()67Write-Host class="text-pastel-mint">"Processing $($ServicePrincipals.Count) service principals..." -ForegroundColor Cyan89foreach ($SP in $ServicePrincipals) {10 try {11 $AppRoleAssignments = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $SP.Id -All12 13 foreach ($Assignment in $AppRoleAssignments) {14 try {15 $Principal = Get-MgDirectoryObject -DirectoryObjectId $Assignment.PrincipalId16 17 class=class="text-pastel-mint">"text-foreground/50 italic"># Get app role details18 $AppRole = $SP.AppRoles | Where-Object { $_.Id -eq $Assignment.AppRoleId }19 20 $Report += [PSCustomObject]@{21 ApplicationName = $SP.DisplayName22 ApplicationId = $SP.AppId23 PrincipalName = $Principal.AdditionalProperties.displayName24 PrincipalType = $Principal.AdditionalProperties.class="text-pastel-mint">'@odata.type' -replace class="text-pastel-mint">'class="text-foreground/50 italicclass="text-pastel-mint">">#microsoft.graph.', class="text-pastel-mint">''25 PrincipalId = $Assignment.PrincipalId26 RoleName = if ($AppRole) { $AppRole.DisplayName } else { class="text-pastel-mint">"Default" }27 RoleDescription = if ($AppRole) { $AppRole.Description } else { class="text-pastel-mint">"Default Access" }28 AssignedDate = $Assignment.CreatedDateTime29 }30 } catch {31 Write-Host class="text-pastel-mint">"Error processing assignment for $($SP.DisplayName)" -ForegroundColor Yellow32 }33 }34 } catch {35 class=class="text-pastel-mint">"text-foreground/50 italic"># Skip if no assignments36 }37}3839Write-Host class="text-pastel-mint">"Total app role assignments: $($Report.Count)" -ForegroundColor Green40$Report | Export-Csv -Path class="text-pastel-mint">"AppRoleAssignments_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation41$Report | Format-Table ApplicationName, PrincipalName, RoleName -AutoSizeManage User Profile Photos
Bulk upload or export user profile photos
1class=class="text-pastel-mint">"text-foreground/50 italic"># Manage user profile photos2Connect-MgGraph -Scopes class="text-pastel-mint">"User.ReadWrite.All"34function Set-UserProfilePhoto {5 param(6 [Parameter(Mandatory=$true)]7 [string]$UserPrincipalName,8 [Parameter(Mandatory=$true)]9 [string]$PhotoPath10 )11 12 try {13 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$UserPrincipalNameclass="text-pastel-mint">'"14 15 if (Test-Path $PhotoPath) {16 $PhotoBytes = [System.IO.File]::ReadAllBytes($PhotoPath)17 Set-MgUserPhotoContent -UserId $User.Id -InFile $PhotoPath18 19 Write-Host class="text-pastel-mint">"Photo updated for: $($User.DisplayName)" -ForegroundColor Green20 } else {21 Write-Host class="text-pastel-mint">"Photo file not found: $PhotoPath" -ForegroundColor Red22 }23 } catch {24 Write-Host class="text-pastel-mint">"Error: $($_.Exception.Message)" -ForegroundColor Red25 }26}2728function Export-UserProfilePhoto {29 param(30 [Parameter(Mandatory=$true)]31 [string]$UserPrincipalName,32 [Parameter(Mandatory=$true)]33 [string]$OutputPath34 )35 36 try {37 $User = Get-MgUser -Filter class="text-pastel-mint">"userPrincipalName eq '$UserPrincipalNameclass="text-pastel-mint">'"38 Get-MgUserPhotoContent -UserId $User.Id -OutFile $OutputPath39 40 Write-Host class="text-pastel-mint">"Photo exported for: $($User.DisplayName) to $OutputPath" -ForegroundColor Green41 } catch {42 Write-Host class="text-pastel-mint">"No photo found for: $UserPrincipalName" -ForegroundColor Yellow43 }44}4546class=class="text-pastel-mint">"text-foreground/50 italic"># Example usage:47Write-Host class="text-pastel-mint">"User Photo Management Functions:" -ForegroundColor Cyan48Write-Host class="text-pastel-mint">"Set-UserProfilePhoto -UserPrincipalName 'user@domain.comclass="text-pastel-mint">' -PhotoPath 'C:\Photos\user.jpgclass="text-pastel-mint">'" -ForegroundColor Yellow49Write-Host class="text-pastel-mint">"Export-UserProfilePhoto -UserPrincipalName 'user@domain.comclass="text-pastel-mint">' -OutputPath 'C:\Export\user.jpgclass="text-pastel-mint">'" -ForegroundColor YellowAudit Application Credentials Expiry
Monitor and report on expiring app registration credentials
1class=class="text-pastel-mint">"text-foreground/50 italic"># Audit application credentials expiry2Connect-MgGraph -Scopes class="text-pastel-mint">"Application.Read.All"34$Applications = Get-MgApplication -All5$WarningDays = 306$Report = @()78Write-Host class="text-pastel-mint">"Auditing $($Applications.Count) applications..." -ForegroundColor Cyan910foreach ($App in $Applications) {11 class=class="text-pastel-mint">"text-foreground/50 italic"># Check password credentials (secrets)12 foreach ($Secret in $App.PasswordCredentials) {13 $DaysUntilExpiry = ($Secret.EndDateTime - (Get-Date)).Days14 15 if ($DaysUntilExpiry -le $WarningDays) {16 $Report += [PSCustomObject]@{17 ApplicationName = $App.DisplayName18 ApplicationId = $App.AppId19 ObjectId = $App.Id20 CredentialType = class="text-pastel-mint">"Secret"21 KeyId = $Secret.KeyId22 DisplayName = $Secret.DisplayName23 StartDate = $Secret.StartDateTime24 ExpiryDate = $Secret.EndDateTime25 DaysUntilExpiry = $DaysUntilExpiry26 Status = if ($DaysUntilExpiry -lt 0) { class="text-pastel-mint">"Expired" } elseif ($DaysUntilExpiry -le 7) { class="text-pastel-mint">"Critical" } else { class="text-pastel-mint">"Warning" }27 }28 }29 }30 31 class=class="text-pastel-mint">"text-foreground/50 italic"># Check certificate credentials32 foreach ($Cert in $App.KeyCredentials) {33 $DaysUntilExpiry = ($Cert.EndDateTime - (Get-Date)).Days34 35 if ($DaysUntilExpiry -le $WarningDays) {36 $Report += [PSCustomObject]@{37 ApplicationName = $App.DisplayName38 ApplicationId = $App.AppId39 ObjectId = $App.Id40 CredentialType = class="text-pastel-mint">"Certificate"41 KeyId = $Cert.KeyId42 DisplayName = $Cert.DisplayName43 StartDate = $Cert.StartDateTime44 ExpiryDate = $Cert.EndDateTime45 DaysUntilExpiry = $DaysUntilExpiry46 Status = if ($DaysUntilExpiry -lt 0) { class="text-pastel-mint">"Expired" } elseif ($DaysUntilExpiry -le 7) { class="text-pastel-mint">"Critical" } else { class="text-pastel-mint">"Warning" }47 }48 }49 }50}5152$Expired = ($Report | Where-Object Status -eq class="text-pastel-mint">"Expired").Count53$Critical = ($Report | Where-Object Status -eq class="text-pastel-mint">"Critical").Count54$Warning = ($Report | Where-Object Status -eq class="text-pastel-mint">"Warning").Count5556Write-Host class="text-pastel-mint">"`nApplication Credentials Status:" -ForegroundColor Cyan57Write-Host class="text-pastel-mint">"Expired: $Expired" -ForegroundColor Red58Write-Host class="text-pastel-mint">"Critical (<7 days): $Critical" -ForegroundColor Yellow59Write-Host class="text-pastel-mint">"Warning (<30 days): $Warning" -ForegroundColor Yellow6061$Report | Sort-Object DaysUntilExpiry | Export-Csv -Path class="text-pastel-mint">"AppCredentialsExpiry_$(Get-Date -Format 'yyyyMMddclass="text-pastel-mint">').csv" -NoTypeInformation62$Report | Format-Table ApplicationName, CredentialType, DaysUntilExpiry, Status -AutoSizeHave a script to share?
We're always looking for community contributions. Submit your PowerShell scripts and help other administrators automate their workflows.
Submit Your Script