Private/Resolve-Win32ToolkitDependencies.ps1
|
function Resolve-Win32ToolkitDependencies { <# .SYNOPSIS Turns a project's declared dependencies into real Intune app ids, ready to be related. .DESCRIPTION A mobileAppDependency can only point at an app that ALREADY EXISTS in the tenant, by id. Each declaration is resolved: intune:<guid> -> used as-is. project:<Template>\<Name> -> that project's publication cache (Intune\Publications.json), else a tenant search by its display name. winget:<id> -> a tenant search for the app the toolkit stamped with that winget id (notes = 'win32-toolkit; <id>'). Resolution is VERSION-AGNOSTIC by design: any published version of the dependency satisfies it. Pinning a version would invalidate the dependency of every dependent app each time the dependency is repackaged. NOT FOUND IS NOT FATAL. The dependency is simply not in the tenant yet — we warn (naming it and what to do), skip it, and let the app publish. Nothing is auto-published: publishing app X must never silently create other apps in the tenant as a side effect. .PARAMETER ProjectPath The project whose dependencies are being resolved. .PARAMETER TenantId Tenant, used to select the right publication-cache entry. .PARAMETER BaseUri Graph base. .OUTPUTS PSCustomObject[]: TargetId, DependencyType, Ref (for messages). Empty when nothing resolved. #> [CmdletBinding()] [OutputType([pscustomobject[]])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ProjectPath, [string]$TenantId = 'unknown', [string]$BaseUri = 'https://graph.microsoft.com/beta/deviceAppManagement' ) $declared = @(Get-Win32ToolkitDependencies -ProjectPath $ProjectPath) if ($declared.Count -eq 0) { return @() } $resolved = [System.Collections.Generic.List[object]]::new() foreach ($d in $declared) { $id = $null $how = $null # A tenant lookup that FAILS (a bad filter, a transient Graph error, a permissions problem) must # never abort the publish — that is the same outcome as "dependency not found", which is defined to # warn and continue. Aborting here would block an otherwise-good app from shipping. try { switch ($d.Source) { 'intune' { $id = $d.Ref; $how = 'explicit app id' } 'project' { $projects = (Get-Win32ToolkitPaths -BasePath (Get-Win32ToolkitBasePath)).Projects $depPath = Join-Path $projects $d.Ref $cached = @(Get-Win32ToolkitPublication -ProjectPath $depPath -TenantId $TenantId) if ($cached.Count -gt 0 -and $cached[0].AppId) { $id = $cached[0].AppId $how = 'publication cache' } else { # Not published from here (or a different machine) — fall back to the tenant, matching # the display name the dependency project would publish under. $name = $null if (Test-Path -LiteralPath $depPath) { $cfg = Get-Win32ToolkitAppConfig -ProjectPath $depPath $app = if ($cfg.PSObject.Properties.Name -contains 'App') { $cfg.App } else { $null } $name = if ($app -and $app.Name) { $app.Name } elseif ($app -and $app.DisplayName) { $app.DisplayName } else { Split-Path -Leaf $d.Ref } } if ($name) { $hits = @(Find-Win32ToolkitIntuneApp -DisplayName $name -BaseUri $BaseUri) if ($hits.Count -eq 1) { $id = $hits[0].Id; $how = "tenant search '$name'" } elseif ($hits.Count -gt 1) { Write-Warning "Dependency 'project:$($d.Ref)' matched $($hits.Count) apps named '$name' in the tenant — refusing to guess. Declare it explicitly as 'intune:<app id>'." continue } } } } 'winget' { $hits = @(Find-Win32ToolkitIntuneApp -WingetId $d.Ref -BaseUri $BaseUri) if ($hits.Count -eq 1) { $id = $hits[0].Id; $how = "tenant search (winget id)" } elseif ($hits.Count -gt 1) { Write-Warning "Dependency 'winget:$($d.Ref)' matched $($hits.Count) apps in the tenant — refusing to guess. Declare it explicitly as 'intune:<app id>'." continue } } } } catch { Write-Warning @" Could not look up dependency '$($d.Source):$($d.Ref)' in Intune: $($_.Exception.Message) The app WILL still publish — but WITHOUT this dependency. Attach it afterwards with Sync-Win32ToolkitAppDependency -ProjectPath '$ProjectPath' "@ continue } if ($id) { Write-Verbose "Dependency resolved: $($d.Source):$($d.Ref) -> $id [$how]" $resolved.Add([pscustomobject]@{ TargetId = $id DependencyType = $d.DependencyType Ref = "$($d.Source):$($d.Ref)" }) } else { # Chosen behaviour: publish anyway, but say clearly what is missing and how to fix it. # NOTE: do NOT tell the operator to "re-publish this app" — Publish always CREATES A NEW APP # (there is no update path), so that would produce a duplicate and leave the assigned app # without its dependency. Sync-Win32ToolkitAppDependency updates the app already in the tenant. Write-Warning @" Dependency '$($d.Source):$($d.Ref)' is NOT published in this Intune tenant, so it cannot be linked. This app WILL still publish — but WITHOUT that dependency, so Intune will not install it first. To fix: package and publish the dependency as its own app, then attach it to THIS app with Sync-Win32ToolkitAppDependency -ProjectPath '$ProjectPath' (Do not simply re-publish this app: publishing always creates a NEW app, which would leave the assigned one without its dependency.) "@ } } return @($resolved) } |