SOLVED

ServicePrincipal StartDate and EndDate not displaying Using Graph API In Power Shell

%3CLINGO-SUB%20id%3D%22lingo-sub-1811320%22%20slang%3D%22en-US%22%3EServicePrincipal%20StartDate%20and%20EndDate%20not%20displaying%20Using%20Graph%20API%20In%20Power%20Shell%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1811320%22%20slang%3D%22en-US%22%3E%3CP%3EHi%2C%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20am%20trying%20to%20get%20list%20of%20SPNs%20that%20are%20going%20to%20expire%20soon.%20Using%20Graph%20API%26nbsp%3B%20I%20am%20executing%20below%20powershell%20script.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20am%20getting%20output%20appid%20and%20name%20always%20but%20StartDate%20and%20EndDate%20are%20not%20displaying%20for%20few%20of%20SPN.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECan%20you%20please%20help%20how%20to%20get%20it%20%3F%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EBelow%20is%20Power%20shell%20script%20I%20am%20using%3A%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-powershell%22%3E%3CCODE%3E%24TenantId%20%3D%20%22*************%22%0A%24ClientId%20%3D%20%22*************%22%0A%24ClientSecret%20%3D%20%22*************%22%0A%0A%24Body%20%3D%20%40%7B%0A%20%20%20%20'tenant'%20%3D%20%24TenantId%0A%20%20%20%20'client_id'%20%3D%20%24ClientId%0A%20%20%20%20'scope'%20%3D%20'https%3A%2F%2Fgraph.microsoft.com%2F.default'%0A%20%20%20%20'client_secret'%20%3D%20%24ClientSecret%0A%20%20%20%20'grant_type'%20%3D%20'client_credentials'%0A%7D%0A%0A%0A%24Params%20%3D%20%40%7B%0A%20%20%20%20'Uri'%20%3D%20%22https%3A%2F%2Flogin.microsoftonline.com%2F%24TenantId%2Foauth2%2Fv2.0%2Ftoken%22%0A%20%20%20%20'Method'%20%3D%20'Post'%0A%20%20%20%20'Body'%20%3D%20%24Body%0A%20%20%20%20'ContentType'%20%3D%20'application%2Fx-www-form-urlencoded'%0A%7D%0A%0A%24AuthResponse%20%3D%20Invoke-RestMethod%20%40Params%0A%0A%24Headers%20%3D%20%40%7B'Authorization'%20%3D%20%22Bearer%20%24(%24AuthResponse.access_token)%22%7D%0A%0A%24method%20%3D%20%22GET%22%0A%0A%24uri2%20%3D%20%22https%3A%2F%2Fgraph.microsoft.com%2Fv1.0%2Fapplications%2F%7BId%7D%22%0A%0A%24query2%20%3D%20Invoke-WebRequest%20-Method%20%24method%20-Uri%20%24uri2%20%20-ContentType%20%22application%2Fjson%22%20-Headers%20%24Headers%20-ErrorAction%20Stop%0A%0A%0A%24query2.content%20%7C%20ConvertFrom-Json%20%7C%20select%20appId%2CdisplayName%2C%40%7Bl%3D%22SecretExpiryDate%22%3Be%3D%7B%24pwdcreds2.passwordCredentials.endDateTime%7D%7D%0A%0A%24pwdcreds2.passwordCredentials%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSPAN%3EI%20have%20another%20Powershell%20script%20it%20is%20giving%20startdate%20and%20enddate%20for%20same%20SPN%20but%20the%20problem%20is%20my%20Org%20is%20not%20allowed%20to%20fetch%20APP%20details%20from%20Azure%20AD%20due%20to%20security%20guidelines.%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-powershell%22%3E%3CCODE%3E%24ServicePrincipalIds%20%3D%20Get-AzADServicePrincipal%20%7C%20Where%20%7B%24_.DisplayName%20-like%20'*'%7D%0A%0Aforeach(%24ServicePrincipalId%20in%20%24ServicePrincipalIds)%0A%7B%0A%24ServicePrincipalInfo%20%3D%20Get-AzADSpCredential%20-ObjectId%20%24ServicePrincipalId.Id%0A%24ServicePrincipalInfo%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThanks%2C%3C%2FP%3E%3CP%3EBrahma%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-1811320%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EAPI%20Management%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EApp%20Services%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EAzure%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1814399%22%20slang%3D%22en-US%22%3ERe%3A%20ServicePrincipal%20StartDate%20and%20EndDate%20not%20displaying%20Using%20Graph%20API%20In%20Power%20Shell%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1814399%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F554371%22%20target%3D%22_blank%22%3E%40Brahmaiah%3C%2FA%3E%2C%26nbsp%3Byou%20can%20use%20Azure%20CLI%20for%20exact%20same%20purpose.%20Do%20the%20following%3A%3C%2FP%3E%3CUL%20class%3D%22lia-list-style-type-circle%22%3E%3CLI%3ESign-in%20to%20your%20account%20in%20azure%3C%2FLI%3E%3CLI%3EOpen%20up%20a%20Cloud%20shell%3C%2FLI%3E%3CLI%3EOnce%26nbsp%3BAzure%20Cloud%20Shell%20is%20initialized%20in%20the%20account%2C%20click%20on%20curly%20braces%20in%20the%20panel%20to%20open%20editor%20(see%20screenshots%20attached%20below)%3C%2FLI%3E%3CLI%3EInsert%20the%20following%20command%20that%20will%20extract%20expiring%20SPs%20in%20the%20next%2060%20days%20(adjust%20the%20timeframe%20if%20needed)%3A%3C%2FLI%3E%3C%2FUL%3E%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Eaz%20ad%20sp%20list%20%5C%0A%20%20--all%20%5C%0A%20%20--query%20%22%5B%3FpasswordCredentials%5B0%5D.endDate%26lt%3B%3D'%24(date%20-d%20%22%2B60%20days%22%20%2B%25Y-%25m-%25d)'%7C%7CkeyCredentials%5B0%5D.endDate%26lt%3B%3D'%24(date%20-d%20%22%2B60%20days%22%20%2B%25Y-%25m-%25d)'%5D.%7B%5C%22App%20ID%20Display%20Name%5C%22%3AappDisplayName%2C%5C%22SP%20appId%5C%22%3AappId%2C%5C%22Password%20Expiry%20Date%5C%22%3ApasswordCredentials%5B0%5D.endDate%2C%20%5C%22Key%20Expiry%20Date%5C%22%3AkeyCredentials%5B0%5D.endDate%7D%22%20%5C%0A%20%20-o%20table%3C%2FCODE%3E%3C%2FPRE%3E%3CUL%20class%3D%22lia-list-style-type-circle%22%3E%3CLI%3ESave%20this%20script%20with%20whatever%20filename%20you%20want%20(%22sp-list%22%20in%20my%20case)%3C%2FLI%3E%3CLI%3EExecute%20with%20%22bash%20sp-list%22%3C%2FLI%3E%3CLI%3EEnjoy%20the%20list%26nbsp%3B%3CIMG%20class%3D%22lia-deferred-image%20lia-image-emoji%22%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Fhtml%2Fimages%2Femoticons%2Fsmile_40x40.gif%22%20alt%3D%22%3Asmile%3A%22%20title%3D%22%3Asmile%3A%22%20%2F%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EScreenshots%3A%3C%2FP%3E%3CP%3EEdit%3C%2FP%3E%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22edit.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F229006i23820A16BD7F0AB6%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22edit.png%22%20alt%3D%22edit.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%3CP%3EExecute%3C%2FP%3E%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22exec.png%22%20style%3D%22width%3A%20786px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F229007iBDEEB4BD243807EA%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22exec.png%22%20alt%3D%22exec.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1820888%22%20slang%3D%22en-US%22%3ERe%3A%20ServicePrincipal%20StartDate%20and%20EndDate%20not%20displaying%20Using%20Graph%20API%20In%20Power%20Shell%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1820888%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F554371%22%20target%3D%22_blank%22%3E%40Brahmaiah%3C%2FA%3E%2C%20I%20think%20you're%20missing%20a%20'foreach'%20to%20go%20through%20the%20collection%20of%20the%20expiring%20SPs%20(had%20no%20chance%20to%20look%20at%20it%20more%20closely).%20Anyway%2C%20please%20take%20a%20look%20at%20the%20script%20below%20that%20generates%20a%20decent%20report%20for%20the%20same%20purpose.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-markup%22%3E%3CCODE%3E%24tenantID%20%3D%20'%3CYOUR%20tenantid%3D%22%22%3E'%0A%24clientID%20%3D%20'%3CYOUR%20clientid%3D%22%22%3E'%0A%24clientSecret%20%3D%20(ConvertTo-SecureString%20'%3CYOUR%20client%3D%22%22%20secret%3D%22%22%3E'%20-AsPlainText%20-Force)%0A%24accessToken%20%3D%20Get-MsalToken%20-clientID%20%24clientID%20-clientSecret%20%24clientSecret%20-tenantID%20%24tenantID%20%7C%20Select-Object%20-Property%20AccessToken%0A%0A%23%20MS%20Graph%20Apps%20URI%0A%24aadAppsURI%20%3D%20'https%3A%2F%2Fgraph.microsoft.com%2Fv1.0%2Fapplications'%0A%23%20Get%20Expiring%20Creds%20in%20x%20Days%0A%24expiryCheck%20%3D%2060%0A%24now%20%3D%20(Get-Date).ToUniversalTime()%20%0A%24expiryLimit%20%3D%20%24now.AddDays(%24expiryCheck)%0A%23%20MS%20Graph%20Directory%20Audit%20URI%0A%24signInsURI%20%3D%20'https%3A%2F%2Fgraph.microsoft.com%2Fv1.0%2FauditLogs%2FdirectoryAudits'%0A%0A%23%20Report%20Template%0A%24aadAppReportTemplate%20%3D%20%5Bpscustomobject%5D%5Bordered%5D%40%7B%20%0A%20%20%20%20displayName%20%20%20%20%20%3D%20%24null%20%0A%20%20%20%20createdDateTime%20%3D%20%24null%20%0A%20%20%20%20signInAudience%20%20%3D%20%24null%20%20%0A%7D%20%0A%0A%23%20Get%20Apps%0A%24aadApplications%20%3D%20%40()%0A%24aadApps%20%3D%20Invoke-RestMethod%20-Headers%20%40%7BAuthorization%20%3D%20%22Bearer%20%24(%24accessToken.AccessToken)%22%20%7D%20%60%0A%20%20%20%20-Uri%20%20%24aadAppsURI%20%60%0A%20%20%20%20-Method%20Get%0A%0A%24aadApps.value.Count%0A%0Aif%20(%24aadApps.value)%20%7B%0A%20%20%20%20%24aadApplications%20%2B%3D%20%24aadApps.value%0A%20%20%20%20%23%20More%20Apps%3F%0A%20%20%20%20if%20(%24aadApps.'%40odata.nextLink')%20%7B%0A%20%20%20%20%20%20%20%20%24nextPageURI%20%3D%20%24aadApps.'%40odata.nextLink'%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24aadApps%20%3D%20%24null%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%24aadApps%20%3D%20Invoke-RestMethod%20-Headers%20%40%7BAuthorization%20%3D%20%22Bearer%20%24(%24accessToken.AccessToken)%22%20%7D%20%60%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-Uri%20%20%24nextPageURI%20%60%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-Method%20Get%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24aadApps.value)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24aadApplications%20%2B%3D%20%24aadApps.value%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24aadApplications.value.Count%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24aadApps.'%40odata.nextLink')%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24nextPageURI%20%3D%20%24aadApps.'%40odata.nextLink'%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24nextPageURI%20%3D%20%24null%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20until%20(!%24nextPageURI)%0A%20%20%20%20%7D%0A%7D%0A%0A%24aadApplications%20%3D%20%24aadApplications%20%7C%20Sort-Object%20-Property%20createdDateTime%20-Descending%0A%24aadAppsReport%20%3D%20%40()%0A%24expiringCredsApps%20%3D%20%40()%0A%0Aforeach%20(%24app%20in%20%24aadApplications)%20%7B%0A%20%20%20%20%24blnExpiringCreds%20%3D%20%24false%20%0A%20%20%20%20%23%20Report%20Output%20%20%20%20%0A%20%20%20%20%24reportData%20%3D%20%24aadAppReportTemplate.PsObject.Copy()%0A%20%20%20%20%24reportData.displayName%20%3D%20%24app.displayName%0A%20%20%20%20%24reportData.createdDateTime%20%3D%20%24app.createdDateTime%0A%20%20%20%20%24reportData.signInAudience%20%3D%20%24app.signInAudience%0A%0A%20%20%20%20%23%20Key%20Expiry%0A%20%20%20%20if%20(%24app.keyCredentials)%20%7B%0A%20%20%20%20%20%20%20%20%24keys%20%3D%20%40()%0A%20%20%20%20%20%20%20%20foreach%20(%24cred%20in%20%24app.keyCredentials)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5Bdatetime%5D%24keyExpiry%20%3D%20%24cred.endDateTime%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24keyExpiry%20-lt%20%24expiryLimit)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Warning%20%22%24(%24app.displayName)%3A%20Key%20expired%2Fexpiring%20on%20%24(%24keyExpiry)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24blnExpiringCreds%20%3D%20%24true%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24keys%20%2B%3D%20%24app.keyCredentials%20%7C%20Select-Object%20-Property%20%40%7BName%20%3D%20'displayName'%3B%20Expression%20%3D%20%7B%20%24cred.displayName%20%7D%20%7D%2C%20%40%7BName%20%3D%20'keyId'%3B%20Expression%20%3D%20%7B%20%24cred.keyId%20%7D%20%7D%2C%20%40%7BName%20%3D%20'startDateTime'%3B%20Expression%20%3D%20%7B%20%24cred.startDateTime%20%7D%20%7D%2C%20%40%7BName%20%3D%20'endDateTime'%3B%20Expression%20%3D%20%7B%20%24cred.endDateTime%20%7D%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%24reportData%20%7C%20Add-Member%20-Type%20NoteProperty%20-Name%20%22keyCredentials%22%20-Value%20%40(%24keys)%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23%20Password%20Expiry%0A%20%20%20%20if%20(%24app.passwordCredentials)%20%7B%0A%20%20%20%20%20%20%20%20%24passwords%20%3D%20%40()%0A%20%20%20%20%20%20%20%20foreach%20(%24cred%20in%20%24app.passwordCredentials)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5Bdatetime%5D%24keyExpiry%20%3D%20%24cred.endDateTime%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24keyExpiry%20-lt%20%24expiryLimit)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Warning%20%22%24(%24app.displayName)%3A%20Password%20expired%2Fexpiring%20on%20%24(%24keyExpiry)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24blnExpiringCreds%20%3D%20%24true%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24passwords%20%2B%3D%20%24app.passwordCredentials%20%7C%20Select-Object%20-Property%20%40%7BName%20%3D%20'displayName'%3B%20Expression%20%3D%20%7B%20%24cred.displayName%20%7D%20%7D%2C%20%40%7BName%20%3D%20'keyId'%3B%20Expression%20%3D%20%7B%20%24cred.keyId%20%7D%20%7D%2C%20%40%7BName%20%3D%20'startDateTime'%3B%20Expression%20%3D%20%7B%20%24cred.startDateTime%20%7D%20%7D%2C%20%40%7BName%20%3D%20'endDateTime'%3B%20Expression%20%3D%20%7B%20%24cred.endDateTime%20%7D%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%24reportData%20%7C%20Add-Member%20-Type%20NoteProperty%20-Name%20%22passwordCredentials%22%20-Value%20%40(%24passwords)%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23%20SignIns%0A%20%20%20%20%24appSignIns%20%3D%20%24null%20%0A%20%20%20%20%24appSignIns%20%3D%20Invoke-RestMethod%20-Headers%20%40%7BAuthorization%20%3D%20%22Bearer%20%24(%24accessToken.AccessToken)%22%20%7D%20%60%0A%20%20%20%20%20%20%20%20-Uri%20%20%22%24(%24signInsURI)%3F%26amp%3B%60%24filter%3DtargetResources%2Fany(t%3A%20t%2Fid%20eq%20%60'%24(%24app.id)%60')%22%20%60%0A%20%20%20%20%20%20%20%20-Method%20Get%0A%20%20%20%0A%20%20%20%20if%20(%24appSignIns.value)%20%7B%0A%20%20%20%20%20%20%20%20%22%24(%24app.displayName)%3A%20%24(%24appSignIns.value.Count)%20recent%20signIns%22%0A%20%20%20%20%20%20%20%20%24reportData%20%7C%20Add-Member%20-Type%20NoteProperty%20-Name%20%22recentSignIns%22%20-Value%20%24appSignIns.value.Count%0A%20%20%20%20%7D%0A%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%22%24(%24app.displayName)%3A%20%24(%24appSignIns.value.Count)%20recent%20signIns%22%0A%20%20%20%20%20%20%20%20%24reportData%20%7C%20Add-Member%20-Type%20NoteProperty%20-Name%20%22recentSignIns%22%20-Value%20'0'%0A%20%20%20%20%7D%0A%20%20%20%20%24aadAppsReport%20%2B%3D%20%24reportData%0A%0A%20%20%20%20if%20(%24blnExpiringCreds)%20%7B%0A%20%20%20%20%20%20%20%20%24expiringCredsApps%20%2B%3D%20%24reportData%0A%20%20%20%20%7D%0A%7D%0A%0A%24expiringCredsApps.count%20%0A%24expiringCredsApps%20%7C%20Format-Table%0A%0A%23%20Report%20%0A%24aadAppsReport%20%7C%20Format-Table%20-AutoSize%3C%2FYOUR%3E%3C%2FYOUR%3E%3C%2FYOUR%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3BUpdate%20the%20information%20in%20the%20first%20three%20lines%20(i.e.%2C%20TenantID%2C%20ClientID%2C%20ClientSecret)%20with%20the%20values%20from%20your%20app%20registration.%20Make%20sure%20that%20the%20app%20you%20registered%20has%20the%20following%20permissions%20(from%20Microsoft%20Graph)%3A%3C%2FP%3E%3CUL%3E%3CLI%3EApplication.Read.All%3C%2FLI%3E%3CLI%3EAuditLog.Read.All%3C%2FLI%3E%3C%2FUL%3E%3CP%3EAlso%2C%26nbsp%3B%3CSPAN%3EThe%20MSAL.PS%20module%20is%20used%20for%20Microsoft%20Graph%20Authentication.%20It%20can%20be%20installed%20with%20the%20following%20command%3A%26nbsp%3B%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3EInstall-Module%20-Name%20MSAL.PS%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20first%20part%20of%20the%20report%20includes%20the%20apps%20whose%20credentials%20will%20be%20expiring%20within%20the%20next%2060%20days%20(on%20the%20number%20you%20specified%20in%20the%20ninth%20line%20of%20the%20script).%26nbsp%3B%20The%20second%20part%20includes%20the%20recent%20sign-ins%20info%20for%20the%20SPs%20that%20are%20already%20exipired%20or%20expiring%20soon.%20The%20third%20part%20is%20all%20about%20all%20the%20registered%20apps%20and%20the%20audit%20log%20of%20the%20recent%20sign-ins%20(usability%20stats).%3C%2FP%3E%3CP%3EThis%20is%20something%20you%20can%20schedule%20and%20even%20expand%20it%20further%20to%20enable%20notifications%20using%20automation.%3C%2FP%3E%3C%2FLINGO-BODY%3E
Highlighted
Contributor

