/commands/entra-id/get-last-sign-in-date-users
Get the last sign-in date of Microsoft Entra ID users with PowerShell (signInActivity)
- tool
- Microsoft Entra ID
- versions
- Microsoft.Graph.Users 2.41.2
- os
- windows, linux, macos
The last sign-in time of Microsoft Entra ID users is the signInActivity property of the user object. With the Microsoft Graph PowerShell SDK, connect with AuditLog.Read.All and User.Read.All, and request the property explicitly with Get-MgUser -Property; it is not returned by default:
Connect-MgGraph -Scopes 'AuditLog.Read.All', 'User.Read.All'
Get-MgUser -All -Property Id, UserPrincipalName, AccountEnabled, SignInActivity |
Select-Object UserPrincipalName, AccountEnabled,
@{n='LastSuccessful'; e={$_.SignInActivity.LastSuccessfulSignInDateTime}},
@{n='LastInteractive'; e={$_.SignInActivity.LastSignInDateTime}},
@{n='LastNonInteractive'; e={$_.SignInActivity.LastNonInteractiveSignInDateTime}} |
Sort-Object LastSuccessfulReading lastSuccessfulSignInDateTime needs a Microsoft Entra ID P1 or P2 license, and Reports Reader is the least privileged role for delegated access. Timestamps are in UTC.
The properties
The block reads the SignInActivity model from Microsoft.Graph.Users 2.41.2 and asks the SDK's offline permission catalog which permission the property needs:
Import-Module Microsoft.Graph.Users
[Microsoft.Graph.PowerShell.Models.MicrosoftGraphSignInActivity].GetProperties() |
Where-Object Name -like '*DateTime' | ForEach-Object { $_.Name }
Find-MgGraphPermission -SearchString AuditLog.Read.All -ExactMatch |
ForEach-Object { '{0} ({1})' -f $_.Name, $_.PermissionType }Output
LastNonInteractiveSignInDateTime LastSignInDateTime LastSuccessfulSignInDateTime AuditLog.Read.All (Delegated) AuditLog.Read.All (Application)
| Property | What it records |
|---|---|
| LastSuccessfulSignInDateTime | Last successful sign-in, interactive or not; best for inactivity reports (from December 2023, not backfilled) |
| LastSignInDateTime | Last interactive attempt, including failed ones |
| LastNonInteractiveSignInDateTime | Last attempt by a client signing in on the user behalf, successful or not; kept since May 2020 |
A blank value means the account never signed in, or its last sign-in was before April 2020.
Find users inactive for 90 days
Filter on the server instead of downloading every user:
$cutoff = (Get-Date).ToUniversalTime().AddDays(-90).ToString('yyyy-MM-ddTHH:mm:ssZ')
Get-MgUser -All -Filter "signInActivity/lastSuccessfulSignInDateTime le $cutoff" `
-Property UserPrincipalName, AccountEnabled, SignInActivity |
Select-Object UserPrincipalName, AccountEnabled, @{n='Last'; e={$_.SignInActivity.LastSuccessfulSignInDateTime}}The signInActivity filter supports eq, ne, not, ge and le, but cannot be combined with other filterable properties in the same -Filter; filter the rest in PowerShell with Where-Object. Users that never signed in have no value and are not matched by le, so list them separately with Where-Object { -not $_.SignInActivity.LastSuccessfulSignInDateTime } on a full export. Microsoft suggests 90 to 180 days as a common window.
Pitfalls
- A property missing from
-Propertyis empty in the output even when it has a value, a common reason for "no data" reports; see the -Property and -ConsistencyLevel notes. - The Graph permissions are not enough on their own:
lastSuccessfulSignInDateTimealso needs a P1 or P2 license in the tenant. - The value can lag up to 24 hours behind the sign-in logs.
- For on-premises accounts, the equivalent is
lastLogonTimestampin Active Directory; see Search-ADAccount -AccountInactive.
Once you have the list, block the accounts with Update-MgUser -AccountEnabled:$false before deleting them.
FAQ
Why is SignInActivity empty in Get-MgUser output?
It is not returned by default. Name it in -Property, and connect with AuditLog.Read.All as well as User.Read.All. The tenant also needs Microsoft Entra ID P1 or P2.
What is the difference between lastSignInDateTime and lastSuccessfulSignInDateTime?
lastSignInDateTime is the last interactive attempt, failed ones included. lastSuccessfulSignInDateTime is the last successful sign-in, interactive or not, and is the one to use for inactive-account reports. It exists since December 2023 and was not backfilled.
How current is the value?
Microsoft says the last sign-in on the user object can take up to 24 hours to update. Use the sign-in logs when you need near real-time data.