Alerting when my Apple certificates expire in Intune using Azure Automation

One of the things I’m always aware of is certificate expiry, especially the ones used for Apple VPP, if those expire and aren’t renewed in time, you may find yourself factory resetting and re-enrolling again which I’m sure we all want to avoid.

Whilst Outlook reminders are a wonderful thing, there is still an element of user error, plus if you renew early, the expiry is now earlier next year so it’s a bit too manual for my liking.

It’s time to automate!

For this script, I’m going to take the excellent work by Peter van der Woude here and extend it slightly to use an Azure Automation Runbook and email me when a certificate is due to expire.

Let’s start with the Automation Account within Azure

Once that’s complete we want to deploy the required modules to it

In PowerShell Gallery select this module and deploy to Azure Automation:

https://www.powershellgallery.com/packages/Microsoft.Graph.Users.Actions/1.9.6

Once deployed, we can reference it in our script

Next up, we need an AAD App Registration we can use to grab the backups

In Azure AD, create a new app registration:

Within API Permissions grant these roles under MS Graph:

  • DeviceManagementApps.Read.All
  • DeviceManagementConfiguration.Read.All
  • DeviceManagementServiceConfig.Real.All
  • Mail.Send

You’ll note it’s still missing permissions so you now need to click the Grant Admin Consent button

Finally create a Secret and save that, the App ID and the Tenant details to use in the script

Now, back to the Azure Automation Account and click Runbook

Create a new Runbook

Enter the Powershell code below (or grab from here) (update the fields as required for your environment)

<#PSScriptInfo
.VERSION 1.0.0
.GUID 1000d8c2-73b3-48a8-b1ec-f894fec7df58
.AUTHOR AndrewTaylor
.DESCRIPTION Alerts when a certificate is due to expire
.COMPANYNAME
.COPYRIGHT GPL
.TAGS intune endpoint MEM environment
.LICENSEURI https://github.com/andrew-s-taylor/public/blob/main/LICENSE
.PROJECTURI https://github.com/andrew-s-taylor/public
.ICONURI
.EXTERNALMODULEDEPENDENCIES microsoft.graph.intune, microsoft.graph.users.actions
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES
.PRIVATEDATA
#>
<# 

.DESCRIPTION 
Alerts on expiry of Apple Certificates with AAD App Registration, Azure Blob and Azure Automation Account

#> 


##############################################################################################################################################
##### UPDATE THESE VALUES #################################################################################################################
##############################################################################################################################################
## Your Azure Tenant Name
$tenant = "<YOUR TENANT NAME>"

##Your Azure Tenant ID
$tenantid = "<YOUR TENANT ID>"

##Your App Registration Details
$clientId = "<YOUR CLIENT ID>"
$clientSecret = "<YOUR CLIENT SECRET>"

$EmailAddress = "<YOUR EMAIL ADDRESS>"

##From Address
$MailSender = "<YOUR FROM ADDRESS>"


##############################################################################################################################################


