Skip to content

Commit

Permalink
Fix for graph context that don't have environment.
Browse files Browse the repository at this point in the history
  • Loading branch information
merill committed May 28, 2024
1 parent 2f0002d commit b029c1c
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 44 deletions.
54 changes: 30 additions & 24 deletions src/Export-MsIdAzureMfaReport.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<#
.SYNOPSIS
Exports the list of users that have signed into the Azure portal, Azure CLI, or Azure PowerShell over the last 30 days by querying the sign in logs. In [Microsoft Entra ID Free](https://learn.microsoft.com/entra/identity/monitoring-health/reference-reports-data-retention#activity-reports) tenants, sign-in log retention is limited to seven days.
Exports the list of users that have signed into the Azure portal, Azure CLI, or Azure PowerShell over the last 30 days by querying the sign-in logs. In [Microsoft Entra ID Free](https://learn.microsoft.com/entra/identity/monitoring-health/reference-reports-data-retention#activity-reports) tenants, sign-in log retention is limited to seven days.
The report also includes each user's multi-factor authentication (MFA) registration status from Microsoft Entra.
Expand Down Expand Up @@ -38,12 +38,12 @@
Connect-MgGraph -Scopes Directory.Read.All, AuditLog.Read.All, UserAuthenticationMethod.Read.All
Export-MsIdAzureMfaReport .\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.
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.
.EXAMPLE
Export-MsIdAzureMfaReport .\report.xlsx -Days 3
Queries sign in logs for the past 3 days and outputs a report of Azure users and their MFA status in Excel format.
Queries sign-in logs for the past 3 days and outputs a report of Azure users and their MFA status in Excel format.
.EXAMPLE
Export-MsIdAzureMfaReport -PassThru | Export-Csv -Path .\report.csv
Expand All @@ -52,6 +52,7 @@
#>
function Export-MsIdAzureMfaReport {
[CmdletBinding(HelpUri = 'https://azuread.github.io/MSIdentityTools/commands/Export-MsIdAzureMfaReport')]
param (
# Output file location for Excel Workbook. e.g. .\report.xlsx
[string]
Expand All @@ -63,7 +64,7 @@ function Export-MsIdAzureMfaReport {
[switch]
$PassThru,

# Number of days to query sign in logs. Defaults to 30 days for premium tenants and 7 days for free tenants
# 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
},
Expand Down Expand Up @@ -99,15 +100,26 @@ function Export-MsIdAzureMfaReport {
}
}

if ($null -eq $Users -and $null -eq $UsersMfa) {
$Users = Get-MsIdAzureUsers -Days $Days
if ($UsersMfa) {
# We only need to generate the report.
$azureUsersMfa = $UsersMfa
}
else {
# Get the users and their MFA status
if ($null -eq $Users) {
# Get the users
$Users = Get-MsIdAzureUsers -Days $Days
}
$azureUsersMfa = GetUserMfaInsight $Users # Get the MFA status
}

if ($UsersMfa) { $azureUsersMfa = $UsersMfa }
else { $azureUsersMfa = GetUserMfaInsight $Users }

if ($isExcel) {
GenerateExcelReport $azureUsersMfa $ExcelWorkbookPath
if ($null -eq $azureUsersMfa) {
Write-Host 'Excel workbook not generated as there are no users to report on.' -ForegroundColor Yellow
}
else {
GenerateExcelReport $azureUsersMfa $ExcelWorkbookPath
}
}

if (-not ($isExcel) -or ($isExcel -and $PassThru)) {
Expand Down Expand Up @@ -207,10 +219,7 @@ 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 (-not $users) { return $null }
if ($UseAuthenticationMethodEndPoint) { $isPremiumTenant = $false } # Force into free tenant mode
else { $isPremiumTenant = GetIsPremiumTenant $users }

Expand All @@ -226,15 +235,15 @@ function Export-MsIdAzureMfaReport {
AddMfaProperties $user
UpdateProgress $currentCount $totalCount $user

$graphUri = (GetGraphBaseUri) + "/v1.0/users/$($user.UserId)/authentication/methods"
$graphUri = "$graphBaseUri/v1.0/users/$($user.UserId)/authentication/methods"
if ($isPremiumTenant) {
$graphUri = (GetGraphBaseUri) + "/v1.0/reports/authenticationMethods/userRegistrationDetails/$($user.UserId)"
$graphUri = "$graphBaseUri/v1.0/reports/authenticationMethods/userRegistrationDetails/$($user.UserId)"
}
$resultsJson = Invoke-MgGraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck
$err = Get-ObjectPropertyValue $resultsJson -Property "error"

if ($err) {
if($err.code -eq "Authentication_RequestFromUnsupportedUserRole") {
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
}
Expand All @@ -250,7 +259,7 @@ function Export-MsIdAzureMfaReport {
$methodInfo = $authMethods | Where-Object { $_.ReportType -eq $method }
if ($null -eq $methodInfo) { $userAuthMethod += $method }
else {
if($methodInfo.IsMfa) { $userAuthMethod += $methodInfo.DisplayName }
if ($methodInfo.IsMfa) { $userAuthMethod += $methodInfo.DisplayName }
}
}
$user.AuthenticationMethods = $userAuthMethod -join ', '
Expand Down Expand Up @@ -283,7 +292,7 @@ function Export-MsIdAzureMfaReport {
$isPremiumTenant = $true
if ($users -and $users.Count -gt 0) {
$user = $users[0]
$graphUri = (GetGraphBaseUri) + "/v1.0/reports/authenticationMethods/userRegistrationDetails/$($user.UserId)"
$graphUri = "$graphBaseUri/v1.0/reports/authenticationMethods/userRegistrationDetails/$($user.UserId)"
$resultsJson = Invoke-MgGraphRequest -Uri $graphUri -Method GET -SkipHttpErrorCheck
$err = Get-ObjectPropertyValue $resultsJson -Property "error"

Expand All @@ -309,10 +318,6 @@ function Export-MsIdAzureMfaReport {
$percent = [math]::Round(($currentCount / $totalCount) * 100)

Write-Progress -Activity "Getting authentication method" -Status "[$currentCount of $totalCount] Checking $userStatusDisplay. $percent% complete" -PercentComplete $percent

}
function GetGraphBaseUri() {
return $((Get-MgEnvironment -Name (Get-MgContext).Environment).GraphEndpoint)
}

function WriteExportProgress(
Expand Down Expand Up @@ -358,7 +363,7 @@ function Export-MsIdAzureMfaReport {
}

function GetAuthMethodInfo($type) {
$methodInfo = $authMethods | Where-Object { $_.Type -eq $type}
$methodInfo = $authMethods | Where-Object { $_.Type -eq $type }
if ($null -eq $methodInfo) {
# Default to the type and assume it is MFA
$methodInfo = @{
Expand Down Expand Up @@ -439,6 +444,7 @@ function Export-MsIdAzureMfaReport {
}
)

$graphBaseUri = Get-GraphBaseUri
# Call main function
Main
}
38 changes: 18 additions & 20 deletions src/Get-MsIdAzureUsers.ps1
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<#
.SYNOPSIS
Returns a list of users that have signed into the Azure portal, Azure CLI, or Azure PowerShell over the last 30 days by querying the sign in logs. In [Microsoft Entra ID Free](https://learn.microsoft.com/entra/identity/monitoring-health/reference-reports-data-retention#activity-reports) tenants, sign-in log retention is limited to seven days.
Returns a list of users that have signed into the Azure portal, Azure CLI, or Azure PowerShell over the last 30 days by querying the sign-in logs. In [Microsoft Entra ID Free](https://learn.microsoft.com/entra/identity/monitoring-health/reference-reports-data-retention#activity-reports) tenants, sign-in log retention is limited to seven days.
- Required permission scopes: **Directory.Read.All**, **AuditLog.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.
- 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.
.EXAMPLE
PS > Connect-MgGraph -Scopes Directory.Read.All, AuditLog.Read.All
Expand All @@ -22,9 +22,9 @@
#>

function Get-MsIdAzureUsers {
[CmdletBinding()]
[CmdletBinding(HelpUri = 'https://azuread.github.io/MSIdentityTools/commands/Get-MsIdAzureUsers')]
param (
# Number of days to query sign in logs. Defaults to 30 days for premium tenants and 7 days for free tenants
# 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
},
Expand Down Expand Up @@ -74,19 +74,20 @@ function Get-MsIdAzureUsers {
Write-Verbose "Graph filter: $filter"
$select = "userId,userPrincipalName,userDisplayName,appId,createdDateTime"

Write-Progress -Activity "Querying sign in logs..."
Write-Progress -Activity "Querying sign-in logs..."

$earliestDate = GetEarliestDate $filter
if ($null -eq $earliestDate) {
Write-Warning "No Azure sign ins found."
Write-Host "No Azure sign-ins found." -ForegroundColor Green
return
}

$dayDiff = (Get-Date).Subtract($earliestDate).Days
Write-Host "Getting sign in logs for the last $dayDiff days (from $earliestDate to now)..." -ForegroundColor Green
$graphUri = (GetGraphBaseUri) + "/beta/auditLogs/signIns?`$select=$select&`$filter=$filter"
if ($Days) { $dayDiff = $Days }
else { $dayDiff = (Get-Date).Subtract($earliestDate).Days }
Write-Host "Getting sign-in logs for the last $dayDiff days (from $earliestDate to now)..." -ForegroundColor Green
$graphUri = "$graphBaseUri/beta/auditLogs/signIns?`$select=$select&`$filter=$filter"

Write-Verbose "Getting sign in logs $graphUri"
Write-Verbose "Getting sign-in logs $graphUri"
$resultsJson = Invoke-GraphRequest -Uri $graphUri -Method GET
$nextLink = Get-ObjectPropertyValue $resultsJson -Property '@odata.nextLink'

Expand Down Expand Up @@ -125,7 +126,7 @@ function Get-MsIdAzureUsers {
Write-Verbose $percent
$formattedDate = GetDateDisplayFormat $latestProcessedDate
$status = "Found $($azureUsers.Count) Azure users. Now processing $formattedDate ($([int]$percent)% completed)"
Write-Progress -Activity "Checking sign in logs" -Status $status -PercentComplete $percent
Write-Progress -Activity "Checking sign-in logs" -Status $status -PercentComplete $percent
$resultsJson = Invoke-GraphRequest -Uri $nextLink
}
$nextLink = Get-ObjectPropertyValue $resultsJson -Property '@odata.nextLink'
Expand Down Expand Up @@ -156,15 +157,15 @@ function Get-MsIdAzureUsers {

function GetEarliestDate($filter) {

$graphUri = (GetGraphBaseUri) + "/beta/auditLogs/signIns?`$select=createdDateTime&`$filter=$filter&`$top=1&`$orderby=createdDateTime asc"
$graphUri = "$graphBaseUri/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 -SkipHttpErrorCheck

$err = Get-ObjectPropertyValue $resultsJson -Property "error"
if ($err) {
$message = $err.message
if($err.code -eq "Authentication_RequestFromUnsupportedUserRole") {
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
Expand All @@ -181,7 +182,7 @@ function Get-MsIdAzureUsers {
function GetDateFilter($pastDays) {
# Get the date range to query by subtracting the number of days from today set to midnight
$dateFilter = $null
if ($pastDays -or $pastDays -gt 0) {
if ($pastDays -and $pastDays -gt 0) {
$dateStart = (Get-Date -Hour 0 -Minute 0 -Second 0).AddDays(-$pastDays)

# convert the date to the correct format
Expand All @@ -199,10 +200,6 @@ function Get-MsIdAzureUsers {
return $allAppFilter
}

function GetGraphBaseUri() {
return $((Get-MgEnvironment -Name (Get-MgContext).Environment).GraphEndpoint)
}

function WriteExportProgress(
# The current step of the overal generation
[ValidateSet("Logs")]
Expand All @@ -215,7 +212,7 @@ function Get-MsIdAzureUsers {
switch ($MainStep) {
"Logs" {
$percent = GetNextPercent $ChildPercent 0 100
$activity = "Checking sign in logs"
$activity = "Checking sign-in logs"
}
}

Expand All @@ -235,6 +232,7 @@ function Get-MsIdAzureUsers {
return $date.ToString("dd MMM yyyy h:00 tt")
}

$graphBaseUri = Get-GraphBaseUri
# Call main function
Main
}
1 change: 1 addition & 0 deletions src/MSIdentityTools.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
'.\internal\ConvertTo-PsString.ps1'
'.\internal\ConvertTo-QueryString.ps1'
'.\internal\Expand-Data.ps1'
'.\internal\Get-GraphBaseUri.ps1'
'.\internal\Get-MsftUserRealm.ps1'
'.\internal\Get-ObjectPropertyValue.ps1'
'.\internal\Get-OpenIdProviderConfiguration.ps1'
Expand Down
28 changes: 28 additions & 0 deletions src/internal/Get-GraphBaseUri.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<#
.SYNOPSIS
Return the base URI for Graph API based on the current Graph Context's environment.
.DESCRIPTION
#>

function Get-GraphBaseUri {
[CmdletBinding()]
[OutputType([string])]
param ()

begin {
$baseUri = 'https://graph.microsoft.com'
try {
$context = Get-MgContext
$environment = Get-ObjectPropertyValue $context -Name 'Environment'
if($null -eq $environment){
$environment = 'Global'
}
$baseUri = (Get-MgEnvironment -Name $environment).GraphEndpoint
}
catch {

}
Write-Output $baseUri
}
}

0 comments on commit b029c1c

Please sign in to comment.