Get-ExpiringSPN.ps1
function Get-ExpiringSPN { [CmdletBinding()] param ( [Parameter(Mandatory = $true)]$TimeFrameInDays, [switch]$Expiry, [switch]$Expired, [switch]$InvalidExpiry ) # Enter the Timefram in Days for the Usage # $TimeFrameInDays = 30 ################################################################ ## Signature $t = @' Package designed and managed by ___ _ _ ___ _ / __| |___ _ _ __| | / __| ___ _ ___ _(_)__ ___ ___ | (__| / _ \ || / _ | \__ \/ -_) '_\ V / / _/ -_|_-< \___|_\___/\_,_\__,_| |___/\___|_| \_/|_\__\___/__/ Powershell package designed to perform IAM housekeeping task for App Registration SP Objects. Contact- Azure Cloud Servives Product Owner. '@ Write-Verbose "`n$($t)" ################################################################ # Authentication part Write-Verbose 'Checking ManagedIdentity Authentication to platform.' try { Connect-AzAccount -Identity } catch { Write-Warning "Not enough autherization to 'Managed Identity' for performing operations." } #Build a Dateformat for the Filter $TimeFrameDate = Get-Date -Format yyyy-MM-dd ((Get-Date).AddDays(-$TimeFrameInDays)) $azContext = Get-AzContext if ($token = Get-AzAccessToken -ResourceTypeName MSGraph -erroraction SilentlyContinue) { Write-Host "Authorization using MSGraph" } else { $token = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com" Write-Host "Authorization using GraphURI" } $authHeader = @{ 'Content-Type' = 'application/json' 'Authorization' = 'Bearer ' + $token.Token } # Fetching all the App registrations $appRegistrations = Get-AzADApplication if (!$appRegistrations) { Write-Warning 'Identity dosenot have AAD Directory ReadAll permission. Get permission for the identity you are running cmdlet with.' } else { if ($Expiry -or $InvalidExpiry -or $Expired) { $ArrayExpiry = @() $ArrayInvalidExpiry = @() $ArrayExpired = @() foreach ($appRegistration in $appRegistrations) { Write-Verbose '-----------------------------------' $appRegName = $($appRegistration.DisplayName) Write-Verbose "Running for $($appRegName)" if ($appRegistration.Id) { $appRegistrationId = $appRegistration.Id } else { $appRegistrationId = $appRegistration.ObjectId } $restUri = "https://graph.microsoft.com/v1.0/myorganization/applications/$($appRegistrationId)" $response = Invoke-RestMethod $restUri -Method 'GET' -Headers $authHeader $allSecrets = ($response.passwordCredentials.displayName -join '; ') $owner = "https://graph.microsoft.com/v1.0/myorganization/applications/$($appRegistrationId)/owners" $response2 = Invoke-RestMethod $owner -Method 'GET' -Headers $authHeader $owners = ($response2.value.userPrincipalName -join '; ') $ownerName = ($response2.value.displayName -join '; ') # $SignIns = Invoke-RestMethod -Method GET -Uri "https://graph.microsoft.com/v1.0/auditLogs/signIns?`$filter=appid eq '$($appRegistration.appId)' and createdDateTime gt $TimeFrameDate" -Headers $authHeader # $SignIns foreach ($expDate in $response.passwordCredentials.endDateTime) { if (($expiry) -and ($expDate -lt (Get-Date).AddDays($TimeFrameInDays)) -and ($expDate -gt (Get-Date))) { $ArrayExpiry += [PSCustomObject]@{ 'AppID' = $appRegistrationId 'AppName' = $appRegistration.displayName 'SecretName' = $allSecrets 'OwnerUPN' = $owners 'OwnerName' = $ownerName 'ExpirationDate' = $expDate # "Usage Count" = ($SignIns.value ).count } # $Array | Select-Object -Property 'AppName', 'SecretName', 'OwnerUPN', 'AppID', 'OwnerName', 'ExpirationDate' | Sort-Object -Property 'Owner Name' -Descending Write-Verbose "$($appRegistrationId) | $($appRegistration.displayName) | $($allSecrets) | $($owners) | $($ownerName) | $($expDate) |" } if (($InvalidExpiry) -and ($expDate -gt (Get-Date).AddDays($TimeFrameInDays))) { <# Action to perform if the condition is true #> $ArrayInvalidExpiry += [PSCustomObject]@{ 'AppID' = $appRegistrationId 'AppName' = $appRegistration.displayName 'SecretName' = $allSecrets 'OwnerUPN' = $owners 'OwnerName' = $ownerName 'InvalidDate' = $expDate # "Usage Count" = ($SignIns.value ).count } # $Array | Select-Object -Property 'AppName', 'SecretName', 'OwnerUPN', 'AppID', 'OwnerName', 'InvalidDate' | Sort-Object -Property 'OwnerName' -Descending Write-Verbose "$($appRegistrationId) | $($appRegistration.displayName) | $($allSecrets) | $($owners) | $($ownerName) | $($expDate) |" } # Expired in past X-Days if (($Expired) -and ($expDate -gt (Get-Date).AddDays(-$TimeFrameInDays)) -and ($expDate -lt (Get-Date))) { $ArrayExpired += [PSCustomObject]@{ 'AppID' = $appRegistrationId 'AppName' = $appRegistration.displayName 'SecretName' = $allSecrets 'OwnerUPN' = $owners 'OwnerName' = $ownerName 'ExpiredDate' = $expDate # "Usage Count" = ($SignIns.value ).count } # $Array | Select-Object -Property 'AppName', 'SecretName', 'OwnerUPN', 'AppID', 'OwnerName', 'InvalidDate' | Sort-Object -Property 'OwnerName' -Descending Write-Verbose "$($appRegistrationId) | $($appRegistration.displayName) | $($allSecrets) | $($owners) | $($ownerName) | $($expDate) |" } } } try { if ($expiry) { # $Array | Export-Csv -Path 'ExpiringSPNs.csv' -NoTypeInformation Write-Output $ArrayExpiry } elseif ($InvalidExpiry) { # $Array | Export-Csv -Path 'InvalidExpiringSPNs.csv' -NoTypeInformation #used to calculate expiry beyond 2 years or invalid expiries like 2029 Write-Output $ArrayInvalidExpiry } elseif ($Expired) { Write-Output $ArrayExpired } } catch { Write-Error "Exception : Cannot create file in the path $($pwd)" } } else { $t = @' +----------------+----------------------------------------------------------+ | Expiry | E.g : Get-ExpiringSPN -TimeFrameInDays 30 -Expiry | +----------------+----------------------------------------------------------+ | InvalidExpiry | E.g : Get-ExpiringSPN -TimeFrameInDays 30 -InvalidExpiry | +----------------+----------------------------------------------------------+ | Expired | E.g : Get-ExpiringSPN -TimeFrameInDays 30 -Expired | +----------------+----------------------------------------------------------+ '@ Write-Warning "You must select one of the switch to perform the operation.`n$($t)" } } ################################################################################################ } |