Forum Discussion
List all users' last login date
Is it possible, using PowerShell, to list all AAD users' last login date (no matter how they logged in)? I have found a couple of scripts that check the last mailbox login, but that is not what we need, because we also want to list unlicensed users.
- StanikoCopper Contributor
JakobRohde this is a classic Microsoft 365 housekeeping task and question. A pity Microsoft is not offering something out of the box.
I would suggest following Powershell script, which returns not only your users last login date as CSV file, but also assigned licenses. This way you may check whether there is someone not logging in and consuming licenses.
Install-Module AzureADPreview -AllowClobber -Force Connect-AzureAD $usersexport = [system.collections.arraylist]@() Get-AzureADUser | % { $User = $_ $UPN = $User.UserPrincipalName Write-Output "Start analysing $UPN" $LoginTime = Get-AzureAdAuditSigninLogs -top 1 -filter "userprincipalname eq '$UPN'" | select CreatedDateTime $Licenses = Get-AzureADUserLicenseDetail -ObjectId $User.ObjectId | % { $_.ServicePlans | Where {$_.AppliesTo -eq "User"}} | select -ExpandProperty ServicePlanName $Export = [pscustomobject]@{ 'DisplayName' = $User.DisplayName; 'UserPrincipalName' = $UPN; 'LastSignInDate' = $LoginTime.CreatedDateTime; 'Licenses' = $Licenses -join ","; } $usersexport.Add($Export) Write-Output $Export } $usersexport | Export-CSV $Home\LastLogonDate.csv
- jjdmsgcCopper Contributor
Staniko
Thank you for the above, looks exactly what I need but am getting the following error when running an elevated ISE PowerShell window:Get-AzureAdAuditSigninLogs : The term 'Get-AzureAdAuditSigninLogs' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:9 char:18
+ $LoginTime = Get-AzureAdAuditSigninLogs -top 1 -filter "userprinc ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-AzureAdAuditSigninLogs:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundExceptionAny ideas? 🙂
- Dia_2Copper ContributorThis is great! how would you set the script to run aganst a specific dynamic cloud security group?
- Joe_GhalebCopper Contributori ran the script but it's giving me empty results on the LastSignInDate, do you know why this is happening?
No. Use the report in the O365 admin center -> Reports -> Usage -> Active users.
- JakobRohdeIron ContributorThanks, Vasil. That will have to do, but what I really needed was to be able to sort on user type (internal user, guest user, administrator etc.)
- Robert LuckIron Contributor
I think this is what you need.
The above functionality is available in AdminDroid Office 365 Reporter.
- Joshua BinesIron Contributoror Get-AzureADAuditSignInLogs (AzureADPreview) or Search-UnifiedAuditLog
- Thijs LecomteBronze ContributorThis is now available native through the Graph API: https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-beta&tabs=http#example-5-list-the-last-sign-in-time-of-users-in-a-specific-time-range
- NicolasHonBrass ContributorThere is a way, please see my post on this topic and unmark your post as answer.
- NicolasHonBrass ContributorYES, This is possible!
But you need to do a little trick because it is only accessible via the Graph API. If you want to achieve that by PowerShell, you need to create an application, with a secret, that has access with the permission AuditLog.Read.All and User.Read.All and call this application with Graph command to do your query.
You can see my PowerShell script bellow:
#Replace [tenant_id], [Application_ID], [client_secret] with your own values
#Provide your Office 365 Tenant Id or Tenant Domain Name
$TenantId = "[tenant_id]"
#Provide Azure AD Application (client) Id of your app.
#You should have granted Admin consent for this app to use the application permissions "AuditLog.Read.All and User.Read.All" in your tenant.
$AppClientId="[Application_ID]"
#Provide Application client secret key
$ClientSecret = "[client_secret]"
$RequestBody = @{client_id=$AppClientId;client_secret=$ClientSecret;grant_type="client_credentials";scope="https://graph.microsoft.com/.default";}
$OAuthResponse = Invoke-RestMethod -Method 'Post' -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Body $RequestBody
$AccessToken = $OAuthResponse.access_token
#Form request headers with the acquired $AccessToken
$headers = @{'Content-Type'="application\json";'Authorization'="Bearer $AccessToken"}
#This request get users list with signInActivity.
$ApiUrl = "https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,signInActivity,userType,assignedLicenses,mail,createdDateTime&`$top=999"
$Result = @()
While ($ApiUrl -ne $Null){ #Perform pagination if next page link (odata.nextlink) returned.
$Response = Invoke-WebRequest -Method 'GET' -Uri $ApiUrl -ContentType "application\json" -Headers $headers | ConvertFrom-Json
if($Response.value){
$Users = $Response.value
ForEach($User in $Users){
#Filter only Guests
if ($User.userType -eq 'Guest'){
$Result += New-Object PSObject -property $([ordered]@{
UserID = $User.id
DisplayName = $User.displayName
ExternalDomain = if ($User.mail) {$User.mail.Split("@")[1]} else {$null}
Email = $user.mail
UserPrincipalName = $User.userPrincipalName
CreationDateTime = if($User.createdDateTime) {[DateTime]$User.createdDateTime} else {$null}
LastSignInDateTime = if($User.signInActivity.lastSignInDateTime) { [DateTime]$User.signInActivity.lastSignInDateTime } else {$null}
IsLicensed = if ($User.assignedLicenses.Count -ne 0) { $true } else { $false }
IsGuestUser = if ($User.userType -eq 'Guest') { $true } else { $false }
URL = "https://portal.azure.com/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/Profile/userId/"+$user.id
})
}
}
}
$ApiUrl=$Response.'@odata.nextlink'
}
#Export to local computer
$Result | Export-CSV "C:\Temp\LastLoginDateReport.CSV" -NoTypeInformation -Encoding UTF8
Enjoy! 🙂- Joshua BinesIron ContributorNicolasHon - FYI AuditLog.Read.All may not work as expected the work around is to use Directory.Read.All permissions. https://docs.microsoft.com/en-us/graph/known-issues#license-check-errors-for-azure-ad-activity-reports
- NicolasHonBrass ContributorThanks for this information. I never had this issue.
- dcorsoCopper Contributor
NicolasHonThanks for this it worked as is. I was close but was having trouble with the actual lastsignindate being output. I think the OP originally wanted all users not just Guest users but should be easy to figure that out.
- DeletedHi NicolasHon, does on have to create an app still? I see in the docs that one can authenticate directly in powershell with an admin account by using graph SDK (https://docs.microsoft.com/en-us/graph/powershell/get-started) Or have I misunderstood?
Could something like this work with only direct commands in powershell?
Install-Module Microsoft.Graph
Connect-MgGraph -Scope "User.Read.All"
Select-MgProfile -Name "beta"
Get-MgUser -Filter "signInActivity/lastSignInDateTime le 2021-09-30T00:00:00Z$select=id,displayName,userType"
$Result | Export-CSV "C:\Temp\LastLoginDateReport.CSV" -NoTypeInformation -Encoding UTF8- NicolasHonBrass ContributorHi Niklask, yes you could also achieve that using this way. The thing is that you need to have an admin role to approve Microsoft Graph module when running it from PowerShell. It is less practical as I don't have a permanent admin so I need to go in PIM, activate my admin role, and then run the script. With the app this is not the case as I don't use Graph commands in PowerShell and just do Graph API's calls. The app allow you also to schedule this script in a scheduled task or to access it from a Power Automate Flow to do periodic report.
- Deleted
This might give you what you're after...
- Robert LuckIron Contributor
The provided script gives you the last login information of users who have Exchange Online license whereas the requirement is to display "last logon time" of unlicensed users as well.
- Deleted
Hi Robert,
I tested the script it also provides the logon times for "Unlicensed Users" as well and exports them to a .CSV.
- Deleted
Once you've logged in and authenticated against your Office 365 tenant, you can then use the below commands.
# Connects you to Windows Azure Active Directory
Connect-MsolService
# Gets Unlicenced users and lists the "DisplayName, LastLogonTime and LastLogoffTime"
Get-MsolUser -UnlicensedUsersOnly | Foreach {Get-MailboxStatistics $_.UserPrincipalName | Select DisplayName, LastLogonTime, LastLogoffTime}
- Jay CarperBrass Contributor
What about users who don't have mailboxes? I have a number of users for whom we have disabled the Exchange Online license. How can I get their logon statistics?
- Max FritzIron Contributor
Just a warning that using the Get-MailboxStatistics cmdlet to get this information is highly unreliable (see TonyRedmond's great blog on that here: https://www.petri.com/get-mailboxstatistics-cmdlet-wrong). The Office 365 usage reports is really the better answer here.
- Kevin_MorganIron Contributor
The Microsoft Graph API now supports the resource property signInActivity in users end-point, this resource exposes the lastSignInDateTime property which shows the last time a user made a successful sign-in. Fetching signInActivity property requires an Azure AD Premium P1/P2 license and the AuditLog.Read.All permission. The following request retrieves user details along with signInActivity property.
#GET Request https://graph.microsoft.com/beta/users?$select=displayName,signInActivity
Before Microsoft Graph supports this property, we need to either get the mailbox last logon time using the Get-MailboxStatistics cmdlet or we need to crawl the Azure AD sign-in logs or the Unified audit logs in the Security and Compliance Center.
You can refer the below post to know more details about how to find and export Last login date for all Azure AD Users using PowerShell.
- Joshua BinesIron Contributor
Kevin_Morgan license? 😉 the lastsignin property is a static value that is populated for all user accounts including guest accounts (see thread) back to apr 2020.
Edit: I'm guessing you mean the tenant has 'any' aad p1/p2. Haven't tested this maybe you are right?
- Kevin_MorganIron Contributor
Yes the value may get populated for all users. But we need the license to retrieve the lastlogin value through Microsoft Graph API. The Microsoft's document itself still indicates the same and so my testing. Hope still there is no other API or PowerShell cmdlet to get the details without Azure AD Premium P1/P2 license. Can you please point me if you know any resources?
- SystemEngineerSteel ContributorHi Jakob, Did you finally get the updated script?
- Malith_JayashanCopper Contributor
This can be done using AzureADPreview
Import-Module AzureADPreview $UsersUPN = (Get-AzureADUser -Top 20000).UserPrincipalName foreach($user in $UsersUPN) { Get-AzureADAuditSignInLogs -Filter "UserPrincipalName eq '$user'" -Top 1| ` select CreatedDateTime, UserPrincipalName, IsInteractive, AppDisplayName, IpAddress, TokenIssuerType, @{Name = 'DeviceOS'; Expression = {$_.DeviceDetail.OperatingSystem}} Start-Sleep -Seconds 5 }
A Start-Sleep -Seconds 5 delay should be added in order to bypass the "Too many requests" error code
- Donald MostellerCopper ContributorWhile this is good information for AAD, it appears to be limited to the past 90 days. We are looking for something static and retrievable like LastLogonTimestamp in AD or LastLogonTime in Exchange Online MailboxStatistics.
- Kevin_MorganIron Contributor
The Microsoft Graph API now supports the resource property signInActivity in users end-point, this resource exposes the lastSignInDateTime property which shows the last time a user made a successful sign-in. Fetching signInActivity property requires an Azure AD Premium P1/P2 license and the AuditLog.Read.All permission. The following request retrieves user details along with signInActivity property.
#GET Request https://graph.microsoft.com/beta/users?$select=displayName,signInActivity
You can refer the below post to know more details about how to find and export Last login date for all Azure AD Users using PowerShell.
- Joshua BinesIron Contributor
The thread that keeps on keeping on....
Here is a new page from MS on the topic with all the required information.
https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/howto-manage-inactive-user-accounts
- maurerisCopper ContributorHi Jakob,
Sorry, is possible to use one command in PowerShell for extraction the last logon in software Microsoft Project?
Thank you