Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save zjorz/b5849c77ef68aefbaab5807786b07ff3 to your computer and use it in GitHub Desktop.
Save zjorz/b5849c77ef68aefbaab5807786b07ff3 to your computer and use it in GitHub Desktop.
Deleting A Specific Application From Entra ID And From Exchange Online
$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