Hi,

 

I am trying to get list of SPNs that are going to expire soon. Using Graph API  I am executing below powershell script.

 

I am getting output appid and name always but StartDate and EndDate are not displaying for few of SPN.

 

Can you please help how to get it ?

 

Below is Power shell script I am using:

$TenantId = "*************"
$ClientId = "*************"
$ClientSecret = "*************"

$Body = @{
    'tenant' = $TenantId
    'client_id' = $ClientId
    'scope' = 'https://graph.microsoft.com/.default'
    'client_secret' = $ClientSecret
    'grant_type' = 'client_credentials'
}


$Params = @{
    'Uri' = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"
    'Method' = 'Post'
    'Body' = $Body
    'ContentType' = 'application/x-www-form-urlencoded'
}

$AuthResponse = Invoke-RestMethod @Params

$Headers = @{'Authorization' = "Bearer $($AuthResponse.access_token)"}

$method = "GET"

$uri2 = "https://graph.microsoft.com/v1.0/applications/{Id}"

$query2 = Invoke-WebRequest -Method $method -Uri $uri2  -ContentType "application/json" -Headers $Headers -ErrorAction Stop


$query2.content | ConvertFrom-Json | select appId,displayName,@{l="SecretExpiryDate";e={$pwdcreds2.passwordCredentials.endDateTime}}

