Azure / azure-powershell

Microsoft Azure PowerShell
Other
4.27k stars 3.87k forks source link

Invoke-AzRestMethod with -AsJob does not await asynchronous operations to complete #13293

Open fawohlsc opened 4 years ago

fawohlsc commented 4 years ago

Description

Invoke-AzRestMethod with -AsJob seems to not await asynchronous operations to complete. The Azure REST API, returns a HTTP status code 201 or 202 for asynchronous operations and a status URL to monitor the operation. In order to await the asynchronous operation to complete, the status URL can be periodically called using busy waiting (See Track asynchronous Azure operations). When using Invoke-AzRestMethod with the parameter -AsJob, it seems to not await the asynchronous operation since it still returns 202 instead of 200/204, which would indicate the operation is complete. Expectation is that Invoke-AzRestMethod with the parameter -AsJob actually awaits for the asynchronous operations to complete. This seems to be currently not handled in the source code.

image

Steps to reproduce

$job = Invoke-AzRestMethod `
   -ResourceGroupName $RouteTable.ResourceGroupName `
   -ResourceProviderName "Microsoft.Network" `
   -ResourceType @("routeTables", "routes") `
   -Name @($RouteTable.Name, $route.Name) `
   -ApiVersion "2020-05-01" `
   -Method "DELETE" `
   -AsJob `
   -Debug
# This will always return HTTP status 202 and...
$httpResponse = $job | Wait-Job | Receive-Job

 # ... hence this error will always be thrown since async operation is still running
if ($httpResponse.StatusCode -ne 200 -and $httpResponse.StatusCode -ne 204) {
   throw "Route '$($route.Name)' could not be removed from route table '$($RouteTable.Name)'."
}

Environment data

Name                           Value
----                           -----
PSVersion                      7.0.3
PSEdition                      Core
GitCommitId                    7.0.3
OS                             Microsoft Windows 10.0.19042
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Module versions


    Directory: C:\Users\fawohlsc\Documents\PowerShell\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Script     4.7.0                 Az                                  Core,Desk 
