Skip to content

Commit 18b4c1e

Browse files
updates to template creation process
1 parent 5404a56 commit 18b4c1e

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
using namespace System.Net
2+
3+
function Invoke-ExecCreateAppTemplate {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Tenant.Application.ReadWrite
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $TriggerMetadata.FunctionName
14+
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug'
15+
16+
try {
17+
$TenantFilter = $Request.Body.TenantFilter
18+
$AppId = $Request.Body.AppId
19+
$DisplayName = $Request.Body.DisplayName
20+
$Type = $Request.Body.Type # 'servicePrincipal' or 'application'
21+
22+
if ([string]::IsNullOrWhiteSpace($AppId)) {
23+
throw 'AppId is required'
24+
}
25+
26+
if ([string]::IsNullOrWhiteSpace($DisplayName)) {
27+
throw 'DisplayName is required'
28+
}
29+
30+
# Get the app details based on type
31+
if ($Type -eq 'servicePrincipal') {
32+
# For enterprise apps (service principals)
33+
$AppDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$filter=appId eq '$AppId'&`$select=id,appId,displayName,appRoles,oauth2PermissionScopes,requiredResourceAccess" -tenantid $TenantFilter
34+
35+
if (-not $AppDetails -or $AppDetails.Count -eq 0) {
36+
throw "Service principal not found for AppId: $AppId"
37+
}
38+
39+
$App = $AppDetails[0]
40+
41+
# Get the application registration to access requiredResourceAccess
42+
try {
43+
$AppRegistration = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$filter=appId eq '$AppId'&`$select=id,appId,displayName,requiredResourceAccess" -tenantid $TenantFilter
44+
if ($AppRegistration -and $AppRegistration.Count -gt 0) {
45+
$RequiredResourceAccess = $AppRegistration[0].requiredResourceAccess
46+
} else {
47+
$RequiredResourceAccess = @()
48+
}
49+
} catch {
50+
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "Could not retrieve app registration for $AppId - will extract from service principal" -Sev 'Warning'
51+
$RequiredResourceAccess = @()
52+
}
53+
54+
# Use requiredResourceAccess if available, otherwise we can't create a proper template
55+
if ($RequiredResourceAccess -and $RequiredResourceAccess.Count -gt 0) {
56+
$Permissions = $RequiredResourceAccess
57+
} else {
58+
# No permissions found - warn the user
59+
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "No permissions found for $AppId. The app registration may not have configured API permissions." -Sev 'Warning'
60+
$Permissions = @()
61+
}
62+
} else {
63+
# For app registrations (applications)
64+
$AppDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$filter=appId eq '$AppId'&`$select=id,appId,displayName,requiredResourceAccess" -tenantid $TenantFilter
65+
if (-not $AppDetails -or $AppDetails.Count -eq 0) {
66+
throw "Application not found for AppId: $AppId"
67+
}
68+
$App = $AppDetails[0]
69+
$Permissions = if ($App.requiredResourceAccess) { $App.requiredResourceAccess } else { @() }
70+
}
71+
72+
# Transform requiredResourceAccess to the CIPP permission format
73+
# CIPP expects: { "resourceAppId": { "applicationPermissions": [], "delegatedPermissions": [] } }
74+
# Graph returns: [ { "resourceAppId": "...", "resourceAccess": [ { "id": "...", "type": "Role|Scope" } ] } ]
75+
$CIPPPermissions = @{}
76+
$PermissionSetId = $null
77+
$PermissionSetName = "$DisplayName (Auto-created)"
78+
79+
if ($Permissions -and $Permissions.Count -gt 0) {
80+
foreach ($Resource in $Permissions) {
81+
$ResourceAppId = $Resource.resourceAppId
82+
$AppPerms = [System.Collections.ArrayList]::new()
83+
$DelegatedPerms = [System.Collections.ArrayList]::new()
84+
85+
foreach ($Access in $Resource.resourceAccess) {
86+
$PermObj = [PSCustomObject]@{
87+
id = $Access.id
88+
value = $Access.id # In the permission set format, both id and value are the permission ID
89+
}
90+
91+
if ($Access.type -eq 'Role') {
92+
[void]$AppPerms.Add($PermObj)
93+
} elseif ($Access.type -eq 'Scope') {
94+
[void]$DelegatedPerms.Add($PermObj)
95+
}
96+
}
97+
98+
$CIPPPermissions[$ResourceAppId] = [PSCustomObject]@{
99+
applicationPermissions = @($AppPerms)
100+
delegatedPermissions = @($DelegatedPerms)
101+
}
102+
}
103+
104+
# Create the permission set in AppPermissions table
105+
$PermissionSetId = (New-Guid).Guid
106+
$PermissionsTable = Get-CIPPTable -TableName 'AppPermissions'
107+
108+
$PermissionEntity = @{
109+
'PartitionKey' = 'Templates'
110+
'RowKey' = [string]$PermissionSetId
111+
'TemplateName' = [string]$PermissionSetName
112+
'Permissions' = [string]($CIPPPermissions | ConvertTo-Json -Depth 10 -Compress)
113+
'UpdatedBy' = [string]'CIPP-API'
114+
}
115+
116+
Add-CIPPAzDataTableEntity @PermissionsTable -Entity $PermissionEntity -Force
117+
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "Permission set created with ID: $PermissionSetId for $($Permissions.Count) resource(s)" -Sev 'Info'
118+
}
119+
120+
# Create the template
121+
$Table = Get-CIPPTable -TableName 'templates'
122+
$TemplateId = (New-Guid).Guid
123+
124+
$TemplateJson = @{
125+
TemplateName = "$DisplayName (Auto-created)"
126+
AppId = $AppId
127+
AppName = $DisplayName
128+
AppType = 'EnterpriseApp'
129+
Permissions = $CIPPPermissions
130+
PermissionSetId = $PermissionSetId
131+
PermissionSetName = $PermissionSetName
132+
AutoCreated = $true
133+
SourceTenant = $TenantFilter
134+
CreatedDate = (Get-Date).ToString('yyyy-MM-ddTHH:mm:ss')
135+
} | ConvertTo-Json -Depth 10 -Compress
136+
137+
$Entity = @{
138+
JSON = "$TemplateJson"
139+
RowKey = "$TemplateId"
140+
PartitionKey = 'AppApprovalTemplate'
141+
}
142+
143+
Add-CIPPAzDataTableEntity @Table -Entity $Entity
144+
145+
$PermissionCount = 0
146+
if ($CIPPPermissions -and $CIPPPermissions.Count -gt 0) {
147+
foreach ($ResourceAppId in $CIPPPermissions.Keys) {
148+
$Resource = $CIPPPermissions[$ResourceAppId]
149+
if ($Resource.applicationPermissions) {
150+
$PermissionCount = $PermissionCount + $Resource.applicationPermissions.Count
151+
}
152+
if ($Resource.delegatedPermissions) {
153+
$PermissionCount = $PermissionCount + $Resource.delegatedPermissions.Count
154+
}
155+
}
156+
}
157+
158+
$Message = "Template created: $DisplayName with $PermissionCount permission(s)"
159+
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message $Message -Sev 'Info'
160+
161+
$Body = @{
162+
Results = $Message
163+
TemplateId = $TemplateId
164+
}
165+
$StatusCode = [HttpStatusCode]::OK
166+
} catch {
167+
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
168+
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create template: $ErrorMessage" -Sev 'Error'
169+
170+
$Body = @{
171+
Results = "Failed to create template: $ErrorMessage"
172+
}
173+
$StatusCode = [HttpStatusCode]::BadRequest
174+
}
175+
176+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
177+
StatusCode = $StatusCode
178+
Body = ($Body | ConvertTo-Json -Depth 10)
179+
})
180+
}

0 commit comments

Comments
 (0)