Forum Discussion

Brahmaiah's avatar
Brahmaiah
Brass Contributor
Oct 23, 2020

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

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

  • 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

    Execute

  • Command0r's avatar
    Command0r
    Iron Contributor

    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

    Execute

    • Brahmaiah's avatar
      Brahmaiah
      Brass Contributor

      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.

       

       

      Thanks,

      Brahma

      • Command0r's avatar
        Command0r
        Iron Contributor

        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.

Resources