Script     1.9.4                 Az.Accounts                         Core,Desk {Disable-AzDataCollection, Disable-AzCo…
Script     1.1.1                 Az.Advisor                          Core,Desk {Get-AzAdvisorRecommendation, Enable-Az…
Script     1.3.0                 Az.Aks                              Core,Desk {Get-AzAksCluster, New-AzAksCluster, Re…
Script     1.1.4                 Az.AnalysisServices                 Core,Desk {Resume-AzAnalysisServicesServer, Suspe…
Script     2.1.0                 Az.ApiManagement                    Core,Desk {Add-AzApiManagementApiToGateway, Add-A…
Script     1.1.0                 Az.ApplicationInsights              Core,Desk {Get-AzApplicationInsights, New-AzAppli…
Script     1.4.0                 Az.Automation                       Core,Desk {Get-AzAutomationHybridWorkerGroup, Rem…
Script     3.1.0                 Az.Batch                            Core,Desk {Remove-AzBatchAccount, Get-AzBatchAcco…
Script     1.0.3                 Az.Billing                          Core,Desk {Get-AzBillingInvoice, Get-AzBillingPer…
Script     1.4.3                 Az.Cdn                              Core,Desk {Get-AzCdnProfile, Get-AzCdnProfileSsoU…
Script     1.6.0                 Az.CognitiveServices                Core,Desk {Get-AzCognitiveServicesAccount, Get-Az…
Script     4.4.0                 Az.Compute                          Core,Desk {Remove-AzAvailabilitySet, Get-AzAvaila…
Script     1.0.3                 Az.ContainerInstance                Core,Desk {New-AzContainerGroup, Get-AzContainerG…
Script     1.1.1                 Az.ContainerRegistry                Core,Desk {New-AzContainerRegistry, Get-AzContain…
Script     1.1.0                 Az.DataBoxEdge                      Core,Desk {Get-AzDataBoxEdgeJob, Get-AzDataBoxEdg…
Script     1.10.1                Az.DataFactory                      Core,Desk {Set-AzDataFactoryV2, Update-AzDataFact…
Script     1.0.2                 Az.DataLakeAnalytics                Core,Desk {Get-AzDataLakeAnalyticsDataSource, New…
Script     1.2.8                 Az.DataLakeStore                    Core,Desk {Get-AzDataLakeStoreTrustedIdProvider, …
Script     1.0.0                 Az.DataShare                        Core,Desk {New-AzDataShareAccount, Get-AzDataShar…
Script     1.1.0                 Az.DeploymentManager                Core,Desk {Get-AzDeploymentManagerArtifactSource,…
Script     1.0.0                 Az.DesktopVirtualization            Core,Desk {Disconnect-AzWvdUserSession, Get-AzWvd…
Script     1.0.2                 Az.DevTestLabs                      Core,Desk {Get-AzDtlAllowedVMSizesPolicy, Get-AzD…
Script     1.1.2                 Az.Dns                              Core,Desk {Get-AzDnsRecordSet, New-AzDnsRecordCon…
Script     1.3.0                 Az.EventGrid                        Core,Desk {New-AzEventGridTopic, Get-AzEventGridT…
Script     1.6.0                 Az.EventHub                         Core,Desk {New-AzEventHubNamespace, Get-AzEventHu…
Script     1.6.1                 Az.FrontDoor                        Core,Desk {New-AzFrontDoor, Get-AzFrontDoor, Set-…
Script     1.0.2                 Az.Functions                        Core,Desk {Get-AzFunctionApp, Get-AzFunctionAppAv…
Script     3.6.0                 Az.HDInsight                        Core,Desk {Get-AzHDInsightJob, New-AzHDInsightSqo…
Script     1.1.0                 Az.HealthcareApis                   Core,Desk {New-AzHealthcareApisService, Remove-Az…
Script     2.5.0                 Az.IotHub                           Core,Desk {Add-AzIotHubKey, Get-AzIotHubEventHubC…
Script     2.2.0                 Az.KeyVault                         Core,Desk {Add-AzKeyVaultCertificate, Update-AzKe…
Script     1.0.0                 Az.Kusto                            Core,Desk {Add-AzKustoClusterLanguageExtension, A…
Script     1.3.2                 Az.LogicApp                         Core,Desk {Get-AzIntegrationAccountAgreement, Get…
Script     1.1.3                 Az.MachineLearning                  Core,Desk {Move-AzMlCommitmentAssociation, Get-Az…
Script     1.1.0                 Az.Maintenance                      Core,Desk {Get-AzApplyUpdate, Get-AzConfiguration…
Script     1.1.0                 Az.ManagedServices                  Core,Desk {Get-AzManagedServicesAssignment, New-A…
Script     1.0.2                 Az.MarketplaceOrdering              Core,Desk {Get-AzMarketplaceTerms, Set-AzMarketpl…
Script     1.1.1                 Az.Media                            Core,Desk {Sync-AzMediaServiceStorageKey, Set-AzM…
Script     2.1.0                 Az.Monitor                          Core,Desk {Get-AzMetricDefinition, Get-AzMetric, …
Script     3.4.0                 Az.Network                          Core,Desk {Add-AzApplicationGatewayAuthentication…
Script     1.1.1                 Az.NotificationHubs                 Core,Desk {Get-AzNotificationHub, Get-AzNotificat…
Script     2.3.0                 Az.OperationalInsights              Core,Desk {New-AzOperationalInsightsAzureActivity…
Script     1.3.1                 Az.PolicyInsights                   Core,Desk {Get-AzPolicyEvent, Get-AzPolicyState, …
Script     1.1.2                 Az.PowerBIEmbedded                  Core,Desk {Remove-AzPowerBIWorkspaceCollection, G…
Script     1.0.3                 Az.PrivateDns                       Core,Desk {Get-AzPrivateDnsZone, Remove-AzPrivate…
Script     2.12.1                Az.RecoveryServices                 Core,Desk {Get-AzRecoveryServicesBackupProperty, …
Script     1.2.1                 Az.RedisCache                       Core,Desk {Remove-AzRedisCachePatchSchedule, New-…
Script     1.0.3                 Az.Relay                            Core,Desk {New-AzRelayNamespace, Get-AzRelayNames…
Script     2.5.1                 Az.Resources                        Core,Desk {Get-AzProviderOperation, Remove-AzRole…
Script     1.4.1                 Az.ServiceBus                       Core,Desk {New-AzServiceBusNamespace, Get-AzServi…
Script     2.2.0                 Az.ServiceFabric                    Core,Desk {Add-AzServiceFabricClientCertificate, …
Script     1.2.0                 Az.SignalR                          Core,Desk {New-AzSignalR, Get-AzSignalR, Get-AzSi…
Script     2.10.0                Az.Sql                              Core,Desk {Get-AzSqlDatabaseTransparentDataEncryp…
Script     1.1.0                 Az.SqlVirtualMachine                Core,Desk {New-AzSqlVM, Get-AzSqlVM, Update-AzSql…
Script     2.6.0                 Az.Storage                          Core,Desk {Get-AzStorageAccount, Get-AzStorageAcc…
Script     1.3.0                 Az.StorageSync                      Core,Desk {Invoke-AzStorageSyncCompatibilityCheck…
Script     1.0.1                 Az.StreamAnalytics                  Core,Desk {Get-AzStreamAnalyticsFunction, Get-AzS…
Script     1.0.0                 Az.Support                          Core,Desk {Get-AzSupportService, Get-AzSupportPro…
Script     1.0.4                 Az.TrafficManager                   Core,Desk {Add-AzTrafficManagerCustomHeaderToEndp…
Script     1.11.0                Az.Websites                         Core,Desk {Get-AzAppServicePlan, Set-AzAppService…
Binary     2.0                   CredentialManager                   Desk      
Script     0.0.1                 MyPsScript                          Desk      Show-Calendar
Script     2.0.385               oh-my-posh                          Desk      {Show-Colors, Show-ThemeColors, Show-Th…
Script     5.1.0      beta1      Pester                              Desk      {Invoke-Pester, Describe, Context, It…}
Script     0.7.3                 posh-git                            Desk      {Invoke-NullCoalescing, Add-PoshGitToPr…
Script     1.0.0                 WindowsPSModulePath                 Core,Desk Add-WindowsPSModulePath

    Directory: C:\program files\powershell\7\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Manifest   7.0.0.0               CimCmdlets                          Core      {Get-CimAssociatedInstance, Get-CimClas…
Manifest   1.2.5                 Microsoft.PowerShell.Archive        Desk      {Compress-Archive, Expand-Archive}
Manifest   7.0.0.0               Microsoft.PowerShell.Diagnostics    Core      {Get-WinEvent, New-WinEvent, Get-Counte…
Manifest   7.0.0.0               Microsoft.PowerShell.Host           Core      {Start-Transcript, Stop-Transcript}
Manifest   7.0.0.0               Microsoft.PowerShell.Management     Core      {Add-Content, Clear-Content, Get-Clipbo…
Manifest   7.0.0.0               Microsoft.PowerShell.Security       Core      {Get-Acl, Set-Acl, Get-PfxCertificate, …
Manifest   7.0.0.0               Microsoft.PowerShell.Utility        Core      {Export-Alias, Get-Alias, Import-Alias,…
Manifest   7.0.0.0               Microsoft.WSMan.Management          Core      {Disable-WSManCredSSP, Enable-WSManCred…
Script     1.4.7                 PackageManagement                   Desk      {Find-Package, Get-Package, Get-Package…
Script     2.2.4.1               PowerShellGet                       Desk      {Find-Command, Find-DSCResource, Find-M…
Script     2.0.5                 PSDesiredStateConfiguration         Core      {Configuration, New-DscChecksum, Get-Ds…
Script     7.0.0.0               PSDiagnostics                       Core      {Disable-PSTrace, Disable-PSWSManCombin…
Script     2.0.2                 PSReadLine                          Desk      {Get-PSReadLineKeyHandler, Set-PSReadLi…
Binary     2.0.3                 ThreadJob                           Desk      Start-ThreadJob

    Directory: C:\Program Files\WindowsPowerShell\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Binary     2.0                   CredentialManager                   Desk      
Script     1.0.1                 Microsoft.PowerShell.Operation.Val… Desk      {Get-OperationValidation, Invoke-Operat…
Script     2.0.385               oh-my-posh                          Desk      {Show-Colors, Show-ThemeColors, Show-Th…
Binary     1.0.0.1               PackageManagement                   Desk      {Find-Package, Get-Package, Get-Package…
Script     0.7.3                 posh-git                            Desk      {Invoke-NullCoalescing, Add-PoshGitToPr…
Script     1.0.0.1               PowerShellGet                       Desk      {Install-Module, Find-Module, Save-Modu…
Script     2.0.0      beta2      PSReadline                          Desk      {Get-PSReadLineKeyHandler, Set-PSReadLi…

    Directory: C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Manifest   1.0.0.0               AppBackgroundTask                   Core,Desk {Disable-AppBackgroundTaskDiagnosticLog…
Manifest   2.0.1.0               Appx                                Core,Desk {Add-AppxPackage, Get-AppxPackage, Get-…
Script     1.0.0.0               AssignedAccess                      Core,Desk {Clear-AssignedAccess, Get-AssignedAcce…
Manifest   1.0.0.0               BitLocker                           Core,Desk {Unlock-BitLocker, Suspend-BitLocker, R…
Manifest   2.0.0.0               BitsTransfer                        Core,Desk {Add-BitsFile, Complete-BitsTransfer, G…
Manifest   1.0.0.0               BranchCache                         Core,Desk {Add-BCDataCacheExtension, Clear-BCCach…
Manifest   1.0                   ConfigDefender                      Core,Desk {Get-MpPreference, Set-MpPreference, Ad…
Manifest   1.0                   Defender                            Core,Desk {Get-MpPreference, Set-MpPreference, Ad…
Manifest   1.0.2.0               DeliveryOptimization                Core,Desk {Delete-DeliveryOptimizationCache, Set-…
Manifest   1.0.0.0               DirectAccessClientComponents        Core,Desk {Disable-DAManualEntryPointSelection, E…
Script     3.0                   Dism                                Core,Desk {Add-AppxProvisionedPackage, Add-Window…
Manifest   1.0.0.0               DnsClient                           Core,Desk {Resolve-DnsName, Clear-DnsClientCache,…
Manifest   1.0.0.0               EventTracingManagement              Core,Desk {Start-EtwTraceSession, New-EtwTraceSes…
Manifest   1.0.0.0               HgsClient                           Core,Desk {Get-HgsAttestationBaselinePolicy, Get-…
Manifest   1.0.0.0               HgsDiagnostics                      Core,Desk {New-HgsTraceTarget, Get-HgsTrace, Get-…
Binary     2.0.0.0               Hyper-V                             Core,Desk {Add-VMAssignableDevice, Add-VMDvdDrive…
Binary     1.1                   Hyper-V                             Core,Desk {Add-VMDvdDrive, Add-VMFibreChannelHba,…
Manifest   2.0.0.0               International                       Core,Desk {Get-WinDefaultInputMethodOverride, Set…
Manifest   1.0.0.0               Kds                                 Core,Desk {Add-KdsRootKey, Get-KdsRootKey, Test-K…
Manifest   3.0.0.0               Microsoft.PowerShell.Diagnostics    Core,Desk {Get-WinEvent, Get-Counter, Import-Coun…
Manifest   1.0.0.0               Microsoft.PowerShell.LocalAccounts  Core,Desk {Add-LocalGroupMember, Disable-LocalUse…
Manifest   3.1.0.0               Microsoft.PowerShell.Management     Core,Desk {Add-Content, Clear-Content, Clear-Item…
Manifest   1.0                   MMAgent                             Core,Desk {Disable-MMAgent, Enable-MMAgent, Set-M…
Manifest   2.0.0.0               NetAdapter                          Core,Desk {Disable-NetAdapter, Disable-NetAdapter…
Manifest   1.0.0.0               NetConnection                       Core,Desk {Get-NetConnectionProfile, Set-NetConne…
Manifest   1.0.0.0               NetEventPacketCapture               Core,Desk {New-NetEventSession, Remove-NetEventSe…
Manifest   2.0.0.0               NetLbfo                             Core,Desk {Add-NetLbfoTeamMember, Add-NetLbfoTeam…
Manifest   1.0.0.0               NetNat                              Core,Desk {Get-NetNat, Get-NetNatExternalAddress,…
Manifest   2.0.0.0               NetQos                              Core,Desk {Get-NetQosPolicy, Set-NetQosPolicy, Re…
Manifest   2.0.0.0               NetSecurity                         Core,Desk {Get-DAPolicyChange, New-NetIPsecAuthPr…
Manifest   1.0.0.0               NetSwitchTeam                       Core,Desk {New-NetSwitchTeam, Remove-NetSwitchTea…
Manifest   1.0.0.0               NetTCPIP                            Core,Desk {Get-NetIPAddress, Get-NetIPInterface, …
Manifest   1.0.0.0               NetworkConnectivityStatus           Core,Desk {Get-DAConnectionStatus, Get-NCSIPolicy…
Manifest   1.0.0.0               NetworkSwitchManager                Core,Desk {Disable-NetworkSwitchEthernetPort, Ena…
Manifest   1.0.0.0               NetworkTransition                   Core,Desk {Add-NetIPHttpsCertBinding, Disable-Net…
Manifest   1.0.0.0               PcsvDevice                          Core,Desk {Get-PcsvDevice, Start-PcsvDevice, Stop…
Manifest   1.0.0.0               PKI                                 Core,Desk {Add-CertificateEnrollmentPolicyServer,…
Manifest   1.0.0.0               PnpDevice                           Core,Desk {Get-PnpDevice, Get-PnpDeviceProperty, …
Manifest   1.1                   PrintManagement                     Core,Desk {Add-Printer, Add-PrinterDriver, Add-Pr…
Binary     1.0.11                ProcessMitigations                  Core,Desk {Get-ProcessMitigation, Set-ProcessMiti…
Script     3.0                   Provisioning                        Core,Desk {Install-ProvisioningPackage, Export-Pr…
Manifest   1.0.0.0               ScheduledTasks                      Core,Desk {Get-ScheduledTask, Set-ScheduledTask, …
Manifest   2.0.0.0               SecureBoot                          Core,Desk {Confirm-SecureBootUEFI, Set-SecureBoot…
Manifest   2.0.0.0               SmbShare                            Core,Desk {Get-SmbShare, Remove-SmbShare, Set-Smb…
Manifest   2.0.0.0               SmbWitness                          Core,Desk {Get-SmbWitnessClient, Move-SmbWitnessC…
Manifest   1.0.0.0               StartLayout                         Core,Desk {Export-StartLayout, Import-StartLayout…
Manifest   2.0.0.0               Storage                             Core,Desk {Add-InitiatorIdToMaskingSet, Add-Parti…
Manifest   2.0.0.0               TLS                                 Core,Desk {New-TlsSessionTicketKey, Enable-TlsSes…
Manifest   1.0.0.0               TroubleshootingPack                 Core,Desk {Get-TroubleshootingPack, Invoke-Troubl…
Manifest   2.0.0.0               TrustedPlatformModule               Core,Desk {Get-Tpm, Initialize-Tpm, Clear-Tpm, Un…
Binary     2.1.639.0             UEV                                 Core,Desk 
Manifest   2.0.0.0               VpnClient                           Core,Desk {Add-VpnConnection, Set-VpnConnection, …
Manifest   1.0.0.0               Wdac                                Core,Desk {Get-OdbcDriver, Set-OdbcDriver, Get-Od…
Manifest   2.0.0.0               Whea                                Core,Desk {Get-WheaMemoryPolicy, Set-WheaMemoryPo…
Manifest   1.0.0.0               WindowsDeveloperLicense             Core,Desk {Get-WindowsDeveloperLicense, Unregiste…
Script     1.0                   WindowsErrorReporting               Core,Desk {Enable-WindowsErrorReporting, Disable-…
Manifest   1.0.0.0               WindowsSearch                       Core,Desk {Get-WindowsSearchSetting, Set-WindowsS…
Manifest   1.0.0.0               WindowsUpdate                       Core,Desk Get-WindowsUpdateLog
Manifest   1.0.0.2               WindowsUpdateProvider               Core,Desk {Get-WUAVersion, Get-WULastInstallation…

    Directory: C:\Program Files (x86)\Microsoft Azure Information Protection\Powershell

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Binary     2.6.111.0             AzureInformationProtection          Desk      
VeryEarly commented 4 years ago

Hi @fawohlsc ,

We currently have technical difficulties to support waiting LRO as job for Invoke-AzRestMethod, for now I think you have to write a loop to get response from "Azure-AsyncOperation"

fawohlsc commented 4 years ago

@VeryEarly thanks for the prompt and insightful answer. Some cmdlets like Start-AzPolicyRemediation and Start-AzPolicyComplianceScan awaiting LRO with the -AsJob parameter. Without it, they just continue without awaiting the operation. Is this generally best practise across Azure PowerShell, so if you want to await LRO use -AsJob? Suggestion is to keep this issue open until Invoke-AzRestMethod supports LRO with -AsJob parameter.

fawohlsc commented 4 years ago

@VeryEarly - Below stating a workaround until Invoke-AzRestMethod supports awaiting async operations:

# Remove-AzRouteConfig will issue a PUT request for routeTables and hence the route will be appended by policy.
# In order to remove the route, directly call the REST API by issuing a DELETE request for route.
$httpResponse = Invoke-AzRestMethod `
    -ResourceGroupName $RouteTable.ResourceGroupName `
    -ResourceProviderName "Microsoft.Network" `
    -ResourceType @("routeTables", "routes") `
    -Name @($RouteTable.Name, $route.Name) `
    -ApiVersion "2020-05-01" `
    -Method "DELETE"

# Handling the HTTP status codes returned by the DELETE request for route 
# See also: https://docs.microsoft.com/en-us/rest/api/virtualnetwork/routes/delete
# Accepted
if ($httpResponse.StatusCode -eq 200) {
    # All good, do nothing
}
# Accepted and the operation will complete asynchronously
elseif ($httpResponse.StatusCode -eq 202) {
    # Invoke-AzRestMethod currently does not support awaiting asynchronous operations
    # See also: https://github.com/Azure/azure-powershell/issues/13293
    $asyncOperation = $httpResponse | Wait-AsyncOperation
    if ($asyncOperation.Status -ne "Succeeded") {
        throw "Route '$($route.Name)' could not be removed from route table '$($RouteTable.Name)'."
    }
}
# Route was deleted or not found
elseif ($httpResponse.StatusCode -eq 204) {
    # All good, do nothing
}
# Error response describing why the operation failed
else {
    throw "Route '$($route.Name)' could not be removed from route table '$($RouteTable.Name)'."
}

function Wait-AsyncOperation {
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNull()]
        [Microsoft.Azure.Commands.Profile.Models.PSHttpResponse]$HttpResponse,
        [Parameter()]
        [ValidateRange(1, [int]::MaxValue)]
        [int]$MaxRetries = 100
    )

    # Asynchronous operations either return HTTP status code 201 (Created) or 202 (Accepted)
    # See also: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/async-operations#status-codes-for-asynchronous-operations
    if ($HttpResponse.StatusCode -notin @(201, 202)) {
        throw "HTTP response status code must be either '201' or '202' to indicate an asynchronous operation."
    }

    # Extracting retry after from HTTP Response Headers
    # See also: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/async-operations#url-to-monitor-status
    $retryAfter = $HttpResponse 
    | Get-HttpResponseHeaderValues -HeaderName "Retry-After" 
    | Select-Object -First 1 

    # Extracting status URL from HTTP Response Headers
    $statusUrl = $HttpResponse 
    | Get-HttpResponseHeaderValues -HeaderName "Azure-AsyncOperation" 
    | Select-Object -First 1 

    if ($null -eq $statusUrl) {
        $statusUrl = $HttpResponse 
        | Get-HttpResponseHeaderValues -HeaderName "Location" 
        | Select-Object -First 1 
    }

    if ($null -eq $statusUrl) {
        throw "HTTP response does not contain any header 'Azure-AsyncOperation' or 'Location' containing the URL to monitor the status of the asynchronous operation."
    }

    # Convert status URL to path
    $statusPath = $statusUrl.Replace("https://management.azure.com", "")

    # Monitor status of asynchronous operation
    $httpResponse = $null
    $stopMonitoring = $false
    $retries = 0
    do {
        Start-Sleep -Second $retryAfter
        $retries++

        $asyncOperation = Invoke-AzRestMethod -Path $statusPath -Method "GET"
        | Select-Object -ExpandProperty Content
        | ConvertFrom-Json

        if ($asyncOperation.Status -in @("Succeeded", "Failed", "Canceled")) {
            $stopMonitoring = $true
        }
    } until (($stopMonitoring -eq $true) -or ($retries -ge $MaxRetries))

    if ($retries -ge $MaxRetries) {
        throw "Maximum retries of $($MaxRetries) reached for monitoring the status of the asynchronous operation."
    }

    return $asyncOperation
}

function Get-HttpResponseHeaderValues {
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNull()]
        [Microsoft.Azure.Commands.Profile.Models.PSHttpResponse]$HttpResponse,
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$HeaderName
    )

    $headerValues = New-Object System.Collections.Generic.List[string] 
    $httpResponse.Headers.TryGetValues($HeaderName, [ref] $headerValues) > $null
    return $headerValues
}
VeryEarly commented 3 years ago

@VeryEarly thanks for the prompt and insightful answer. Some cmdlets like Start-AzPolicyRemediation and Start-AzPolicyComplianceScan awaiting LRO with the -AsJob parameter. Without it, they just continue without awaiting the operation. Is this generally best practise across Azure PowerShell, so if you want to await LRO use -AsJob? Suggestion is to keep this issue open until Invoke-AzRestMethod supports LRO with -AsJob parameter.

Sorry for the delay response.

-AsJob is a way for you to wait the job and get the output after it was finished without blocking the current process. It really depends on do you have to wait for the LRO to be finished.

fawohlsc commented 3 years ago

Thank you @VeryEarly and no worries regarding delay. In my case, I want to wait for the LRO to finish.

shikhaLogic commented 1 year ago

Hi, I am struggling to use Invoke-AzRestMethod to call SendGrid api post method for sending mails. Please suggest how can we use that in place of Invoke-RestMethod,or Its not possible to use Invoke-AzRestMethod with Post method to call sendgrid api