From 755469f08fd352f71afe474b6d5d2b28382c851a Mon Sep 17 00:00:00 2001 From: Kennedy Kangethe Munga Date: Wed, 5 Nov 2025 12:37:22 +0300 Subject: [PATCH 1/4] Add Samples for getting authentication methods using batch operations --- samples/batch/Invoke-BatchWithRetry.ps1 | 79 +++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 samples/batch/Invoke-BatchWithRetry.ps1 diff --git a/samples/batch/Invoke-BatchWithRetry.ps1 b/samples/batch/Invoke-BatchWithRetry.ps1 new file mode 100644 index 000000000..defa55894 --- /dev/null +++ b/samples/batch/Invoke-BatchWithRetry.ps1 @@ -0,0 +1,79 @@ +function Invoke-BatchWithRetry { + param( + [array]$BatchRequests, + [int]$MaxRetries = 3 + ) + $batchUri = "https://graph.microsoft.com/v1.0/`$batch" + $responses = @{} + $pending = @($BatchRequests) # Ensure it's an array + $retryCount = 0 + + while ($pending -ne $null -and $pending.Count -gt 0 -and $retryCount -le $MaxRetries) { + $batchBody = @{ + requests = $pending + } | ConvertTo-Json -Depth 5 + + $result = Invoke-MgGraphRequest -Method POST -Uri $batchUri -Body $batchBody -ContentType "application/json" + foreach ($resp in $result.responses) { + "Id : $($resp.id), Status : $($resp.status)" | Out-File -FilePath "Path\To\log.txt" -Append + if ($resp.status -eq 429) { + # Add to retry list + $pending = $pending | Where-Object { $_.id -eq $resp.id } + } else { + $responses[$resp.id] = $resp + # Remove from pending + $pending = $pending | Where-Object { $_.id -ne $resp.id } + } + } + + if ($pending -ne $null -and $pending.Count -gt 0) { + Start-Sleep -Seconds 5 + $retryCount++ + } + } + return $responses +} + +# Get Users + +if (-not (Get-Command Connect-Entra -ErrorAction SilentlyContinue)) { + Write-Error "Connect-Entra not found. Install Microsoft.Entra and run Connect-Entra." + return +} + +if (-not (Get-EntraContext)) { + $errorMessage = "Not connected to Microsoft Entra. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." + Write-Error -Message $errorMessage -ErrorAction Stop + return +} + +$users = Get-EntraUser -All + +# Prepare batch requests (20 per batch) +$batchSize = 20 +$allResults = @{} +for ($i = 0; $i -lt $users.Count; $i += $batchSize) { + $batch = @() + $batchUsers = $users[$i..([Math]::Min($i+$batchSize-1, $users.Count-1))] + foreach ($user in $batchUsers) { + $batch += @{ + id = $user.id + method = "GET" + url = "/users/$($user.id)/authentication/methods" + } + } + $responses = Invoke-BatchWithRetry -BatchRequests $batch -debug + foreach ($id in $responses.Keys) { + $allResults[$id] = $responses[$id] + } + + $activity = "Processed Users - $i of $($users.count) - $([System.Math]::Round($i / $($users.count) * 100))%" + + Write-Progress -Activity $activity -Status "Fetching authentication methods" -PercentComplete (($i / $users.count) * 100) +} + +Write-Output "Completed fetching authentication methods for $($users.count) users. Returned results for $($allResults.Count) users." + +# How to execute this script: + +# . .\samples\batch\Invoke-BatchWithRetry.ps1 \ No newline at end of file From d87507082350bd3a399ff436ae4ffad4d8173a02 Mon Sep 17 00:00:00 2001 From: Kennedy Kangethe Munga Date: Wed, 5 Nov 2025 12:48:13 +0300 Subject: [PATCH 2/4] Add comments --- samples/batch/Invoke-BatchWithRetry.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/samples/batch/Invoke-BatchWithRetry.ps1 b/samples/batch/Invoke-BatchWithRetry.ps1 index defa55894..9bc92d92e 100644 --- a/samples/batch/Invoke-BatchWithRetry.ps1 +++ b/samples/batch/Invoke-BatchWithRetry.ps1 @@ -76,4 +76,8 @@ Write-Output "Completed fetching authentication methods for $($users.count) user # How to execute this script: -# . .\samples\batch\Invoke-BatchWithRetry.ps1 \ No newline at end of file +# . .\samples\batch\Invoke-BatchWithRetry.ps1 + +# To execute the script and measure performance, you can use the following command: + +# Measure-Command { . .\samples\batch\Invoke-BatchWithRetry.ps1 } \ No newline at end of file From 6eaf8f5585a5df5698d4474fa674139043503030 Mon Sep 17 00:00:00 2001 From: Kennedy Kangethe Munga Date: Mon, 24 Nov 2025 10:38:45 +0300 Subject: [PATCH 3/4] Fix bug --- samples/batch/Invoke-BatchWithRetry.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/batch/Invoke-BatchWithRetry.ps1 b/samples/batch/Invoke-BatchWithRetry.ps1 index 9bc92d92e..3774c6a60 100644 --- a/samples/batch/Invoke-BatchWithRetry.ps1 +++ b/samples/batch/Invoke-BatchWithRetry.ps1 @@ -17,8 +17,7 @@ function Invoke-BatchWithRetry { foreach ($resp in $result.responses) { "Id : $($resp.id), Status : $($resp.status)" | Out-File -FilePath "Path\To\log.txt" -Append if ($resp.status -eq 429) { - # Add to retry list - $pending = $pending | Where-Object { $_.id -eq $resp.id } + # Do nothing - will retry later } else { $responses[$resp.id] = $resp # Remove from pending From c1ff91dbd9658a91ff19b26fe86f58b2247f3e91 Mon Sep 17 00:00:00 2001 From: Kennedy Kangethe Munga Date: Thu, 27 Nov 2025 10:00:09 +0300 Subject: [PATCH 4/4] Remove null check --- samples/batch/Invoke-BatchWithRetry.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/batch/Invoke-BatchWithRetry.ps1 b/samples/batch/Invoke-BatchWithRetry.ps1 index 3774c6a60..e0aa344e1 100644 --- a/samples/batch/Invoke-BatchWithRetry.ps1 +++ b/samples/batch/Invoke-BatchWithRetry.ps1 @@ -8,7 +8,7 @@ function Invoke-BatchWithRetry { $pending = @($BatchRequests) # Ensure it's an array $retryCount = 0 - while ($pending -ne $null -and $pending.Count -gt 0 -and $retryCount -le $MaxRetries) { + while ($pending.Count -gt 0 -and $retryCount -le $MaxRetries) { $batchBody = @{ requests = $pending } | ConvertTo-Json -Depth 5 @@ -25,7 +25,7 @@ function Invoke-BatchWithRetry { } } - if ($pending -ne $null -and $pending.Count -gt 0) { + if ($pending.Count -gt 0) { Start-Sleep -Seconds 5 $retryCount++ }