Skip to content

Commit da130b0

Browse files
authored
Merge pull request #354 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 0b2be27 + fff1b07 commit da130b0

File tree

4 files changed

+172
-14
lines changed

4 files changed

+172
-14
lines changed

Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function Push-ExecAppApprovalTemplate {
4343
# Check if the app already exists in the tenant
4444
$ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -tenantid $Item.Tenant
4545
if ($TemplateData.GalleryTemplateId -in $ServicePrincipalList.applicationTemplateId) {
46-
Write-LogMessage -message "Gallery Template app $($TemplateData.AppName) already exists in tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info
46+
Write-LogMessage -message "Gallery Template app $($TemplateData.AppName) already exists in tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Gallery App' -sev Info
4747
return
4848
}
4949

@@ -55,10 +55,70 @@ function Push-ExecAppApprovalTemplate {
5555
$InstantiateResult = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applicationTemplates/$GalleryTemplateId/instantiate" -type POST -tenantid $Item.tenant -body $InstantiateBody
5656

5757
if ($InstantiateResult.application.appId) {
58-
Write-LogMessage -message "Successfully deployed Gallery Template $($TemplateData.AppName) to tenant $($Item.Tenant). Application ID: $($InstantiateResult.application.appId)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info
59-
New-CIPPApplicationCopy -App $InstantiateResult.application.appId -Tenant $Item.Tenant
58+
Write-LogMessage -message "Successfully deployed Gallery Template $($TemplateData.AppName) to tenant $($Item.Tenant). Application ID: $($InstantiateResult.application.appId)" -tenant $Item.Tenant -API 'Add Gallery App' -sev Info
59+
# Get application registration
60+
$App = $InstantiateResult.application.appId
61+
$Application = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications(appId='$App')" -tenantid $Item.tenant -AsApp $true
62+
if ($Application.requiredResourceAccess) {
63+
Add-CIPPDelegatedPermission -RequiredResourceAccess $Application.requiredResourceAccess -ApplicationId $App -Tenantfilter $Item.Tenant
64+
Add-CIPPApplicationPermission -RequiredResourceAccess $Application.requiredResourceAccess -ApplicationId $App -Tenantfilter $Item.Tenant
65+
}
6066
} else {
61-
Write-LogMessage -message "Gallery Template deployment completed but application ID not returned for $($TemplateData.AppName) in tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Warning
67+
Write-LogMessage -message "Gallery Template deployment completed but application ID not returned for $($TemplateData.AppName) in tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Gallery App' -sev Warning
68+
}
69+
70+
} elseif ($AppType -eq 'ApplicationManifest') {
71+
Write-Information "Deploying Application Manifest $($TemplateData.AppName) to tenant $($Item.Tenant)."
72+
73+
# Get the application manifest from template data
74+
$ApplicationManifest = $TemplateData.ApplicationManifest
75+
if (!$ApplicationManifest) {
76+
Write-LogMessage -message 'Application Manifest not found in template data' -tenant $Item.Tenant -API 'Add Multitenant App' -sev Error
77+
return
78+
}
79+
80+
# Check for existing application by display name
81+
$ExistingApp = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/applications?`$filter=displayName eq '$($TemplateData.AppName)'&`$top=1" -tenantid $Item.Tenant -NoAuthCheck $true
82+
if ($ExistingApp -and $ExistingApp.value) {
83+
Write-LogMessage -message "Application Manifest $($TemplateData.AppName) already exists in tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add App Manifest' -sev Info
84+
return
85+
}
86+
87+
$PropertiesToRemove = @('appId', 'id', 'createdDateTime', 'publisherDomain', 'servicePrincipalLockConfiguration', 'identifierUris', 'applicationIdUris')
88+
89+
# Strip tenant-specific data that might cause conflicts
90+
$CleanManifest = $ApplicationManifest | ConvertTo-Json -Depth 10 | ConvertFrom-Json
91+
foreach ($Property in $PropertiesToRemove) {
92+
$CleanManifest.PSObject.Properties.Remove($Property)
93+
}
94+
95+
# Create the application from manifest
96+
try {
97+
$CreateBody = $CleanManifest | ConvertTo-Json -Depth 10
98+
$CreatedApp = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/applications' -type POST -tenantid $Item.tenant -body $CreateBody
99+
100+
if ($CreatedApp.appId) {
101+
# Create service principal for the application
102+
$ServicePrincipalBody = @{
103+
appId = $CreatedApp.appId
104+
} | ConvertTo-Json
105+
106+
$ServicePrincipal = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/servicePrincipals' -type POST -tenantid $Item.tenant -body $ServicePrincipalBody
107+
108+
Write-LogMessage -message "Successfully deployed Application Manifest $($TemplateData.AppName) to tenant $($Item.Tenant). Application ID: $($CreatedApp.appId)" -tenant $Item.Tenant -API 'Add App Manifest' -sev Info
109+
$DelegateResourceAccess = $ApplicationManifest.requiredResourceAccess
110+
$ApplicationResourceAccess = $ApplicationManifest.requiredResourceAccess
111+
if ($ApplicationManifest.requiredResourceAccess) {
112+
Add-CIPPDelegatedPermission -RequiredResourceAccess $ApplicationManifest.requiredResourceAccess -ApplicationId $App -Tenantfilter $Tenant
113+
Add-CIPPApplicationPermission -RequiredResourceAccess $ApplicationManifest.requiredResourceAccess -ApplicationId $App -Tenantfilter $Tenant
114+
}
115+
116+
} else {
117+
Write-LogMessage -message "Application Manifest deployment failed - no application ID returned for $($TemplateData.AppName) in tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add App Manifest' -sev Error
118+
}
119+
} catch {
120+
Write-LogMessage -message "Error creating application from manifest in tenant $($Item.Tenant) - $($_.Exception.Message)" -tenant $Item.Tenant -API 'Add App Manifest' -sev Error
121+
throw
62122
}
63123

64124
} else {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ function Invoke-ExecServicePrincipals {
6161
$Results = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/servicePrincipals/$($Request.Query.Id)" -tenantid $TenantFilter -NoAuthCheck $true
6262
} else {
6363
$Action = 'List'
64-
$Results = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$orderby=displayName&$count=true' -ComplexFilter -tenantid $TenantFilter -NoAuthCheck $true
64+
$Uri = 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$orderby=displayName&$count=true'
65+
if ($Request.Query.Select) {
66+
$Uri = '{0}&$select={1}' -f $Uri, $Request.Query.Select
67+
}
68+
69+
$Results = New-GraphGetRequest -Uri $Uri -ComplexFilter -tenantid $TenantFilter -NoAuthCheck $true
6570
}
6671
}
6772
}

Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using namespace System.Net
22

