-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathrun_EntraFalcon.ps1
More file actions
439 lines (357 loc) · 23.6 KB
/
run_EntraFalcon.ps1
File metadata and controls
439 lines (357 loc) · 23.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
<#
.Synopsis
PowerShell-based security assessment tool for Microsoft Entra ID environments.
.Description
EntraFalcon is a PowerShell-based assessment tool for pentesters, security analysts, and system administrators to evaluate the security posture of a Microsoft Entra ID environment.
The tool identifies potential privilege escalation paths, excessive permissions, inactive accounts, and Conditional Access misconfigurations across users, groups, applications, roles, and policies. Findings are compiled into interactive HTML reports with a simple risk scoring.
Designed with a focus on ease of use, EntraFalcon runs on PowerShell 5.1 and 7, supports Windows, Linux, and macOS, and requires no external dependencies or Microsoft Graph API consent.
.PARAMETER Tenant
Specifies the Entra ID tenant to authenticate against.
Use this to target a specific tenant ID or domain, especially when enumerating tenants other than the account’s home tenant.
- `organizations` (for multi-tenant apps)
- A specific tenant ID
Default: `organizations`
.PARAMETER UserAgent
Specifies the user agent string to be used in the HTTP requests to the token endpoint and APIs
Default: `EntraFalcon`
.PARAMETER ApiTop
Specifies the Graph API page size (number of objects per response). Use a lower value if you encounter HTTP 504 errors (this will result in more API requests).
The default value used by Microsoft Graph API is 100. Valid range: 5–999.
Default: `999`
.PARAMETER DisableCAE
Disables Continuous Access Evaluation (CAE), resulting in shorter-lived access tokens.
Useful when CAE breaks the script.
.PARAMETER LimitResults
Limits the number of groups or users included in the report.
The limit is applied *after* sorting by risk score, ensuring only the highest-risk groups and users are processed and reported. This helps improve performance and keep the reports usable in large environments.
.PARAMETER AuthFlow
Preferred authentication flow selector.
Supported values:
- `BroCi` (default): BroCi flow
- `AuthCode`: Auth Code flow (non-BroCi)
- `DeviceCode`: Device Code flow
- `ManualCode`: Auth Code + Manual Code flow (non-BroCi)
- `BroCiManualCode`: BroCi + Manual Code flow
- `BroCiToken`: BroCi flow using a supplied refresh token (`-BroCiToken`)
.PARAMETER BroCiToken
Optional Bring Your Own BroCi refresh token.
Required when using `-AuthFlow BroCiToken`.
The provided token must be a valid refresh token for the Azure Portal client (c44b4083-3bb0-49c1-b47d-974e53cbdf3c).
Treat this value as sensitive secret material.
.PARAMETER SkipPimForGroups
Skips the enumeration of PIM for Groups, avoiding the need for a secondary authentication flow.
.PARAMETER IncludeMsApps
Includes Microsoft-owned enterprise applications in the enumeration and analysis.
By default, these are excluded to reduce noise.
.PARAMETER LogLevel
Controls runtime status output.
- `Off` (default): No additional status output
- `Verbose`: High-level status messages
- `Debug`: Includes Verbose plus additional details useful for debugging
- `Trace`: Includes Debug plus very detailed output (may be noisy)
.PARAMETER QAMode
Dumps the AllGroups and AllUsers objects as JSON for internal QA tests.
.PARAMETER Csv
Enables CSV report generation for enumeration modules.
By default, reports are written as HTML and TXT only.
.NOTES
Author: Christian Feuchter, Compass Security Switzerland AG, https://www.compass-security.com/
Source: https://github.com/CompassSecurity/EntraFalcon
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $false)]
[ValidateSet("BroCi", "AuthCode", "DeviceCode", "ManualCode", "BroCiManualCode", "BroCiToken")]
[string]$AuthFlow = "BroCi",
[Parameter(Mandatory = $false)]
[ValidateSet("Off", "Verbose", "Debug", "Trace")]
[string]$LogLevel = "Off",
[Parameter(Mandatory = $false)]
[string]$UserAgent = "EntraFalcon",
[Parameter(Mandatory = $false)]
[switch]$SkipPimForGroups = $false,
[Parameter(Mandatory = $false)]
[switch]$IncludeMsApps = $false,
[Parameter(Mandatory=$false)]
[switch]$DisableCAE = $false,
[Parameter(Mandatory=$false)]
[string]$Tenant,
[Parameter(Mandatory = $false)]
[string]$OutputFolder,
[Parameter(Mandatory = $false)]
[int]$LimitResults,
[Parameter(Mandatory = $false)]
[ValidateRange(5, 999)]
[int]$ApiTop = 999,
[Parameter(Mandatory=$false)]
[switch]$QAMode = $false,
[Parameter(Mandatory=$false)]
[switch]$Csv = $false,
[Parameter(Mandatory=$false)]
[switch]$ExportCapUncoveredUsers = $false,
[Parameter(Mandatory = $false)]
[string]$BroCiToken
)
#Constants
$EntraFalconVersion = "V20260414"
# Import shared functions
$ScriptRoot = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
Import-Module (Join-Path $ScriptRoot 'modules\EntraTokenAid.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\Send-ApiRequest.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\shared_Functions.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_Groups.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_EnterpriseApps.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_AppRegistrations.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_Users.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_ManagedIdentities.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_Roles.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_CAPs.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\Send-GraphBatchRequest.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\Send-GraphRequest.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\export_Summary.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_PIM.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_Tenant.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_AgentIdentityBlueprints.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_AgentIdentityBlueprintsPrincipals.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_AgentIdentities.psm1') -Force
Import-Module (Join-Path $ScriptRoot 'modules\check_AgentsFinalize.psm1') -Force
if ($AuthFlow -ne "BroCiToken" -and -not [string]::IsNullOrWhiteSpace($BroCiToken)) {
Write-Error "Invalid parameter combination: -BroCiToken can only be used with -AuthFlow BroCiToken." -ErrorAction Stop
}
if ($AuthFlow -eq "BroCiToken" -and [string]::IsNullOrWhiteSpace($BroCiToken)) {
Write-Error "Invalid parameter combination: -AuthFlow BroCiToken requires -BroCiToken." -ErrorAction Stop
}
# Check non-Windows auth flow compatibility (Linux/macOS)
if (-not (Test-NonWindowsAuthFlowCompatibility -AuthFlow $AuthFlow -ReadmePath (Join-Path $ScriptRoot 'README.md'))) {
return
}
#Splat AuthMethods
$Global:GLOBALAuthMethods = @{
AuthFlow = $AuthFlow
}
if (-not [string]::IsNullOrWhiteSpace($BroCiToken)) {
# Access tokens (JWT) typically start with 'ey'
if ($BroCiToken.StartsWith("ey")) {
Write-Error "Invalid -BroCiToken: access token (JWT) detected. A refresh token is required." -ErrorAction Stop
}
# Must look like a refresh token (Azure refresh tokens usually start with "1.")
if (-not $BroCiToken.StartsWith("1.")) {
Write-Error "Invalid -BroCiToken: expected a refresh token starting with '1.'." -ErrorAction Stop
}
$GLOBALAuthMethods.BroCiToken = $BroCiToken
}
#Define additional authentication parameters
$Global:GLOBALEntraFalconLogLevel = $LogLevel
$Global:GLOBALAuthParameters = @{}
$GLOBALAuthParameters['UserAgent'] = $UserAgent
if ($DisableCAE) {
$GLOBALAuthParameters['DisableCAE'] = $true
}
if ($null -ne $Tenant -and "" -ne $Tenant) {
$GLOBALAuthParameters['Tenant'] = $Tenant
}
# Optional parameters for the sub-modules
$optionalParamsET = @{}
if ($IncludeMsApps) {
$optionalParamsET['IncludeMsApps'] = $true
}
$optionalParamsUserandGroup = @{}
if ($LimitResults) {
$optionalParamsUserandGroup['LimitResults'] = $LimitResults
}
if ($QAMode) {
$optionalParamsUserandGroup['QAMode'] = $QAMode
}
$optionalParamsOutput = @{}
if ($Csv) {
$optionalParamsOutput['Csv'] = $true
}
$optionalParamsCap = @{}
if ($ExportCapUncoveredUsers) {
$optionalParamsCap['ExportCapUncoveredUsers'] = $true
}
#Define summary array and show banner
Start-InitTasks -EntraFalconVersion $EntraFalconVersion -UserAgent $UserAgent
Show-EntraFalconBanner -EntraFalconVersion $EntraFalconVersion
write-host ""
write-host "********************************** Main Authentication **********************************"
# Perform authentication check and authenticate if required
if (-Not(EnsureAuthMsGraph)) {
Return
}
if (-not($SkipPimForGroups)) {
write-host ""
write-host "********************************** PIM for Groups: Pre-Collection Phase **********************************"
$TenantPimForGroupsAssignments = Get-PimforGroupsAssignments
} else {
$global:GLOBALPimForGroupsChecked = $false
}
write-host ""
write-host "********************************** Gather Basic Data **********************************"
# Gather basic data
$CurrentTenant = Get-OrgInfo
$StartTimestamp = Get-Date -Format "yyyyMMdd_HHmm"
$GlobalAuditSummary.Tenant.Name = $CurrentTenant.DisplayName
$GlobalAuditSummary.Tenant.Id = $CurrentTenant.Id
$licenseResult = Get-EffectiveEntraLicense
$GlobalAuditSummary.TenantLicense.Name = $licenseResult.EntraIDLicencesString
$GlobalAuditSummary.TenantLicense.Level = $licenseResult.EntraIDLicencesInt
$TenantDomains = Get-TenantDomains
#Define output folder if not defined
if ($null -eq $OutputFolder -or "" -eq $OutputFolder) {
$OutputFolder = "Results_$($CurrentTenant.DisplayName)_$($StartTimestamp)"
}
# Create report directory
if (-not (Test-Path -Path $OutputFolder)) {
try {
New-Item -ItemType Directory -Path $OutputFolder -ErrorAction Stop | out-null
} catch {
Write-Host "[!] Failed to create folder '$OutputFolder': $($_.Exception.Message)"
Write-Host "[!] Aborting..."
Start-CleanUp
exit 1
}
}
$AdminUnitWithMembers = Get-AdministrativeUnitsWithMembers
$Caps = Get-ConditionalAccessPolicies
# Get PIM eligible role assignments
if (Invoke-MsGraphAuthPIM) {
$TenantPimRoleAssignments = Get-EntraPIMRoleAssignments
}
#Get active role assignments and merge eligible
$TenantRoleAssignments = Get-EntraRoleAssignments -TenantPimRoleAssignments $TenantPimRoleAssignments
# Check if authentication to Azure ARM API works and if the user has access to a subscription
if ((EnsureAuthAzurePsNative) -and (checkSubscriptionNative)){
$global:GLOBALAzurePsChecks = $true
$AzureIAMAssignments = Get-AllAzureIAMAssignmentsNative
} else {
$global:GLOBALAzurePsChecks = $false
Write-Host "[!] No AzurePS session: No Azure IAM assignments will be checked"
$AzureIAMAssignments = @{}
}
if ($TenantPimForGroupsAssignments) {
Write-Host "[*] Post processing PIM for Groups results..."
$TenantPimForGroupsAssignments = Get-PIMForGroupsAssignmentsDetails -TenantPimForGroupsAssignments $TenantPimForGroupsAssignments
}
# Prepare authentication context for Security Findings extra API calls.
$global:GLOBALSecurityFindingsAccessContext = @{
TokenSource = "MainGraph"
IsAvailable = $true
Reason = ""
}
# Authentication for Security Findings
$isBroCiFlow = @("BroCi", "BroCiManualCode", "BroCiToken") -contains $AuthFlow
if ($isBroCiFlow) {
Write-Log -Level Verbose -Message "[SecurityFindings] BroCi flow detected. Reusing existing Graph token for special policy endpoints."
} elseif ($AuthFlow -eq "DeviceCode") {
$global:GLOBALSecurityFindingsAccessContext.TokenSource = "Unavailable"
$global:GLOBALSecurityFindingsAccessContext.IsAvailable = $false
$global:GLOBALSecurityFindingsAccessContext.Reason = "DeviceCodeNotSupported"
Write-Log -Level Verbose -Message "[SecurityFindings] DeviceCode flow detected. Special policy endpoints are skipped for this flow."
} else {
if (EnsureAuthSecurityFindingsMsGraph) {
$global:GLOBALSecurityFindingsAccessContext.TokenSource = "SecurityFindingsSpecial"
Write-Log -Level Verbose -Message "[SecurityFindings] Special Graph token acquired."
} else {
$global:GLOBALSecurityFindingsAccessContext.TokenSource = "Unavailable"
$global:GLOBALSecurityFindingsAccessContext.IsAvailable = $false
$global:GLOBALSecurityFindingsAccessContext.Reason = "AuthenticationFailed"
Write-Log -Level Verbose -Message "[SecurityFindings] Special policy endpoints will be skipped because special authentication failed."
}
}
# Get user's MFA status
$UserAuthMethodsTable = Get-RegisterAuthMethodsUsers
# Get Devices
$Devices = Get-Devices -ApiTop $ApiTop
# Get Basic User info
$AllUsersBasicHT = Get-UsersBasic -ApiTop $ApiTop
# Preload agent-specific basics so early reports can resolve mixed owner/member objects correctly.
$AgentObjectBasics = Get-AgentObjectBasics -CurrentTenant $CurrentTenant -ApiTop $ApiTop
# Determine which reports will be generated
$TenantReports = [pscustomobject]@{
Users = $true
Groups = $false
EnterpriseApps = $true
ManagedIdentities = $false
AppRegistrations = $false
AgentIdentities = $false
AgentIdentityBlueprintsPrincipals = $false
AgentIdentityBlueprints = $false
ConditionalAccessPolicies = $false
EntraRoles = $true
AzureRoles = $false
PimForEntra = $false
SecurityFindings = $true
Summary = $true
}
$ReportsBasedOnObjects = Get-TenantReportAvailability -IncludeMsApps:$IncludeMsApps
$global:GLOBALAzureIamWarningText = $null
if (-not $GLOBALAzurePsChecks) {
if ($ReportsBasedOnObjects.ManagedIdentities) {
$global:GLOBALAzureIamWarningText = "Coverage gap: Azure IAM not assessed (no subscription visible or accessible, but managed identities exist). Azure role assignments are therefore missing from this report."
} else {
$global:GLOBALAzureIamWarningText = "Coverage gap: Azure IAM not assessed (no subscriptions exist or no access). Azure role assignments are therefore missing from this report."
}
}
$TenantReports.ConditionalAccessPolicies = ($null -ne $Caps -and $Caps.Count -gt 0)
$TenantReports.PimForEntra = ($null -ne $TenantPimRoleAssignments -and $TenantPimRoleAssignments.Count -gt 0)
$TenantReports.AzureRoles = ($null -ne $AzureIAMAssignments -and $AzureIAMAssignments.Count -gt 0)
$TenantReports.Groups = $ReportsBasedOnObjects.Groups
$TenantReports.AppRegistrations = $ReportsBasedOnObjects.AppRegistrations
$TenantReports.ManagedIdentities = $ReportsBasedOnObjects.ManagedIdentities
$TenantReports.AgentIdentities = $ReportsBasedOnObjects.AgentIdentities
$TenantReports.AgentIdentityBlueprintsPrincipals = $ReportsBasedOnObjects.AgentIdentityBlueprintsPrincipals
$TenantReports.AgentIdentityBlueprints = $ReportsBasedOnObjects.AgentIdentityBlueprints
#$TenantReports.EnterpriseApps = $ReportsBasedOnObjects.EnterpriseApps
$global:ReportContext = [pscustomobject]@{
TenantName = $CurrentTenant.DisplayName
TenantId = $CurrentTenant.Id
StartTimestamp = $StartTimestamp
}
Initialize-TenantReportTabs -StartTimestamp $global:ReportContext.StartTimestamp -CurrentTenant $CurrentTenant -TenantReports $TenantReports
$TenantReportsText = ($TenantReports.PSObject.Properties | Sort-Object Name | ForEach-Object { "{0} = {1}" -f $_.Name, $_.Value }) -join " | "
Write-Log -Level Debug -Message ("Reports:{0}" -f $TenantReportsText)
$ServicePrincipalSignInActivityLookup = Get-ServicePrincipalSignInActivityLookup -ApiTop $ApiTop
# Main enumeration
write-host "`n********************************** [1/15] Enumerating Groups **********************************"
$AllGroupsDetails = Invoke-CheckGroups -AdminUnitWithMembers $AdminUnitWithMembers -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -ConditionalAccessPolicies $Caps -AzureIAMAssignments $AzureIAMAssignments -TenantRoleAssignments $TenantRoleAssignments -TenantPimForGroupsAssignments $TenantPimForGroupsAssignments -OutputFolder $OutputFolder -Devices $Devices -AllUsersBasicHT $AllUsersBasicHT -AgentObjectBasics $AgentObjectBasics -ApiTop $ApiTop @optionalParamsUserandGroup @optionalParamsOutput
write-host "`n********************************** [2/15] Enumerating Enterprise Apps **********************************"
$AppRoleReferenceCache = @{}
$EnterpriseApps = Invoke-CheckEnterpriseApps -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -AzureIAMAssignments $AzureIAMAssignments -TenantRoleAssignments $TenantRoleAssignments -AllGroupsDetails $AllGroupsDetails -OutputFolder $OutputFolder -AllUsersBasicHT $AllUsersBasicHT -AgentObjectBasics $AgentObjectBasics -ApiTop $ApiTop -ServicePrincipalSignInActivityLookup $ServicePrincipalSignInActivityLookup -AppRoleReferenceCacheOut ([ref]$AppRoleReferenceCache) @optionalParamsET @optionalParamsOutput
write-host "`n********************************** [3/15] Enumerating Managed Identities **********************************"
$ManagedIdentities = Invoke-CheckManagedIdentities -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -AzureIAMAssignments $AzureIAMAssignments -AppRoleReferenceCache $AppRoleReferenceCache -TenantRoleAssignments $TenantRoleAssignments -AllGroupsDetails $AllGroupsDetails -OutputFolder $OutputFolder -ApiTop $ApiTop @optionalParamsOutput
write-host "`n********************************** [4/15] Enumerating App Registrations **********************************"
$AppRegistrations = Invoke-CheckAppRegistrations -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -EnterpriseApps $EnterpriseApps -AllGroupsDetails $AllGroupsDetails -AgentObjectBasics $AgentObjectBasics -TenantRoleAssignments $TenantRoleAssignments -OutputFolder $OutputFolder @optionalParamsOutput
write-host "`n********************************** [5/15] Enumerating Agent Identities **********************************"
$AgentIdentities = Invoke-AgentIdentities -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -AzureIAMAssignments $AzureIAMAssignments -AppRoleReferenceCache $AppRoleReferenceCache -TenantRoleAssignments $TenantRoleAssignments -AllGroupsDetails $AllGroupsDetails -AllUsersBasicHT $AllUsersBasicHT -ApiTop $ApiTop -ServicePrincipalSignInActivityLookup $ServicePrincipalSignInActivityLookup @optionalParamsET
write-host "`n********************************** [6/15] Enumerating Agent Identity Blueprint Principals **********************************"
$AgentIdentityBlueprintsPrincipals = Invoke-AgentIdentityBlueprintsPrincipals -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -AzureIAMAssignments $AzureIAMAssignments -AppRoleReferenceCache $AppRoleReferenceCache -TenantRoleAssignments $TenantRoleAssignments -AllGroupsDetails $AllGroupsDetails -AgentIdentities $AgentIdentities -AllUsersBasicHT $AllUsersBasicHT -ApiTop $ApiTop -ServicePrincipalSignInActivityLookup $ServicePrincipalSignInActivityLookup @optionalParamsET
write-host "`n********************************** [7/15] Enumerating Agent Identity Blueprints **********************************"
$AgentIdentityBlueprints = Invoke-AgentIdentityBlueprints -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -AppRoleReferenceCache $AppRoleReferenceCache -EnterpriseApps $EnterpriseApps -AllGroupsDetails $AllGroupsDetails -AgentIdentityBlueprintsPrincipals $AgentIdentityBlueprintsPrincipals
write-host "`n********************************** [8/15] Enumerating Users **********************************"
$UserReportState = $null
$Users = Invoke-CheckUsers -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -EnterpriseApps $EnterpriseApps -AllGroupsDetails $AllGroupsDetails -ConditionalAccessPolicies $Caps -AzureIAMAssignments $AzureIAMAssignments -TenantRoleAssignments $TenantRoleAssignments -AppRegistrations $AppRegistrations -AdminUnitWithMembers $AdminUnitWithMembers -TenantPimForGroupsAssignments $TenantPimForGroupsAssignments -UserAuthMethodsTable $UserAuthMethodsTable -Devices $Devices -AgentIdentities $AgentIdentities -AgentIdentityBlueprintsPrincipals $AgentIdentityBlueprintsPrincipals -OutputFolder $OutputFolder -ApiTop $ApiTop -ReportStateOut ([ref]$UserReportState) @optionalParamsUserandGroup @optionalParamsOutput
write-host "`n********************************** [9/15] Finalizing Agent Objects **********************************"
Invoke-CheckAgentsFinalize -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -OutputFolder $OutputFolder -AllUsersBasicHT $AllUsersBasicHT -Users $Users -AgentIdentities $AgentIdentities -AgentIdentityBlueprintsPrincipals $AgentIdentityBlueprintsPrincipals -AgentIdentityBlueprints $AgentIdentityBlueprints @optionalParamsOutput
write-host "`n********************************** [10/15] Finalizing Users Report **********************************"
Write-Host "[*] Applying finalized Agent Identity Blueprint ownership impact to Users"
Update-EntraFalconUserBlueprintOwnershipImpact -Users $Users -AgentIdentityBlueprints $AgentIdentityBlueprints
Write-EntraFalconUsersReport -UserReportState $UserReportState -Users $Users
write-host "`n********************************** [11/15] Generating Role Assignments **********************************"
Invoke-CheckRoles -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -EnterpriseApps $EnterpriseApps -AllGroupsDetails $AllGroupsDetails -AzureIAMAssignments $AzureIAMAssignments -TenantRoleAssignments $TenantRoleAssignments -AppRegistrations $AppRegistrations -AdminUnitWithMembers $AdminUnitWithMembers -Users $Users -ManagedIdentities $ManagedIdentities -AgentIdentities $AgentIdentities -AgentIdentityBlueprintsPrincipals $AgentIdentityBlueprintsPrincipals -OutputFolder $OutputFolder @optionalParamsOutput
write-host "`n********************************** [12/15] Enumerating Conditional Access Policies **********************************"
$AllCaps = Invoke-CheckCaps -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -AllGroupsDetails $AllGroupsDetails -Users $Users -OutputFolder $OutputFolder -TenantRoleAssignments $TenantRoleAssignments @optionalParamsOutput @optionalParamsCap
write-host "`n********************************** [13/15] Enumerating PIM Role Settings **********************************"
if ($GLOBALPIMForEntraRolesChecked) {
$PimforEntraRoles = Invoke-CheckPIM -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -OutputFolder $OutputFolder -AllGroupsDetails $AllGroupsDetails -Users $Users -TenantRoleAssignments $TenantRoleAssignments -AllCaps $AllCaps @optionalParamsOutput
} else {
write-host "[!] Tenant is not licensed to use PIM. Skipping role settings checks..."
$PimforEntraRoles = @{}
}
write-host "`n********************************** [14/15] Enumerating Security Findings **********************************"
Invoke-CheckTenant -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -OutputFolder $OutputFolder -EnterpriseApps $EnterpriseApps -AppRegistrations $AppRegistrations -ManagedIdentities $ManagedIdentities -AllCaps $AllCaps -PimforEntraRoles $PimforEntraRoles -AllGroupsDetails $AllGroupsDetails -Users $Users -Devices $Devices -TenantRoleAssignments $TenantRoleAssignments
write-host "`n********************************** [15/15] Generating Summary Report **********************************"
# Show assessment summary and generate summary HTML report
Export-Summary -CurrentTenant $CurrentTenant -StartTimestamp $StartTimestamp -OutputFolder $OutputFolder -TenantDomains $TenantDomains -Users $Users
# Remove global variables
Start-CleanUp