Azure App Registrations are a secure way to provide Credentials and Access to the Azure World. The Amount of Azure App Registrations in a Tenant is increasing very fast, so it is not that easy to control and monitor all those Secrets, Zert, and SPN’s Expire Date.
So I have written a PowerShell Script to send an Email, when an Azure App Secret or Zert, or an Azure SPN is expiring in the near future. This Script can be executed in your OnPrem Datacenter or as an Azure Automation Runbook.
Prerequisites
First, we need to create an Azure App to provide all permissions required. Yes, that one will also be monitored by the Script 🙂
MS Graph References:
- List applications – Microsoft Graph v1.0 | Microsoft Docs
- List servicePrincipals – Microsoft Graph v1.0 | Microsoft Docs
Create an Azure App Registration and add the following GRAPH API Application Permissions
- Application.Read.All
- Application.ReadWrite.All
- Directory.Read.All
- User.Read
Create a Secret and copy the Value
If your are not familiar with Azur eapp Regs, and how als this work together, see my Blogs Post for Details:
To learn more from Microsoft GRAPH API, see my Blog Series:
Part 1 – Authentication and Azure App – Use Microsoft Graph API with PowerShell – Part 1 » TechGuy
Part 2 – Oauth2.0 – Use Microsoft Graph API with PowerShell – Part 2 » TechGuy
Part 3 – First Powershell Script to get a Teams Lis and Walkthrough – Use Microsoft Graph API with PowerShell – Part 3 » TechGuy
Part 4 – this one – Use Microsoft Graph API with PowerShell – Part 4 » TechGuy
Second, we are sending an Email using Graph API, so see my previous Blog Post for Details and Enter the GRAPH Details in the Script: Send Mail with PowerShell and Microsoft Graph API – TechGuy
With all those information, we can take a look at the Script
The Script
Please fill Settings and the Azure App Details til the Line “#STOP HERE”
The Script will send you an Email for each Azure App or SP which will expire within the next 90 Days ($TimeSpanInDays). Already expired ones will not trigger an Email
#Settings
$TimeSpanInDays=90
$MailSender="Mail Sender Mail"
$MailRecipient="Mail Recipient Mail"
#Azure App Credentials to get Apps and SP
$EXPIRE_AppId = "your EXPIRE APP Client ID"
$EXPIRE_secret = "your EXPIRE APP Secret"
$tenantID = "Azure Tenant ID"
#Azure App Credentials to send the Mail
$MAIL_AppId = "your Mail Client ID"
$MAIL_secret = "your Mail Secret"
#STOP HERE!
#Connect to GRAPH API with EXPIRE credentials
$EXPIRE_tokenBody = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $EXPIRE_AppId
Client_Secret = $EXPIRE_secret
}
$EXPIRE_tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $EXPIRE_tokenBody
$EXPIRE_headers = @{
"Authorization" = "Bearer $($EXPIRE_tokenResponse.access_token)"
"Content-type" = "application/json"
}
#Connect to GRAPH API with MAIL Credentials
$MAIL_tokenBody = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $MAIL_AppId
Client_Secret = $MAIL_secret
}
$MAIL_tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $MAIL_tokenBody
$MAIL_headers = @{
"Authorization" = "Bearer $($MAIL_tokenResponse.access_token)"
"Content-type" = "application/json"
}
#Build Array to store PSCustomObject
$Array = @()
# List Get all Apps from Azure
$URLGetApps = "https://graph.microsoft.com/v1.0/applications"
$AllApps = Invoke-RestMethod -Method GET -Uri $URLGetApps -Headers $EXPIRE_headers
#Go through each App and add to our Array
foreach ($App in $AllApps.value) {
$URLGetApp = "https://graph.microsoft.com/v1.0/applications/$($App.ID)"
$App = Invoke-RestMethod -Method GET -Uri $URLGetApp -Headers $EXPIRE_headers
if ($App.passwordCredentials) {
foreach ($item in $App.passwordCredentials) {
$Array += [PSCustomObject]@{
"Type" = "AZAPP"
"displayName" = $app.displayName
"ID" = $App.ID
"AppID" = $app.appId
"SecType" = "Secret"
"Secret" = $item.displayName
"Secret-EndDate" = (Get-date $item.endDateTime)
}
}
}
if ($App.keyCredentials) {
foreach ($item in $App.keyCredentials) {
$Array += [PSCustomObject]@{
'Type' = "AZAPP"
'displayName' = $app.displayName
'ID' = $App.ID
'AppID' = $app.appId
'SecType' = "Zert"
'Secret' = $item.displayName
'Secret-EndDate' = (Get-date $item.endDateTime)
}
}
}
}
#Get all Service Principals
$servicePrincipals = "https://graph.microsoft.com/v1.0/servicePrincipals"
$SP = Invoke-RestMethod -Method GET -Uri $servicePrincipals -Headers $EXPIRE_headers
$SPList = $SP.value
$UserNextLink = $SP."@odata.nextLink"
while ($UserNextLink -ne $null) {
$SP = (Invoke-RestMethod -Uri $UserNextLink -Headers $EXPIRE_headers -Method Get )
$UserNextLink = $SP."@odata.nextLink"
$SPList += $SP.value
}
#Go through each SP and add to our Array
foreach ($SAML in $SPList) {
if ($Saml.passwordCredentials) {
foreach ($PW in $Saml.passwordCredentials) {
$Array += [PSCustomObject]@{
'Type' = "SP"
'displayName' = $SAML.displayName
'ID' = $SAML.id
'AppID' = $Saml.appId
'SecType' = "Secret"
'Secret' = $PW.displayName
'Secret-EndDate' = (Get-date $PW.endDateTime)
}
}
}
}
$ExpireringZerts = $Array | Where-Object -Property Secret-EndDate -Value (Get-Date).AddDays($TimeSpanInDays) -lt | Where-Object -Property Secret-EndDate -Value (Get-Date) -gt
foreach ($Zert in $ExpireringZerts) {
$HTML = $Zert | Convertto-HTML -Fragment -As List
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
{
"message": {
"subject": "Azure App or SPN will expire soon $($Zert.displayName)",
"body": {
"contentType": "HTML",
"content": "$HTML
<br>
Michael Seidl (au2mator)
<br>
"
},
"toRecipients": [
{
"emailAddress": {
"address": "$MailRecipient"
}
}
]
},
"saveToSentItems": "false"
}
"@
Invoke-RestMethod -Method POST -Uri $URLsend -Headers $MAIL_headers -Body $BodyJsonsend
}
GitHub Repo
Here you can find the GitHub Repo: Seidlm/Microsoft-Azure: Azure Rest API Examples (github.com) with the Script
Michael Seidl aka Techguy
au2mate everything
Hi Michael thank you for this post! I have a question, how do we get the result in one email? instead of multiple emails? thanks!
Hi, What if there are many apps about to expire?
I tried the script, and it send for one app each time.
isnt possible to send the list of the apps?
HI, thanks a lot .
Why is Application.ReadWrite.All needed ?
Hi, post was created about 2 years ago, when you see the Microsoft Documentation, you now see more accurate Permissions.