$pwdcreds2.passwordCredentials

 

I have another Powershell script it is giving startdate and enddate for same SPN but the problem is my Org is not allowed to fetch APP details from Azure AD due to security guidelines.

 

$ServicePrincipalIds = Get-AzADServicePrincipal | Where {$_.DisplayName -like '*'}

foreach($ServicePrincipalId in $ServicePrincipalIds)
{
$ServicePrincipalInfo = Get-AzADSpCredential -ObjectId $ServicePrincipalId.Id
$ServicePrincipalInfo
}

 

Thanks,

Brahma

3 Replies
Highlighted
Best Response confirmed by Brahmaiah (Contributor)
Solution

@Brahmaiah, you can use Azure CLI for exact same purpose. Do the following:

  • Sign-in to your account in azure
  • Open up a Cloud shell
  • Once Azure Cloud Shell is initialized in the account, click on curly braces in the panel to open editor (see screenshots attached below)
  • Insert the following command that will extract expiring SPs in the next 60 days (adjust the timeframe if needed):
az ad sp list \
  --all \
  --query "[?passwordCredentials[0].endDate<='$(date -d "+60 days" +%Y-%m-%d)'||keyCredentials[0].endDate<='$(date -d "+60 days" +%Y-%m-%d)'].{\"App ID Display Name\":appDisplayName,\"SP appId\":appId,\"Password Expiry Date\":passwordCredentials[0].endDate, \"Key Expiry Date\":keyCredentials[0].endDate}" \
  -o table
  • Save this script with whatever filename you want ("sp-list" in my case)
  • Execute with "bash sp-list"
  • Enjoy the list :smile:

 

