diff --git a/assets/aadconsentgrantpermissiontable.csv b/assets/aadconsentgrantpermissiontable.csv new file mode 100644 index 0000000000..d472e6f92e --- /dev/null +++ b/assets/aadconsentgrantpermissiontable.csv @@ -0,0 +1,57 @@ +Type,Permission,Privilege,Reason +Delegated,Mail.ReadBasic,Medium,DataExfiltration +Delegated,Mail,High,Phishing +Delegated,Contacts,High,Phishing +Delegated,MailboxSettings,High,Phishing +Delegated,People,High,Phishing +Delegated,Files,High,Phishing +Delegated,AllSites,High,Phishing +Delegated,Notes,High,Phishing +Delegated,Policy,High,Phishing +Delegated,AppRoleAssignment.ReadWrite.All,High,Phishing +Delegated,Directory.AccessAsUser.All,High,Phishing +Delegated,user_impersonation,High,Phishing +Delegated,Application.ReadWrite.All,High,BroadImpact +Delegated,Directory.ReadWrite.All,High,BroadImpact +Delegated,Domain.ReadWrite.All,High,BroadImpact +Delegated,EduRoster.ReadWrite.All,High,BroadImpact +Delegated,Group.ReadWrite.All,High,BroadImpact +Delegated,Member.Read.Hidden,High,BroadImpact +Delegated,RoleManagement.ReadWrite.Directory,High,BroadImpact +Delegated,RoleAssignmentSchedule.ReadWrite.Directory,High,BroadImpact +Delegated,RoleEligibilitySchedule.ReadWrite.Directory,High,BroadImpact +Delegated,User.ReadWrite.All,High,BroadImpact +Delegated,User.ManageCreds.All,High,BroadImpact +Delegated,User.Export.All,High,BroadImpact +Application,Mail,High,Phishing +Application,Contacts,High,Phishing +Application,MailboxSettings,High,Phishing +Application,People,High,Phishing +Application,Files,High,Phishing +Application,Sites,High,Phishing +Application,AllSites,High,Phishing +Application,Notes,High,Phishing +Application,Policy,High,BroadImpact +Application,PrivilegedAccess,High,BroadImpact +Application,PrivilegedAssignmentSchedule,High,BroadImpact +Application,PrivilegedEligibilitySchedule,High,BroadImpact +Application,AppRoleAssignment.ReadWrite.All,High,Phishing +Application,Directory.AccessAsUser.All,High,Phishing +Application,user_impersonation,High,Phishing +Application,Application.ReadWrite.All,High,BroadImpact +Application,Directory.ReadWrite.All,High,BroadImpact +Application,Domain.ReadWrite.All,High,BroadImpact +Application,EduRoster.ReadWrite.All,High,BroadImpact +Application,Group.ReadWrite.All,High,BroadImpact +Application,Member.Read.Hidden,High,BroadImpact +Application,UserAuthenticationMethod.ReadWrite.All,High,BroadImpact +Application,RoleManagement.ReadWrite.Directory,High,BroadImpact +Application,User.ReadWrite.All,High,BroadImpact +Application,User.ManageCreds.All,High,BroadImpact +Application,CallRecords.Read.All,High,SensitiveData +Delegated,User.Read,Low,Common pattern +Delegated,User.ReadBasic.All,Low,Common pattern +Delegated,openid,Low,Common pattern +Delegated,email,Low,Common pattern +Delegated,profile,Low,Common pattern +Delegated,offline_access,Low,Common pattern when used with other low permissions \ No newline at end of file diff --git a/samples/authentication/create-custom-app-with-application-permissions.ps1 b/samples/authentication/create-custom-app-with-application-permissions.ps1 new file mode 100644 index 0000000000..cdfb0c6cb7 --- /dev/null +++ b/samples/authentication/create-custom-app-with-application-permissions.ps1 @@ -0,0 +1,51 @@ +# Connect to Entra with required scopes +Connect-Entra -Scopes 'AppRoleAssignment.ReadWrite.All', 'Application.ReadWrite.All', 'User.Read.All', 'Group.Read.All', 'DelegatedPermissionGrant.ReadWrite.All', 'AuditLog.Read.All' + +# Define application name and redirect URI +$appName = "Entra PowerShell App (Application)" +$redirectUri = "http://localhost" + +# Define Application permission and Graph API ID +$applicationPermission = 'Group.Read.All' +$graphApiId = '00000003-0000-0000-c000-000000000000' + +# Get a user and a group +$user = Get-EntraUser -UserId 'AdeleV@contoso.com' +$group = Get-EntraGroup -Search 'Sales and Marketing' + +# Create a new application +$app = New-EntraApplication -DisplayName $appName -PublicClient @{ RedirectUris = $redirectUri } -IsFallbackPublicClient $False + +# Create a service principal for the application +$servicePrincipal = New-EntraServicePrincipal -AppId $app.AppId + +# Assign users and groups to the application +$emptyGuidUser = [Guid]::Empty.ToString() +New-EntraUserAppRoleAssignment -ObjectId $user.Id -PrincipalId $user.Id -ResourceId $servicePrincipal.Id -Id $emptyGuidUser + +$emptyGuidGroup = [Guid]::Empty.ToString() +New-EntraGroupAppRoleAssignment -GroupId $group.Id -PrincipalId $group.Id -ResourceId $servicePrincipal.Id -Id $emptyGuidGroup + +# Get Graph service principal +$graphServicePrincipal = Get-EntraServicePrincipal -Filter "AppId eq '$graphApiId'" + +# Create resource access object +$resourceAccessAppPerms = New-Object Microsoft.Open.MSGraph.Model.ResourceAccess +$resourceAccessAppPerms.Id = ((Get-EntraServicePrincipal -ServicePrincipalId $graphServicePrincipal.ObjectId).AppRoles | Where-Object { $_.Value -eq $applicationPermission}).Id +$resourceAccessAppPerms.Type = 'Scope' + +# Create required resource access object +$requiredResourceAccessAppPerms = New-Object Microsoft.Open.MSGraph.Model.RequiredResourceAccess +$requiredResourceAccessAppPerms.ResourceAppId = $graphApiId +$requiredResourceAccessAppPerms.ResourceAccess = $resourceAccessAppPerms + +# Set application required resource access +Set-EntraApplication -ApplicationId $app.Id -RequiredResourceAccess $requiredResourceAccessAppPerms + +# Set service principal parameters +Set-EntraServicePrincipal -ServicePrincipalId $servicePrincipal.Id -AppRoleAssignmentRequired $True + +# Get application role ID +$appRoleId = ($graphServicePrincipal.AppRoles | Where-Object { $_.Value -eq $applicationPermission }).Id + +New-EntraServicePrincipalAppRoleAssignment -ObjectId $servicePrincipal.Id -ResourceId $graphServicePrincipal.Id -Id $appRoleId -PrincipalId $servicePrincipal.Id \ No newline at end of file diff --git a/samples/authentication/create-custom-app-with-delegated-permissions.ps1 b/samples/authentication/create-custom-app-with-delegated-permissions.ps1 new file mode 100644 index 0000000000..659b0b8f04 --- /dev/null +++ b/samples/authentication/create-custom-app-with-delegated-permissions.ps1 @@ -0,0 +1,52 @@ +# Connect to Entra with required scopes +Connect-Entra -Scopes 'AppRoleAssignment.ReadWrite.All', 'Application.ReadWrite.All', 'User.Read.All', 'Group.Read.All', 'DelegatedPermissionGrant.ReadWrite.All', 'AuditLog.Read.All' + +# Define application name and redirect URI +$appName = "Entra PowerShell App (Delegated)" +$redirectUri = "http://localhost" + +# Define delegated permission and Graph API ID +$delegatedPermission = 'User.Read.All' +$graphApiId = '00000003-0000-0000-c000-000000000000' + +# Get a user and a group +$user = Get-EntraUser -UserId 'AdeleV@contoso.com' +$group = Get-EntraGroup -Search 'Sales and Marketing' + +# Create a new application +$app = New-EntraApplication -DisplayName $appName -PublicClient @{ RedirectUris = $redirectUri } -IsFallbackPublicClient $False + +# Create a service principal for the application +$servicePrincipal = New-EntraServicePrincipal -AppId $app.AppId + +# Assign users and groups to the application +$emptyGuidUser = [Guid]::Empty.ToString() +New-EntraUserAppRoleAssignment -ObjectId $user.Id -PrincipalId $user.Id -ResourceId $servicePrincipal.Id -Id $emptyGuidUser + +$emptyGuidGroup = [Guid]::Empty.ToString() +New-EntraGroupAppRoleAssignment -GroupId $group.Id -PrincipalId $group.Id -ResourceId $servicePrincipal.Id -Id $emptyGuidGroup + +# Get Graph service principal +$graphServicePrincipal = Get-EntraServicePrincipal -Filter "AppId eq '$graphApiId'" + +# Create resource access object +$resourceAccessDelegated = New-Object Microsoft.Open.MSGraph.Model.ResourceAccess +$resourceAccessDelegated.Id = ((Get-EntraServicePrincipal -ServicePrincipalId $graphServicePrincipal.Id).Oauth2PermissionScopes | Where-Object { $_.Value -eq $delegatedPermission }).Id +$resourceAccessDelegated.Type = 'Scope' + +# Create required resource access object +$requiredResourceAccessDelegated = New-Object Microsoft.Open.MSGraph.Model.RequiredResourceAccess +$requiredResourceAccessDelegated.ResourceAppId = $graphApiId +$requiredResourceAccessDelegated.ResourceAccess = $resourceAccessDelegated + +# Set application required resource access +Set-EntraApplication -ApplicationId $app.Id -RequiredResourceAccess $requiredResourceAccessDelegated + +# Set service principal parameters +Set-EntraServicePrincipal -ServicePrincipalId $servicePrincipal.Id -AppRoleAssignmentRequired $True + +# Grant OAuth2 permission +$permissionGrant = New-EntraOauth2PermissionGrant -ClientId $servicePrincipal.Id -ConsentType 'AllPrincipals' -ResourceId $graphServicePrincipal.Id -Scope $delegatedPermission + +# Get and filter OAuth2 permission grants +Get-EntraOAuth2PermissionGrant -All | Where-Object { $_.Id -eq $permissionGrant.Id } \ No newline at end of file diff --git a/samples/entitlement-management/identify-assignment-policies-without-approval.ps1 b/samples/entitlement-management/identify-assignment-policies-without-approval.ps1 new file mode 100644 index 0000000000..7c89f5637f --- /dev/null +++ b/samples/entitlement-management/identify-assignment-policies-without-approval.ps1 @@ -0,0 +1,54 @@ +<# +DISCLAIMER: This script is not an official PowerShell script and is specifically designed for the current situation you are facing. +It is provided "AS IS" with no warranties of any kind, either express or implied, including, but not limited to, any implied warranties of merchantability or fitness for a particular purpose. +This script is not supported by any official Microsoft support programs or services. Microsoft disclaims all implied warranties, including but not limited to implied warranties of merchantability or fitness for a particular purpose. +You assume all risk related to the use or performance of this script and its associated documentation. Under no circumstances shall Microsoft, its authors, or any other party involved in the creation, production, or delivery of this script be liable for any damages (including, but not limited to, loss of business profits, business interruptions, loss of business information, or other financial losses) arising from the use or inability to use the script or documentation, even if Microsoft has been advised of the possibility of such damages. + +This script requires Microsoft Graph v1.0, as its logic depends on specific property values from this version. It is only compatible with Microsoft Graph PowerShell v2.x.x, which ensures that Microsoft Graph v1.0 is used. If you are using Microsoft Graph PowerShell v1, please upgrade to v2. +For more information, visit: https://devblogs.microsoft.com/microsoft365dev/microsoft-graph-powershell-v2-is-now-in-public-preview-half-the-size-and-will-speed-up-your-automations/ + +Ensure you have the appropriate privileges when running this script, such as `Global Reader` or `Identity Governance Administrator`. +#> +Import-Module Microsoft.Graph.Authentication +Import-Module Microsoft.Graph.Identity.Governance + +# Connect to Microsoft Graph with the required scopes +Connect-MgGraph -Scopes EntitlementManagement.Read.All + +# Define allowed target scopes +$allowedTargetScopes = @("allExternalUsers","allConfiguredConnectedOrganizationUsers","specificConnectedOrganizationUsers") +$PoliciesToReview = @() + +Write-Host "Starting to search for policies..." +try{ + $Policies = Get-MgEntitlementManagementAssignmentPolicy -Property Id,DisplayName,AllowedTargetScope,RequestApprovalSettings -All -Top 999 + Write-Host "Successfully imported $($Policies.Count) policies" +}catch{ + Write-Error "Error importing policies: $_" + return +} + +Write-Host "Starting to analyze policies" +foreach($Policy in $Policies){ + if($allowedTargetScopes -contains $Policy.AllowedTargetScope){ + if($Policy.RequestApprovalSettings.IsApprovalRequiredForAdd -ne $true){ + try { + $PolicyDetails = Get-MgEntitlementManagementAssignmentPolicy -AccessPackageAssignmentPolicyId $Policy.Id -ExpandProperty accessPackage,catalog + $PoliciesToReview += $PolicyDetails + } + catch { + Write-Error "Error getting policy details: $_" + return + } + + } + } +} + +Write-Host "Analysis completed we have identified $($PoliciesToReview.Count) policies which should be reviewed:" +Write-Host ($PoliciesToReview | Format-Table | Out-String) + +Write-Host "Access packages associated with these policies:" +Write-Host ($PoliciesToReview.AccessPackage | Format-Table | Out-String) + +Write-Host "Script completed. More information can be found in the `$PoliciesToReview variable." diff --git a/samples/export-apps-with-expiring-secrets-modified.ps1 b/samples/migration/export-apps-with-expiring-secrets-modified.ps1 similarity index 100% rename from samples/export-apps-with-expiring-secrets-modified.ps1 rename to samples/migration/export-apps-with-expiring-secrets-modified.ps1 diff --git a/samples/export-apps-with-expiring-secrets.ps1 b/samples/migration/export-apps-with-expiring-secrets.ps1 similarity index 100% rename from samples/export-apps-with-expiring-secrets.ps1 rename to samples/migration/export-apps-with-expiring-secrets.ps1 diff --git a/samples/sampleGroups.ps1 b/samples/migration/sampleGroups.ps1 similarity index 100% rename from samples/sampleGroups.ps1 rename to samples/migration/sampleGroups.ps1 diff --git a/samples/zero-trust/README.md b/samples/zero-trust/README.md new file mode 100644 index 0000000000..add83fabb6 --- /dev/null +++ b/samples/zero-trust/README.md @@ -0,0 +1,27 @@ +--- +title: Zero Trust Scenarios +description: Zero Trust scenarios. + +ms.service: microsoft-entra-powershell +ms.topic: reference +ms.date: 02/03/2025 +ms.author: eunicewaweru +ms.reviewer: stevemutungi +manager: CelesteDG +author: msewaweru +--- + +# Zero Trust Scenarios + +This section explains how scenario assessments can reduce the attack surface and limit the impact of breaches. + +| Scenario | Rationale | +| -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Inactive applications shouldn't have highly privileged Microsoft Graph API permissions](./get-inactive-apps-with-high-priv-permissions.ps1) | Attackers can exploit inactive yet privileged applications to gain initial access and execute further attacks without detection. They may also manipulate these applications, such as by adding credentials, to maintain persistent access even if their primary method is discovered | +| Scenario 2 | Description of scenario 2 | +| Scenario 3 | Description of scenario 3 | +| Scenario 4 | Description of scenario 4 | +| Scenario 4 | Description of scenario 4 | +| Scenario 4 | Description of scenario 4 | +| Scenario 4 | Description of scenario 4 | +| Scenario 4 | Description of scenario 4 | diff --git a/samples/zero-trust/get-inactive-apps-with-high-priv-permissions.ps1 b/samples/zero-trust/get-inactive-apps-with-high-priv-permissions.ps1 new file mode 100644 index 0000000000..a3b9f58e11 --- /dev/null +++ b/samples/zero-trust/get-inactive-apps-with-high-priv-permissions.ps1 @@ -0,0 +1,92 @@ +# ------------------------------------------------------------------------------ +# Copyright (c) Microsoft Corporation. All Rights Reserved. +# Licensed under the MIT License. See License in the project root for license information. +# ------------------------------------------------------------------------------ + +# Connect to Microsoft Graph with necessary permissions +Connect-Entra -Scopes "Application.Read.All", "Directory.Read.All", "AuditLog.Read.All" -NoWelcome + +# Define inactivity threshold (e.g., 90 days) +$inactiveThreshold = (Get-Date).AddDays(-90) + +# Sample list of highly privileged Microsoft Graph API permissions +$highPrivPermissions = @( + "Directory.ReadWrite.All", + "Directory.AccessAsUser.All", + "User.ReadWrite.All", + "Group.ReadWrite.All", + "Application.ReadWrite.All", + "RoleManagement.ReadWrite.Directory", + "Policy.ReadWrite.ConditionalAccess", + "Device.ReadWrite.All" +) + +# Get Microsoft Graph Service Principal - Note: You can also use the AppId ""00000003-0000-0000-c000-000000000000"" instead of the DisplayName +$msGraphServicePrincipal = Get-EntraServicePrincipal -Filter "displayName eq 'Microsoft Graph'" + +# Map permission IDs to friendly names +$highPrivPermIds = @{} + +foreach ($role in $msGraphServicePrincipal.AppRoles) { + if ($highPrivPermissions -contains $role.Value) { + $highPrivPermIds[$role.Id] = $role.Value + } +} + +foreach ($scope in $msGraphServicePrincipal.OAuth2PermissionScopes) { + if ($highPrivPermissions -contains $scope.Value) { + $highPrivPermIds[$scope.Id] = $scope.Value + } +} + +# Retrieve all registered applications +$applications = Get-EntraApplication -All +$appsWithHighPriv = @() + +foreach ($app in $applications) { + $hasHighPriv = $false + $appHighPrivPermissions = @() + if ($app.RequiredResourceAccess) { + foreach ($req in $app.RequiredResourceAccess) { + if ($req.ResourceAppId -eq $msGraphServicePrincipal.AppId) { + foreach ($perm in $req.ResourceAccess) { + if ($highPrivPermIds.ContainsKey($perm.Id)) { + $hasHighPriv = $true + $appHighPrivPermissions += $highPrivPermIds[$perm.Id] + } + } + } + if ($hasHighPriv) { break } + } + } + if ($hasHighPriv) { + $app | Add-Member -MemberType NoteProperty -Name HighPrivilegedPermissions -Value $appHighPrivPermissions + $appsWithHighPriv += $app + } +} + +# Check inactivity based on sign-in activity +$inactiveApps = @() + +foreach ($app in $appsWithHighPriv) { + $sp = Get-EntraServicePrincipal -Filter "appId eq '$($app.AppId)'" -ErrorAction SilentlyContinue + $lastSignIn = $null + + if ($sp -and $sp.SignInActivity) { + $lastSignIn = $sp.SignInActivity.LastSignInDateTime + } + + # Mark as inactive if never signed in or last sign-in is older than threshold + $isInactive = -not $lastSignIn -or ([datetime]$lastSignIn -lt $inactiveThreshold) + + if ($isInactive) { + $inactiveApps += [PSCustomObject]@{ + ApplicationName = $app.DisplayName + AppId = $app.AppId + LastSignIn = $lastSignIn + HighPrivilegedPermissions = $app.HighPrivilegedPermissions -join ", " + } + } +} + +$inactiveApps | Format-Table -AutoSize