So, hope someone can help me across the finish line with this. I've cobbled together a bit of code, basically something I got from a much smarter forum user for a similar purpose.
I'm trying to take all the App Registrations and their secrets/certificate expiry dates and put that information into a PSCustomObject.
This is the bit of code that does the work
# Loop through all apps and add to PSCustomObject
$uri = 'https://graph.microsoft.com/beta/applications?$select=displayName, passwordCredentials, id'
$result = do {
$Data = Invoke-RestMethod -Method Get -Uri $uri -Headers $Headers
$uri = $Data.'@odata.nextLink'
foreach ($app in $Data.value) {
$appUri = 'https://graph.microsoft.com/beta/applications?$select=displayName, passwordCredentials, id'
$allAppSecretsExpiry = do {
$cred = Invoke-RestMethod -Method Get -Uri $appUri -Headers $Headers
$appUri = $cred.'@odata.nextLink'
if ($cred) {
$cred.value.passwordCredentials.endDateTime
}
}
while ($appUri)
[pscustomobject]@{
displayName = $app.displayName
id = $app.id
Credentials = $allAppSecretsExpiry
}
}
}
while ($uri)
Then, what I get is a list of all apps and their ID, but the property for expiration date, I get all expiry dates for all apps, something like this
APP1 {2025-05-15 17:55:57, 2024-08-13 08:55:07, 2026-04-15 09:06:50, 202…
APP2 {2025-05-15 17:55:57, 2024-08-13 08:55:07, 2026-04-15 09:06:50, 202…
APP3 {2025-05-15 17:55:57, 2024-08-13 08:55:07, 2026-04-15 09:06:50, 202…
APP4 {2025-05-15 17:55:57, 2024-08-13 08:55:07, 2026-04-15 09:06:50, 202…
I'm sure I've made a mistake in the foreach loop, but I can't see where.
Hopefully some kind soul can help me out and I'll learn something along the way.
The main issue with your code is that you're missing an inner loop to go through each secret (.passwordCredentials
property). Because applications can have more than one secret, you are ending up with a single object per app with all secrets as an array. Fixing the problem is fairly simple:
$invokeRestMethodSplat = @{
Method = 'GET'
Uri = 'https://graph.microsoft.com/v1.0/applications?$select=displayName, passwordCredentials, id'
Headers = @{
Authorization = 'Bearer {myTokenGoesHere}'
}
}
$result = do {
$Data = Invoke-RestMethod @invokeRestMethodSplat
$invokeRestMethodSplat['Uri'] = $Data.'@odata.nextLink'
foreach ($app in $Data.value) {
foreach ($secret in $app.passwordCredentials) {
[pscustomobject]@{
displayName = $app.displayName
id = $app.id
startDateTime = $secret.startDateTime
endDateTime = $secret.endDateTime
secretDisplayName = $secret.displayName
}
}
}
}
while ($invokeRestMethodSplat['Uri'])
# do stuff with `$result`
$result ...
Do note this current implementation only covers Client Secrets (clientId + secret password). If you want to also include Client Certificates you need to include keyCredentials
in your $select
parameter and would need to include an additional inner loop on $app.keyCredentials
.