xmlpowershellxml-parsingappxappxmanifest

Modify Appxmanifest - Add Element to XML via Powershell


Right now I'm working on a Azure DevOps Building Pipeline and got stuck at manipulating the generated Package.appxmanifest in a way I need it.

What I have:

<Package>
  <Capabilities>
    <uap2:Capability Name="spatialPerception" />
  </Capabilities>
</Package>

What I need:

<Package>
  <Capabilities>
    <uap2:Capability Name="spatialPerception" />
    <rescap:Capability Name="perceptionSensorsExperimental" />
  </Capabilities>
</Package>

I tried to create an Element, add an Attribute to it and then add the Element as child to the Capabilities. But this generates wrong stuff. For example:

PowerShell #1:

$newElement = $manifest.Package.Capabilities.AppendChild($manifest.CreateElement("rescap:Capability"))
$newElement.SetAttribute(“Name”,”perceptionSensorsExperimental”)

Generates #1:

<Package>
  <Capabilities>
    <uap2:Capability Name="spatialPerception" />
    <Capability Name="perceptionSensorsExperimental" xmlns="" />
  </Capabilities>
</Package>

How can I create the mentioned line, consisting of rescap:Capability and the attribute Name="perceptionSensorsExperimental"?

--Edit
Initial Package.appxmanifest document in its entirety:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
         xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
         xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
         xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
         xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
         xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
         xmlns:mobile="http://schemas.microsoft.com/appx/manifest/mobile/windows10"
         ignorableNamespaces="uap uap2 uap3 uap4 mp mobile iot rescap"
         xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
         xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
  <Identity Name="XXXX" Publisher="CN=XXXX" Version="1.0.0.0" />
  <Properties>
    <DisplayName>XXXX</DisplayName>
    <PublisherDisplayName>XXXXX</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
  </Properties>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.22621.0" />
  </Dependencies>
  <Resources>
    <Resource Language="x-generate" />
  </Resources>
  <Applications>
    <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="XXXX.App">
      <uap:VisualElements DisplayName="XXXXX" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="XXXX" BackgroundColor="transparent">
        <uap:DefaultTile ShortName="XXXX" Wide310x150Logo="Assets\Wide310x150Logo.png" />
        <uap:SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="#FFFFFF" />
        <uap:InitialRotationPreference>
          <uap:Rotation Preference="landscape" />
          <uap:Rotation Preference="landscapeFlipped" />
          <uap:Rotation Preference="portrait" />
          <uap:Rotation Preference="portraitFlipped" />
        </uap:InitialRotationPreference>
      </uap:VisualElements>
    </Application>
  </Applications>
  <Capabilities>
    <Capability Name="internetClient" />
    <Capability Name="internetClientServer" />
    <Capability Name="privateNetworkClientServer" />
    <uap:Capability Name="sharedUserCertificates" />
    <uap2:Capability Name="spatialPerception" />
    <DeviceCapability Name="webcam" />
    <DeviceCapability Name="microphone" />
    <DeviceCapability Name="gazeinput" />
  </Capabilities>
</Package>

Solution

  • When you use .CreateElement() to create the new node, there is a third parameter you can give it, which is the url taken from the xmlns:rescap declaration

    By using that, things should work as wanted:

    # the full path and filename
    $file = 'D:\Test\Package.appxmanifest'
    # load the xml file. This way, you are ensured to get the file encoding correct
    $xml = [System.Xml.XmlDocument]::new()
    $xml.Load($file)
    
    # use the url from the `xmlns:rescap` declaration
    $nsUri   = $xml.DocumentElement.GetNamespaceOfPrefix('rescap')
    $newNode = $xml.CreateElement("rescap", "Capability", $nsUri)
    $newNode.SetAttribute("Name","perceptionSensorsExperimental")
    [void]$xml.Package.Capabilities.AppendChild($newNode)
    
    $xml.Save($file)
    

    Result (shortened)

    . . .
      <Capabilities>
        <Capability Name="internetClient" />
        <Capability Name="internetClientServer" />
        <Capability Name="privateNetworkClientServer" />
        <uap:Capability Name="sharedUserCertificates" />
        <uap2:Capability Name="spatialPerception" />
        <DeviceCapability Name="webcam" />
        <DeviceCapability Name="microphone" />
        <DeviceCapability Name="gazeinput" />
        <rescap:Capability Name="perceptionSensorsExperimental" />
      </Capabilities>
    </Package>