If you’ve recently restricted user registration for applications or are analyzing your Enterprise applications, you might find a significant amount of work ahead.
First, you may want to find if there are applications with no user assigned. Then you may wonder if there are applications without sign-ins in the last 30 days.
To ease your work, you may find it useful to query all applications for these fields and get the output in a CSV. This script is based on Ravenswood PoC code, with the intent of helping out and refining it a bit.
First, head to Enterprise Applications | AAD and click “Download (Export)”, then download the CSV.

This is done via the portal and not via PowerShell for practicality. If you are not interested in reviewing Microsoft Applications, filter the csv file to just keep “Enterprise Application” under applicationType. This will greatly improve the processing time.
Then save the following script in the same directory where you downloaded the EnterpriseAppsList.csv. Name the script StaleApplicationAnalysis.ps1.
The script will require AzureADPreview.
Update 2024: The script does not detect non-interactive sign-ins. To detect non-interactive sign-ins, Get-MgAuditLogSignIn should be used. I have not modified this script yet to use Graph.
# Connect to Azure AD
# Check if AzureAD module is installed
if (-not (Get-Module -Name AzureADPreview -ListAvailable)) {
Write-Host "AzureADPreview module is not installed. Installing..."
Install-Module -Name AzureADPreview -Force
}
# Import AzureAD module
try {
Import-Module -Name AzureADPreview -ErrorAction Stop
Write-Host "AzureADPreview module imported successfully."
} catch {
Write-Host "Failed to import AzureADPreview module: $_" -ForegroundColor Red
}
Connect-AzureAD
$AllApplications = Import-Csv .\EnterpriseAppsList.csv
$Output = @() # Array to store output objects
foreach ($Application in $AllApplications) {
# Retrieve the objectid and signin logs, format the user assigned to the app
$app = Get-AzureADServicePrincipal -All $true | where { $_.objectid -eq $application.id }
$Log = Get-AzureADAuditSignInLogs -All $true -Filter "appid eq '$($App.AppID)'"
$userassigned = Get-AzureADServiceAppRoleAssignment -ObjectId $App.ObjectId | Select ResourceDisplayName, PrincipalDisplayName
$userCount = 0
if ($userassigned -ne $null) {
$format = $userassigned.GetType()
if ($format.basetype.name -eq "Object") {
$userassigned = [string]$userassigned
}
$userCount = $userassigned.Count;
}
# Create a custom object for output
$Table = [PSCustomObject]@{
ApplicationName = $App.DisplayName
ApplicationID = $App.AppID
SignIns = $Log.Count
Users = $userCount
}
$Output += $Table
$Table
Start-Sleep 4 # The sleep is to avoid throttling
}
# Export the output to CSV
$Output | Export-Csv -Path .\StaleApplicationCleanup.csv -NoTypeInformation
And finally, run the script. This will take a bit of time since I had to implement a sleep timer to prevent throttling.
.\StaleApplicationAnalysis.ps1
The output will be along these lines, with an additional column for the App ID:

If you happen to find any optimization, feel free to let me know, and I’ll update the post.