Continuing the Journey to Explore the SDK

Recently, I’ve been looking at how to use the Microsoft Graph SDK for PowerShell. As you might recall, the SDK cmdlets essentially act as wrappers around Graph API calls. Microsoft’s hope is that the SDK will make it easier for developers and administrators to embrace and use the Graph through familiar PowerShell.

So far, I’ve explored the practical aspects of using the SDK by explaining how to remove individual service plans from Office 365 licenses, how to create a licensing report for a tenant, and how to send email from Exchange Online. I’ve also pointed out some considerations administrators and developers should understand when using the SDK. In this article, we’ll look at accessing Azure AD sign-in information. Specifically, how to report the last sign-in for accounts.

Why Review Account Sign-in Data

Azure AD sign-in data is available for the last 30 days. You can access the data interactively through the Azure AD admin center, where you can filter the data and download whatever you want (in CSV or JSON format). The data is also available through the Get-AzureADAuditSignInLogs cmdlet.

Why pay any attention to sign-in data? For tenant accounts, the lack of any sign-in activity might point to unused accounts which might hold valuable licenses. There are good reasons why an account might be inactive for a period, such as extended leave. Even so, it’s good to know if accounts are inactive.

Guest accounts don’t generate any cost for a tenant unless you use premium Azure AD features like conditional access or dynamic Microsoft 365 groups. The older method of licensing operates on the basis that the tenant needs to buy premium licenses based on a 1:5 ratio (five guests for each Azure AD premium license. Since September 2020, Microsoft has advocated a newer monthly active user (MAU) model where tenants pay only if they exceed a 50,000 monthly active user threshold for premium features.

Even if guest accounts don’t incur a big licensing overhead, that’s no reason to ignore guest account sign-ins. For instance, it’s good to know if any guest accounts come from competitor domains or other organizations that you’d prefer not to share information with (an Azure B2B collaboration policy can stop people adding new guest accounts for blacklisted domains).

Coding a Report

The script (downloadable from GitHub) is straightforward. Here are the major steps:

  • Connect to the Microsoft Graph, specifying that the Auditlog.Read.All permission is required. If the service principal for the SDK doesn’t already have consent for this permission, it prompts to receive administrative approval.
  • Find all accounts using the Get-MgUser cmdlet.
  • For each account, use the Get-MgAuditLogSignIn cmdlet to see if we can retrieve the most recent sign-in record. Some applications (like Teams) generate many sign-in records over a day. We’re only interested in knowing the last time an account signed in, so use the Top parameter to specify that the Graph should return 1 record. Given that the Graph returns the most recent data first, the first record is the latest.
  • Extract information for reporting from the sign-in data, including calculating the number of days since the last sign-in.
  • Report what’s been found and generate a CSV file containing the results. Also display the data using Out-GridView (Figure 1).
Reviewing Azure AD sign-in data for tenant and guest accounts
Figure 1: Reviewing Azure AD sign-in data for tenant and guest accounts

A Usable SDK

In this instance, switching from Azure AD to SDK cmdlets doesn’t pose any great challenge, and the experience of working with SDK cmdlets as documented in this series of articles show that the SDK is more than usable. Any issues that exist with the Microsoft Graph SDK for PowerShell are in other areas, like the poor documentation and permissions creep for the service principal if scripts are run interactively. Documentation will improve over time, and you can run Graph-based scripts in the background using certificate-based authentication.

The point is that the Graph SDK is a project still in the early stages of development. It will get better as Microsoft removes the rough edges. For now, developers might prefer to call Graph APIs direct without using the SDK. In a year’s time, who knows?

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Comments

  1. Fernando Gualano

    Thanks Tony! Great Post! 🙂
    I’d like to know how can I add the “Status” (Success | Failed | Interrupted) to the script. This is displayed in the “Basic info” tab of each Sign In Log:

    Date: xxx
    Request ID: xxx-xxx-xxx-xxx-xxx
    Correlation ID: xxx-xxx-xxx-xxx-xxx
    Authentication requirement :xxx
    Status: Success
    Continuous access evaluation: No

    Even though the Get-MgAuditLogSignIn cmdlet returned the “Status”, I only see the errorCode, failureReason and additionalDetails fields and none of them returned the actual status (Success | Failed | Interrupted).

    Is it possible to return the Status of each Sign In the same way I get it from the Azure Sign In Logs portal?

    Thanks!

    1. Avatar photo
      Tony Redmond

      The Status gives a value like this:

      $lastsignin.status

      AdditionalDetails ErrorCode FailureReason
      —————– ——— ————-
      MFA requirement satisfied by claim in the token 0 Other.

      I think you’ll have to interpret the ErrorCode and output a value like Success, Failed, or Interrupted depending on its value.

      1. Fernando Gualano

        Thank you Tony!! 😉

  2. Elbert Santos

    Hi,

    Thank you for the amazing work.

    I’d like to know how can I add the Location to the script.

    1. Avatar photo
      Tony Redmond

      The location for the sign-in is returned in

      $lastSignIn.Location

      City CountryOrRegion State
      —- ————— —–
      Dublin IE Dublin

      Add whatever property you want to the set included in the report and the job is done.

  3. Carl Knecht

    Looks like this only captures interactive user sign-ins. Are you aware of any method to capture non-interactive user sign-ins as well?

  4. Ariel

    Which attribute should I look for if I want to know if that specific entry or sign in used TLS 1.0/1.1?

    1. Avatar photo
      Tony Redmond

      [array]$LastSignIn = Get-MgAuditLogSignIn -Filter “UserId eq ‘$($User.Id)'” -Top 1

      Looking at $LastSignIn.AdditionalProperties[“uniqueTokenIdentifier”], I think you’ll see a token if modern authentication. It’s kind of hard for me to know because none of the clients in my tenant use basic authentication.

Leave a Reply