Skip to content

Commit 24c462e

Browse files
committed
Enhance app template creation and logging
Refactored logging to use headers instead of user principal, improved app registration handling for partner tenants, and updated response structure for better error and success reporting. Added logic to copy app registrations between tenants and create service principals as needed.
1 parent 53c35e6 commit 24c462e

File tree

1 file changed

+98
-14
lines changed

1 file changed

+98
-14
lines changed

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecCreateAppTemplate.ps1

Lines changed: 98 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function Invoke-ExecCreateAppTemplate {
1111
param($Request, $TriggerMetadata)
1212

1313
$APIName = $TriggerMetadata.FunctionName
14-
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug'
14+
Write-LogMessage -headers $Request.headers -API $APINAME -message 'Accessed this API' -Sev 'Debug'
1515

1616
try {
1717
$TenantFilter = $Request.Body.TenantFilter
@@ -47,7 +47,7 @@ function Invoke-ExecCreateAppTemplate {
4747
$RequiredResourceAccess = @()
4848
}
4949
} 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'
50+
Write-LogMessage -headers $Request.headers -API $APINAME -message "Could not retrieve app registration for $AppId - will extract from service principal" -Sev 'Warning'
5151
$RequiredResourceAccess = @()
5252
}
5353

@@ -56,16 +56,91 @@ function Invoke-ExecCreateAppTemplate {
5656
$Permissions = $RequiredResourceAccess
5757
} else {
5858
# 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'
59+
Write-LogMessage -headers $Request.headers -API $APINAME -message "No permissions found for $AppId. The app registration may not have configured API permissions." -Sev 'Warning'
6060
$Permissions = @()
6161
}
6262
} else {
6363
# 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"
64+
$App = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$AppId')" -tenantid $TenantFilter
65+
if (-not $App -or $App.Count -eq 0) {
66+
throw "App registration not found for AppId: $AppId"
6767
}
68-
$App = $AppDetails[0]
68+
69+
$Tenant = Get-Tenants -TenantFilter $TenantFilter
70+
if ($Tenant.customerId -ne $env:TenantID) {
71+
$ExistingApp = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications?`$filter=displayName eq '$DisplayName'" -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true
72+
73+
if ($ExistingApp) {
74+
Write-Information "App Registration $AppId already exists in partner tenant"
75+
$AppId = $ExistingApp.appId
76+
$App = $ExistingApp
77+
Write-LogMessage -headers $Request.headers -API $APINAME -message "App Registration $($AppDetails.displayName) already exists in partner tenant" -Sev 'Info'
78+
} else {
79+
Write-Information "Copying App Registration $AppId from customer tenant $TenantFilter to partner tenant"
80+
$PropertiesToRemove = @(
81+
'appId'
82+
'id'
83+
'createdDateTime'
84+
'deletedDateTime'
85+
'publisherDomain'
86+
'servicePrincipalLockConfiguration'
87+
'identifierUris'
88+
'applicationIdUris'
89+
'keyCredentials'
90+
'passwordCredentials'
91+
'isDisabled'
92+
)
93+
$AppCopyBody = $App | Select-Object -Property * -ExcludeProperty $PropertiesToRemove
94+
# Remove any null properties
95+
$NullProperties = [System.Collections.Generic.List[string]]::new()
96+
foreach ($Property in $AppCopyBody.PSObject.Properties.Name) {
97+
if ($null -eq $AppCopyBody.$Property -or $AppCopyBody.$Property -eq '' -or !$AppCopyBody.$Property) {
98+
Write-Information "Removing null property $Property from app copy body"
99+
$NullProperties.Add($Property)
100+
}
101+
}
102+
$AppCopyBody = $AppCopyBody | Select-Object -Property * -ExcludeProperty $NullProperties
103+
if ($AppCopyBody.signInAudience -eq 'AzureADMyOrg') {
104+
# Enterprise apps cannot be copied to another tenant
105+
$AppCopyBody.signInAudience = 'AzureADMultipleOrgs'
106+
}
107+
if ($AppCopyBody.web -and $AppCopyBody.web.redirectUris) {
108+
# Remove redirect URI settings if property exists
109+
$AppCopyBody.web.PSObject.Properties.Remove('redirectUriSettings')
110+
}
111+
if ($AppCopyBody.api.oauth2PermissionScopes) {
112+
$AppCopyBody.api.oauth2PermissionScopes = @(foreach ($Scope in $AppCopyBody.api.oauth2PermissionScopes) {
113+
$Scope | Select-Object * -ExcludeProperty 'isPrivate'
114+
})
115+
}
116+
if ($AppCopyBody.appRoles) {
117+
$AppCopyBody.appRoles = @(foreach ($Role in $AppCopyBody.api.appRoles) {
118+
$Role | Select-Object * -ExcludeProperty 'isPreAuthorizationRequired', 'isPrivate'
119+
})
120+
}
121+
if ($AppCopyBody.api -and $AppCopyBody.api.tokenEncryptionSetting) {
122+
# Remove token encryption settings if property exists
123+
$AppCopyBody.api.PSObject.Properties.Remove('tokenEncryptionSetting')
124+
}
125+
126+
$NewApp = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/v1.0/applications' -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true -type POST -body ($AppCopyBody | ConvertTo-Json -Depth 10)
127+
128+
if (-not $NewApp) {
129+
throw 'Failed to copy app registration to partner tenant'
130+
}
131+
132+
Write-Information "App Registration copied. New AppId: $($NewApp.appId)"
133+
$App = $NewApp
134+
$AppId = $NewApp.appId
135+
Write-Information "Creating service principal for AppId: $AppId in partner tenant"
136+
$Body = @{
137+
appId = $AppId
138+
}
139+
$NewSP = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true -type POST -body ($Body | ConvertTo-Json -Depth 10)
140+
Write-LogMessage -headers $Request.headers -API $APINAME -message "App Registration $($AppDetails.displayName) copied to partner tenant" -Sev 'Info'
141+
}
142+
}
143+
69144
$Permissions = if ($App.requiredResourceAccess) { $App.requiredResourceAccess } else { @() }
70145
}
71146

@@ -114,7 +189,7 @@ function Invoke-ExecCreateAppTemplate {
114189
}
115190

116191
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'
192+
Write-LogMessage -headers $Request.headers -API $APINAME -message "Permission set created with ID: $PermissionSetId for $($Permissions.Count) resource(s)" -Sev 'Info'
118193
}
119194

120195
# Create the template
@@ -156,24 +231,33 @@ function Invoke-ExecCreateAppTemplate {
156231
}
157232

158233
$Message = "Template created: $DisplayName with $PermissionCount permission(s)"
159-
Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message $Message -Sev 'Info'
234+
Write-LogMessage -headers $Request.headers -API $APINAME -message $Message -Sev 'Info'
160235

161236
$Body = @{
162-
Results = $Message
163-
TemplateId = $TemplateId
237+
Results = @{'resultText' = $Message; 'state' = 'success' }
238+
Metadata = @{
239+
TemplateId = $TemplateId
240+
SourceTenant = $TenantFilter
241+
}
164242
}
165243
$StatusCode = [HttpStatusCode]::OK
166244
} catch {
167245
$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'
246+
Write-LogMessage -headers $Request.headers -API $APINAME -message "Failed to create template: $ErrorMessage" -Sev 'Error' -LogData (Get-CippException -Exception $_)
247+
Write-Warning "Failed to create template: $ErrorMessage"
248+
Write-Information $_.InvocationInfo.PositionMessage
169249

170250
$Body = @{
171-
Results = "Failed to create template: $ErrorMessage"
251+
Results = @(@{
252+
resultText = "Failed to create template: $ErrorMessage"
253+
state = 'error'
254+
details = Get-CippException -Exception $_
255+
})
172256
}
173257
$StatusCode = [HttpStatusCode]::BadRequest
174258
}
175259

176-
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
260+
return ([HttpResponseContext]@{
177261
StatusCode = $StatusCode
178262
Body = ($Body | ConvertTo-Json -Depth 10)
179263
})

0 commit comments

Comments
 (0)