I'm using the following script to get inactive sign in from azure:
$AppClientId=""
$Secret = ""
$uri = "https://login.microsoft.com/a1a5384f-f0fc-4df9-9f37-caf775af43c1/oauth2/token"
$body = @{
grant_type = "client_credentials"
client_id = $AppClientId
client_secret = $Secret
resource = "https://graph.microsoft.com"
$resp = Invoke-RestMethod -Method Post -Uri $uri -Body $body -ContentType "application/x-www-form-urlencoded"
Write-Host $resp.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&`$top=999"
$Result = @()
While ($ApiUrl -ne $Null) #Perform pagination if next page link (odata.nextlink) returned.
$Response = Invoke-RestMethod -Method GET -Uri $ApiUrl -ContentType "application\json" -Headers $headers
if($Response.value)
$Users = $Response.value
ForEach($User in $Users)
$Result += New-Object PSObject -property $([ordered]@{
DisplayName = $User.displayName
UserPrincipalName = $User.userPrincipalName
LastSignInDateTime = if($User.signInActivity.lastSignInDateTime) { [DateTime]$User.signInActivity.lastSignInDateTime } Else {$null}
LastNonInteractiveSignInDateTime = if($User.signInActivity.lastNonInteractiveSignInDateTime) { [DateTime]$User.signInActivity.lastNonInteractiveSignInDateTime } Else { $null }
IsLicensed = if ($User.assignedLicenses.Count -ne 0) { $true } else { $false }
IsGuestUser = if ($User.userType -eq 'Guest') { $true } else { $false }
$ApiUrl=$Response.'@odata.nextlink'
$Result | Export-CSV "C:\LastLoginDateReport.CSV" -NoTypeInformation -Encoding UTF8
It gives the following output:
Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.
At D:\Work Data\Get Inactive Users from Azure AD.ps1:34 char:14
... Response = Invoke-RestMethod -Method GET -Uri $ApiUrl -ContentType " ...
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I tried to get the access token by Postman and import it manual to the variable and the connection is success but the problem is the token has a limited time.
So, I need to do that through the script.
Thanks
You have almost everything already, just need to parse the $body response variable. Here's an example from one of my scripts:
#region Authentication
#We use the client credentials flow as an example. For production use, REPLACE the code below with your preferred auth method. NEVER STORE CREDENTIALS IN PLAIN TEXT!!!
#Variables to configure
$tenantID = "tenant.onmicrosoft.com" #your tenantID or tenant root domain
$appID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #the GUID of your app.
$client_secret = "verylongsecurestring" #client secret for the app
#Prepare token request
$url = 'https://login.microsoftonline.com/' + $tenantId + '/oauth2/v2.0/token'
$body = @{
grant_type = "client_credentials"
client_id = $appID
client_secret = $client_secret
scope = "https://graph.microsoft.com/.default"
#Obtain the token
Write-Verbose "Authenticating..."
try { $tokenRequest = Invoke-WebRequest -Method Post -Uri $url -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing -ErrorAction Stop }
catch { Write-Host "Unable to obtain access token, aborting..."; return }
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
$authHeader = @{
'Content-Type'='application\json'
'Authorization'="Bearer $token"
#endregion Authentication
Also, you can take a look at the MSAL.PS module.