Read-only PowerShell script generator
Pick the reports you need and get one script that writes each to CSV. It only reads, runs on your machine and sends nothing to us.
configcobra-reports.ps1 · 4 reports# ConfigCobra read-only report script
# Built at https://configcobra.com/tools/powershell-script-generator
#
# Read-only: besides signing in it only calls Get-*, Search-* and Resolve-* cmdlets, and writes CSV files to .\configcobra-reports.
# Nothing is sent to ConfigCobra. Run it in PowerShell 7 (SharePoint: Windows PowerShell 5.1).
#
# Install the modules once:
# Install-Module Microsoft.Graph -Scope CurrentUser
$ErrorActionPreference = 'Stop'
$InactiveDays = 90
$ExpiryDays = 30
$OutDir = Join-Path (Get-Location) 'configcobra-reports'
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
function Save-Report($Rows, $Name) {
$rows = @($Rows)
$path = Join-Path $OutDir "$Name.csv"
if ($rows.Count) { $rows | Export-Csv -Path $path -NoTypeInformation -Encoding utf8 }
Write-Host ('{0,-34} {1,6} rows{2}' -f $Name, $rows.Count, $(if ($rows.Count) { " -> $path" } else { '' }))
}
# ─── Microsoft Entra ID (Microsoft Graph) ────────────────────────
Connect-MgGraph -Scopes 'User.Read.All','AuditLog.Read.All','Application.Read.All' -NoWelcome
# One read of all users, shared by the user reports (sign-in dates need Entra ID P1/P2).
$Users = Get-MgUser -All -Property id,displayName,userPrincipalName,mail,userType,accountEnabled,createdDateTime,externalUserState,signInActivity
function Get-LastSignIn($u) {
@($u.SignInActivity.LastSignInDateTime, $u.SignInActivity.LastNonInteractiveSignInDateTime, $u.SignInActivity.LastSuccessfulSignInDateTime) |
Where-Object { $_ } | Sort-Object -Descending | Select-Object -First 1
}
# Users inactive 90 days
$cutoff = (Get-Date).AddDays(-$InactiveDays)
$rows = $Users | Where-Object { $_.UserType -eq 'Member' -and $_.AccountEnabled -and (Get-LastSignIn $_) -and (Get-LastSignIn $_) -lt $cutoff } |
Select-Object DisplayName, UserPrincipalName, @{n='LastSignIn';e={ Get-LastSignIn $_ }}, CreatedDateTime
Save-Report $rows 'inactive-users'
# Guests who never signed in
$rows = $Users | Where-Object { $_.UserType -eq 'Guest' -and -not (Get-LastSignIn $_) } |
Select-Object DisplayName, Mail, ExternalUserState, CreatedDateTime
Save-Report $rows 'guests-never-signed-in'
# Users with no MFA registered
$rows = Get-MgReportAuthenticationMethodUserRegistrationDetail -All |
Where-Object { -not $_.IsMfaRegistered } |
Select-Object UserDisplayName, UserPrincipalName, UserType, IsAdmin, @{n='MethodsRegistered';e={ $_.MethodsRegistered -join ', ' }}
Save-Report $rows 'users-without-mfa'
# Expired or soon-expiring app credentials
$limit = (Get-Date).AddDays($ExpiryDays)
$rows = Get-MgApplication -All -Property displayName,appId,passwordCredentials,keyCredentials | ForEach-Object {
$app = $_
foreach ($c in $app.PasswordCredentials) { [pscustomobject]@{ App = $app.DisplayName; AppId = $app.AppId; Type = 'Secret'; Name = $c.DisplayName; Expires = $c.EndDateTime } }
foreach ($c in $app.KeyCredentials) { [pscustomobject]@{ App = $app.DisplayName; AppId = $app.AppId; Type = 'Certificate'; Name = $c.DisplayName; Expires = $c.EndDateTime } }
} | Where-Object { $_.Expires -and $_.Expires -lt $limit } |
Select-Object App, AppId, Type, Name, Expires, @{n='Status';e={ if ($_.Expires -lt (Get-Date)) { 'Expired' } else { 'Expiring' } }} |
Sort-Object Expires
Save-Report $rows 'expiring-app-credentials'
Disconnect-MgGraph | Out-Null
Write-Host "Done. Reports are in $OutDir"
Read the script before you run it — it is short on purpose. Run it from the folder where you want the CSVs.
How the script works
Read-only by design
Apart from signing in, every report uses Get-*, Search-* or Resolve-* cmdlets only, and Microsoft Graph is asked for .Read. scopes only. The script cannot change users, mailboxes, sites or resources.
Runs on your machine
You run the script yourself, signed in as yourself. The results go to CSV files in a local folder; nothing is uploaded anywhere, including to ConfigCobra.
Permissions it asks for
Microsoft Graph shows a consent prompt listing exactly the read scopes of the reports you picked. Exchange, SharePoint and Azure use the roles you already have; Reader is enough for Azure.
Licences
Sign-in dates and MFA registration details come from Microsoft Entra ID P1 or P2. Without them those reports come back empty; the others work on any tenant.
Go further
- Microsoft 365 tenant lookupFind the tenant ID behind any domain, its region, cloud and sign-in type.
- CIS benchmark checklistsEvery control of a CIS benchmark in one list, as a CSV download.
- Email domain checkerCheck SPF, DKIM and DMARC for any domain in seconds, with what to fix.
- InsightsWhy each of these findings matters and how to fix it
- All free tools6 no-login helpers for admins
Want these reports without running scripts?
ConfigCobra's inventory has these risk views built in, next to the CIS benchmark checks. Read-only.