#Connect to GRAPH API
$tokenBody = @{
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    Client_Id     = $clientId
    Client_Secret = $clientSecret
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $tokenBody
$headers = @{
    "Authorization" = "Bearer $($tokenResponse.access_token)"
    "Content-type"  = "application/json"
}

#MDM Push
$30days = ((get-date).AddDays(30)).ToString("yyyy-MM-dd")
$pushuri = "https://graph.microsoft.com/beta/deviceManagement/applePushNotificationCertificate"
$pushcert = (Invoke-RestMethod -Uri $pushuri -Headers $headers -Method Get)
$pushexpiryplaintext = $pushcert.expirationDateTime
$pushexpiry = ($pushcert.expirationDateTime).ToString("yyyy-MM-dd")
if ($pushexpiry -lt $30days) {
write-host "Cert Expiring" -ForegroundColor Red

#Send Mail    
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
                    {
                        "message": {
                          "subject": "Apple Push Certificate Expiry",
                          "body": {
                            "contentType": "HTML",
                            "content": "Your Apple Push Certificate is due to expire on <br>
                            $pushexpiryplaintext <br>
                            Please Renew before this date
                            "
                          },
                          "toRecipients": [
                            {
                              "emailAddress": {
                                "address": "$EmailAddress"
                              }
                            }
                          ]
                        },
                        "saveToSentItems": "false"
                      }
"@

Invoke-RestMethod -Method POST -Uri $URLsend -Headers $headers -Body $BodyJsonsend

}
else {
write-host "All fine" -ForegroundColor Green
}


#VPP
$30days = ((get-date).AddDays(30)).ToString("yyyy-MM-dd")
$vppuri = "https://graph.microsoft.com/beta/deviceAppManagement/vppTokens"
$vppcert = (Invoke-RestMethod -Uri $vppuri -Headers $headers -Method Get)
$vppexpiryvalue = $vppcert.value
$vppexpiryplaintext = $vppexpiryvalue.expirationDateTime
$vppexpiry = ($vppexpiryvalue.expirationDateTime).ToString("yyyy-MM-dd")
if ($vppexpiry -lt $30days) {
write-host "Cert Expiring" -ForegroundColor Red
#Send Mail    
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
                    {
                        "message": {
                          "subject": "Apple VPP Certificate Expiry",
                          "body": {
                            "contentType": "HTML",
                            "content": "Your Apple VPP Certificate is due to expire on <br>
                            $vppexpiryplaintext <br>
                            Please Renew before this date
                            "
                          },
                          "toRecipients": [
                            {
                              "emailAddress": {
                                "address": "$EmailAddress"
                              }
                            }
                          ]
                        },
                        "saveToSentItems": "false"
                      }
"@

Invoke-RestMethod -Method POST -Uri $URLsend -Headers $headers -Body $BodyJsonsend
}
else {
write-host "All fine" -ForegroundColor Green
}






#DEP
$30days = ((get-date).AddDays(30)).ToString("yyyy-MM-dd")
$depuri = "https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings"
$depcert = (Invoke-RestMethod -Uri $depuri -Headers $headers -Method Get)
$depexpiryvalue = $depcert.value
$depexpiryplaintext = $depexpiryvalue.tokenexpirationDateTime

$depexpiry = ($depexpiryvalue.tokenExpirationDateTime).ToString("yyyy-MM-dd")
if ($depexpiry -lt $30days) {
write-host "Cert Expiring" -ForegroundColor Red

#Send Mail    
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
                    {
                        "message": {
                          "subject": "Apple DEP Certificate Expiry",
                          "body": {
                            "contentType": "HTML",
                            "content": "Your Apple DEP Certificate is due to expire on <br>
                            $depexpiryplaintext <br>
                            Please Renew before this date
                            "
                          },
                          "toRecipients": [
                            {
                              "emailAddress": {
                                "address": "$EmailAddress"
                              }
                            }
                          ]
                        },
                        "saveToSentItems": "false"
                      }
"@

Invoke-MgGraphRequest -Method POST -Uri $URLsend -Body $BodyJsonsend

}
else {
write-host "All fine" -ForegroundColor Green
}

Click Test Pane to make sure it’s worked

Now we need to publish it once it’s tested ok

Now add a schedule to run it daily

That’s it, you should now be annoyed by daily emails until you renew the certificates!

8 thoughts on “Alerting when my Apple certificates expire in Intune using Azure Automation”

  1. I was going through your tutorial and I get this error when doing the testing

    System.Management.Automation.RuntimeException: You cannot call a method on a null-valued expression.
    at CallSite.Target(Closure , CallSite , Object , String )
    at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
    at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

    Reply
  2. Great idea, I have not tested the code yet but how will this work if you have several VPP/DEP tokens in your tenant.

    Reply
  3. I cannot get the graph authentication to work. This seems to be the problem with most online scripts I find. They don’t appear to use best practices for authentication in a way that is easy to reproduce and that works in 2022.

    Does your single token connection request work in 2022 without MFA and without certificates? I see conflicting info that says you must use one or both of those things.

    Script error: The remote server returned an error: (400) Bad Request

    Reply
    • Hi, this one uses an App Registration so there isn’t any MFA required. Do you have the app reg configured with all of the required permissions?
      The other option would be to use the MS.Graph.Intune module and replace the invoke-webrequest queries with invoke-msgraphrequest (and connect-msgraph with secret values)

      Reply
  4. I may try the second option. I think I have setup the app registration properly. I wish I could just use a system managed identity, but it seems that feature is too new for anyone to have written a guide.

    Reply

Leave a Comment