Skip to content

Commit 3033c41

Browse files
authored
Merge pull request #355 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents da130b0 + fa50f5d commit 3033c41

File tree

3 files changed

+161
-4
lines changed

3 files changed

+161
-4
lines changed

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ function Invoke-ExecServicePrincipals {
33
.FUNCTIONALITY
44
Entrypoint,AnyTenant
55
.ROLE
6-
CIPP.Core.ReadWrite
6+
Tenant.Application.ReadWrite
77
#>
88
[CmdletBinding()]
99
param($Request, $TriggerMetadata)
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
function Invoke-ExecApplication {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Tenant.Application.ReadWrite
7+
#>
8+
[CmdletBinding()]
9+
param($Request, $TriggerMetadata)
10+
11+
$APIName = $Request.Params.CIPPEndpoint
12+
$Headers = $Request.Headers
13+
Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug'
14+
15+
$ValidTypes = @('applications', 'servicePrincipals')
16+
$ValidActions = @('Update', 'Upsert', 'Delete', 'RemoveKey', 'RemovePassword')
17+
18+
$Id = $Request.Query.Id ?? $Request.Body.Id
19+
$Type = $Request.Query.Type ?? $Request.Body.Type
20+
if (-not $Id) {
21+
$AppId = $Request.Query.AppId ?? $Request.Body.AppId
22+
if (-not $AppId) {
23+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
24+
StatusCode = [HttpStatusCode]::BadRequest
25+
Body = "Required parameter 'Id' or 'AppId' is missing"
26+
})
27+
return
28+
}
29+
$IdPath = "(appId='$AppId')"
30+
} else {
31+
$IdPath = "/$Id"
32+
}
33+
if ($Type -and $ValidTypes -notcontains $Type) {
34+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
35+
StatusCode = [HttpStatusCode]::BadRequest
36+
Body = "Invalid Type specified. Valid types are: $($ValidTypes -join ', ')"
37+
})
38+
return
39+
}
40+
41+
$Uri = "https://graph.microsoft.com/beta/$($Type)$($IdPath)"
42+
$Action = $Request.Query.Action ?? $Request.Body.Action
43+
44+
if ($ValidActions -notcontains $Action) {
45+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
46+
StatusCode = [HttpStatusCode]::BadRequest
47+
Body = "Invalid Action specified. Valid actions are: $($ValidActions -join ', ')"
48+
})
49+
return
50+
}
51+
52+
$PostParams = @{
53+
Uri = $Uri
54+
}
55+
56+
if ($Action -eq 'Delete') {
57+
$PostParams.Type = 'DELETE'
58+
}
59+
if ($Action -eq 'Update' -or $Action -eq 'Upsert') {
60+
$PostParams.Type = 'PATCH'
61+
}
62+
63+
if ($Action -eq 'Upsert') {
64+
$PostParams.AddedHeaders = @{
65+
'Prefer' = 'create-if-missing'
66+
}
67+
}
68+
69+
if ($Request.Body) {
70+
$PostParams.Body = $Request.Body.Payload | ConvertTo-Json -Compress
71+
}
72+
73+
$TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter
74+
75+
try {
76+
if ($Action -eq 'RemoveKey' -or $Action -eq 'RemovePassword') {
77+
# Handle credential removal
78+
$KeyIds = $Request.Body.KeyIds.value ?? $Request.Body.KeyIds
79+
if (-not $KeyIds -or $KeyIds.Count -eq 0) {
80+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
81+
StatusCode = [HttpStatusCode]::BadRequest
82+
Body = "KeyIds parameter is required for $Action action"
83+
})
84+
return
85+
}
86+
87+
if ($Action -eq 'RemoveKey') {
88+
# For key credentials, use a single PATCH request
89+
$CurrentObject = New-GraphGetRequest -Uri $Uri -tenantid $TenantFilter -AsApp $true
90+
$UpdatedKeyCredentials = $CurrentObject.keyCredentials | Where-Object { $_.keyId -notin $KeyIds }
91+
$PatchBody = @{
92+
keyCredentials = @($UpdatedKeyCredentials)
93+
}
94+
95+
$Response = New-GraphPOSTRequest -Uri $Uri -Type 'PATCH' -Body ($PatchBody | ConvertTo-Json -Depth 10) -tenantid $TenantFilter -AsApp $true
96+
97+
$Results = @{
98+
resultText = "Successfully removed $($KeyIds.Count) key credential(s) from $Type"
99+
state = 'success'
100+
details = @($Response)
101+
}
102+
} else {
103+
# For password credentials, use bulk removePassword requests
104+
$BulkRequests = foreach ($KeyId in $KeyIds) {
105+
$RemoveBody = @{
106+
keyId = $KeyId
107+
}
108+
109+
@{
110+
id = $KeyId
111+
method = 'POST'
112+
url = "$($Type)$($IdPath)/removePassword"
113+
body = $RemoveBody
114+
headers = @{
115+
'Content-Type' = 'application/json'
116+
}
117+
}
118+
}
119+
120+
$BulkResults = New-GraphBulkRequest -Requests @($BulkRequests) -tenantid $TenantFilter -AsApp $true
121+
122+
$SuccessCount = ($BulkResults | Where-Object { $_.status -eq 204 }).Count
123+
$FailureCount = ($BulkResults | Where-Object { $_.status -ne 204 }).Count
124+
125+
$Results = @{
126+
resultText = "Bulk RemovePassword completed. Success: $SuccessCount, Failures: $FailureCount"
127+
state = if ($FailureCount -eq 0) { 'success' } else { 'error' }
128+
details = @($BulkResults)
129+
}
130+
}
131+
} else {
132+
# Handle regular actions
133+
$null = New-GraphPOSTRequest @PostParams -tenantid $TenantFilter -AsApp $true
134+
$Results = @{
135+
resultText = "Successfully executed $Action on $Type with Id: $Id"
136+
state = 'success'
137+
}
138+
}
139+
140+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
141+
StatusCode = [HttpStatusCode]::OK
142+
Body = @{ Results = $Results }
143+
})
144+
} catch {
145+
$Results = @{
146+
resultText = "Failed to execute $Action on $Type with Id: $Id. Error: $($_.Exception.Message)"
147+
state = 'error'
148+
}
149+
150+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
151+
StatusCode = [HttpStatusCode]::InternalServerError
152+
Body = @{ Results = @($Results) }
153+
})
154+
}
155+
}

Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ function New-GraphBulkRequest {
33
.FUNCTIONALITY
44
Internal
55
#>
6-
Param(
6+
param(
77
$tenantid,
88
$NoAuthCheck,
99
$scope,
1010
$asapp,
1111
$Requests,
12-
$NoPaginateIds = @()
12+
$NoPaginateIds = @(),
13+
[ValidateSet('v1.0', 'beta')]
14+
$Version = 'beta'
1315
)
1416

1517
if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) {
1618
$headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp
1719

18-
$URL = 'https://graph.microsoft.com/beta/$batch'
20+
$URL = "https://graph.microsoft.com/$Version/`$batch"
1921

2022
# Track consecutive Graph API failures
2123
$TenantsTable = Get-CippTable -tablename Tenants

0 commit comments

Comments
 (0)