diff --git a/src/Accounts/Accounts.Test/SessionRecords/Microsoft.Azure.Commands.Profile.Test.InvokeAzRestTests/TestInvokeAzRest.json b/src/Accounts/Accounts.Test/SessionRecords/Microsoft.Azure.Commands.Profile.Test.InvokeAzRestTests/TestInvokeAzRest.json index a033d9a0e1d1..4bfdbfd8b118 100644 --- a/src/Accounts/Accounts.Test/SessionRecords/Microsoft.Azure.Commands.Profile.Test.InvokeAzRestTests/TestInvokeAzRest.json +++ b/src/Accounts/Accounts.Test/SessionRecords/Microsoft.Azure.Commands.Profile.Test.InvokeAzRestTests/TestInvokeAzRest.json @@ -1,22 +1,21 @@ { "Entries": [ { - "RequestUri": "/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test?api-version=2019-10-01", - "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvOWUyMjNkYmUtMzM5OS00ZTE5LTg4ZWItMDk3NWYwMmFjODdmL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", + "RequestUri": "/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test?api-version=2019-10-01", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvMGIxZjY0NzEtMWJmMC00ZGRhLWFlYzMtY2I5MjcyZjA5NTkwL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", "RequestMethod": "PUT", - "RequestBody": "{\r\n \"Location\": \"eastus\"\r\n}", "RequestHeaders": { "x-ms-client-request-id": [ - "81de12fa-bbcf-47d5-a8fd-943c1ad886e1" + "5f3d8d11-abc3-42e9-8cd8-ce8c9b012a1b" ], "Accept-Language": [ "en-US" ], "User-Agent": [ - "FxVersion/4.6.28928.01", - "OSName/Windows", - "OSVersion/Microsoft.Windows.10.0.18363.", - "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.17" + "FxVersion/6.0.3324.36610", + "OSName/MacOs", + "OSVersion/Darwin.24.0.0.Darwin.Kernel.Version.24.0.0.Mon.Aug.12.20.52.31.PDT.2024.root.xnu.11215.1.10.2RELEASE.ARM64.T6030", + "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.101" ], "Content-Type": [ "application/json; charset=utf-8" @@ -25,6 +24,7 @@ "22" ] }, + "RequestBody": "{\n \"Location\": \"eastus\"\n}", "ResponseHeaders": { "Cache-Control": [ "no-cache" @@ -33,16 +33,19 @@ "no-cache" ], "x-ms-ratelimit-remaining-subscription-writes": [ - "1199" + "199" + ], + "x-ms-ratelimit-remaining-subscription-global-writes": [ + "2999" ], "x-ms-request-id": [ - "7cc85e9c-718e-4ce9-92cd-76098f863590" + "1c59e989-4aa0-4566-af56-186ca4756375" ], "x-ms-correlation-request-id": [ - "7cc85e9c-718e-4ce9-92cd-76098f863590" + "1c59e989-4aa0-4566-af56-186ca4756375" ], "x-ms-routing-request-id": [ - "SOUTHEASTASIA:20200630T032251Z:7cc85e9c-718e-4ce9-92cd-76098f863590" + "AUSTRALIACENTRAL:20241023T075013Z:1c59e989-4aa0-4566-af56-186ca4756375" ], "Strict-Transport-Security": [ "max-age=31536000; includeSubDomains" @@ -50,8 +53,14 @@ "X-Content-Type-Options": [ "nosniff" ], + "X-Cache": [ + "CONFIG_NOCACHE" + ], + "X-MSEdge-Ref": [ + "Ref A: E5AB01C176634C379FBC8B5383ED0045 Ref B: SYD03EDGE0721 Ref C: 2024-10-23T07:50:09Z" + ], "Date": [ - "Tue, 30 Jun 2020 03:22:51 GMT" + "Wed, 23 Oct 2024 07:50:13 GMT" ], "Content-Length": [ "219" @@ -63,28 +72,28 @@ "-1" ] }, - "ResponseBody": "{\r\n \"id\": \"/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test\",\r\n \"name\": \"mockRG4Test\",\r\n \"type\": \"Microsoft.Resources/resourceGroups\",\r\n \"location\": \"eastus\",\r\n \"properties\": {\r\n \"provisioningState\": \"Succeeded\"\r\n }\r\n}", + "ResponseBody": "{\n \"id\": \"/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test\",\n \"name\": \"mockRG4Test\",\n \"type\": \"Microsoft.Resources/resourceGroups\",\n \"location\": \"eastus\",\n \"properties\": {\n \"provisioningState\": \"Succeeded\"\n }\n}", "StatusCode": 201 }, { - "RequestUri": "/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test?api-version=2019-10-01", - "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvOWUyMjNkYmUtMzM5OS00ZTE5LTg4ZWItMDk3NWYwMmFjODdmL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", + "RequestUri": "/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test?api-version=2019-10-01", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvMGIxZjY0NzEtMWJmMC00ZGRhLWFlYzMtY2I5MjcyZjA5NTkwL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", "RequestMethod": "GET", - "RequestBody": "", "RequestHeaders": { "x-ms-client-request-id": [ - "d64d1bd0-4477-4d0f-b846-10fd6344bb1a" + "29826450-723d-4285-9f0b-bdfdaf2a91d2" ], "Accept-Language": [ "en-US" ], "User-Agent": [ - "FxVersion/4.6.28928.01", - "OSName/Windows", - "OSVersion/Microsoft.Windows.10.0.18363.", - "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.17" + "FxVersion/6.0.3324.36610", + "OSName/MacOs", + "OSVersion/Darwin.24.0.0.Darwin.Kernel.Version.24.0.0.Mon.Aug.12.20.52.31.PDT.2024.root.xnu.11215.1.10.2RELEASE.ARM64.T6030", + "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.101" ] }, + "RequestBody": "", "ResponseHeaders": { "Cache-Control": [ "no-cache" @@ -93,16 +102,19 @@ "no-cache" ], "x-ms-ratelimit-remaining-subscription-reads": [ - "11994" + "249" + ], + "x-ms-ratelimit-remaining-subscription-global-reads": [ + "3749" ], "x-ms-request-id": [ - "3812dcc9-0254-4fe9-b88f-40706ff4a59a" + "17062fca-df7d-4c82-9a39-8f397780b3a1" ], "x-ms-correlation-request-id": [ - "3812dcc9-0254-4fe9-b88f-40706ff4a59a" + "17062fca-df7d-4c82-9a39-8f397780b3a1" ], "x-ms-routing-request-id": [ - "SOUTHEASTASIA:20200630T032251Z:3812dcc9-0254-4fe9-b88f-40706ff4a59a" + "AUSTRALIAEAST:20241023T075013Z:17062fca-df7d-4c82-9a39-8f397780b3a1" ], "Strict-Transport-Security": [ "max-age=31536000; includeSubDomains" @@ -110,39 +122,44 @@ "X-Content-Type-Options": [ "nosniff" ], + "X-Cache": [ + "CONFIG_NOCACHE" + ], + "X-MSEdge-Ref": [ + "Ref A: B086E2886F074F4BA4F6775E652EC9E3 Ref B: SYD03EDGE1007 Ref C: 2024-10-23T07:50:13Z" + ], "Date": [ - "Tue, 30 Jun 2020 03:22:51 GMT" + "Wed, 23 Oct 2024 07:50:13 GMT" + ], + "Content-Length": [ + "219" ], "Content-Type": [ "application/json; charset=utf-8" ], "Expires": [ "-1" - ], - "Content-Length": [ - "219" ] }, - "ResponseBody": "{\r\n \"id\": \"/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test\",\r\n \"name\": \"mockRG4Test\",\r\n \"type\": \"Microsoft.Resources/resourceGroups\",\r\n \"location\": \"eastus\",\r\n \"properties\": {\r\n \"provisioningState\": \"Succeeded\"\r\n }\r\n}", + "ResponseBody": "{\n \"id\": \"/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test\",\n \"name\": \"mockRG4Test\",\n \"type\": \"Microsoft.Resources/resourceGroups\",\n \"location\": \"eastus\",\n \"properties\": {\n \"provisioningState\": \"Succeeded\"\n }\n}", "StatusCode": 200 }, { - "RequestUri": "/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test?api-version=2019-10-01", - "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvOWUyMjNkYmUtMzM5OS00ZTE5LTg4ZWItMDk3NWYwMmFjODdmL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", + "RequestUri": "/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test?api-version=2019-10-01", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvMGIxZjY0NzEtMWJmMC00ZGRhLWFlYzMtY2I5MjcyZjA5NTkwL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", "RequestMethod": "PATCH", - "RequestBody": "{\r\n \"tags\": {\r\n \"key\": \"val\"\r\n }\r\n}", "RequestHeaders": { "x-ms-client-request-id": [ - "28343bc5-2bb1-4156-b4a4-aa5d93f6d5a1" + "3ffeebc6-47e9-4996-9ddb-40419b407d8c" ], "Accept-Language": [ "en-US" ], "User-Agent": [ - "FxVersion/4.6.28928.01", - "OSName/Windows", - "OSVersion/Microsoft.Windows.10.0.18363.", - "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.17" + "FxVersion/6.0.3324.36610", + "OSName/MacOs", + "OSVersion/Darwin.24.0.0.Darwin.Kernel.Version.24.0.0.Mon.Aug.12.20.52.31.PDT.2024.root.xnu.11215.1.10.2RELEASE.ARM64.T6030", + "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.101" ], "Content-Type": [ "application/json; charset=utf-8" @@ -151,6 +168,7 @@ "24" ] }, + "RequestBody": "{\n \"tags\": {\n \"key\": \"val\"\n }\n}", "ResponseHeaders": { "Cache-Control": [ "no-cache" @@ -159,16 +177,19 @@ "no-cache" ], "x-ms-ratelimit-remaining-subscription-writes": [ - "1196" + "199" + ], + "x-ms-ratelimit-remaining-subscription-global-writes": [ + "2999" ], "x-ms-request-id": [ - "61d06e8b-185e-4c2e-a7b3-83a92c0b252b" + "3c871636-7afd-44e1-bb90-95d0e6dc499d" ], "x-ms-correlation-request-id": [ - "61d06e8b-185e-4c2e-a7b3-83a92c0b252b" + "3c871636-7afd-44e1-bb90-95d0e6dc499d" ], "x-ms-routing-request-id": [ - "SOUTHEASTASIA:20200630T032254Z:61d06e8b-185e-4c2e-a7b3-83a92c0b252b" + "AUSTRALIAEAST:20241023T075017Z:3c871636-7afd-44e1-bb90-95d0e6dc499d" ], "Strict-Transport-Security": [ "max-age=31536000; includeSubDomains" @@ -176,8 +197,14 @@ "X-Content-Type-Options": [ "nosniff" ], + "X-Cache": [ + "CONFIG_NOCACHE" + ], + "X-MSEdge-Ref": [ + "Ref A: 2A52BCD884E84BFEB917EEB3C30AD8C6 Ref B: SYD03EDGE1016 Ref C: 2024-10-23T07:50:14Z" + ], "Date": [ - "Tue, 30 Jun 2020 03:22:54 GMT" + "Wed, 23 Oct 2024 07:50:16 GMT" ], "Content-Length": [ "240" @@ -189,28 +216,28 @@ "-1" ] }, - "ResponseBody": "{\r\n \"id\": \"/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test\",\r\n \"name\": \"mockRG4Test\",\r\n \"type\": \"Microsoft.Resources/resourceGroups\",\r\n \"location\": \"eastus\",\r\n \"tags\": {\r\n \"key\": \"val\"\r\n },\r\n \"properties\": {\r\n \"provisioningState\": \"Succeeded\"\r\n }\r\n}", + "ResponseBody": "{\n \"id\": \"/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test\",\n \"name\": \"mockRG4Test\",\n \"type\": \"Microsoft.Resources/resourceGroups\",\n \"location\": \"eastus\",\n \"tags\": {\n \"key\": \"val\"\n },\n \"properties\": {\n \"provisioningState\": \"Succeeded\"\n }\n}", "StatusCode": 200 }, { - "RequestUri": "/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/resourceGroups/mockRG4Test?api-version=2019-10-01", - "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvOWUyMjNkYmUtMzM5OS00ZTE5LTg4ZWItMDk3NWYwMmFjODdmL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", + "RequestUri": "/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/mockRG4Test?api-version=2019-10-01", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvMGIxZjY0NzEtMWJmMC00ZGRhLWFlYzMtY2I5MjcyZjA5NTkwL3Jlc291cmNlR3JvdXBzL21vY2tSRzRUZXN0P2FwaS12ZXJzaW9uPTIwMTktMTAtMDE=", "RequestMethod": "DELETE", - "RequestBody": "", "RequestHeaders": { "x-ms-client-request-id": [ - "3ab6d714-2aea-4d95-a43d-f07e26d47f81" + "baba728a-e504-494c-895e-78ee68f9b0d6" ], "Accept-Language": [ "en-US" ], "User-Agent": [ - "FxVersion/4.6.28928.01", - "OSName/Windows", - "OSVersion/Microsoft.Windows.10.0.18363.", - "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.17" + "FxVersion/6.0.3324.36610", + "OSName/MacOs", + "OSVersion/Darwin.24.0.0.Darwin.Kernel.Version.24.0.0.Mon.Aug.12.20.52.31.PDT.2024.root.xnu.11215.1.10.2RELEASE.ARM64.T6030", + "Microsoft.Azure.Internal.Common.AzureRestClient/1.3.101" ] }, + "RequestBody": "", "ResponseHeaders": { "Cache-Control": [ "no-cache" @@ -219,22 +246,25 @@ "no-cache" ], "Location": [ - "https://management.azure.com/subscriptions/9e223dbe-3399-4e19-88eb-0975f02ac87f/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1NT0NLUkc0VEVTVC1FQVNUVVMiLCJqb2JMb2NhdGlvbiI6ImVhc3R1cyJ9?api-version=2019-10-01" + "https://management.azure.com/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1NT0NLUkc0VEVTVC1FQVNUVVMiLCJqb2JMb2NhdGlvbiI6ImVhc3R1cyJ9?api-version=2019-10-01&t=638652666236086739&c=MIIHhzCCBm-gAwIBAgITHgV0Am0HtpbJw6qd5wAABXQCbTANBgkqhkiG9w0BAQsFADBEMRMwEQYKCZImiZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRgwFgYDVQQDEw9BTUUgSW5mcmEgQ0EgMDYwHhcNMjQwOTI3MDgyMjIxWhcNMjUwMzI2MDgyMjIxWjBAMT4wPAYDVQQDEzVhc3luY29wZXJhdGlvbnNpZ25pbmdjZXJ0aWZpY2F0ZS5tYW5hZ2VtZW50LmF6dXJlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMgJCEWh3POrqbhsQ_nsNPLTwMLltYItV3Z2pLAl_He3H3n9lLYypfqFjRus3fxOmreXBun3pTgw0v5M1o11tIQ35A7GfGR3PLJZvLyUnyOLlUulmId1qHlB_Eca__W1QAJaCzhMdXbRDdBRfSh4tMQrZ1mgb1Z63c8TVF1VZ97Qofq_U4BDvOArvARLjWJkr-iuNAH25YQRu42HmDr9cpH1_Pm_mMAmxzntUZOrlBisJAnpwgu0Luy1HHf3ZppLbooRq4hI6pxzNHpvJFjssmnXyZ5DGriBYq8TC9qcfOahYhGW34zW4uw8y3oc11MypcccV6JvsqIHCTv-HIPqHMUCAwEAAaOCBHQwggRwMCcGCSsGAQQBgjcVCgQaMBgwCgYIKwYBBQUHAwEwCgYIKwYBBQUHAwIwPQYJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIhpDjDYTVtHiE8Ys-hZvdFs6dEoFghfmRS4WsmTQCAWQCAQcwggHLBggrBgEFBQcBAQSCAb0wggG5MGMGCCsGAQUFBzAChldodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpaW5mcmEvQ2VydHMvQkwyUEtJSU5UQ0EwMi5BTUUuR0JMX0FNRSUyMEluZnJhJTIwQ0ElMjAwNi5jcnQwUwYIKwYBBQUHMAKGR2h0dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0JMMlBLSUlOVENBMDIuQU1FLkdCTF9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3J0MFMGCCsGAQUFBzAChkdodHRwOi8vY3JsMi5hbWUuZ2JsL2FpYS9CTDJQS0lJTlRDQTAyLkFNRS5HQkxfQU1FJTIwSW5mcmElMjBDQSUyMDA2LmNydDBTBggrBgEFBQcwAoZHaHR0cDovL2NybDMuYW1lLmdibC9haWEvQkwyUEtJSU5UQ0EwMi5BTUUuR0JMX0FNRSUyMEluZnJhJTIwQ0ElMjAwNi5jcnQwUwYIKwYBBQUHMAKGR2h0dHA6Ly9jcmw0LmFtZS5nYmwvYWlhL0JMMlBLSUlOVENBMDIuQU1FLkdCTF9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3J0MB0GA1UdDgQWBBSkNXFG7HFDf4QA2iXQGug0G-qNYzAOBgNVHQ8BAf8EBAMCBaAwggEmBgNVHR8EggEdMIIBGTCCARWgggERoIIBDYY_aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL0NSTC9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3JshjFodHRwOi8vY3JsMS5hbWUuZ2JsL2NybC9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3JshjFodHRwOi8vY3JsMi5hbWUuZ2JsL2NybC9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3JshjFodHRwOi8vY3JsMy5hbWUuZ2JsL2NybC9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3JshjFodHRwOi8vY3JsNC5hbWUuZ2JsL2NybC9BTUUlMjBJbmZyYSUyMENBJTIwMDYuY3JsMIGdBgNVHSAEgZUwgZIwDAYKKwYBBAGCN3sBATBmBgorBgEEAYI3ewICMFgwVgYIKwYBBQUHAgIwSh5IADMAMwBlADAAMQA5ADIAMQAtADQAZAA2ADQALQA0AGYAOABjAC0AYQAwADUANQAtADUAYgBkAGEAZgBmAGQANQBlADMAMwBkMAwGCisGAQQBgjd7AwEwDAYKKwYBBAGCN3sEAjAfBgNVHSMEGDAWgBTxRmjG8cPwKy19i2rhsvm-NfzRQTAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBADrusw-PCkO5ei7sAu22p4jTkhqxE2MuMN7zYajMba7fxwRXcayq8HSZt_rwwShrvXkY0WeBM3y3z6tIG0XSNBjEsROaQ6XEbNmIxwWMRyPrxlwsItCYOT17HSiV3wFR_kQlokJJ1sZq3To7Rsv604dkrmrydte_K4YvVKkXwnJa_yTfuXK118cFukluMiUmJX7V0_tyYsp4SLM_dVIOaBxQkhowJMURLOTEPHPGuLIC9Be58aPxpGMGRWscVeCY1VX4Tdot9sVtpMFY9IhiPztzmGhZSClhSVPCpp_zI_P39KtiZII31hr57v-TKTRNCOo2V4Ph57EhbpHwUqEBrFQ&s=tfNVfVi-a5wzeFyAhfJRUTSTN4wYvjPiwg7FRAubXn5_Xck-TeJJIl4hvGmYioWh6w7W7uNMpozhP15IiVim3hosDvdan_htJ--D_Gtz919l8X8wBGdhh_3S3sU_a4UDzEmmMjJRSWW6_IWNXc2h53RRiP8fLUcAgfRG5pu_NKmkSNFBqe8DwSih1nkKmrnEbAd_-RM9sTtZ_MsWNLBh_9tKlFXNT4ko9LZXEbI8Kg20-a_Ph0FNT6D-XaTX8-_6bVc-lzVP31Urt4u-22OlTJiRaw1VwH801UtfHAjZ2qGUZuw_SOOy8iQgfTXsMG8KzXTej8ZTKwyWJfOB4KznTg&h=53mCMkS9ZoLCkrIeA44acApxDRxLqdBX8Dx-3oyqeus" ], "Retry-After": [ "15" ], "x-ms-ratelimit-remaining-subscription-deletes": [ - "14999" + "199" + ], + "x-ms-ratelimit-remaining-subscription-global-deletes": [ + "2999" ], "x-ms-request-id": [ - "2307c7dc-bddf-42b1-81e0-5b42931cbc56" + "a3a932c1-1750-4e64-baf6-1f45e3c90030" ], "x-ms-correlation-request-id": [ - "2307c7dc-bddf-42b1-81e0-5b42931cbc56" + "a3a932c1-1750-4e64-baf6-1f45e3c90030" ], "x-ms-routing-request-id": [ - "SOUTHEASTASIA:20200630T032258Z:2307c7dc-bddf-42b1-81e0-5b42931cbc56" + "AUSTRALIAEAST:20241023T075023Z:a3a932c1-1750-4e64-baf6-1f45e3c90030" ], "Strict-Transport-Security": [ "max-age=31536000; includeSubDomains" @@ -242,8 +272,14 @@ "X-Content-Type-Options": [ "nosniff" ], + "X-Cache": [ + "CONFIG_NOCACHE" + ], + "X-MSEdge-Ref": [ + "Ref A: CE0FAD1795C34118AF6FB2B7ADCE3CD3 Ref B: SYD03EDGE1119 Ref C: 2024-10-23T07:50:18Z" + ], "Date": [ - "Tue, 30 Jun 2020 03:22:57 GMT" + "Wed, 23 Oct 2024 07:50:23 GMT" ], "Expires": [ "-1" @@ -258,6 +294,6 @@ ], "Names": {}, "Variables": { - "SubscriptionId": "9e223dbe-3399-4e19-88eb-0975f02ac87f" + "SubscriptionId": "0b1f6471-1bf0-4dda-aec3-cb9272f09590" } } \ No newline at end of file diff --git a/src/Accounts/Accounts/ChangeLog.md b/src/Accounts/Accounts/ChangeLog.md index 2c75de82e74c..af104e32ac1e 100644 --- a/src/Accounts/Accounts/ChangeLog.md +++ b/src/Accounts/Accounts/ChangeLog.md @@ -19,6 +19,7 @@ --> ## Upcoming Release +* Added Long Running Operation Support for Invoke-AzRest command. ## Version 3.0.5 * Fixed the issue that `Export-AzSshConfig` and `Enter-AzVM` from Az.Ssh are not able to use when WAM is enabled. diff --git a/src/Accounts/Accounts/Rest/InvokeAzRestMethodCommand.cs b/src/Accounts/Accounts/Rest/InvokeAzRestMethodCommand.cs index a7f2d7c837d0..2c5319ac88d0 100644 --- a/src/Accounts/Accounts/Rest/InvokeAzRestMethodCommand.cs +++ b/src/Accounts/Accounts/Rest/InvokeAzRestMethodCommand.cs @@ -21,8 +21,15 @@ using Microsoft.Rest.Azure; using Microsoft.WindowsAzure.Commands.Utilities.Common; using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; +using System.Net.Http; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace Microsoft.Azure.Commands.Profile.Rest { @@ -91,6 +98,51 @@ public class InvokeAzRestMethodCommand : AzureRMCmdlet [Parameter(Mandatory = false, HelpMessage = "Run cmdlet in the background")] public SwitchParameter AsJob { get; set; } + [Parameter(Mandatory = false, HelpMessage = "Waits for the long-running operation to complete before returning the result.")] + public SwitchParameter WaitForCompletion { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Specifies the polling header (to fetch from) for long-running operation status.")] + [ArgumentCompleter(typeof(PollFromCompleter))] + public string PollFrom { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Specifies the header for final GET result after the long-running operation completes.")] + [ArgumentCompleter(typeof(FinalResultFromCompleter))] + public string FinalResultFrom { get; set; } + + + // Define the ArgumentCompleter for PollFrom + public class PollFromCompleter : IArgumentCompleter + { + public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) + { + var suggestions = new List { "AzureAsyncLocation", "Location", "OriginalUri", "Operation-Location" }; + foreach (var suggestion in suggestions) + { + if (suggestion.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase)) + { + yield return new CompletionResult(suggestion); + } + } + } + } + + // Define the ArgumentCompleter for FinalResultFrom + public class FinalResultFromCompleter : IArgumentCompleter + { + public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) + { + var suggestions = new List { "FinalStateVia", "Location", "OriginalUri", "Operation-Location" }; + foreach (var suggestion in suggestions) + { + if (suggestion.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase)) + { + yield return new CompletionResult(suggestion); + } + } + } + } + + #endregion IAzureContext context; @@ -100,7 +152,6 @@ public override void ExecuteCmdlet() this.ValidateParameters(); context = DefaultContext; - AzureOperationResponse response = null; if (ByParameters.Equals(this.ParameterSetName)) { @@ -111,66 +162,244 @@ public override void ExecuteCmdlet() this.Path = Uri.PathAndQuery; } - IAzureRestClient serviceClient = null; - if (ByPath.Equals(this.ParameterSetName) || ByParameters.Equals(this.ParameterSetName)) + IAzureRestClient serviceClient = this.InitializeServiceClient(); + + AzureOperationResponse response = ExecuteRestRequest(serviceClient); + + if(WaitForCompletion.IsPresent) { - serviceClient = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); + if (IsRequestLRO(response)) + { + response = ExecuteLRORequest(serviceClient, response); + } + else + { + WriteObject(new PSHttpResponse(response)); + WriteWarning("The -WaitForCompletion flag was specified, but the request does not appear to be a long-running operation."); + } } - else if (ByURI.Equals(this.ParameterSetName)) + else { - string targetResourceIdKey = null; - string resourceId = this.IsParameterBound(c => c.ResourceId) ? ResourceId.ToString() : null; - if(this.IsParameterBound(c => c.ResourceId) - && context.Environment.ActiveDirectoryServiceEndpointResourceId.Equals(resourceId) - && !HasSameEndpoint(Uri.Authority, context.Environment.ResourceManagerUrl)) + WriteObject(new PSHttpResponse(response)); + } + + } + + private AzureOperationResponse ExecuteLRORequest(IAzureRestClient serviceClient, AzureOperationResponse response) + { + + while (IsRequestLRO(response)) + { + // Delay between polling requests; default to 30 seconds if not specified + int delay = response.Response.Headers.Contains("Retry-After") + ? int.Parse(response.Response.Headers.GetValues("Retry-After").FirstOrDefault()) + : 30; + + Thread.Sleep(TimeSpan.FromSeconds(delay)); + + // Polling logic; uses GET method to check operation status + string pollingUri = DeterminePollingUri(response); + response = serviceClient.Operations.GetResourceWithFullResponse(pollingUri, this.ApiVersion); + + + if (response.Response.StatusCode == System.Net.HttpStatusCode.Created || + response.Response.StatusCode == System.Net.HttpStatusCode.Accepted) { - throw new AzPSArgumentException("The resource ID of Azure Resource Manager cannot be used for other endpoint. Please make sure to input the correct resource ID that matches the request URI.", - nameof(ResourceId)); + continue; } - var targetResourceId = string.IsNullOrEmpty(resourceId) ? MatchResourceId(context, Uri.Authority, out targetResourceIdKey) : resourceId; - if (string.IsNullOrWhiteSpace(targetResourceId)) + else + if (response.Response.StatusCode == System.Net.HttpStatusCode.OK) { - throw new AzPSArgumentException("Cannot find resource id(audience) for authentication", nameof(ResourceId)); + var error = false; + try + { + string state = GetProvisioningState(response); + if (state is null) + { + // There is insufficient information to continue LRO + // We will return the final request-response + break; + } + + switch (state?.ToLower()) + { + case "failed": + error = true; + break; + case "succeeded": + case "canceled": + break; + + default: + // Continue Polling + response.Response.StatusCode = System.Net.HttpStatusCode.Created; + continue; + } + + } + catch {} // Cannot Peek into response + + if (error) + { + throw new AzPSException("Azure Service operation failed.", Commands.Common.ErrorKind.ServiceError); + } + + + // Polling is Complete, Return Final Response + // Retrieve final resource state based on FinalResultFrom + if (!Method.ToUpper().Equals("DELETE")) + { + string finalUri = DetermineFinalUri(response); + response = serviceClient.Operations.GetResourceWithFullResponse(finalUri, this.ApiVersion); + + WriteObject(new PSHttpResponse(response)); + } + break; } + + } - ServiceClientCredentials creds = null; - if (AzureSession.Instance.AuthenticationFactory is Commands.Common.Authentication.Factories.AuthenticationFactory factory) + + return response; + } + + public string DetermineFinalUri(AzureOperationResponse response) + { + /* + final-state-via SHOULD BE one of + + azure-async-operation - poll until terminal state, skip any final GET on Location or Origin-URI and use the final response at the uri pointed to by the header Azure-AsyncOperation. + location - poll until terminal state, if the initial response had a Location header, a final GET will be done. Default behavior for POST operation. + original-uri - poll until terminal state, a final GET will be done at the original resource URI. Default behavior for PUT operations. + operation-location - poll until terminal state, skip any final GET on Location or Origin-URI and use the final response at the uri pointed to by the header Operation-Location + */ + + if(!string.IsNullOrEmpty(FinalResultFrom)) + { + return GetUriFromHeader(response, FinalResultFrom); + } + + string[] priorityHeaders = new string[3]; + + + switch (this.Method.ToUpper()) + { + case "POST": + priorityHeaders[0] = "Operation-Location"; + priorityHeaders[1] = "Location"; + priorityHeaders[2] = "Azure-AsyncOperation"; + break; + + // This case will never execute. + case "DELETE": + priorityHeaders[0] = "Location"; + priorityHeaders[1] = "Azure-AsyncOperation"; + priorityHeaders[2] = "Operation-Location"; + break; + + case "PUT": + case "PATCH": + return this.Path; + + default: + throw new AzPSArgumentException("Invalid HTTP Method", nameof(Method)); + } + + foreach (string header in priorityHeaders) + { + if (response.Response.Headers.Contains(header)) { - creds = factory.GetServiceClientCredentials(context, targetResourceIdKey, targetResourceId); + return GetUriFromHeader(response, header); } - else + } + return this.Path; + + } + + public string DeterminePollingUri(AzureOperationResponse response) + { + /* + * Priority of Polling Uri: + * 1. `PollFrom` (User Ovrride) + * 2. "Azure-AsyncOperation" + * 3. "Location" + * 4. originalUri (Resource Uri) + * + */ + + // User input (PollFrom) overrides everything + if (!string.IsNullOrEmpty(PollFrom)) + { + return GetUriFromHeader(response, PollFrom); + } + + + // Check if each header is present in response following certain priority + string[] priorityHeaders = { "Azure-AsyncOperation", "Location" }; + + foreach (string header in priorityHeaders) + { + if (response.Response.Headers.Contains(header)) { - creds = AzureSession.Instance.AuthenticationFactory.GetServiceClientCredentials(context, targetResourceId); + return GetUriFromHeader(response, header); } - Uri baseUri = new Uri($"{Uri.Scheme}://{Uri.Authority}"); - serviceClient = AzureSession.Instance.ClientFactory.CreateCustomArmClient(baseUri, creds); } - else + + return this.Path; // Default to original URI + } + + private string GetUriFromHeader(AzureOperationResponse response, string chosenHeader) + { + if (!response.Response.Headers.Contains(chosenHeader)) { - WriteErrorWithTimestamp("Parameter set is not implemented"); + throw new AzPSInvalidOperationException($"Polling header `{chosenHeader}` is not present in the response."); } + var headerValues = response.Response.Headers.GetValues(chosenHeader); + return new Uri(headerValues.FirstOrDefault()).PathAndQuery; + } + + private bool IsRequestLRO(AzureOperationResponse response) + { + return (response.Response.RequestMessage.Method == System.Net.Http.HttpMethod.Put && + response.Response.StatusCode == System.Net.HttpStatusCode.OK) || + response.Response.StatusCode == System.Net.HttpStatusCode.Created || + response.Response.StatusCode == System.Net.HttpStatusCode.Accepted; + } + + public string GetProvisioningState(AzureOperationResponse response) + { + var content = response.Body; + var json = Newtonsoft.Json.JsonConvert.DeserializeObject(content); + return json["properties"]?["provisioningState"]?.ToString() ?? json["status"]?.ToString(); + } + + + private AzureOperationResponse ExecuteRestRequest(IAzureRestClient serviceClient) + { + AzureOperationResponse response = null; + switch (this.Method.ToUpper()) { case "GET": response = serviceClient .Operations - .GetResourceWithFullResponse(this.Path, this.ApiVersion); + .GetResourceWithFullResponse(Path, ApiVersion); break; case "POST": if (this.ShouldProcess(Path, "POST")) { response = serviceClient .Operations - .PostResourceWithFullResponse(this.Path, this.ApiVersion, this.Payload); - } + .PostResourceWithFullResponse(Path, ApiVersion, Payload); + } break; case "PUT": if (this.ShouldProcess(Path, "PUT")) { response = serviceClient .Operations - .PutResourceWithFullResponse(this.Path, this.ApiVersion, this.Payload); + .PutResourceWithFullResponse(Path, ApiVersion, Payload); } break; case "PATCH": @@ -178,7 +407,7 @@ public override void ExecuteCmdlet() { response = serviceClient .Operations - .PatchResourceWithFullResponse(this.Path, this.ApiVersion, this.Payload); + .PatchResourceWithFullResponse(Path, ApiVersion, Payload); } break; case "DELETE": @@ -186,16 +415,63 @@ public override void ExecuteCmdlet() { response = serviceClient .Operations - .DeleteResourceWithFullResponse(this.Path, this.ApiVersion); - } + .DeleteResourceWithFullResponse(Path, ApiVersion); + } break; default: throw new AzPSArgumentException("Invalid HTTP Method", nameof(Method)); } - WriteObject(new PSHttpResponse(response)); + return response; } + + private IAzureRestClient InitializeServiceClient() + { + IAzureRestClient serviceClient = null; + + if (ByPath.Equals(this.ParameterSetName) || ByParameters.Equals(this.ParameterSetName)) + { + serviceClient = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); + } + else if (ByURI.Equals(this.ParameterSetName)) + { + string targetResourceIdKey = null; + string resourceId = this.IsParameterBound(c => c.ResourceId) ? ResourceId.ToString() : null; + if (this.IsParameterBound(c => c.ResourceId) + && context.Environment.ActiveDirectoryServiceEndpointResourceId.Equals(resourceId) + && !HasSameEndpoint(Uri.Authority, context.Environment.ResourceManagerUrl)) + { + throw new AzPSArgumentException("The resource ID of Azure Resource Manager cannot be used for other endpoint. Please make sure to input the correct resource ID that matches the request URI.", + nameof(ResourceId)); + } + var targetResourceId = string.IsNullOrEmpty(resourceId) ? MatchResourceId(context, Uri.Authority, out targetResourceIdKey) : resourceId; + if (string.IsNullOrWhiteSpace(targetResourceId)) + { + throw new AzPSArgumentException("Cannot find resource id(audience) for authentication", nameof(ResourceId)); + } + + ServiceClientCredentials creds = null; + if (AzureSession.Instance.AuthenticationFactory is Commands.Common.Authentication.Factories.AuthenticationFactory factory) + { + creds = factory.GetServiceClientCredentials(context, targetResourceIdKey, targetResourceId); + } + else + { + creds = AzureSession.Instance.AuthenticationFactory.GetServiceClientCredentials(context, targetResourceId); + } + Uri baseUri = new Uri($"{Uri.Scheme}://{Uri.Authority}"); + serviceClient = AzureSession.Instance.ClientFactory.CreateCustomArmClient(baseUri, creds); + } + else + { + WriteErrorWithTimestamp("Parameter set is not implemented"); + } + + return serviceClient; + } + + private string MatchResourceId(IAzureContext context, string authority, out string targetResourceIdKey) { var env = context.Environment; @@ -353,5 +629,8 @@ private string ConstructPath(string sub, string rg, string rp, string[] types, s } return sb.ToString(); } + + + } } diff --git a/src/Accounts/Accounts/help/Invoke-AzRestMethod.md b/src/Accounts/Accounts/help/Invoke-AzRestMethod.md index 417dc64ad6a8..c1f3781a6b5d 100644 --- a/src/Accounts/Accounts/help/Invoke-AzRestMethod.md +++ b/src/Accounts/Accounts/help/Invoke-AzRestMethod.md @@ -14,21 +14,26 @@ Construct and perform HTTP request to Azure resource management endpoint only ### ByPath (Default) ``` -Invoke-AzRestMethod -Path [-Method ] [-Payload ] [-AsJob] - [-DefaultProfile ] [-WhatIf] [-Confirm] [] +Invoke-AzRestMethod -Path [-Method ] [-Payload ] [-AsJob] [-WaitForCompletion] + [-PollFrom ] [-FinalResultFrom ] [-DefaultProfile ] + [-ProgressAction ] [-WhatIf] [-Confirm] [] ``` ### ByParameters ``` Invoke-AzRestMethod [-SubscriptionId ] [-ResourceGroupName ] [-ResourceProviderName ] [-ResourceType ] [-Name ] -ApiVersion [-Method ] [-Payload ] - [-AsJob] [-DefaultProfile ] [-WhatIf] [-Confirm] [] + [-AsJob] [-WaitForCompletion] [-PollFrom ] [-FinalResultFrom ] + [-DefaultProfile ] [-ProgressAction ] [-WhatIf] [-Confirm] + [] ``` ### ByURI ``` Invoke-AzRestMethod [-Uri] [-ResourceId ] [-Method ] [-Payload ] [-AsJob] - [-DefaultProfile ] [-WhatIf] [-Confirm] [] + [-WaitForCompletion] [-PollFrom ] [-FinalResultFrom ] + [-DefaultProfile ] [-ProgressAction ] [-WhatIf] [-Confirm] + [] ``` ## DESCRIPTION @@ -156,6 +161,91 @@ Invoke-AzRestMethod -Method POST -Uri https://graph.microsoft.com/v1.0/servicePr Call Microsoft Graph API to assign App Role by constructing a hashtable, converting to a JSON string, and passing the payload to `Invoke-AzRestMethod`. +### Example 5 +```powershell +# This example demonstrates creating or updating a resource with a long-running PUT request. +Invoke-AzRestMethod -Method PUT -Uri "https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/managedHSMs/{hsm-name}?api-version=2023-07-01" ` + -Payload (@{ + location = "eastus"; + properties = @{ + softDeleteRetentionDays = 7; + tenantId = "{tenant-id}"; + initialAdminObjectIds = @("{admin-object-id}") + }; + sku = @{ + name = "Standard_B1"; + family = "B" + } + } | ConvertTo-Json -Depth 10) ` + -WaitForCompletion +``` + +```output +StatusCode : 200 +Content : { + "sku": { + "family": "B", + "name": "Standard_B1" + }, + "id": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/managedHSMs/{hsm-name}", + "name": "{hsm-name}", + "type": "Microsoft.KeyVault/managedHSMs", + "location": "{region}", + "tags": {}, + "systemData": { + "createdBy": "{user-email}", + "createdByType": "User", + "createdAt": "2024-10-29T05:05:49.229Z", + "lastModifiedBy": "{user-email}", + "lastModifiedByType": "User", + "lastModifiedAt": "2024-10-29T05:05:49.229Z" + }, + "properties": { + "tenantId": "{tenant-id}", + "hsmUri": "https://{hsm-name}.managedhsm.azure.net/", + "initialAdminObjectIds": [ + "{admin-object-id}" + ], + "enableSoftDelete": true, + "softDeleteRetentionInDays": 90, + "enablePurgeProtection": false, + "provisioningState": "Succeeded", + "statusMessage": "The Managed HSM is provisioned and ready to use.", + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Allow", + "ipRules": [], + "virtualNetworkRules": [] + }, + "publicNetworkAccess": "Enabled", + "regions": [], + "securityDomainProperties": { + "activationStatus": "NotActivated", + "activationStatusMessage": "Your HSM has been provisioned, but cannot be used for cryptographic operations until it is activated. To activate the HSM, download the security domain." + } + } + } +Headers : { + "Cache-Control": "no-cache", + "Pragma": "no-cache", + "x-ms-client-request-id": "{client-request-id}", + "x-ms-keyvault-service-version": "1.5.1361.0", + "x-ms-request-id": "{request-id}", + "x-ms-ratelimit-remaining-subscription-reads": "249", + "x-ms-ratelimit-remaining-subscription-global-reads": "3749", + "x-ms-correlation-request-id": "{correlation-request-id}", + "x-ms-routing-request-id": "{routing-request-id}", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "Date": "Tue, 29 Oct 2024 05:18:44 GMT" + } +Method : GET +RequestUri : https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/managedHSMs/{hsm-name}?api-version=2023-07-01 +Version : 1.1 +``` + +Sends a long-running PUT request to create or update a Managed HSM resource in Azure, polling until completion if the operation requires it. +This example uses placeholders ({subscription-id}, {resource-group}, {hsm-name}, {tenant-id}, and {admin-object-id}) that the user should replace with their specific values. + ## PARAMETERS ### -ApiVersion @@ -203,6 +293,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -FinalResultFrom +Specifies the header for final GET result after the long-running operation completes. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: +Accepted values: FinalStateVia, Location, OriginalUri, Operation-Location + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Method Http Method @@ -264,6 +370,37 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -PollFrom +Specifies the polling header (to fetch from) for long-running operation status. + +```yaml +Type: System.String +Parameter Sets: (All) +Aliases: +Accepted values: AzureAsyncLocation, Location, OriginalUri, Operation-Location + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ProgressAction +{{ Fill ProgressAction Description }} + +```yaml +Type: System.Management.Automation.ActionPreference +Parameter Sets: (All) +Aliases: proga + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -ResourceGroupName Target Resource Group Name @@ -354,6 +491,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -WaitForCompletion +Waits for the long-running operation to complete before returning the result. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Confirm Prompts you for confirmation before running the cmdlet.