Skip to content

Commit 5a82592

Browse files
author
rvdwegen
committed
New-CIPPAzRestRequest
1 parent 06fc021 commit 5a82592

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
function New-CIPPAzRestRequest {
2+
<#
3+
.SYNOPSIS
4+
Create and send a REST request to Azure APIs using Managed Identity authentication
5+
.DESCRIPTION
6+
Wraps Invoke-RestMethod with automatic Azure Managed Identity token authentication.
7+
Automatically adds the Authorization header using Get-CIPPAzIdentityToken.
8+
Supports all Invoke-RestMethod parameters.
9+
.PARAMETER Uri
10+
The URI of the Azure REST API endpoint
11+
.PARAMETER Method
12+
The HTTP method (GET, POST, PUT, PATCH, DELETE, etc.). Defaults to GET.
13+
.PARAMETER ResourceUrl
14+
The Azure resource URL to get a token for. Defaults to 'https://management.azure.com/' for Azure Resource Manager.
15+
Use 'https://vault.azure.net' for Key Vault, 'https://api.loganalytics.io' for Log Analytics, etc.
16+
.PARAMETER Body
17+
The request body (can be string, hashtable, or PSCustomObject)
18+
.PARAMETER Headers
19+
Additional headers to include in the request. Authorization header is automatically added.
20+
.PARAMETER ContentType
21+
The content type of the request body. Defaults to 'application/json' if Body is provided and ContentType is not specified.
22+
.PARAMETER SkipHttpErrorCheck
23+
Skip checking HTTP error status codes
24+
.PARAMETER ResponseHeadersVariable
25+
Variable name to store response headers
26+
.PARAMETER StatusCodeVariable
27+
Variable name to store HTTP status code
28+
.PARAMETER MaximumRetryCount
29+
Maximum number of retry attempts
30+
.PARAMETER RetryIntervalSec
31+
Interval between retries in seconds
32+
.PARAMETER TimeoutSec
33+
Request timeout in seconds
34+
.PARAMETER UseBasicParsing
35+
Use basic parsing (for older PowerShell versions)
36+
.PARAMETER WebSession
37+
Web session object for maintaining cookies/state
38+
.EXAMPLE
39+
New-CIPPAzRestRequest -Uri 'https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/{name}?api-version=2020-06-01'
40+
Gets Azure Resource Manager resource using managed identity
41+
.EXAMPLE
42+
New-CIPPAzRestRequest -Uri 'https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/{name}/config/authsettingsV2/list?api-version=2020-06-01' -Method POST
43+
POST request to Azure Resource Manager API
44+
.EXAMPLE
45+
New-CIPPAzRestRequest -Uri 'https://{vault}.vault.azure.net/secrets/{secret}?api-version=7.4' -ResourceUrl 'https://vault.azure.net'
46+
Gets a Key Vault secret using managed identity
47+
.EXAMPLE
48+
New-CIPPAzRestRequest -Uri 'https://management.azure.com/...' -Method PUT -Body @{ property = 'value' } -ContentType 'application/json'
49+
PUT request with JSON body
50+
#>
51+
[CmdletBinding()]
52+
param(
53+
[Parameter(Mandatory = $true, Position = 0)]
54+
[Alias('Url')]
55+
[uri]$Uri,
56+
57+
[Parameter(Mandatory = $false)]
58+
[ValidateSet('GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE')]
59+
[string]$Method = 'GET',
60+
61+
[Parameter(Mandatory = $false)]
62+
[string]$ResourceUrl = 'https://management.azure.com/',
63+
64+
[Parameter(Mandatory = $false)]
65+
[object]$Body,
66+
67+
[Parameter(Mandatory = $false)]
68+
[hashtable]$Headers = @{},
69+
70+
[Parameter(Mandatory = $false)]
71+
[string]$ContentType,
72+
73+
[Parameter(Mandatory = $false)]
74+
[switch]$SkipHttpErrorCheck,
75+
76+
[Parameter(Mandatory = $false)]
77+
[string]$ResponseHeadersVariable,
78+
79+
[Parameter(Mandatory = $false)]
80+
[string]$StatusCodeVariable,
81+
82+
[Parameter(Mandatory = $false)]
83+
[int]$MaximumRetryCount,
84+
85+
[Parameter(Mandatory = $false)]
86+
[int]$RetryIntervalSec,
87+
88+
[Parameter(Mandatory = $false)]
89+
[int]$TimeoutSec,
90+
91+
[Parameter(Mandatory = $false)]
92+
[switch]$UseBasicParsing,
93+
94+
[Parameter(Mandatory = $false)]
95+
[Microsoft.PowerShell.Commands.WebRequestSession]$WebSession
96+
)
97+
98+
# Get Azure Managed Identity token
99+
try {
100+
$Token = Get-CIPPAzIdentityToken -ResourceUrl $ResourceUrl
101+
} catch {
102+
$errorMessage = "Failed to get Azure Managed Identity token: $($_.Exception.Message)"
103+
Write-Error -Message $errorMessage -ErrorAction $ErrorActionPreference
104+
return
105+
}
106+
107+
# Build headers - add Authorization, merge with user-provided headers
108+
$RequestHeaders = @{
109+
'Authorization' = "Bearer $Token"
110+
}
111+
112+
# Merge user-provided headers (user headers take precedence)
113+
foreach ($key in $Headers.Keys) {
114+
$RequestHeaders[$key] = $Headers[$key]
115+
}
116+
117+
# Handle Content-Type
118+
if ($Body -and -not $ContentType) {
119+
$ContentType = 'application/json'
120+
}
121+
122+
# Convert Body to JSON if it's an object and ContentType is JSON
123+
$RequestBody = $Body
124+
if ($Body -and $ContentType -eq 'application/json' -and $Body -isnot [string]) {
125+
try {
126+
$RequestBody = $Body | ConvertTo-Json -Depth 10 -Compress
127+
} catch {
128+
Write-Warning "Failed to convert Body to JSON: $($_.Exception.Message). Sending as-is."
129+
$RequestBody = $Body
130+
}
131+
}
132+
133+
# Build Invoke-RestMethod parameters
134+
$RestMethodParams = @{
135+
Uri = $Uri
136+
Method = $Method
137+
Headers = $RequestHeaders
138+
ErrorAction = $ErrorActionPreference
139+
}
140+
141+
if ($Body) {
142+
$RestMethodParams['Body'] = $RequestBody
143+
}
144+
145+
if ($ContentType) {
146+
$RestMethodParams['ContentType'] = $ContentType
147+
}
148+
149+
if ($SkipHttpErrorCheck) {
150+
$RestMethodParams['SkipHttpErrorCheck'] = $true
151+
}
152+
153+
if ($ResponseHeadersVariable) {
154+
$RestMethodParams['ResponseHeadersVariable'] = $ResponseHeadersVariable
155+
}
156+
157+
if ($StatusCodeVariable) {
158+
$RestMethodParams['StatusCodeVariable'] = $StatusCodeVariable
159+
}
160+
161+
if ($MaximumRetryCount) {
162+
$RestMethodParams['MaximumRetryCount'] = $MaximumRetryCount
163+
}
164+
165+
if ($RetryIntervalSec) {
166+
$RestMethodParams['RetryIntervalSec'] = $RetryIntervalSec
167+
}
168+
169+
if ($TimeoutSec) {
170+
$RestMethodParams['TimeoutSec'] = $TimeoutSec
171+
}
172+
173+
if ($UseBasicParsing) {
174+
$RestMethodParams['UseBasicParsing'] = $true
175+
}
176+
177+
if ($WebSession) {
178+
$RestMethodParams['WebSession'] = $WebSession
179+
}
180+
181+
# Invoke the REST method
182+
try {
183+
$Response = Invoke-RestMethod @RestMethodParams
184+
185+
# For compatibility with Invoke-AzRestMethod behavior, return object with Content property if response is a string
186+
# Otherwise return the parsed object directly
187+
if ($Response -is [string]) {
188+
return [PSCustomObject]@{
189+
Content = $Response
190+
}
191+
}
192+
193+
return $Response
194+
} catch {
195+
$errorMessage = "Azure REST API call failed: $($_.Exception.Message)"
196+
if ($_.Exception.Response) {
197+
try {
198+
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
199+
$responseBody = $reader.ReadToEnd()
200+
$reader.Close()
201+
$errorMessage += "`nResponse: $responseBody"
202+
} catch {
203+
# Ignore errors reading response stream
204+
}
205+
}
206+
207+
Write-Error -Message $errorMessage -ErrorAction $ErrorActionPreference
208+
return
209+
}
210+
}

0 commit comments

Comments
 (0)