Screenshots:

Edit

edit.png

Execute

exec.png

Highlighted

@Command0r  thank you so much for your reply.

 

Can you please suggest why I am not able to get result using Graph API, this is happening only when SPN has too many start and end date. I need run this script in automation account by scheduling without any manual intervention.

 

Another Power shell script giving result as bellow.

 

SPN_Date_List.png

 

Thanks,

Brahma

Highlighted

@Brahmaiah, I think you're missing a 'foreach' to go through the collection of the expiring SPs (had no chance to look at it more closely). Anyway, please take a look at the script below that generates a decent report for the same purpose.

 

 

$tenantID = '<your TenantID>'
$clientID = '<your ClientID>'
$clientSecret = (ConvertTo-SecureString '<your Client Secret>' -AsPlainText -Force)
$accessToken = Get-MsalToken -clientID $clientID -clientSecret $clientSecret -tenantID $tenantID | Select-Object -Property AccessToken

# MS Graph Apps URI
$aadAppsURI = 'https://graph.microsoft.com/v1.0/applications'
# Get Expiring Creds in x Days
$expiryCheck = 60
$now = (Get-Date).ToUniversalTime() 
$expiryLimit = $now.AddDays($expiryCheck)
# MS Graph Directory Audit URI
$signInsURI = 'https://graph.microsoft.com/v1.0/auditLogs/directoryAudits'

