Public/Set-MSIXApplication.ps1

function Set-MSIXApplication {
<#
.SYNOPSIS
    Updates Application-level settings in AppxManifest.xml: working directory, default
    parameters (uap11) and autostart (windows.startupTask).
.DESCRIPTION
    General editor for the Application node. Only parameters that are explicitly passed are
    acted upon; everything else is left unchanged. Pipeline-friendly from Get-MSIXApplications.

    VisualElements (logos, tile, AppListEntry, VisualGroup) are NOT handled here - use the
    dedicated Set-MSIXApplicationVisualElements for those.
.PARAMETER MSIXFolderPath
    Expanded MSIX package folder. Pipeline by property name.
.PARAMETER AppId
    Application Id to update. Binds from Get-MSIXApplications (Id). Omit to update all applications.
.PARAMETER NewId
    Renames Application/@Id to this value. Requires -AppId (single target). WARNING: changing
    the Id changes the package AUMID and can break existing shortcuts, jump lists and Start pins.
.PARAMETER Executable
    New launch executable (Application/@Executable), e.g. to repoint at a different .exe or launcher.
.PARAMETER UAP11WorkingDirectory
    Initial working directory (uap11:CurrentDirectoryPath). Supports macros such as
    $(package.effectivePath). Requires a recent Windows 11 build; ignored on older builds.
.PARAMETER UAP11Parameters
    Default command-line parameters (uap11:Parameters); also supports macros.
.PARAMETER Autostart
    $true creates/enables a windows.startupTask so the app runs at sign-in; $false disables
    an existing task (Enabled="false"). TaskId/DisplayName/Executable default to the app's values.
.PARAMETER AutostartTaskId
    Optional startup TaskId (default: the AppId). Must be unique within the package.
.PARAMETER AutostartDisplayName
    Optional startup display name shown under Task Manager > Startup apps (default: the AppId).
.PARAMETER AutostartExecutable
    Optional executable the startup task launches (default: the application's Executable).
.EXAMPLE
    Get-MSIXApplications -MSIXFolder $pkg |
        Set-MSIXApplication -UAP11WorkingDirectory '$(package.effectivePath)\VFS\ProgramFilesX64\PuTTY'
.EXAMPLE
    Set-MSIXApplication -MSIXFolderPath $pkg -AppId PUTTY -Autostart $true
.EXAMPLE
    Set-MSIXApplication -MSIXFolderPath $pkg -AppId PUTTY -Executable 'PsfLauncher64.exe' -NewId PUTTYMain
.NOTES
    Andreas Nick, 2026
#>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
        [Alias('MSIXFolder')]
        [System.IO.DirectoryInfo] $MSIXFolderPath,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [Alias('Id')]
        [string] $AppId,

        [string] $NewId,
        [string] $Executable,

        [string] $UAP11WorkingDirectory,
        [string] $UAP11Parameters,

        [bool]   $Autostart,
        [string] $AutostartTaskId,
        [string] $AutostartDisplayName,
        [string] $AutostartExecutable
    )

    process {
        $doNewId  = $PSBoundParameters.ContainsKey('NewId')
        $doExe    = $PSBoundParameters.ContainsKey('Executable')
        $doWD     = $PSBoundParameters.ContainsKey('UAP11WorkingDirectory')
        $doParams = $PSBoundParameters.ContainsKey('UAP11Parameters')
        $doAuto   = $PSBoundParameters.ContainsKey('Autostart')

        if (-not ($doNewId -or $doExe -or $doWD -or $doParams -or $doAuto)) {
            Write-Warning "No settings specified - nothing to do."
            return
        }
        if ($doWD -and $UAP11WorkingDirectory -match '[<>|?*]') {
            Write-Error "UAP11WorkingDirectory must not contain any of: < > | ? *"
            return
        }
        if ($doNewId) {
            if (-not $AppId) {
                Write-Error "Renaming requires -AppId to identify the single application to rename."
                return
            }
            if ([string]::IsNullOrWhiteSpace($NewId)) {
                Write-Error "NewId must not be empty."
                return
            }
        }

        $manifestPath = Join-Path $MSIXFolderPath 'AppxManifest.xml'
        if (-not (Test-Path $manifestPath)) {
            Write-Error "AppxManifest.xml not found in: $($MSIXFolderPath.FullName)"
            return
        }

        $manifest = New-Object System.Xml.XmlDocument
        $manifest.Load($manifestPath)

        $prefixes = @()
        if ($doWD -or $doParams) { $prefixes += 'uap11' }
        if ($doAuto)             { $prefixes += 'desktop' }
        if ($prefixes.Count -gt 0) {
            Add-MSIXManifestNamespace -Manifest $manifest -Prefixes $prefixes
        }

        $nsmgr = New-Object System.Xml.XmlNamespaceManager($manifest.NameTable)
        $AppXNamespaces.GetEnumerator() | ForEach-Object { $null = $nsmgr.AddNamespace($_.Key, $_.Value) }
        $nsUri      = $AppXNamespaces['ns']
        $uap11Uri   = $AppXNamespaces['uap11']
        $desktopUri = $AppXNamespaces['desktop']

        $apps = @($manifest.SelectNodes('//ns:Package/ns:Applications/ns:Application', $nsmgr))
        $changed = $false

        foreach ($app in $apps) {
            $thisId = $app.GetAttribute('Id')
            if ($AppId -and $thisId -ne $AppId) { continue }
            if (-not $PSCmdlet.ShouldProcess($thisId, 'Update Application settings')) { continue }

            if ($doExe) {
                $null = $app.SetAttribute('Executable', $Executable)
                Write-Verbose "Set Executable '$Executable' on '$thisId'."
            }

            if ($doWD)     { $null = $app.SetAttribute('CurrentDirectoryPath', $uap11Uri, $UAP11WorkingDirectory) }
            if ($doParams) { $null = $app.SetAttribute('Parameters',           $uap11Uri, $UAP11Parameters) }

            if ($doAuto) {
                $ext = $app.SelectSingleNode('ns:Extensions', $nsmgr)
                $startNode = $null
                if ($null -ne $ext) {
                    $startNode = $ext.SelectSingleNode("desktop:Extension[@Category='windows.startupTask']/desktop:StartupTask", $nsmgr)
                }

                if ($Autostart) {
                    if ($null -eq $ext) {
                        $ext = $manifest.CreateElement('Extensions', $nsUri)
                        $null = $app.AppendChild($ext)
                    }
                    $taskId  = if ($AutostartTaskId)      { $AutostartTaskId }      else { $thisId }
                    $display = if ($AutostartDisplayName) { $AutostartDisplayName } else { $thisId }

                    if ($null -eq $startNode) {
                        $exe = if ($AutostartExecutable) { $AutostartExecutable } else { $app.GetAttribute('Executable') }
                        $stExt = $manifest.CreateElement('desktop:Extension', $desktopUri)
                        $null = $stExt.SetAttribute('Category', 'windows.startupTask')
                        $null = $stExt.SetAttribute('Executable', $exe)
                        $null = $stExt.SetAttribute('EntryPoint', 'Windows.FullTrustApplication')
                        $startNode = $manifest.CreateElement('desktop:StartupTask', $desktopUri)
                        $null = $startNode.SetAttribute('TaskId', $taskId)
                        $null = $startNode.SetAttribute('Enabled', 'true')
                        $null = $startNode.SetAttribute('DisplayName', $display)
                        $null = $stExt.AppendChild($startNode)
                        $null = $ext.AppendChild($stExt)
                        Write-Verbose "Created startup task '$taskId' on '$thisId'."
                    }
                    else {
                        $null = $startNode.SetAttribute('Enabled', 'true')
                        if ($AutostartTaskId)      { $null = $startNode.SetAttribute('TaskId', $AutostartTaskId) }
                        if ($AutostartDisplayName) { $null = $startNode.SetAttribute('DisplayName', $AutostartDisplayName) }
                        if ($AutostartExecutable)  { $null = $startNode.ParentNode.SetAttribute('Executable', $AutostartExecutable) }
                        Write-Verbose "Enabled startup task on '$thisId'."
                    }
                }
                else {
                    if ($null -ne $startNode) {
                        $null = $startNode.SetAttribute('Enabled', 'false')
                        Write-Verbose "Disabled startup task on '$thisId'."
                    }
                    else {
                        Write-Verbose "No startup task on '$thisId' to disable."
                    }
                }
            }

            if ($doNewId) {
                $clash = $manifest.SelectSingleNode("//ns:Package/ns:Applications/ns:Application[@Id='$NewId']", $nsmgr)
                if ($null -ne $clash -and -not [object]::ReferenceEquals($clash, $app)) {
                    Write-Error "Another Application already uses Id '$NewId' - rename skipped."
                }
                else {
                    $null = $app.SetAttribute('Id', $NewId)
                    Write-Warning "Renamed Application Id '$thisId' -> '$NewId'. This changes the AUMID and can break existing shortcuts, jump lists and Start pins."
                }
            }

            $changed = $true
        }

        if ($changed) {
            $manifest.Save($manifestPath)
            Write-Verbose "Saved $manifestPath"
        }
        else {
            Write-Warning "No matching Application found to update."
        }
    }
}