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).
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?
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!
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.
Thank you Tony!! 😉
Hi,
Thank you for the amazing work.
I’d like to know how can I add the Location to the script.
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.
Looks like this only captures interactive user sign-ins. Are you aware of any method to capture non-interactive user sign-ins as well?
I’m not sure the API supports retrieval for non-interactive sign-ins. At least, I haven’t seen any documentation to that effect. It looks as if the Get-MgAuditLogSignin cmdlet requires a user id https://docs.microsoft.com/en-us/powershell/module/microsoft.graph.reports/get-mgauditlogsignin?view=graph-powershell-beta
Which attribute should I look for if I want to know if that specific entry or sign in used TLS 1.0/1.1?
[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.