# Report Template
$aadAppReportTemplate = [pscustomobject][ordered]@{ 
    displayName     = $null 
    createdDateTime = $null 
    signInAudience  = $null  
} 

# Get Apps
$aadApplications = @()
$aadApps = Invoke-RestMethod -Headers @{Authorization = "Bearer $($accessToken.AccessToken)" } `
    -Uri  $aadAppsURI `
    -Method Get

$aadApps.value.Count

if ($aadApps.value) {
    $aadApplications += $aadApps.value
    # More Apps?
    if ($aadApps.'@odata.nextLink') {
        $nextPageURI = $aadApps.'@odata.nextLink'
        do {
            $aadApps = $null 
            $aadApps = Invoke-RestMethod -Headers @{Authorization = "Bearer $($accessToken.AccessToken)" } `
                -Uri  $nextPageURI `
                -Method Get
            if ($aadApps.value) {
                $aadApplications += $aadApps.value
                $aadApplications.value.Count
            }
            if ($aadApps.'@odata.nextLink') {
                $nextPageURI = $aadApps.'@odata.nextLink'
            }
            else {
                $nextPageURI = $null
            }
        } until (!$nextPageURI)
    }
}

$aadApplications = $aadApplications | Sort-Object -Property createdDateTime -Descending
$aadAppsReport = @()
$expiringCredsApps = @()

