Public/Set-Win32ToolkitAppDependency.ps1
|
function Set-Win32ToolkitAppDependency { <# .SYNOPSIS Declares which apps must be installed BEFORE this one (Intune app dependencies). .DESCRIPTION Writes the `Dependencies` section of the project's SupportFiles\AppConfig.json. At publish time each declaration is resolved to a real Intune app id and attached to the published app as a `mobileAppDependency` relationship, so the Intune Management Extension installs the dependency FIRST (the classic case: a Visual C++ redistributable). Dependencies are stored as DATA (winget id / project name / Intune app id) and are never spliced into a generated script. Nothing is installed or published by this command — it only declares. Because Intune honours the DEPENDENCY app's own detection rule, an already-present dependency is skipped on the device automatically; there is no separate "skip if installed" setting. NOTE: a dependency must exist in the tenant as a published Win32 app before the relationship can be created. If it does not, publishing warns and continues (the app still publishes, just without that relationship) — package and publish the dependency, then re-publish this app to attach it. .PARAMETER ProjectPath The PSADT project that HAS the dependencies. .PARAMETER DependsOn One or more references. Accepts 'winget:<id>', 'project:<Template>\<Name>', 'intune:<guid>', or a bare string (a GUID -> intune, one containing '\' -> project, otherwise winget). .PARAMETER DependencyType 'autoInstall' (default) installs the dependency first. 'detect' ONLY detects it — if it is absent the parent install is NOT attempted at all, so use it deliberately. .PARAMETER Clear Remove all declared dependencies (alone, or before adding the supplied set). .OUTPUTS PSCustomObject[] — the normalized dependency list now stored in AppConfig.json. .EXAMPLE Set-Win32ToolkitAppDependency -ProjectPath $p -DependsOn 'winget:Microsoft.VCRedist.2015+.x64' .EXAMPLE Set-Win32ToolkitAppDependency -ProjectPath $p -DependsOn 'project:Contoso\VCRedist_x64_14.38' #> [CmdletBinding(SupportsShouldProcess)] [OutputType([pscustomobject[]])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ProjectPath, [string[]]$DependsOn, [ValidateSet('autoInstall', 'detect')] [string]$DependencyType = 'autoInstall', [switch]$Clear ) if (-not (Test-Path -LiteralPath $ProjectPath)) { throw "Project not found: $ProjectPath" } if (-not $Clear -and -not $DependsOn) { throw 'Supply -DependsOn with at least one reference, or -Clear to remove all dependencies.' } # This project's own 'project:' identity — an app cannot depend on itself (Intune rejects it too). $self = '{0}\{1}' -f (Split-Path -Leaf (Split-Path -Parent $ProjectPath)), (Split-Path -Leaf $ProjectPath) $existing = if ($Clear) { @() } else { @(Get-Win32ToolkitDependencies -ProjectPath $ProjectPath) } $added = @() foreach ($r in @($DependsOn)) { if ([string]::IsNullOrWhiteSpace($r)) { continue } $parsed = ConvertTo-Win32ToolkitDependencyRef -Reference $r -DependencyType $DependencyType if ($parsed.Source -eq 'project' -and $parsed.Ref -eq $self) { throw "An app cannot depend on itself ('$self')." } $added += $parsed } # Upsert by Source+Ref (the new DependencyType wins on collision), preserving declaration order. $merged = [System.Collections.Generic.List[object]]::new() foreach ($d in @($existing) + @($added)) { $dup = $merged | Where-Object { $_.Source -eq $d.Source -and $_.Ref -eq $d.Ref } | Select-Object -First 1 if ($dup) { $dup.DependencyType = $d.DependencyType; continue } $merged.Add([pscustomobject]@{ Source = $d.Source; Ref = $d.Ref; DependencyType = $d.DependencyType }) } if ($PSCmdlet.ShouldProcess($ProjectPath, "Set $($merged.Count) app dependency(ies)")) { $cfg = Get-Win32ToolkitAppConfig -ProjectPath $ProjectPath $cfg | Add-Member -NotePropertyName 'Dependencies' -NotePropertyValue @($merged) -Force $null = Set-Win32ToolkitAppConfig -ProjectPath $ProjectPath -Config $cfg } return @($merged) } |