이 문서에서는 이전에 애플리케이션에 부여된 철회된 권한을 복원하는 방법을 알아봅니다. 조직의 데이터에 액세스할 수 있는 권한이 부여된 애플리케이션에 대한 권한을 복원할 수 있습니다. 사용자 역할을 할 수 있는 권한이 부여된 애플리케이션에 대한 권한을 복원할 수도 있습니다.
현재 권한 복원은 Microsoft Graph PowerShell 및 Microsoft Graph API 호출을 통해서만 가능합니다. Microsoft Entra 관리 센터를 통해 권한을 복원할 수 없습니다. 이 문서에서는 Microsoft Graph PowerShell을 사용하여 권한을 복원하는 방법을 알아봅니다.
철회된 권한을 모르는 경우 이 문서에 제공된 스크립트를 사용하여 철회된 권한을 검색하고 복원할 수 있습니다.
먼저 스크립트의 servicePrincipalId 값을 권한을 복원하려는 엔터프라이즈 앱의 ID 값으로 설정합니다. 이 ID는 Microsoft Entra 관리 센터의 엔터프라이즈 애플리케이션 페이지에서 object ID라고도 합니다.
그런 다음, 제거되었을 수 있는 위임된 권한 또는 앱 전용 권한 목록을 보려면 $ForceGrantUpdate = $false를 사용하여 각 스크립트를 실행합니다. 권한이 이미 복원된 경우에도 감사 로그의 철회 이벤트가 스크립트 결과에 계속 나타날 수 있습니다.
스크립트가 검색한 철회된 권한을 복원하려고 시도하도록 하려면 $ForceGrantUpdate를 $true로 설정된 상태로 둡니다. 스크립트는 확인을 요청하지만 복원하는 각 권한에 대해 개별 승인을 요청하지는 않습니다.
앱에 권한을 부여할 때는 주의합니다. 권한을 평가하는 방법에 대해 자세히 알아보려면 권한 평가를 참조하세요.
위임된 권한 복원
PowerShell
# WARNING: Setting $ForceGrantUpdate to true will modify permission grants without# prompting for confirmation. This can result in unintended changes to your# application's security settings. Use with caution!$ForceGrantUpdate = $false# Set the start and end dates for the audit log search# If setting date use yyyy-MM-dd format# endDate is set to tomorrow to include today's audit logs$startDate = (Get-Date).AddDays(-7).ToString('yyyy-MM-dd')
$endDate = (Get-Date).AddDays(1).ToString('yyyy-MM-dd')
# Set the service principal ID$servicePrincipalId = "aaaaaaaa-bbbb-cccc-1111-222222222222"Write-Host"Searching for audit logs between $startDate and $endDate" -ForegroundColor Green
Write-Host"Searching for audit logs for service principal $servicePrincipalId" -ForegroundColor Green
if ($ForceGrantUpdate -eq$true) {
Write-Host"WARNING: ForceGrantUpdate is set to true. This will modify permission grants without prompting for confirmation. This can result in unintended changes to your application's security settings. Use with caution!" -ForegroundColor Red
$continue = Read-Host"Do you want to continue? (Y/N)"if ($continue -eq"Y" -or$continue -eq"y") {
Write-Host"Continuing..."
} else {
Write-Host"Exiting..."exit
}
}
# Connect to MS GraphConnect-MgGraph -Scopes"AuditLog.Read.All","DelegatedPermissionGrant.ReadWrite.All" -ErrorAction Stop | Out-Null# Create a hashtable to store the OAuth2PermissionGrants$oAuth2PermissionGrants = @{}
functionMerge-Scopes($oldScopes, $newScopes) {
$oldScopes = $oldScopes.Trim() -split'\s+'$newScopes = $newScopes.Trim() -split'\s+'$mergedScopesArray = $oldScopes + $newScopes | Select-Object -Unique$mergedScopes = $mergedScopesArray -join' 'return$mergedScopes.Trim()
}
# Function to merge scopes if multiple OAuth2PermissionGrants are found in the audit logsfunctionAdd-Scopes($resourceId, $newScopes) {
if($oAuth2PermissionGrants.ContainsKey($resourceId)) {
$oldScopes = $oAuth2PermissionGrants[$resourceId]
$oAuth2PermissionGrants[$resourceId] = Merge-Scopes$oldScopes$newScopes
}
else {
$oAuth2PermissionGrants[$resourceId] = $newScopes
}
}
functionGet-ScopeDifference ($generatedScope, $currentScope) {
$generatedScopeArray = $generatedScope.Trim() -split'\s+'$currentScopeArray = $currentScope.Trim() -split'\s+'$difference = $generatedScopeArray | Where-Object { $_ -notin$currentScopeArray }
$difference = $difference -join' 'return$difference.Trim()
}
# Set the filter for the audit log search$filterOAuth2PermissionGrant = "activityDateTime ge $startDate and activityDateTime le $endDate" +
" and Result eq 'success'" +
" and ActivityDisplayName eq 'Remove delegated permission grant'" +
" and targetResources/any(x: x/id eq '$servicePrincipalId')"try {
# Retrieve the audit logs for removed OAuth2PermissionGrants$oAuth2PermissionGrantsAuditLogs = Get-MgAuditLogDirectoryAudit -Filter$filterOAuth2PermissionGrant -All -ErrorAction Stop
}
catch {
Disconnect-MgGraph | Out-Nullthrow$_
}
# Remove User Delegated Permission Grants$oAuth2PermissionGrantsAuditLogs = $oAuth2PermissionGrantsAuditLogs | Where-Object {
-not ($_.TargetResources.ModifiedProperties.OldValue -eq'"Principal"')
}
# Merge duplicate OAuth2PermissionGrants from AuditLogs using Add-Scopesforeach ($auditLogin$oAuth2PermissionGrantsAuditLogs) {
$resourceId = $auditLog.TargetResources[0].Id
# We only want to process OAuth2PermissionGrant Audit Logs where $servicePrincipalId is the clientId not the resourceIdif ($resourceId -eq$servicePrincipalId) {
continue
}
$oldScope = $auditLog.TargetResources[0].ModifiedProperties | Where-Object { $_.DisplayName -eq"DelegatedPermissionGrant.Scope" } | Select-Object -ExpandProperty OldValue
if ($oldScope -eq$null) {
$oldScope = ""
}
$oldScope = $oldScope.Replace('"', '')
$newScope = $auditLog.TargetResources[0].ModifiedProperties | Where-Object { $_.DisplayName -eq"DelegatedPermissionGrant.Scope" } | Select-Object -ExpandProperty NewValue
if ($newScope -eq$null) {
$newScope = ""
}
$newScope = $newScope.Replace('"', '')
$scope = Merge-Scopes$oldScope$newScopeAdd-Scopes$resourceId$scope
}
$permissionCount = 0foreach ($resourceIdin$oAuth2PermissionGrants.keys) {
$scope = $oAuth2PermissionGrants[$resourceId]
$params = @{
clientId = $servicePrincipalId
consentType = "AllPrincipals"
resourceId = $resourceId
scope = $scope
}
try {
$currentOAuth2PermissionGrant = Get-MgOauth2PermissionGrant -Filter"clientId eq '$servicePrincipalId' and consentType eq 'AllPrincipals' and resourceId eq '$resourceId'" -ErrorAction Stop
$action = "Creating"if ($currentOAuth2PermissionGrant -ne$null) {
$action = "Updating"
}
Write-Host"--------------------------"if ($ForceGrantUpdate -eq$true) {
Write-Host"$action OAuth2PermissionGrant with the following parameters:"
} else {
Write-Host"Potentially removed OAuth2PermissionGrant scopes with the following parameters:"
}
Write-Host" clientId: $($params.clientId)"Write-Host" consentType: $($params.consentType)"Write-Host" resourceId: $($params.resourceId)"if ($currentOAuth2PermissionGrant -ne$null) {
$scopeDifference = Get-ScopeDifference$scope$currentOAuth2PermissionGrant.Scope
if ($scopeDifference -eq"") {
Write-Host"OAuth2PermissionGrant already exists with the same scope" -ForegroundColor Yellow
if ($ForceGrantUpdate -eq$true) {
Write-Host"Skipping Update" -ForegroundColor Yellow
}
continue
}
else {
Write-Host" scope diff: '$scopeDifference'"
}
}
else {
Write-Host" scope: '$($params.scope)'"
}
if ($ForceGrantUpdate -eq$true -and$currentOAuth2PermissionGrant -eq$null) {
New-MgOauth2PermissionGrant -BodyParameter$params -ErrorAction Stop | Out-NullWrite-Host"OAuth2PermissionGrant was created successfully" -ForegroundColor Green
}
if ($ForceGrantUpdate -eq$true -and$currentOAuth2PermissionGrant -ne$null) {
Write-Host" Current Scope: '$($currentOAuth2PermissionGrant.scope)'" -ForegroundColor Yellow
Write-Host" Merging with scopes from audit logs" -ForegroundColor Yellow
$params.scope = Merge-Scopes$currentOAuth2PermissionGrant.scope $params.scope
Write-Host" New Scope: '$($params.scope)'" -ForegroundColor Yellow
Update-MgOauth2PermissionGrant -OAuth2PermissionGrantId$currentOAuth2PermissionGrant.id -BodyParameter$params -ErrorAction Stop | Out-NullWrite-Host"OAuth2PermissionGrant was updated successfully" -ForegroundColor Green
}
$permissionCount++
}
catch {
Disconnect-MgGraph | Out-Nullthrow$_
}
}
Disconnect-MgGraph | Out-Nullif ($ForceGrantUpdate -eq$true) {
Write-Host"--------------------------"Write-Host"$permissionCount OAuth2PermissionGrants were created/updated successfully" -ForegroundColor Green
} else {
Write-Host"--------------------------"Write-Host"$permissionCount OAuth2PermissionGrants were found" -ForegroundColor Green
}
앱 전용 권한 복원
참고
앱 전용 Microsoft Graph 권한을 부여하려면 권한 있는 역할 관리자 역할이 필요합니다.
PowerShell
# WARNING: Setting $ForceGrantUpdate to true will modify permission grants without# prompting for confirmation. This can result in unintended changes to your# application's security settings. Use with caution!$ForceGrantUpdate = $false# Set the start and end dates for the audit log search# If setting date use yyyy-MM-dd format# endDate is set to tomorrow to include today's audit logs$startDate = (Get-Date).AddDays(-7).ToString('yyyy-MM-dd')
$endDate = (Get-Date).AddDays(1).ToString('yyyy-MM-dd')
# Set the service principal ID$servicePrincipalId = "aaaaaaaa-bbbb-cccc-1111-222222222222"Write-Host"Searching for audit logs between $startDate and $endDate" -ForegroundColor Green
Write-Host"Searching for audit logs for service principal $servicePrincipalId" -ForegroundColor Green
if ($ForceGrantUpdate -eq$true) {
Write-Host"WARNING: ForceGrantUpdate is set to true. This will modify permission grants without prompting for confirmation. This can result in unintended changes to your application's security settings. Use with caution!" -ForegroundColor Red
$continue = Read-Host"Do you want to continue? (Y/N)"if ($continue -eq"Y" -or$continue -eq"y") {
Write-Host"Continuing..."
} else {
Write-Host"Exiting..."exit
}
}
# Connect to MS GraphConnect-MgGraph -Scopes"AuditLog.Read.All","Application.Read.All","AppRoleAssignment.ReadWrite.All" -ErrorAction Stop | Out-Null# Set the filter for the audit log search$filterAppRoleAssignment = "activityDateTime ge $startDate and activityDateTime le $endDate" +
" and Result eq 'success'" +
" and ActivityDisplayName eq 'Remove app role assignment from service principal'" +
" and targetResources/any(x: x/id eq '$servicePrincipalId')"try {
# Retrieve the audit logs for removed AppRoleAssignments$appRoleAssignmentsAuditLogs = Get-MgAuditLogDirectoryAudit -Filter$filterAppRoleAssignment -All -ErrorAction Stop
}
catch {
Disconnect-MgGraph | Out-Nullthrow$_
}
$permissionCount = 0foreach ($auditLogin$appRoleAssignmentsAuditLogs) {
$resourceId = $auditLog.TargetResources[0].Id
# We only want to process AppRoleAssignments Audit Logs where $servicePrincipalId is the principalId not the resourceIdif ($resourceId -eq$servicePrincipalId) {
continue
}
$appRoleId = $auditLog.TargetResources[0].ModifiedProperties | Where-Object { $_.DisplayName -eq"AppRole.Id" } | Select-Object -ExpandProperty OldValue
$appRoleId = $appRoleId.Replace('"', '')
$params = @{
principalId = $servicePrincipalId
resourceId = $resourceId
appRoleId = $appRoleId
}
try {
$sp = Get-MgServicePrincipal -ServicePrincipalId$resourceId$appRole = $sp.AppRoles | Where-Object { $_.Id -eq$appRoleId }
Write-Host"--------------------------"if ($ForceGrantUpdate -eq$true) {
Write-Host"Creating AppRoleAssignment with the following parameters:"
} else {
Write-Host"Potentially removed AppRoleAssignment with the following parameters:"
}
Write-Host" principalId: $($params.principalId)"Write-Host" resourceId: $($params.resourceId)"Write-Host" appRoleId: $($params.appRoleId)"Write-Host" appRoleValue: $($appRole.Value)"Write-Host" appRoleDisplayName: $($appRole.DisplayName)"if ($ForceGrantUpdate -eq$true) {
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId$servicePrincipalId -BodyParameter$params -ErrorAction Stop | Out-NullWrite-Host"AppRoleAssignment was created successfully" -ForegroundColor Green
}
$permissionCount++
}
catch {
if ($_.Exception.Message -like"*Permission being assigned already exists on the object*") {
Write-Host"AppRoleAssignment already exists skipping creation" -ForegroundColor Yellow
}
else {
Disconnect-MgGraph | Out-Nullthrow$_
}
}
}
Disconnect-MgGraph | Out-Nullif ($ForceGrantUpdate -eq$true) {
Write-Host"--------------------------"Write-Host"$permissionCount AppRoleAssignments were created successfully" -ForegroundColor Green
} else {
Write-Host"--------------------------"Write-Host"$permissionCount AppRoleAssignments were found" -ForegroundColor Green
}