foreach ($app in $aadApplications) {
    $blnExpiringCreds = $false 
    # Report Output    
    $reportData = $aadAppReportTemplate.PsObject.Copy()
    $reportData.displayName = $app.displayName
    $reportData.createdDateTime = $app.createdDateTime
    $reportData.signInAudience = $app.signInAudience

    # Key Expiry
    if ($app.keyCredentials) {
        $keys = @()
        foreach ($cred in $app.keyCredentials) {
            [datetime]$keyExpiry = $cred.endDateTime
            if ($keyExpiry -lt $expiryLimit) {
                Write-Warning "$($app.displayName): Key expired/expiring on $($keyExpiry)"
                $blnExpiringCreds = $true
            }
            $keys += $app.keyCredentials | Select-Object -Property @{Name = 'displayName'; Expression = { $cred.displayName } }, @{Name = 'keyId'; Expression = { $cred.keyId } }, @{Name = 'startDateTime'; Expression = { $cred.startDateTime } }, @{Name = 'endDateTime'; Expression = { $cred.endDateTime } }
        }
        $reportData | Add-Member -Type NoteProperty -Name "keyCredentials" -Value @($keys)
    }

    # Password Expiry
    if ($app.passwordCredentials) {
        $passwords = @()
        foreach ($cred in $app.passwordCredentials) {
            [datetime]$keyExpiry = $cred.endDateTime
            if ($keyExpiry -lt $expiryLimit) {
                Write-Warning "$($app.displayName): Password expired/expiring on $($keyExpiry)"
                $blnExpiringCreds = $true
            }
            $passwords += $app.passwordCredentials | Select-Object -Property @{Name = 'displayName'; Expression = { $cred.displayName } }, @{Name = 'keyId'; Expression = { $cred.keyId } }, @{Name = 'startDateTime'; Expression = { $cred.startDateTime } }, @{Name = 'endDateTime'; Expression = { $cred.endDateTime } }
        }
        $reportData | Add-Member -Type NoteProperty -Name "passwordCredentials" -Value @($passwords)
    }

    # SignIns
    $appSignIns = $null 
    $appSignIns = Invoke-RestMethod -Headers @{Authorization = "Bearer $($accessToken.AccessToken)" } `
        -Uri  "$($signInsURI)?&`$filter=targetResources/any(t: t/id eq `'$($app.id)`')" `
        -Method Get
   
    if ($appSignIns.value) {
        "$($app.displayName): $($appSignIns.value.Count) recent signIns"
        $reportData | Add-Member -Type NoteProperty -Name "recentSignIns" -Value $appSignIns.value.Count
    }
    else {
        "$($app.displayName): $($appSignIns.value.Count) recent signIns"
        $reportData | Add-Member -Type NoteProperty -Name "recentSignIns" -Value '0'
    }
    $aadAppsReport += $reportData

    if ($blnExpiringCreds) {
        $expiringCredsApps += $reportData
    }
}

$expiringCredsApps.count 
$expiringCredsApps | Format-Table

# Report 
$aadAppsReport | Format-Table -AutoSize

 

 

 Update the information in the first three lines (i.e., TenantID, ClientID, ClientSecret) with the values from your app registration. Make sure that the app you registered has the following permissions (from Microsoft Graph):

  • Application.Read.All
  • AuditLog.Read.All

Also, The MSAL.PS module is used for Microsoft Graph Authentication. It can be installed with the following command: 

 

 

Install-Module -Name MSAL.PS

 

 

The first part of the report includes the apps whose credentials will be expiring within the next 60 days (on the number you specified in the ninth line of the script).  The second part includes the recent sign-ins info for the SPs that are already exipired or expiring soon. The third part is all about all the registered apps and the audit log of the recent sign-ins (usability stats).

This is something you can schedule and even expand it further to enable notifications using automation.