3-
Function Invoke-ExecCSPLicense {
3+
function Invoke-ExecCSPLicense {
44
<#
55
.FUNCTIONALITY
66
Entrypoint
@@ -17,7 +17,7 @@ Function Invoke-ExecCSPLicense {
1717
# Interact with query parameters or the body of the request.
1818
$TenantFilter = $Request.Body.tenantFilter
1919
$Action = $Request.Body.Action
20-
$SKU = $Request.Body.SKU
20+
$SKU = $Request.Body.SKU.value ?? $Request.Body.SKU
2121

2222
try {
2323
if ($Action -eq 'Add') {

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,60 @@ function Invoke-CIPPStandardAppDeploy {
4747
$Template = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'AppApprovalTemplate' and RowKey eq '$TemplateId'"
4848
if ($Template) {
4949
$TemplateData = $Template.JSON | ConvertFrom-Json
50-
if ($TemplateData.AppId) {
51-
$TemplateData.AppId ?? $TemplateData.GalleryTemplateId
50+
# Default to EnterpriseApp for backward compatibility with older templates
51+
$AppType = $TemplateData.AppType
52+
if (-not $AppType) {
53+
$AppType = 'EnterpriseApp'
54+
}
55+
56+
# Return different identifiers based on app type for checking
57+
if ($AppType -eq 'ApplicationManifest') {
58+
# For Application Manifests, use display name for checking
59+
$TemplateData.AppName
60+
} elseif ($AppType -eq 'GalleryTemplate') {
61+
# For Gallery Templates, use gallery template ID
62+
$TemplateData.GalleryTemplateId
63+
} else {
64+
# For Enterprise Apps, use app ID
65+
$TemplateData.AppId
5266
}
5367
}
5468
}
5569
}
56-
$MissingApps = foreach ($App in $AppsToAdd) {
57-
if ($App -notin $AppExists.appId -and $App -notin $AppExists.applicationTemplateId) {
58-
$App
70+
71+
# Check for missing apps based on template type
72+
$MissingApps = [System.Collections.Generic.List[string]]::new()
73+
if ($Mode -eq 'template') {
74+
$Table = Get-CIPPTable -TableName 'templates'
75+
foreach ($TemplateId in $Settings.templateIds.value) {
76+
$Template = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'AppApprovalTemplate' and RowKey eq '$TemplateId'"
77+
if ($Template) {
78+
$TemplateData = $Template.JSON | ConvertFrom-Json
79+
$AppType = $TemplateData.AppType ?? 'EnterpriseApp'
80+
81+
$IsAppMissing = $false
82+
if ($AppType -eq 'ApplicationManifest') {
83+
# For Application Manifests, check by display name
84+
$IsAppMissing = $TemplateData.AppName -notin $AppExists.displayName
85+
} elseif ($AppType -eq 'GalleryTemplate') {
86+
# For Gallery Templates, check by application template ID
87+
$IsAppMissing = $TemplateData.GalleryTemplateId -notin $AppExists.applicationTemplateId
88+
} else {
89+
# For Enterprise Apps, check by app ID
90+
$IsAppMissing = $TemplateData.AppId -notin $AppExists.appId
91+
}
92+
93+
if ($IsAppMissing) {
94+
$MissingApps.Add($TemplateData.AppName ?? $TemplateData.AppId ?? $TemplateData.GalleryTemplateId)
95+
}
96+
}
97+
}
98+
} else {
99+
# For copy mode, check by app ID as before
100+
$MissingApps = foreach ($App in $AppsToAdd) {
101+
if ($App -notin $AppExists.appId -and $App -notin $AppExists.applicationTemplateId) {
102+
$App
103+
}
59104
}
60105
}
61106
if ($Settings.remediate -eq $true) {
@@ -76,8 +121,6 @@ function Invoke-CIPPStandardAppDeploy {
76121
}
77122
} elseif ($Mode -eq 'template') {
78123
$TemplateIds = $Settings.templateIds.value
79-
$TemplateName = $Settings.templateIds.label
80-
$AppIds = $Settings.templateIds.addedFields.AppId
81124

82125
# Get template data to determine deployment type for each template
83126
$Table = Get-CIPPTable -TableName 'templates'
@@ -129,6 +172,56 @@ function Invoke-CIPPStandardAppDeploy {
129172
Write-LogMessage -API 'Standards' -tenant $tenant -message "Gallery Template deployment completed but application ID not returned for $($TemplateData.AppName) in tenant $Tenant" -sev Warning
130173
}
131174

175+
} elseif ($AppType -eq 'ApplicationManifest') {
176+
# Handle Application Manifest deployment
177+
Write-Information "Deploying Application Manifest $($TemplateData.AppName) to tenant $Tenant."
178+
179+
$ApplicationManifest = $TemplateData.ApplicationManifest
180+
if (!$ApplicationManifest) {
181+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Application Manifest not found in template data for $($TemplateData.TemplateName)" -sev Error
182+
continue
183+
}
184+
185+
# Check if an application with the same display name already exists
186+
$ExistingApp = $AppExists | Where-Object { $_.displayName -eq $TemplateData.AppName }
187+
if ($ExistingApp) {
188+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Application with name '$($TemplateData.AppName)' already exists in tenant $Tenant" -sev Info
189+
continue
190+
}
191+
192+
$PropertiesToRemove = @('appId', 'id', 'createdDateTime', 'publisherDomain', 'servicePrincipalLockConfiguration', 'identifierUris', 'applicationIdUris')
193+
194+
# Strip tenant-specific data that might cause conflicts
195+
$CleanManifest = $ApplicationManifest | ConvertTo-Json -Depth 10 | ConvertFrom-Json
196+
foreach ($Property in $PropertiesToRemove) {
197+
$CleanManifest.PSObject.Properties.Remove($Property)
198+
}
199+
# Create the application from manifest
200+
try {
201+
$CreateBody = $CleanManifest | ConvertTo-Json -Depth 10
202+
$CreatedApp = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/applications' -type POST -tenantid $Tenant -body $CreateBody
203+
204+
if ($CreatedApp.appId) {
205+
# Create service principal for the application
206+
$ServicePrincipalBody = @{
207+
appId = $CreatedApp.appId
208+
} | ConvertTo-Json
209+
210+
$ServicePrincipal = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/servicePrincipals' -type POST -tenantid $Tenant -body $ServicePrincipalBody
211+
212+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully deployed Application Manifest $($TemplateData.AppName) to tenant $Tenant. Application ID: $($CreatedApp.appId)" -sev Info
213+
214+
if ($CreatedApp.requiredResourceAccess) {
215+
Add-CIPPDelegatedPermission -RequiredResourceAccess $CreatedApp.requiredResourceAccess -ApplicationId $CreatedApp.appId -Tenantfilter $Tenant
216+
Add-CIPPApplicationPermission -RequiredResourceAccess $CreatedApp.requiredResourceAccess -ApplicationId $CreatedApp.appId -Tenantfilter $Tenant
217+
}
218+
} else {
219+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Application Manifest deployment failed - no application ID returned for $($TemplateData.AppName) in tenant $Tenant" -sev Error
220+
}
221+
} catch {
222+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Error creating application from manifest in tenant $Tenant - $($_.Exception.Message)" -sev Error
223+
}
224+
132225
} else {
133226
# Handle Enterprise App deployment (existing logic)
134227
$AppId = $TemplateData.AppId

0 commit comments

Comments
 (0)