Skip to content

Commit

Permalink
Added permission checks
Browse files Browse the repository at this point in the history
  • Loading branch information
merill committed May 25, 2024
1 parent 56c8b2a commit 68eae4f
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 52 deletions.
3 changes: 2 additions & 1 deletion src/Export-MsIdAppConsentGrantReport.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<#
.SYNOPSIS
Lists and categorizes privilege for delegated permissions (OAuth2PermissionGrants) and application permissions (AppRoleAssignments).
NOTE: This cmdlet can take many hours to run on large tenants.
Watch the video [Run a quick OAuth app audit of your Microsoft Entra tenant](https://youtu.be/vO0m5yE3dZA?list=PL06Jj3_onEzGBkrZXybUZZWpJpbn1OpiK) for a quick walkthrough and demo of this command.
.DESCRIPTION
This cmdlet requires the `ImportExcel` module to be installed if you use the `-ReportOutputType ExcelWorkbook` parameter.
Expand Down
84 changes: 41 additions & 43 deletions src/Export-MsIdAzureMfaReport.ps1
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
<#
.SYNOPSIS
Exports a spreadsheet with a list of all the users that have signed into the Azure portal, CLI, or PowerShell.
Exports a spreadsheet with a list of all the users that have signed into the Azure portal, CLI, or PowerShell (past 30 days for Entra ID premium tenants and 7 days for free tenants).
The report includes each user's MFA registration status.
Required scopes: AuditLog.Read.All, UserAuthenticationMethod.Read.All
In addition to the delegated permissions, the signed-in user needs to belong to at least one of the following Microsoft Entra roles that allow them to read sign-in reports.
- Global Reader
- Reports Reader
- Security Administrator
- Security Operator
- Security Reader
Required permission scopes: **Directory.Read.All**, **AuditLog.Read.All**, **UserAuthenticationMethod.Read.All**
Required Microsoft Entra role: **Global Reader**
.DESCRIPTION
- Entra ID free tenants have access to sign in logs for the last 7 days.
Expand All @@ -21,7 +15,7 @@
.EXAMPLE
PS > Install-Module ImportExcel
PS > Connect-MgGragh -Scopes AuditLog.Read.All, UserAuthenticationMethod.Read.All
PS > Connect-MgGraph -Scopes Directory.Read.All, AuditLog.Read.All, UserAuthenticationMethod.Read.All
PS > Export-MsIdAzureMfaReport -ReportOutputType ExcelWorkbook -ExcelWorkbookPath .\report.xlsx
Queries last 30 days (7 days for Free tenants) sign in logs and outputs a report of users accessing Azure and their MFA status in Excel format.
Expand All @@ -44,24 +38,21 @@
#>
function Export-MsIdAzureMfaReport {
param (
# Output file location for Excel Workbook
[Parameter(ParameterSetName = 'Excel', Mandatory = $true, Position = 1)]
# Output file location for Excel Workbook. e.g. .\report.xlsx
[string]
[Parameter(Position = 1)]
[string]
$ExcelWorkbookPath,

# Output type for the report.
[ValidateSet("ExcelWorkbook", "PowerShellObjects")]
[Parameter(ParameterSetName = 'Excel', Mandatory = $false, Position = 2)]
[Parameter(ParameterSetName = 'PowerShell', Mandatory = $false, Position = 1)]
[string]
$ReportOutputType = "ExcelWorkbook",
# Switch to include the results in the output
[switch]
$PassThru,

# Number of days to query sign in logs. Defaults to 30 days for premium tenants and 7 days for free tenants
[ValidateScript({
$_ -ge 0 -and $_ -le 30
},
ErrorMessage = "Logs are only available for the last 7 days for free tenants and 30 days for premium tenants. Please enter a number between 0 and 30."
)]
ErrorMessage = "Logs are only available for the last 7 days for free tenants and 30 days for premium tenants. Please enter a number between 0 and 30.")]
[int]
$Days,

Expand All @@ -73,22 +64,24 @@ function Export-MsIdAzureMfaReport {
[array]
$UsersMfa,

# If enabled, the user auth method will be used (slower) instead of the reporting API. Not applicable for Free tenants since they don't have access to the reporting API.
# If enabled, the user auth method will be used (slower) instead of the reporting API. This is the default for free tenants as the reporting API requires a premium license.
[switch]
$UseAuthenticationMethodEndPoint
)

function Main() {

if ("ExcelWorkbook" -eq $ReportOutputType) {
if (-not (Test-MgModulePrerequisites @('AuditLog.Read.All', 'Directory.Read.All', 'UserAuthenticationMethod.Read.All'))) { return }

$isExcel = ![string]::IsNullOrEmpty($ExcelWorkbookPath)
if ($isExcel) {
# Determine if the ImportExcel module is installed since the parameter was included
if ($null -eq (Get-Module -Name ImportExcel -ListAvailable)) {
throw "The ImportExcel module is not installed. This is used to export the results to an Excel worksheet. Please install the ImportExcel Module before using this parameter or run without this parameter."
Write-Error "The ImportExcel module is not installed. This is used to export the results to an Excel worksheet. Please install the ImportExcel Module before using this parameter or run without this parameter." -ErrorAction Stop
}
}

if ($null -eq (Get-MgContext)) {
throw "You must connect to the Microsoft Graph before running this command."
if ([IO.Path]::GetExtension($ExcelWorkbookPath) -notmatch ".xlsx") {
Write-Error "The ExcelWorkbookPath '$ExcelWorkbookPath' is not a valid Excel file. Please provide a valid Excel file path. E.g. .\report.xlsx" -ErrorAction Stop
}
}

if ($null -eq $Users -and $null -eq $UsersMfa) {
Expand All @@ -98,12 +91,13 @@ function Export-MsIdAzureMfaReport {
if ($UsersMfa) { $azureUsersMfa = $UsersMfa }
else { $azureUsersMfa = GetUserMfaInsight $Users }

if ("PowerShellObjects" -eq $ReportOutputType) {
return $azureUsersMfa
}
else {
if ($isExcel) {
GenerateExcelReport $azureUsersMfa $ExcelWorkbookPath
}

if (-not ($isExcel) -or ($isExcel -and $PassThru)) {
return $azureUsersMfa
}
}

function GenerateExcelReport ($UsersMfa, $Path) {
Expand Down Expand Up @@ -198,6 +192,10 @@ function Export-MsIdAzureMfaReport {
# Get the authentication method state for each user
function GetUserMfaInsight($users) {

if(!$users) {
Write-Error "No users available to create MFA report." -ErrorAction Stop
}

if ($UseAuthenticationMethodEndPoint) { $isPremiumTenant = $false } # Force into free tenant mode
else { $isPremiumTenant = GetIsPremiumTenant $users }

Expand All @@ -217,32 +215,32 @@ function Export-MsIdAzureMfaReport {
if ($isPremiumTenant) {
$graphUri = (GetGraphBaseUri) + "/v1.0/reports/authenticationMethods/userRegistrationDetails/$($user.UserId)"
}
$resultJson = Invoke-MgGraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck
$err = Get-ObjectPropertyValue $resultJson -Property "error"
$resultsJson = Invoke-MgGraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck
$err = Get-ObjectPropertyValue $resultsJson -Property "error"

if ($err) {
$note = "Could not retrieve authentication methods for user."

if ($null -ne $err) {
$note = $err.message
if($err.code -eq "Authentication_RequestFromUnsupportedUserRole") {
$message += $err.message + " The signed-in user needs to be assigned the Microsoft Entra Global Reader role."
Write-Error $message -ErrorAction Stop
}
$user.Note = $note

$user.Note = $err.message
continue
}

if ($isPremiumTenant) {
$methodsRegistered = Get-ObjectPropertyValue $resultJson -Property 'methodsRegistered'
$methodsRegistered = Get-ObjectPropertyValue $resultsJson -Property 'methodsRegistered'
$userAuthMethod = @()
foreach ($method in $methodsRegistered) {
$methodInfo = $authMethods | Where-Object { $_.ReportType -eq $method }
if ($null -eq $methodInfo) { $userAuthMethod += $method }
else { $userAuthMethod += $methodInfo.DisplayName }
}
$user.AuthenticationMethods = $userAuthMethod -join ', '
$user.IsMfaRegistered = Get-ObjectPropertyValue $resultJson -Property 'isMfaRegistered'
$user.IsMfaRegistered = Get-ObjectPropertyValue $resultsJson -Property 'isMfaRegistered'
}
else {
$graphMethods = Get-ObjectPropertyValue $resultJson -Property "value"
$graphMethods = Get-ObjectPropertyValue $resultsJson -Property "value"
$userAuthMethods = @()
$isMfaRegistered = $false
$types = $graphMethods | Select-Object '@odata.type' -Unique
Expand All @@ -269,8 +267,8 @@ function Export-MsIdAzureMfaReport {
if ($users -and $users.Count -gt 0) {
$user = $users[0]
$graphUri = (GetGraphBaseUri) + "/v1.0/reports/authenticationMethods/userRegistrationDetails/$($user.UserId)"
$resultJson = Invoke-MgGraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck
$err = Get-ObjectPropertyValue $resultJson -Property "error"
$resultsJson = Invoke-MgGraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck
$err = Get-ObjectPropertyValue $resultsJson -Property "error"

if ($err) {
$isPremiumTenant = $err.code -ne "Authentication_RequestFromNonPremiumTenantOrB2CTenant"
Expand Down
24 changes: 19 additions & 5 deletions src/Get-MsIdAzureUsers.ps1
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
<#
.SYNOPSIS
Returns a list of all the users that have signed into the Azure portal, CLI, PowerShell.
Returns a list of all the users that have signed into the Azure portal, CLI, PowerShell (past 30 days for Entra ID premium tenants and 7 days for free tenants).
Required permission scopes: **Directory.Read.All**, **AuditLog.Read.All**, **UserAuthenticationMethod.Read.All**
Required Microsoft Entra role: **Global Reader**
.DESCRIPTION
- Entra ID free tenants have access to sign in logs for the last 7 days.
- Entra ID premium tenants have access to sign in logs for the last 30 days.
- The cmdlet will query the sign in log from the most recent day and work backwards.
.EXAMPLE
PS > Connect-MgGragh -Scopes AuditLog.Read.All
PS > Connect-MgGraph -Scopes Directory.Read.All, AuditLog.Read.All
PS > Get-MsIdAzureUsers
Queries all available logs and returns all the users that have signed into Azure.
Expand Down Expand Up @@ -49,6 +52,8 @@ function Get-MsIdAzureUsers {

function Main() {

if (!(Test-MgModulePrerequisites @('AuditLog.Read.All', 'Directory.Read.All'))) { return }

$users = GetAzureUsers $Days
if ($users) {
$users.Values
Expand Down Expand Up @@ -78,7 +83,7 @@ function Get-MsIdAzureUsers {
return
}

$graphUri = (GetGraphBaseUri) + "/v1.0/auditLogs/signIns?`$select=$select&`$filter=$filter"
$graphUri = (GetGraphBaseUri) + "/beta/auditLogs/signIns?`$select=$select&`$filter=$filter"

Write-Verbose "Getting sign in logs $graphUri"
$resultsJson = Invoke-GraphRequest -Uri $graphUri -Method GET
Expand Down Expand Up @@ -150,10 +155,19 @@ function Get-MsIdAzureUsers {

function GetEarliestDate($filter) {

$graphUri = (GetGraphBaseUri) + "/v1.0/auditLogs/signIns?`$select=createdDateTime&`$filter=$filter&`$top=1&`$orderby=createdDateTime asc"
$graphUri = (GetGraphBaseUri) + "/beta/auditLogs/signIns?`$select=createdDateTime&`$filter=$filter&`$top=1&`$orderby=createdDateTime asc"

Write-Verbose "Getting earliest date in logs $graphUri"
$resultsJson = Invoke-GraphRequest -Uri $graphUri -Method GET
$resultsJson = Invoke-GraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck

$err = Get-ObjectPropertyValue $resultsJson -Property "error"
if ($err) {
$message = $err.message
if($err.code -eq "Authentication_RequestFromUnsupportedUserRole") {
$message += " The signed-in user needs to be assigned the Microsoft Entra Global Reader role."
}
Write-Error $message -ErrorAction Stop
}

$minDate = $null
if ($resultsJson.value.Count -ne 0) {
Expand Down
7 changes: 4 additions & 3 deletions src/MSIdentityTools.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
Copyright = '(c) 2023 Microsoft Corporation. All rights reserved.'

# Description of the functionality provided by this module
Description = 'Tools for managing, troubleshooting, and reporting on various aspects of Microsoft Identity products and services, primarily Azure AD.'
Description = 'Tools for managing, troubleshooting, and reporting on various aspects of Microsoft Identity products and services, primarily Microsoft Entra ID.'

# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '7.0'
Expand All @@ -50,7 +50,8 @@

# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @(
@{ ModuleName = 'Microsoft.Graph.Authentication'; Guid = '883916f2-9184-46ee-b1f8-b6a2fb784cee'; ModuleVersion = '1.9.2' }
@{ ModuleName = 'Microsoft.Graph.Authentication'; Guid = '883916f2-9184-46ee-b1f8-b6a2fb784cee'; ModuleVersion = '1.9.2' },
@{ ModuleName = 'ImportExcel'; Guid = '60dd4136-feff-401a-ba27-a84458c57ede'; ModuleVersion = '7.8.6'}
)

# Assemblies that must be loaded prior to importing this module
Expand Down Expand Up @@ -245,7 +246,7 @@
LicenseUri = 'https://raw.githubusercontent.com/AzureAD/MSIdentityTools/main/LICENSE'

# A URL to the main website for this project.
ProjectUri = 'https://github.com/AzureAD/MSIdentityTools'
ProjectUri = 'https://aka.ms/msid'

# A URL to an icon representing this module.
# IconUri = ''
Expand Down

0 comments on commit 68eae4f

Please sign in to comment.