Last active
February 28, 2025 23:04
-
-
Save zjorz/b5849c77ef68aefbaab5807786b07ff3 to your computer and use it in GitHub Desktop.
Deleting A Specific Application From Entra ID And From Exchange Online
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$tenantFQDN = "<TENANT NAME>.ONMICROSOFT.COM" # <= CONFIGURE THIS!!!!! | |
$applicationName = "<APPLICATION DISPLAY NAME>" # <= CONFIGURE THIS!!!!! | |
Invoke-Command -ArgumentList $tenantFQDN,$applicationName -ScriptBlock { | |
Param ( | |
$tenantFQDN, | |
$applicationName | |
) | |
<# | |
.SYNOPSIS | |
This PoSH Code The Application In Both Entra ID And Exchange Online That Could Be Used By On-Premises PowerShell Scripts To Send E-mails | |
.DESCRIPTION | |
This PoSH code provides the following functions in the order listed: | |
- Authenticate and get an access token for MSFT Graph API | |
- Authenticate and get an access token for Office 365 Exchange Online | |
- Deletion of a targeted management role assignement in Office 365 Exchange Online | |
- Deletion of a targeted management scope in Office 365 Exchange Online | |
- Deletion of a targeted Service Principal in Office 365 Exchange Online | |
- Deletion of a targeted Service Principal in Entra ID | |
- Deletion of a targeted Application Registration in Entra ID | |
.NOTES | |
- Requires => PSMSALNet Module (https://github.com/SCOMnewbie/PSMSALNet) to authenticate against Entra ID for all actions performed by this script/code | |
- Requires PowerShell v7.4 or higher | |
- For Entra ID Related Tasks/Actions..........: membership of the "Application Administrator", "Cloud Application Administrator" OR "Global Administrator" built-in role is required | |
- For Exchange Online Related Tasks/Actions...: membership of the "Exchange Administrator" OR "Global Administrator" built-in role is required | |
- The PowerShell code requires the permissions to execute all actions during the same run | |
- Through Exchange Online PoSH CMDlets | |
- Install-Module -Name ExchangeOnlineManagement | |
- Import-module ExchangeOnlineManagement | |
- Connect-ExchangeOnline -Organization XXXXXX.ONMICROSOFT.COM | |
- Get-ManagementRoleAssignment | Sort-Object -Property Name | |
- Get-ManagementScope | |
- Get-ServicePrincipal | |
#> | |
Write-Host "" | |
Write-Host "###############################################################################" -Foregroundcolor Yellow | |
Write-Host "### Deleting A Send Mail Application In Entra ID ###" -Foregroundcolor Yellow | |
Write-Host "###############################################################################" -Foregroundcolor Yellow | |
################################################################ | |
### FUNCTIONS ### | |
################################################################ | |
# FUNCTION: Get The OpenID Configuration For The Specified Entra ID Tenant FQDN. | |
Function Get-MSFTApiOpenIDConfiguration { | |
<# | |
.SYNOPSIS | |
Get The OpenID Configuration For The Specified Entra ID Tenant FQDN. | |
.DESCRIPTION | |
Get The OpenID Configuration For The Specified Entra ID Tenant FQDN. | |
.PARAMETER tenantFQDN | |
The FQDN Of The Entra ID Tenant Being Targeted. | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE, ValueFromPipeline = $TRUE, ValueFromPipelineByPropertyName = $TRUE, HelpMessage = 'Please Specify The Entra ID Tenant FQDN')] | |
[ValidateNotNullOrEmpty()] | |
[String]$tenantFQDN | |
) | |
Begin { | |
# Specify The Tenant Specific Discovery Endpoint URL | |
$oidcConfigDiscoveryURL = "https://login.microsoftonline.com/$tenantFQDN/v2.0/.well-known/openid-configuration" | |
} | |
Process { | |
$oidcTenantConfig = Invoke-RestMethod -Uri $oidcConfigDiscoveryURL | |
Return $oidcTenantConfig | |
} | |
} | |
# FUNCTION: Get The Entra ID Tenant ID From The OIDC Configuration. | |
Function Get-MSFTTenantID { | |
<# | |
.SYNOPSIS | |
Get The Entra ID Tenant ID From The OIDC Configuration. | |
.DESCRIPTION | |
Get The Entra ID Tenant ID From The OIDC Configuration. | |
.PARAMETER oidcTenantConfig | |
The OIDC Configuration Of The Entra ID Tenant Being Targeted. | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[System.Management.Automation.PSObject]$oidcTenantConfig | |
) | |
Begin { | |
$tenantID = $null | |
} | |
Process { | |
$tenantID = $oidcTenantConfig.authorization_endpoint.Split("/")[3] | |
Return $tenantID | |
} | |
} | |
# FUNCTION: Remove The Management Role Assignment In Office 365 Exchange Online | |
Function Remove-EXOApiManagementRoleAssignment { | |
<# | |
.SYNOPSIS | |
Remove The Management Role Assignment In Office 365 Exchange Online | |
.DESCRIPTION | |
Remove The Management Role Assignment In Office 365 Exchange Online | |
.PARAMETER accessToken | |
The Access Token To Be Used To Execute The Operation | |
.PARAMETER managementScopeAssignmentName | |
The Management Role Assignment Name | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$accessToken, | |
[Parameter(Mandatory = $FALSE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$managementRoleAssignmentName | |
) | |
Begin { | |
$requestHeader = $null | |
$requestBody = $null | |
$response = $null | |
} | |
Process { | |
# Define The Request Header To Execute The Required Action | |
$requestHeader = @{ | |
Authorization = "Bearer $accessToken" | |
} | |
Write-Verbose "Request Header...........................: $($requestHeader | Out-String)" | |
# Define The Request Body To Execute The Required Action | |
$requestBody = [PSCustomObject]@{ | |
CmdletInput = [PSCustomObject]@{ | |
CmdletName = "Remove-ManagementRoleAssignment" | |
Parameters = [PSCustomObject]@{ | |
Identity = $managementRoleAssignmentName | |
Confirm = $false | |
} | |
} | |
} | |
Write-Verbose "Request Body.............................: $($requestBody | Out-String)" | |
# Get The Response From The Office 365 Exchange Online API | |
Try { | |
$response = Invoke-RestMethod -UseBasicParsing -Uri "https://outlook.office365.com/adminapi/beta/$tenantID/InvokeCommand" -Method POST -Headers $requestHeader -Body $($requestBody | ConvertTo-Json) -ContentType "application/json; charset=UTF-8" -ErrorAction Stop | |
Write-Verbose "Removed The Exchange Online Management Role Assignment '$managementScopeAssignmentName'" | |
} Catch { | |
If ($_.ErrorDetails.Message) { | |
$err = $_.ErrorDetails.Message | ConvertFrom-Json | |
$errorMessage = $err.error.details.message | |
} Else { | |
$errorMessage = $_ | |
} | |
Throw $errorMessage | |
} | |
# Return | |
Return $response | |
} | |
} | |
# FUNCTION: Remove The Management Scope In Office 365 Exchange Online | |
Function Remove-EXOApiManagementScope { | |
<# | |
.SYNOPSIS | |
Remove The Management Scope In Office 365 Exchange Online | |
.DESCRIPTION | |
Remove The Management Scope In Office 365 Exchange Online | |
.PARAMETER accessToken | |
The Access Token To Be Used To Execute The Operation | |
.PARAMETER managementScopeName | |
The Management Scope Name | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$accessToken, | |
[Parameter(Mandatory = $FALSE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$managementScopeName | |
) | |
Begin { | |
$requestHeader = $null | |
$requestBody = $null | |
$response = $null | |
} | |
Process { | |
# Define The Request Header To Execute The Required Action | |
$requestHeader = @{ | |
Authorization = "Bearer $accessToken" | |
} | |
Write-Verbose "Request Header...........................: $($requestHeader | Out-String)" | |
# Define The Request Body To Execute The Required Action | |
$requestBody = [PSCustomObject]@{ | |
CmdletInput = [PSCustomObject]@{ | |
CmdletName = "Remove-ManagementScope" | |
Parameters = [PSCustomObject]@{ | |
Identity = $managementScopeName | |
Confirm = $false | |
} | |
} | |
} | |
Write-Verbose "Request Body.............................: $($requestBody | Out-String)" | |
# Get The Response From The Office 365 Exchange Online API | |
Try { | |
$response = Invoke-RestMethod -UseBasicParsing -Uri "https://outlook.office365.com/adminapi/beta/$tenantID/InvokeCommand" -Method POST -Headers $requestHeader -Body $($requestBody | ConvertTo-Json) -ContentType "application/json; charset=UTF-8" -ErrorAction Stop | |
Write-Verbose "Removed The Exchange Online Management Scope '$managementScopeName'" | |
} Catch { | |
If ($_.ErrorDetails.Message) { | |
$err = $_.ErrorDetails.Message | ConvertFrom-Json | |
$errorMessage = $err.error.details.message | |
} Else { | |
$errorMessage = $_ | |
} | |
Throw $errorMessage | |
} | |
# Return | |
Return $response | |
} | |
} | |
# FUNCTION: Remove The Service Principal With A Specific Application Name Or Service Principal Object OD From Office 365 Exchange Online | |
Function Remove-EXOApiServicePrincipal { | |
<# | |
.SYNOPSIS | |
Remove The Service Principal With A Specific Application Name Or Service Principal Object OD From Office 365 Exchange Online | |
.DESCRIPTION | |
Remove The Service Principal With A Specific Application Name Or Service Principal Object OD From Office 365 Exchange Online | |
.PARAMETER accessToken | |
The Access Token To Be Used To Execute The Operation | |
.PARAMETER applicationName | |
The Application Name Assigned And Configured On The Service Principal In Entra ID | |
.PARAMETER servicePrincipalObjectID | |
The Object ID From The Service Principal In Entra ID | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$accessToken, | |
[Parameter(Mandatory = $FALSE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$applicationName, | |
[Parameter(Mandatory = $FALSE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$servicePrincipalObjectID | |
) | |
Begin { | |
$requestHeader = $null | |
$requestBody = $null | |
$response = $null | |
# Making Sure The Correct Combination Of Parameters Are Used | |
If (-not [string]::IsNullOrEmpty($applicationName) -And [string]::IsNullOrEmpty($servicePrincipalObjectID)) { | |
$identity = $applicationName | |
} ElseIf ([string]::IsNullOrEmpty($applicationName) -And -not [string]::IsNullOrEmpty($servicePrincipalObjectID)) { | |
$identity = $servicePrincipalObjectID | |
} ElseIf (-not [string]::IsNullOrEmpty($applicationName) -And -not [string]::IsNullOrEmpty($servicePrincipalObjectID)) { | |
$identity = $servicePrincipalObjectID | |
} Else { | |
Write-Error "The Correct Combination Of Parameters Is Not Being Used" | |
Write-Host " * You Need To Either Specify '-applicationName' And Specify An Application Name Or '-servicePrincipalObjectID' And Specify The Service Principal Object ID" -ForegroundColor red | |
Write-Host "" | |
BREAK | |
} | |
} | |
Process { | |
# Define The Request Header To Execute The Required Action | |
$requestHeader = @{ | |
Authorization = "Bearer $accessToken" | |
} | |
Write-Verbose "Request Header...........................: $($requestHeader | Out-String)" | |
# Define The Request Body To Execute The Required Action | |
$requestBody = [PSCustomObject]@{ | |
CmdletInput = [PSCustomObject]@{ | |
CmdletName = "Remove-ServicePrincipal" | |
Parameters = [PSCustomObject]@{ | |
Identity = $identity | |
Confirm = $false | |
} | |
} | |
} | |
Write-Verbose "Request Body.............................: $($requestBody | Out-String)" | |
# Get The Response From The Office 365 Exchange Online API | |
Try { | |
$response = Invoke-RestMethod -UseBasicParsing -Uri "https://outlook.office365.com/adminapi/beta/$tenantID/InvokeCommand" -Method POST -Headers $requestHeader -Body $($requestBody | ConvertTo-Json) -ContentType "application/json; charset=UTF-8" -ErrorAction Stop | |
Write-Verbose "Removed The Exchange Online Service Principal '$identity'" | |
} Catch { | |
If ($_.ErrorDetails.Message) { | |
$err = $_.ErrorDetails.Message | ConvertFrom-Json | |
$errorMessage = $err.error.details.message | |
} Else { | |
$errorMessage = $_ | |
} | |
Throw $errorMessage | |
} | |
# Return | |
Return $response | |
} | |
} | |
# FUNCTION: Get The Service Principal With A Specific Application ID Or Specific Service Principal Display Name | |
Function Get-GraphApiServicePrincipal { | |
<# | |
.SYNOPSIS | |
Get The Service Principal With A Specific Application ID Or Specific Service Principal Display Name | |
.DESCRIPTION | |
Get The Service Principal With A Specific Application ID Or Specific Service Principal Display Name | |
.PARAMETER accessToken | |
The Access Token To Be Used To Execute The Operation | |
.PARAMETER applicationId | |
The Application ID Assigned And Configured On The Service Principal To Process | |
.PARAMETER svcPrincDisplayName | |
The Application Display Name Assigned And Configured On The Service Principal To Process | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$accessToken, | |
[Parameter(Mandatory = $FALSE)] | |
[string]$applicationId, | |
[Parameter(Mandatory = $FALSE)] | |
[string]$svcPrincDisplayName | |
) | |
Begin { | |
# Making Sure The Correct Combination Of Parameters Are Used | |
If ([string]::IsNullOrEmpty($applicationId) -And [string]::IsNullOrEmpty($svcPrincDisplayName)) { | |
Write-Error "The Correct Combination Of Parameters Is Not Being Used" | |
Write-Host " * You Need To Either Specify '-applicationId' And Specify An Application Id Or '-svcPrincDisplayName' And Specify The Service Principal Display Name" -ForegroundColor red | |
Write-Host "" | |
BREAK | |
} | |
$requestHeader = $null | |
$response = $null | |
} | |
Process { | |
# Define The Request Header To Execute The Required Action | |
$requestHeader = @{ | |
Authorization = "Bearer $accessToken" | |
} | |
Write-Verbose "Request Header...........................: $($requestHeader | Out-String)" | |
# Get The Response From The Microsoft Graph | |
Try { | |
If (-not [string]::IsNullOrEmpty($applicationId)) { | |
$response = Invoke-RestMethod -UseBasicParsing -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=appId+eq+'$applicationId'" -Method GET -Headers $requestHeader -ErrorAction Stop | |
If ([string]::IsNullOrEmpty($($response.value | Out-String))) { | |
Write-Verbose "Unable To Find The Service Principal With App Id '$applicationId' Because It Does Not Exist In This Tenant" | |
} Else { | |
Write-Verbose "Found The Service Principal '$($response.value.displayName)' With Object Id '$($response.value.id)' And App Id '$($response.value.appId)'" | |
} | |
} | |
If (-not [string]::IsNullOrEmpty($svcPrincDisplayName)) { | |
$response = Invoke-RestMethod -UseBasicParsing -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=displayName+eq+'$svcPrincDisplayName'" -Method GET -Headers $requestHeader -ErrorAction Stop | |
If ([string]::IsNullOrEmpty($($response.value | Out-String))) { | |
Write-Verbose "Unable To Find The Service Principal With Display Name '$svcPrincDisplayName' Because It Does Not Exist In This Tenant" | |
} Else { | |
Write-Verbose "Found The Service Principal '$($response.value.displayName)' With Object Id '$($response.value.id)' And App Id '$($response.value.appId)'" | |
} | |
} | |
} Catch { | |
If ($_.ErrorDetails.Message) { | |
$errorMessage = $_.ErrorDetails.Message | |
} Else { | |
$errorMessage = $_ | |
If ($_ -like "*(401) Unauthorized*") { | |
Write-Verbose "Error: (401) Unauthorized - Not Authenticated, Or Access Token Has Expired" | |
} | |
} | |
Throw $errorMessage | |
} | |
Return $response.value | |
} | |
} | |
# FUNCTION: Remove An Existing Service Principal With A Specific Service Principal Object Id or A Specific Application Id. | |
Function Remove-GraphApiServicePrincipal { | |
<# | |
.SYNOPSIS | |
Remove An Existing Service Principal With A Specific Service Principal Object Id or A Specific Application Id. | |
.DESCRIPTION | |
Remove An Existing Service Principal With A Specific Service Principal Object Id or A Specific Application Id. | |
.PARAMETER accessToken | |
The Access Token To Be Used To Execute The Operation | |
.PARAMETER applicationId | |
The Application ID Assigned And Configured On The Service Principal To Process | |
.PARAMETER servicePrincipalId | |
The Object Id Of The Service Principal To Process | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$accessToken, | |
[Parameter(Mandatory = $FALSE)] | |
[string]$applicationId, | |
[Parameter(Mandatory = $FALSE)] | |
[string]$servicePrincipalId | |
) | |
Begin { | |
# Making Sure The Correct Combination Of Parameters Are Used | |
If ([string]::IsNullOrEmpty($applicationId) -And [string]::IsNullOrEmpty($servicePrincipalId)) { | |
Write-Error "The Correct Combination Of Parameters Is Not Being Used" | |
Write-Host " * You Need To Either Specify '-applicationId' And Specify An Application Id Or '-servicePrincipalId' And Specify The Service Principal Object Id" -ForegroundColor red | |
Write-Host "" | |
BREAK | |
} | |
$requestHeader = $null | |
$response = $null | |
} | |
Process { | |
# Define The Request Header To Execute The Required Action | |
$requestHeader = @{ | |
Authorization = "Bearer $accessToken" | |
} | |
Write-Verbose "Request Header...........................: $($requestHeader | Out-String)" | |
# Get The Response From The Microsoft Graph | |
Try { | |
If (-not [string]::IsNullOrEmpty($applicationId)) { | |
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='{$applicationId}')" -Method DELETE -Headers $requestHeader -ErrorAction Stop | |
Write-Verbose "Deleted Service Principal With Application Id '$applicationId'" | |
} | |
If (-not [string]::IsNullOrEmpty($servicePrincipalId)) { | |
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$servicePrincipalId" -Method DELETE -Headers $requestHeader -ErrorAction Stop | |
Write-Verbose "Deleted Service Principal With Object Id '$servicePrincipalId'" | |
} | |
} Catch { | |
If ($_.ErrorDetails.Message) { | |
$errorMessage = $_.ErrorDetails.Message | |
} Else { | |
$errorMessage = $_ | |
If ($_ -like "*(401) Unauthorized*") { | |
Write-Verbose "Error: (401) Unauthorized - Not Authenticated, Or Access Token Has Expired" | |
} | |
If ($_ -like "*(404) Not Found*") { | |
Write-Verbose "Error: (404) Not Found - The Service Principal With $(If (-not [string]::IsNullOrEmpty($applicationId)) {"Application Id '$applicationId'"} ElseIf (-not [string]::IsNullOrEmpty($servicePrincipalId)) {"Object Id '$servicePrincipalId'"}) Does Not Exist In This Tenant" | |
} | |
} | |
Throw $errorMessage | |
} | |
# Return | |
Return $response | |
} | |
} | |
# FUNCTION: Remove An Existing Application Registration With A Specific Application Registration Object Id or A Specific Application Id. | |
Function Remove-GraphApiApplicationRegistration { | |
<# | |
.SYNOPSIS | |
Remove An Existing Application Registration With A Specific Application Registration Object Id or A Specific Application Id. | |
.DESCRIPTION | |
Remove An Existing Application Registration With A Specific Application Registration Object Id or A Specific Application Id. | |
.PARAMETER accessToken | |
The Access Token To Be Used To Execute The Operation | |
.PARAMETER applicationId | |
The Application ID Assigned And Configured On The Application Registration To Process | |
.PARAMETER applicationRegistrationObjectId | |
The Object Id Of The Application Registration To Process | |
#> | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory = $TRUE)] | |
[ValidateNotNullOrEmpty()] | |
[string]$accessToken, | |
[Parameter(Mandatory = $FALSE)] | |
[string]$applicationId, | |
[Parameter(Mandatory = $FALSE)] | |
[string]$applicationRegistrationObjectId | |
) | |
Begin { | |
# Making Sure The Correct Combination Of Parameters Are Used | |
If ([string]::IsNullOrEmpty($applicationId) -And [string]::IsNullOrEmpty($applicationRegistrationObjectId)) { | |
Write-Error "The Correct Combination Of Parameters Is Not Being Used" | |
Write-Host " * You Need To Either Specify '-applicationId' And Specify An Application Id Or '-applicationRegistrationObjectId' And Specify The Application Registration Object Id" -ForegroundColor red | |
Write-Host "" | |
BREAK | |
} | |
$requestHeader = $null | |
$response = $null | |
} | |
Process { | |
# Define The Request Header To Execute The Required Action | |
$requestHeader = @{ | |
Authorization = "Bearer $accessToken" | |
} | |
Write-Verbose "Request Header...........................: $($requestHeader | Out-String)" | |
# Get The Response From The Microsoft Graph | |
Try { | |
If (-not [string]::IsNullOrEmpty($applicationId)) { | |
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://graph.microsoft.com/v1.0/applications(appId='{$applicationId}')" -Method DELETE -Headers $requestHeader -ErrorAction Stop | |
Write-Verbose "Deleted Application Registration With Application Id '$applicationId'" | |
} | |
If (-not [string]::IsNullOrEmpty($applicationRegistrationObjectId)) { | |
$response = Invoke-WebRequest -UseBasicParsing -Uri "https://graph.microsoft.com/v1.0/applications/$applicationRegistrationObjectId" -Method DELETE -Headers $requestHeader -ErrorAction Stop | |
Write-Verbose "Deleted Application Registration With Object Id '$applicationRegistrationObjectId'" | |
} | |
} Catch { | |
If ($_.ErrorDetails.Message) { | |
$errorMessage = $_.ErrorDetails.Message | |
} Else { | |
$errorMessage = $_ | |
If ($_ -like "*(401) Unauthorized*") { | |
Write-Verbose "Error: (401) Unauthorized - Not Authenticated, Or Access Token Has Expired" | |
} | |
If ($_ -like "*(404) Not Found*") { | |
Write-Verbose "Error: (404) Not Found - The Application Registration With $(If (-not [string]::IsNullOrEmpty($applicationId)) {"Application Id '$applicationId'"} ElseIf (-not [string]::IsNullOrEmpty($applicationRegistrationObjectId)) {"Object Id '$applicationRegistrationObjectId'"}) Does Not Exist In This Tenant" | |
} | |
} | |
Throw $errorMessage | |
} | |
# Return | |
Return $response | |
} | |
} | |
Clear-Host | |
################################################################ | |
### CONSTANTS ### | |
################################################################ | |
If (-not [String]::IsNullOrEmpty($certCERFilePath) -And $certCERFilePath -ne "<CERTIFICATE CER FILE PATH>") { | |
If (!(Test-Path $certCERFilePath)) { | |
Write-Host "" | |
Write-Host "The CER File '$certCERFilePath' DOES NOT Exist..." -Foregroundcolor Red | |
Write-Host "" | |
Write-Host " => Aborting Script..." -ForegroundColor Red | |
Write-Host "" | |
BREAK | |
} | |
} | |
################################################################ | |
### CHECKING REQUIREMENTS ### | |
################################################################ | |
# Due To The Use Of The PowerShell Module "PSMSALNet" For Authentication Against Entra ID, The Minimum PowerShell Version Is 7.4, So Let's Check If That Requirement Is Met. | |
If ($psVersionTable.PSVersion -lt [version]"7.4") { | |
Write-Host "" | |
Write-Host "This Script Depends On The PowerShell Module 'PSMSALNet' Which Has A minum Requirement Of PowerShell Version 7.4." -Foregroundcolor Red | |
Write-Host "" | |
Write-Host "Please Visit 'https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4'..." -Foregroundcolor Red | |
Write-Host "" | |
Write-Host "" | |
Write-Host " => Aborting Script..." -ForegroundColor Red | |
Write-Host "" | |
BREAK | |
} | |
# The Module "PSMSALNet" Is Used For Authentication Against Entra ID, So Let's Check If That Is Installed Or Not. If It Is Load The Most Recent Module | |
$moduleName = "PSMSALNet" | |
$psMSALNetModule = Get-Module -Name $moduleName -ListAvailable | |
If ([String]::IsNullOrEmpty($psMSALNetModule)) { | |
Write-Host "" | |
Write-Host "The $moduleName PowerShell Module IS NOT Installed" -ForegroundColor Red | |
Write-Host "" | |
Write-Host " => The $moduleName PowerShell Module Can Be Installed From An Elevated PowerShell Command Prompt By Running:" -ForegroundColor Red | |
Write-Host " - 'Install-Module $moduleName'" -ForegroundColor Red | |
Write-Host "" | |
Write-Host " => Aborting Script..." -ForegroundColor Red | |
Write-Host "" | |
BREAK | |
} Else { | |
$psMSALNetModuleVersionInstalled = $psMSALNetModule.Version | |
$psMSALNetModuleVersionAvailable = (Find-Module -Name $moduleName).Version | |
If ([version]$psMSALNetModuleVersionAvailable -gt $psMSALNetModuleVersionInstalled) { | |
Write-Host "" | |
Write-Host "A Newer Version Of The '$moduleName' PowerShell Module Is Available For Download/Install..." -ForegroundColor Red | |
Write-Host "" | |
} | |
} | |
If ($psMSALNetModule.count -gt 1) { | |
$latestVersionPSMSALNetModule = ($psMSALNetModule | Select-Object version | Sort-Object)[-1] | |
$psMSALNetModule = $psMSALNetModule | Where-Object {$_.version -eq $latestVersionMSFTGraphModule.version} | |
} | |
Import-Module $psMSALNetModule | |
################################################################ | |
### MAIN CODE ### | |
################################################################ | |
# Using The Tenant FQDN, Determine The Tenant ID | |
$oidcConfig = Get-MSFTApiOpenIDConfiguration -tenantFQDN $tenantFQDN | |
$tenantID = Get-MSFTTenantID -oidcTenantConfig $oidcConfig | |
If (!$([guid]::TryParse($tenantID, $([ref][guid]::Empty)))) { | |
Write-Host "" | |
Write-Host "Specified Tenant '$tenantFQDN' DOES NOT Exist..." -ForegroundColor Red | |
Write-Host "" | |
Write-Host " => Aborting Script..." -ForegroundColor Red | |
Write-Host "" | |
BREAK | |
} | |
Write-Host "" | |
Write-Host "Tenant FQDN.........................: $tenantFQDN" | |
Write-Host "Tenant ID...........................: $tenantID" | |
Write-Host "" | |
# Authenticate And Get An Access Token For MSFT Graph API To Execute Actions In Entra ID | |
$clientId1 = "14d82eec-204b-4c2f-b7e8-296a70dab67e" # "Microsoft Graph Command Line Tools" | |
Write-Host "" | |
Write-Host "### Getting Access Token For Client App 'Microsoft Graph Command Line Tools' And The MSFT Graph API Resource In Entra ID Tenant '$tenantFQDN'..." -ForegroundColor Cyan | |
Write-Host "" | |
Try { | |
$entraTokenParametersHT1 = @{ | |
ClientId = $clientId1 | |
TenantId = $tenantID | |
RedirectUri = "http://localhost" | |
Resource = "GraphAPI" | |
Permissions = @("Directory.AccessAsUser.All") | |
verbose = $false | |
ErrorAction = "Stop" | |
} | |
$entraTokenMSGraphAPI = Get-EntraToken -PublicAuthorizationCodeFlow @entraTokenParametersHT1 | |
} Catch { | |
Write-Host "" | |
Write-Host " => Getting Access Token For Client App '$($clientIdAndNameMappings[$clientId1])' And The MSFT Graph API Resource In Entra ID Tenant '$tenantFQDN' Failed..." -ForegroundColor Red | |
Write-Host "" | |
Write-Host " - Exception Type......: $($_.Exception.GetType().FullName)" -ForegroundColor Red | |
Write-Host " - Exception Message...: $($_.Exception.Message)" -ForegroundColor Red | |
Write-Host " - Error On Script Line: $($_.InvocationInfo.ScriptLineNumber)" -ForegroundColor Red | |
Write-Host "" | |
Write-Host " => Aborting Script..." -ForegroundColor Red | |
Write-Host "" | |
Write-Host "" | |
Try { | |
Remove-Module $psMSALNetModule -ErrorAction SilentlyContinue | |
} Catch { | |
} | |
BREAK | |
} | |
$accessTokenMSGraphAPI = $entraTokenMSGraphAPI.AccessToken | |
# Authenticate And Get An Access Token For Office 365 Exchange Online To Execute Actions In Exchange Online | |
$clientId3 = "fb78d390-0c51-40cd-8e17-fdbfab77341b" # "Microsoft Exchange REST API Based Powershell" | |
Write-Host "" | |
Write-Host "### Getting Access Token For Client App 'Microsoft Exchange REST API Based Powershell' And The Office 365 Exchange Online Resource In Entra ID Tenant '$tenantFQDN'..." -ForegroundColor Cyan | |
Write-Host "" | |
Try { | |
$entraTokenParametersHT3 = @{ | |
ClientId = $clientId3 | |
TenantId = $tenantID | |
RedirectUri = "http://localhost" | |
Resource = "Custom" | |
CustomResource = "00000002-0000-0ff1-ce00-000000000000" # Resource ID For Office 365 Exchange Online (=> https://outlook.office365.com) | |
Permissions = @("AdminApi.AccessAsUser.All","FfoPowerShell.AccessAsUser.All","RemotePowerShell.AccessAsUser.All") | |
verbose = $false | |
ErrorAction = "Stop" | |
} | |
$entraTokenO365EXO = Get-EntraToken -PublicAuthorizationCodeFlow @entraTokenParametersHT3 | |
} Catch { | |
Write-Host "" | |
Write-Host " => Getting Access Token For Client App '$($clientIdAndNameMappings[$clientId3])' And The Office 365 Exchange Online Resource Resource In Entra ID Tenant '$tenantFQDN' Failed..." -ForegroundColor Red | |
Write-Host "" | |
Write-Host " - Exception Type......: $($_.Exception.GetType().FullName)" -ForegroundColor Red | |
Write-Host " - Exception Message...: $($_.Exception.Message)" -ForegroundColor Red | |
Write-Host " - Error On Script Line: $($_.InvocationInfo.ScriptLineNumber)" -ForegroundColor Red | |
Write-Host "" | |
Write-Host " => Aborting Script..." -ForegroundColor Red | |
Write-Host "" | |
Write-Host "" | |
Try { | |
Remove-Module $psMSALNetModule -ErrorAction SilentlyContinue | |
} Catch { | |
} | |
BREAK | |
} | |
$accessTokenO365EXO = $entraTokenO365EXO.AccessToken | |
# Deleting The Management Role Assignment In Office 365 Exchange Online | |
Try { | |
If ("RBAC-ASSIGN-APP_$applicationName".Length -gt 64) { | |
$managementRoleAssignmentName = "RBAC-ASSIGN-APP_$applicationName".Substring(0,64) | |
} Else{ | |
$managementRoleAssignmentName = "RBAC-ASSIGN-APP_$applicationName" | |
} | |
$result = Remove-EXOApiManagementRoleAssignment -accessToken $accessTokenO365EXO -managementRoleAssignmentName $managementRoleAssignmentName | |
Write-Host " => Office 365 Exchange Online: Management Role Assignment '$managementRoleAssignmentName' Has Been Deleted Successfully..." -ForegroundColor Green | |
Write-Host "" | |
} catch { | |
$_ | |
} | |
# Deleting The Management Scope In Office 365 Exchange Online | |
Try { | |
If ("RBAC-SCOPE-APP_$applicationName".Length -gt 64) { | |
$managementScopeName = "RBAC-SCOPE-APP_$applicationName".Substring(0,64) | |
} Else{ | |
$managementScopeName = "RBAC-SCOPE-APP_$applicationName" | |
} | |
$result = Remove-EXOApiManagementScope -accessToken $accessTokenO365EXO -managementScopeName $managementScopeName | |
Write-Host " => Office 365 Exchange Online: Management Scope '$managementScopeName' Has Been Deleted Successfully..." -ForegroundColor Green | |
Write-Host "" | |
} catch { | |
$_ | |
} | |
# Deleting The Service Principal In Office 365 Exchange Online | |
Try { | |
$result = Remove-EXOApiServicePrincipal -accessToken $accessTokenO365EXO -applicationName $applicationName | |
Write-Host " => Office 365 Exchange Online: Service Principal '$applicationName' Has Been Deleted Successfully..." -ForegroundColor Green | |
Write-Host "" | |
} catch { | |
$_ | |
} | |
# Deleting The Service Principal In Entra ID | |
$eidSvcPrincipal = Get-GraphApiServicePrincipal -accessToken $accessTokenMSGraphAPI -svcPrincDisplayName $applicationName | |
Try { | |
$result = Remove-GraphApiServicePrincipal -accessToken $accessTokenMSGraphAPI -applicationId $($eidSvcPrincipal.appId) | |
Write-Host " => Entra ID: Service Principal '$($eidSvcPrincipal.appDisplayName)' Has Been Deleted Successfully..." -ForegroundColor Green | |
Write-Host "" | |
} catch { | |
$_ | |
} | |
# Deleting The Application Registration In Entra ID | |
Try { | |
$result = Remove-GraphApiApplicationRegistration -accessToken $accessTokenMSGraphAPI -applicationId $($eidSvcPrincipal.appId) | |
Write-Host " => Entra ID: Application Registration '$($eidSvcPrincipal.appDisplayName)' In Has Been Deleted Successfully..." -ForegroundColor Green | |
Write-Host "" | |
} catch { | |
$_ | |
} | |
### | |
# THE END OF THE SCRIPT | |
### | |
Try { | |
Remove-Module $psMSALNetModule -ErrorAction SilentlyContinue | |
} Catch { | |
$_ | |
} | |
Write-Host "" | |
Write-Host " +++ DONE +++ " -ForegroundColor Cyan | |
Write-Host "" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment