Skip to content

Commit 9785934

Browse files
authored
Add files via upload
1 parent 946edff commit 9785934

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#requires -Version 7.0
2+
<#
3+
.SYNOPSIS
4+
Checks accounts from any CSV against Microsoft Entra ID and reports disabled users.
5+
6+
.DESCRIPTION
7+
Reads a CSV, identifies the column containing a user principal name or Entra object ID,
8+
queries Microsoft Graph, and exports accounts whose Entra accountEnabled property is false.
9+
The script requires internet access to Microsoft Graph but does not require a corporate
10+
network, VPN, domain controller, RSAT, or the ActiveDirectory module.
11+
12+
.PARAMETER CsvPath
13+
Input CSV path.
14+
15+
.PARAMETER IdentityColumn
16+
Column containing a user principal name or Entra user object ID. If omitted, the script
17+
auto-detects a common column name.
18+
19+
.PARAMETER OutputPath
20+
CSV path for disabled Entra accounts.
21+
22+
.PARAMETER FullReportPath
23+
Optional path for all lookup results, including enabled, disabled, not found, and errors.
24+
25+
.EXAMPLE
26+
./find_disabled_accounts.ps1 -CsvPath ./accounts.csv
27+
28+
.EXAMPLE
29+
./find_disabled_accounts.ps1 -CsvPath ./accounts.csv -IdentityColumn UserPrincipalName `
30+
-OutputPath ./DisabledAccounts_Report.csv -FullReportPath ./AccountLookup_FullReport.csv
31+
#>
32+
33+
[CmdletBinding()]
34+
param(
35+
[Parameter(Mandatory, Position = 0)]
36+
[ValidateScript({ Test-Path $_ -PathType Leaf })]
37+
[string]$CsvPath,
38+
39+
[Parameter()]
40+
[string]$IdentityColumn,
41+
42+
[Parameter()]
43+
[string]$OutputPath = (Join-Path $PWD 'DisabledAccounts_Report.csv'),
44+
45+
[Parameter()]
46+
[string]$FullReportPath
47+
)
48+
49+
Set-StrictMode -Version Latest
50+
$ErrorActionPreference = 'Stop'
51+
52+
foreach ($commandName in @('Connect-MgGraph','Get-MgContext','Get-MgUser')) {
53+
if (-not (Get-Command $commandName -ErrorAction SilentlyContinue)) {
54+
throw "Required command '$commandName' was not found. Install Microsoft.Graph.Authentication and Microsoft.Graph.Users."
55+
}
56+
}
57+
58+
$rows = @(Import-Csv -Path $CsvPath)
59+
if ($rows.Count -eq 0) { throw "The input CSV contains no rows: $CsvPath" }
60+
61+
$columns = @($rows[0].PSObject.Properties.Name)
62+
if ([string]::IsNullOrWhiteSpace($IdentityColumn)) {
63+
$candidateColumns = @(
64+
'UserPrincipalName','UPN','MemberUPNorAppId','MemberUserPrincipalName',
65+
'Email','Mail','UserEmail','Account','Username','UserId','Id','ObjectId'
66+
)
67+
$IdentityColumn = $candidateColumns | Where-Object { $_ -in $columns } | Select-Object -First 1
68+
if ([string]::IsNullOrWhiteSpace($IdentityColumn)) {
69+
throw "Could not auto-detect an identity column. Available columns: $($columns -join ', '). Use -IdentityColumn."
70+
}
71+
}
72+
elseif ($IdentityColumn -notin $columns) {
73+
throw "Identity column '$IdentityColumn' was not found. Available columns: $($columns -join ', ')."
74+
}
75+
76+
$requiredScopes = @('User.Read.All')
77+
$context = Get-MgContext
78+
$mustConnect = $null -eq $context -or 'User.Read.All' -notin @($context.Scopes)
79+
if ($mustConnect) { Connect-MgGraph -Scopes $requiredScopes -NoWelcome | Out-Null }
80+
81+
$identities = @(
82+
$rows | ForEach-Object { [string]$_.PSObject.Properties[$IdentityColumn].Value } |
83+
ForEach-Object { $_.Trim() } |
84+
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
85+
Sort-Object -Unique
86+
)
87+
88+
$results = [System.Collections.Generic.List[object]]::new()
89+
foreach ($identity in $identities) {
90+
try {
91+
$user = Get-MgUser -UserId $identity -Property Id,DisplayName,UserPrincipalName,Mail,AccountEnabled,UserType,OnPremisesSyncEnabled,OnPremisesSamAccountName -ErrorAction Stop
92+
$results.Add([pscustomobject]@{
93+
InputIdentity = $identity
94+
FoundInEntra = $true
95+
DisplayName = $user.DisplayName
96+
UserPrincipalName = $user.UserPrincipalName
97+
Mail = $user.Mail
98+
EntraObjectId = $user.Id
99+
AccountEnabled = $user.AccountEnabled
100+
UserType = $user.UserType
101+
OnPremisesSyncEnabled = $user.OnPremisesSyncEnabled
102+
OnPremisesSamAccountName = $user.OnPremisesSamAccountName
103+
Status = if ($user.AccountEnabled -eq $false) { 'Disabled' } else { 'Enabled' }
104+
Error = $null
105+
})
106+
}
107+
catch {
108+
$results.Add([pscustomobject]@{
109+
InputIdentity = $identity
110+
FoundInEntra = $false
111+
DisplayName = $null
112+
UserPrincipalName = $null
113+
Mail = $null
114+
EntraObjectId = $null
115+
AccountEnabled = $null
116+
UserType = $null
117+
OnPremisesSyncEnabled = $null
118+
OnPremisesSamAccountName = $null
119+
Status = 'NotFoundOrLookupError'
120+
Error = $_.Exception.Message
121+
})
122+
}
123+
}
124+
125+
$disabled = @($results | Where-Object { $_.FoundInEntra -eq $true -and $_.AccountEnabled -eq $false })
126+
$parent = Split-Path -Parent $OutputPath
127+
if ($parent) { New-Item -Path $parent -ItemType Directory -Force | Out-Null }
128+
$disabled | Sort-Object DisplayName,UserPrincipalName |
129+
Export-Csv -Path $OutputPath -NoTypeInformation -Encoding utf8
130+
131+
if (-not [string]::IsNullOrWhiteSpace($FullReportPath)) {
132+
$fullParent = Split-Path -Parent $FullReportPath
133+
if ($fullParent) { New-Item -Path $fullParent -ItemType Directory -Force | Out-Null }
134+
$results | Sort-Object Status,DisplayName,InputIdentity |
135+
Export-Csv -Path $FullReportPath -NoTypeInformation -Encoding utf8
136+
}
137+
138+
Write-Host "Identity column: $IdentityColumn"
139+
Write-Host "Unique identities checked: $($identities.Count)"
140+
Write-Host "Found in Entra: $(@($results | Where-Object FoundInEntra -eq $true).Count)"
141+
Write-Host "Disabled in Entra: $($disabled.Count)" -ForegroundColor $(if ($disabled.Count) { 'Yellow' } else { 'Green' })
142+
Write-Host "Not found or error: $(@($results | Where-Object FoundInEntra -eq $false).Count)"
143+
Write-Host "Disabled report: $OutputPath" -ForegroundColor Cyan
144+
if ($FullReportPath) { Write-Host "Full report: $FullReportPath" -ForegroundColor Cyan }
145+
if ($disabled.Count -gt 0) {
146+
$disabled | Select-Object DisplayName,UserPrincipalName,Mail,UserType,OnPremisesSyncEnabled |
147+
Format-Table -AutoSize -Wrap
148+
}

0 commit comments

Comments
 (0)