15. Jun 2020
Lesedauer 22 Min.
Unter der Haube von MSIX
MSIX-Pakete verwalten
Verwalten von Anwendungspaketen in einem individuell anpassbaren Zielsystem.

Die Architekturen von MSIX und Windows Installer lassen sich durchaus vergleichen. Beide Systeme verfolgen einen deklarativen Ansatz, bei dem die Beschreibung der Installation innerhalb des jeweiligen Pakets erfolgt. Es wird jedoch nicht festgeschrieben, wie die Installation erfolgen soll, sondern es wird lediglich das Endergebnis skizziert. Die tatsächliche Implementierung befindet sich in einer Betriebssystemkomponente. Beim MSI erledigt der Windows-Installer-Service diese Tätigkeiten und bei MSIX der Package Manager [1]. Er ist somit das Herzstück der Technologie und stellt die Funktionalitäten zur Bereitstellung und Verwaltung von MSIX-Paketen bereit, sodass hiermit auch Paketinstallationen durchgeführt werden können.
sual-Studio-Projekt ein Verweis auf die Metadatei Windows.winmd, die sich unter %ProgramFiles(x86)%\Windows Kits\ 10\UnionMetadata befindet und eine Definition aller unterstützten APIs beinhaltet.Nach diesen Vorbereitungen lässt sich die Installation eines Anwendungspakets durch das folgende Codefragment in die eigene Anwendung integrieren.
Querladen von Anwendungspaketen
Der Package Manager lässt sich aus unterschiedlichen Clienttechnologien wie der Windows PowerShell oder dem App-Installer [2] heraus verwenden. Der App-Installer startet automatisch, wenn ein Anwendungspaket (MSIX, MSIXBundle, APPX, APPXBundle) doppelt angeklickt wird. Mit der PowerShell dagegen lässt sich die Paketinstallation durch den Befehl Add-AppxPackage starten.Darüber hinaus kann die Nutzung des Package Managers auch aus einer eigenen Anwendung heraus erfolgen. Hierzu müssen WINMD-Dateien (Windows Meta Data; technisch gesehen handelt es sich um eine erweiterte Form des Binärformats von .NET) in das Entwicklungsprojekt eingebunden werden. Diese Dateien enthalten Metadaten für Windows-Betriebssystem-APIs, sodass diese aus der verwalteten Welt genutzt werden können. Unbedingt erforderlich ist im Vi-sual-Studio-Projekt ein Verweis auf die Metadatei Windows.winmd, die sich unter %ProgramFiles(x86)%\Windows Kits\ 10\UnionMetadata befindet und eine Definition aller unterstützten APIs beinhaltet.Nach diesen Vorbereitungen lässt sich die Installation eines Anwendungspakets durch das folgende Codefragment in die eigene Anwendung integrieren.
<span class="hljs-built_in">Uri</span> packageUri = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Uri</span>(inputPackageUri);
<span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> PackageManager().AddPackageAsync(
packageUri, <span class="hljs-keyword">null</span>, DeploymentOptions.None);
Die aufgezeigten Vorgehensweisen des direkten Installationsaufrufs werden als Querladen oder Sideloading bezeichnet. Dieser Installationsansatz war vom Ursprung her für Entwickler konzipiert, sodass die Software über eine Webseite oder ein gemeinsames Verzeichnis zum Download und zur Installation bereitgestellt werden konnte. Dem gegenüber stehen die verwalteten Bereitstellungsmethoden über den Windows Store, das Mobile Device Management oder den System Center Configuration Manager (SCCM), wie in Bild 1 gezeigt [3].

Bereitstellungsoptionenvon MSIX-Paketen(Bild 1)
Autor
Zur Bereitstellung eines Anwendungspakets per Querladefunktion müssen zwei Systembedingungen erfüllt sein.
- Das Sideloading muss per Unternehmensrichtlinie oder in den lokalen Einstellungen auf dem System aktiviert werden. Ist dieses nicht erfolgt, wird die Installation mit dem Fehler HResult=0x80073CFF terminiert. Für die Installation dieser Anwendung wird eine Windows-Entwicklerlizenz oder ein sideloadfähiges System benötigt.
- Das MSIX-Paket muss zudem mit einem auf der Maschine anerkannten Zertifikat digital signiert sein [4].

Geänderter Einstellungsdialogfür Entwickler ab Windows 10 Version 2004(Bild 2)
Autor
[HKEY_LOCAL_MACHINE<span class="hljs-symbol">\S</span>OFTWARE<span class="hljs-symbol">\P</span>olicies<span class="hljs-symbol">\M</span>icrosoft<span class="hljs-symbol">\W</span>indows<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> Appx]
"AllowAllTrustedApps"=dword:00000000
Während bis Windows 10 Version 1909 eine aktive Handlung erfolgen musste, um die Installation von quergeladenen Apps zu ermöglichen, ist seit Version 2004 das Gegenteil der Fall.
Konfiguration der Installationsziele
Bei klassischen Desktop-Apps existiert keine zentralisierte Option zur Verwaltung der installierten Anwendungen. Der Windows Installer bietet zwar entsprechende Verwaltungsoptionen, aber die Verwendung dieser Technologie ist nicht zwingend. Desktop-Apps können durch unterschiedliche Technologien auf das System gebracht werden, wobei die Verwaltung der Anwendung der jeweiligen Installationstechnologie unterliegt und nicht dem Betriebssystem.Bei MSIX-Paketen ist das anders. Der Package Manager ist hierfür die zentrale Verwaltungskomponente und integraler Bestandteil des Betriebssystems. Dies gewährleistet, dass das Betriebssystem immer Kenntnis über die Installationsaktivitäten erhält und steuernd hierauf einwirken kann. Die Installation, Aktualisierung und Deinstallation sowie alle Verwaltungsoptionen sind ohne Mitwirkung des Betriebssystems nicht möglich. Die finale Entscheidung trifft immer das Betriebssystem, nicht mehr die individuell erstellte Installationsroutine. Das Installationsergebnis steht somit im Einklang mit den Vorgaben des Betriebssystems. Installationen etwa ins Windows-Systemverzeichnis sind nicht mehr möglich; die Stabilität und Performance des Systems bleiben erhalten.Alle Apps werden standardmäßig auf dem System-Volume unter %ProgramFiles%\WindowsApps gespeichert. Das Zielverzeichnis ist somit vorgegeben und kann während der App-Installation zunächst nicht beeinflusst werden. Über die in Bild 3 gezeigten Windows-Einstellungen kann der Standard-Speicherort jedoch systemweit verändert werden. Dabei wird ein neues Package-Volume erstellt und so konfiguriert, dass der Package-Manager es nutzen kann. Neu zu installierende Apps verwenden dieses Volume als Installationsziel. Bereits installierte Apps können nachträglich dorthin verschoben werden. Voraussetzung ist aber, dass dies nicht über eine Richtlinie eingeschränkt ist, wie es nachfolgend der Fall wäre:
Standardspeicherortfür Appsverändern(Bild 3)
Autor
[HKEY_LOCAL_MACHINE<span class="hljs-symbol">\S</span>OFTWARE<span class="hljs-symbol">\P</span>olicies<span class="hljs-symbol">\M</span>icrosoft<span class="hljs-symbol">\W</span>indows<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> Appx]
"RestrictAppToSystemVolume"=dword:00000001
Die Konfigurationsänderungen lassen sich nicht nur über die Windows-Einstellungen umsetzen, sondern auch mit der Windows PowerShell, die zudem weitere Möglichkeiten bietet.Das Hinzufügen eines Volumes erledigt der Befehl PS C:\> Add-AppPackageVolume x:, wobei alle Befehle zur Verwaltung der Volumes administrative Privilegien erfordern. Bei der Ausführung werden mehrere Ordner wie ProgramFiles, WindowsApps und WpSystem dem zugewiesenen Laufwerk hinzugefügt, damit es als Installationsziel fungieren kann. Zudem werden die Eigenschaften des Volumes ausgegeben.Um dieses Volume als Standardziel für die Apps zu konfigurieren, ist der Befehl Set-AppPackageDefaultVolume zu verwenden. Zur Spezifizierung des jeweiligen Volumes kann entweder der voll qualifizierte Name des Volumes, die GUID oder der PackageStorePath, verwendet werden.
PS C:\> Set-AppPackageDefaultVolume -Volume "{
92f89eab<span class="hljs-string">-0000</span><span class="hljs-string">-0000</span><span class="hljs-string">-0000</span><span class="hljs-string">-010000000000</span>}"
Folgt nach dieser Konfigurationsänderung die Installation eines MSIX-Pakets, so wird es unter x:\WindowsApps gespeichert. Ist jedoch die Richtlinie RestrictAppToSystemVolume gesetzt, so endet die Installation mit einem Fehler.Das System-Volume wird ebenfalls verändert. In diesem wird eine Verknüpfung vom Typ Junction angelegt, die auf das Installationsziel verweist, wie auch die folgende Ausgabe mit [5] zeigt.
C:<span class="hljs-symbol">\T</span>ools<span class="hljs-symbol">\S</span>ysinternalsSuite>junction -s
"c:<span class="hljs-symbol">\P</span>rogram Files<span class="hljs-symbol">\W</span>indowsApps"
<span class="hljs-symbol">\\</span>?<span class="hljs-symbol">\c</span>:<span class="hljs-symbol">\P</span>rogram Files<span class="hljs-symbol">\W</span>indowsApps<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a: JUNCTION
Print Name : <span class="hljs-symbol">\\</span>?<span class="hljs-symbol">\x</span>:<span class="hljs-symbol">\W</span>indowsApps<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a
Substitute Name: x:<span class="hljs-symbol">\W</span>indowsApps<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a
Zum Ermitteln des Standard-Volumes ist Get-AppPackageDefaultVolume zu verwenden, und mit dem Befehl Dismount-AppPackageVolume kann ein entsprechendes Volume wieder deaktiviert werden. Auf die Apps, die auf diesem Volume abgelegt wurden, ist danach kein Zugriff mehr möglich. Die Verknüpfungen innerhalb des Betriebssystems beispielsweise im Startmenü bleiben zwar bestehen; sie sind aber nicht mehr aktivierbar.Der Befehl Mount-AppPackageVolume ermöglicht wiederum die Aktivierung des Volumes und damit einhergehend die Nutzbarkeit der darauf abgelegten Apps. Mit Get-AppPackageVolume können alle auf dem System vorhandenen Volumes abgerufen werden. Die Eigenschaft IsOffline informiert über die Verfügbarkeit des Volumes.Der Befehl Remove-AppPackageVolume entfernt schließlich die Volumes wieder. Dies ist jedoch nur möglich, wenn das Volume leer ist. Bereits vorhandene Pakete lassen sich – nicht nur zu diesem Zweck – mit dem Move-AppPackage in ein anderes Volume verschieben.
Exkurs: Identifizierung von MSIX-Paketen
Jedes MSIX-Paket besitzt die in Tabelle 1 dargestellten Identifizierungsmerkmale. Sie werden beim Erstellen des Pakets festgelegt und finden sich im Element <Identity/> der Manifest-Datei [4], wie auch das folgende Codefragment zeigt.Tabelle 1: Bestandteile der Paketidentität
|
<<span class="hljs-keyword">Identity</span> Name=<span class="hljs-string">"NativeNotepadApp"</span> Publisher=<span class="hljs-string">"CN=AK"</span>
<span class="hljs-keyword">Version</span>=<span class="hljs-string">"2.0.8.0"</span> ProcessorArchitecture=<span class="hljs-string">"x64"</span> />
Für die Verwaltung von MSIX-Paketen sind jedoch die Eigenschaften PackageFullName und PackageFamilyName unabdingbar, die aus den Attributen der Paketidentität generiert werden.
Name : <span class="hljs-type">NativeNotepadApp</span>
Publisher : <span class="hljs-type">CN</span>=AK
Architecture : <span class="hljs-type">X64</span>
ResourceId :
<span class="hljs-type">Version</span> : 2.0.8.0
<span class="hljs-type">PackageFullName</span> : <span class="hljs-type">NativeNotepadApp_2.0.8.0_x64</span>__
yf5adtgdrdj2a
InstallLocation : <span class="hljs-type">C</span>:\Program Files\WindowsApps\Native
NotepadApp_2.<span class="hljs-number">0.8</span>.<span class="hljs-number">0_</span>x64__yf5adtgdrdj2a
PackageFamilyName : <span class="hljs-type">NativeNotepadApp_yf5adtgdrdj2a</span>
PublisherId : <span class="hljs-type">yf5adtgdrdj2a</span>
Der PackageFamilyName setzt sich, wie in Bild 4 zu erkennen, aus dem Paketnamen und einem Hashwert des Publishers zusammen, wobei die Werte durch einen Unterstrich voneinander getrennt sind. Hiermit wird eine Anwendungsfamilie definiert, in der somit Versions- und Architekturangaben ignoriert werden. Der PackageFamilyName ist in Aktualisierungsszenarien äußerst relevant, da hierdurch der Zusammenhang der Pakete modelliert wird. Nur Pakete innerhalb einer Familie lassen sich aktualisieren. Da der PackageFamilyName einen Hashwert des Herausgebers beinhaltet und dieser wiederum eine Abhängigkeit zum Zertifikat aufweist, mit dem das Paket signiert wurde, wird deutlich, dass bei der Erstellung von Aktualisierungspaketen immer das gleiche Zertifikat wie beim Hauptpaket verwendet werden muss.

Vergleichvon PackageFamilyName und PackageFullName(Bild 4)
Autor
Der PackageFullName ist eine String-Repräsentation aller Identifizierungsmerkmale im Format
<span class="hljs-tag"><<span class="hljs-name">Name</span>></span>_<span class="hljs-tag"><<span class="hljs-name">Version</span>></span>_<span class="hljs-tag"><<span class="hljs-name">Architecture</span>></span>_<span class="hljs-tag"><<span class="hljs-name">ResourceId</span>></span>_<span class="hljs-tag"><<span class="hljs-name">PublisherId</span>></span>
und wird benötigt, wenn für Verwaltungsaufgaben ein Paket eindeutig identifiziert werden muss, wie das bei der Deinstallation oder dem Verschieben der Fall ist. Darüber hinaus wird dieser Name auch als Bezeichnung für den Installationsordner auf dem Package-Volume verwendet. Obwohl innerhalb einer Paketfamilie immer nur eine App auf dem System installiert sein kann, ist der PackageFamilyName als Ordnerbezeichnung dennoch ungeeignet. Durch die Verwendung des vollständigen Namens können somit schon Aktualisierungen heruntergeladen werden, ohne diese letztlich zu installieren.Die Konstruktion beider Eigenschaften aus den im Manifest befindlichen Identifizierungsmerkmalen stellt mit Ausnahme der PublisherId keine große Herausforderung dar, da diese im Klartext zu verwenden sind. Bei der PublisherId handelt es sich um eine Crockford’s-Base32-Codierung [6] der ersten acht Bytes des SHA-256-Hash des Publisher-Strings, der in UTF-16 (Little Endian) vorliegen muss. Nach Kenntnis dieses Algorithmus ist nun die Ermittlung der PublisherId möglich, wie das in Listing 1 dargestellt wird. Zur Nutzung der Crockford’s-Base32-Funktionalität wurde der entsprechende Code aus [7] integriert und innerhalb der Funktion GetPublisherIdFromPublisher() verwendet. Die beiden Paketeigenschaften werden letztlich durch die Funktionen GetPackageFullName() und GetPackageFamilyName() ermittelt.
Listing 1: Generierung des PackageFullName und des PackageFamilyName
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetPackageFullName</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name, </span></span><br/><span class="hljs-function"><span class="hljs-params"> Version version, <span class="hljs-keyword">string</span> publisher, <span class="hljs-keyword">string</span> </span></span><br/><span class="hljs-function"><span class="hljs-params"> resourceId, PackageArchitecture architecture</span>) </span><br/>{ <br/> <span class="hljs-keyword">string</span> publisherId = GetPublisherIdFromPublisher(<br/> publisher); <br/> <span class="hljs-keyword">return</span> (<span class="hljs-string">$"<span class="hljs-subst">{name}</span>_<span class="hljs-subst">{version.ToString()}</span>_<span class="hljs-subst">{architecture.</span></span><br/><span class="hljs-string"><span class="hljs-subst"> ToString()}</span>_<span class="hljs-subst">{resourceId}</span>_<span class="hljs-subst">{publisherId}</span>"</span>); <br/>} <br/><br/><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetPackageFamilyName</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name,</span></span><br/><span class="hljs-function"><span class="hljs-params"> <span class="hljs-keyword">string</span> publisher</span>) </span><br/>{ <br/> <span class="hljs-keyword">string</span> publisherId = GetPublisherIdFromPublisher(<br/> publisher); <br/> <span class="hljs-keyword">return</span> (<span class="hljs-string">$"<span class="hljs-subst">{name}</span>_<span class="hljs-subst">{publisherId}</span>"</span>); <br/>} <br/><br/><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetPublisherIdFromPublisher</span>(</span><br/><span class="hljs-function"><span class="hljs-params"> <span class="hljs-keyword">string</span> publisher</span>) </span><br/>{ <br/> <span class="hljs-keyword">using</span> (SHA256 sha256Hash = SHA256.Create()) <br/> { <br/> <span class="hljs-keyword">byte</span>[] data = sha256Hash.ComputeHash(<br/> Encoding.Unicode.GetBytes(publisher)); <br/> <span class="hljs-keyword">return</span> Crockbase32.Encode(data, <span class="hljs-number">0</span>, <span class="hljs-number">8</span>).ToLower(); <br/> } <br/>}
Das Betriebssystem-API stellt hierfür auch einige nicht verwaltete Funktionen zur Verfügung, die sich in der kernel32.dll befinden. Listing 2 enthält die entsprechenden Codefragmente, mit denen identische Ergebnisse ermittelt werden wie in Listing 1. Darüber hinaus kann über die Funktion GetPackageFamilyNameFromFullNameNative() der PackageFamilyName aus dem PackageFullName generiert werden.
Listing 2: Native Funktionen zur Generierung des PackageFullName und des PackageFamilyName
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> GetPackageFamilyNameFromFullName<br/> Native(<span class="hljs-built_in">string</span> packageFullName) <br/>{ <br/> <span class="hljs-built_in">uint</span> packageFamilyNameLength = UnsafeNativeMethods.<br/> MAX_PATH; <br/> StringBuilder packageFamilyNameBuilder = <span class="hljs-keyword">new</span> <br/> StringBuilder((<span class="hljs-keyword">int</span>)UnsafeNativeMethods.MAX_PATH); <br/> <span class="hljs-keyword">int</span> errorCode = UnsafeNativeMethods.PackageFamily<br/> NameFromFullName(packageFullName, <span class="hljs-keyword">ref</span> <span class="hljs-keyword">package</span><br/> FamilyNameLength, packageFamilyNameBuilder); <br/> <span class="hljs-keyword">if</span> (errorCode != UnsafeNativeMethods.ERROR_SUCCESS) <br/> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Win32Exception(errorCode); <br/> <span class="hljs-keyword">return</span> packageFamilyNameBuilder.ToString(); <br/>} <br/><br/><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> GetPackageFamilyNameNative(<br/> <span class="hljs-built_in">string</span> name, <span class="hljs-built_in">string</span> publisher) <br/>{ <br/> <span class="hljs-built_in">string</span> packageFamilyName = <span class="hljs-literal">null</span>; <br/> UnsafeNativeMethods.PACKAGE_ID packageId = <span class="hljs-keyword">new</span> <br/> UnsafeNativeMethods.PACKAGE_ID <br/> { <br/> name = name, <br/> publisher = publisher <br/> }; <br/> <span class="hljs-built_in">uint</span> packageFamilyNameLength = <span class="hljs-number">0</span>; <br/> <br/> <span class="hljs-keyword">if</span> (UnsafeNativeMethods.PackageFamilyNameFromId(<br/> packageId, <span class="hljs-keyword">ref</span> packageFamilyNameLength, <span class="hljs-literal">null</span>) == <br/> ERROR_INSUFFICIENT_BUFFER) <br/> { <br/> StringBuilder packageFamilyNameBuilder = <span class="hljs-keyword">new</span> <br/> StringBuilder((<span class="hljs-keyword">int</span>)packageFamilyNameLength); <br/> <span class="hljs-keyword">if</span> (UnsafeNativeMethods.PackageFamilyNameFromId(<br/> packageId, <span class="hljs-keyword">ref</span> packageFamilyNameLength, <br/> packageFamilyNameBuilder) == <span class="hljs-number">0</span>) <br/> { <br/> packageFamilyName = packageFamilyNameBuilder.<br/> ToString(); <br/> } <br/> } <br/> <span class="hljs-keyword">return</span> packageFamilyName; <br/>} <br/><br/><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> GetPackageFullNameNative(<span class="hljs-built_in">string</span> <br/> name, Version <span class="hljs-keyword">version</span>, <span class="hljs-built_in">string</span> publisherId, <span class="hljs-built_in">string</span> <br/> resourceId, PackageArchitecture architecture) <br/>{ <br/> <span class="hljs-built_in">string</span> packageFullName = <span class="hljs-literal">null</span>; <br/> UnsafeNativeMethods.PACKAGE_ID packageId = <span class="hljs-keyword">new</span> <br/> UnsafeNativeMethods.PACKAGE_ID <br/> { <br/> name = name, <br/> <span class="hljs-keyword">version</span> = <span class="hljs-keyword">new</span> UnsafeNativeMethods.PACKAGE_VERSION <br/> { <br/> Major = (<span class="hljs-built_in">ushort</span>)<span class="hljs-keyword">version</span>.Major, <br/> Minor = (<span class="hljs-built_in">ushort</span>)<span class="hljs-keyword">version</span>.Minor, <br/> Build = (<span class="hljs-built_in">ushort</span>)<span class="hljs-keyword">version</span>.Build, <br/> Revision = (<span class="hljs-built_in">ushort</span>)<span class="hljs-keyword">version</span>.Revision <br/> }, <br/> processorArchitecture = (<span class="hljs-built_in">uint</span>)architecture, <br/> resourceId = resourceId, <br/> publisher = publisherId <br/> }; <br/> <span class="hljs-built_in">uint</span> packageFullNameLength = <span class="hljs-number">0</span>; <br/> <br/> <span class="hljs-keyword">if</span> (UnsafeNativeMethods.PackageFullNameFromId(<br/> packageId, <span class="hljs-keyword">ref</span> packageFullNameLength, <span class="hljs-literal">null</span>) == <br/> ERROR_INSUFFICIENT_BUFFER) <br/> { <br/> StringBuilder packageFullNameBuilder = <span class="hljs-keyword">new</span> <br/> StringBuilder((<span class="hljs-keyword">int</span>)packageFullNameLength); <br/> <span class="hljs-keyword">if</span> (UnsafeNativeMethods.PackageFullNameFromId(<br/> packageId, <span class="hljs-keyword">ref</span> packageFullNameLength, <br/> packageFullNameBuilder) == <span class="hljs-number">0</span>) <br/> { <br/> packageFullName = packageFullNameBuilder.<br/> ToString(); <br/> } <br/> } <br/> <span class="hljs-keyword">return</span> packageFullName; <br/>}
Interaktive Installationen mit dem App-Installer
Der Microsoft App-Installer [8] unterstützt bei der interaktiven Installation von Windows-10-Apps. Ein Doppelklick auf das jeweilige MSIX-Paket genügt, um den App-Installer aufzurufen und die Benutzeroberfläche mit diversen Paketinformationen wie Name, Herausgeber, Version und Anzeigelogo der App und den von der App angeforderten Funktionen anzuzeigen. Die Installation lässt sich direkt starten und eventuelle Installationsfehler werden im Dialog angezeigt. Befindet sich bereits eine ältere Version der zu installierenden Software auf dem System, wird ebenfalls die Benutzeroberfläche angezeigt, aber eine Aktualisierungsoption angeboten. Befindet sich jedoch eine neuere Version der Software auf dem Zielsystem, wurde die Installation der niedrigeren Version mit dem App-Installer standardmäßig geblockt, obwohl seit Windows 10 Version 1809 ein Downgrade generell möglich ist. Dieses funktionierte jedoch nur, wenn es per Windows PowerShell oder innerhalb der APPINSTALLER-Datei [9] wie nachfolgend dargestellt initiiert wurde.- Windows PowerShell: Add-AppPackage […] -ForceUpdateFromAnyVersion
- APPINSTALLER-Datei: UpdateSettings -ForceUpdateFromAnyVersion

Darstellung eines Downgradesim App-Installer und Hinweis zur Vertrauenswürdigkeit der App(Bild 5)
Autor
Erweiterte Möglichkeiten mit der Windows PowerShell
Der App-Installer bietet einfache Möglichkeiten zur Installation von Anwendungspaketen, die per Querladefunktion auf das System gebracht werden sollen. Wie beschrieben sind die zuvor nötigen Einstellungsänderungen seit Windows 10 Version 2004 entfallen. Auch wenn der App-Installer eine gute und einfache Option zur Installation von MSIX-Paketen bietet, setzt ein professionelles Paketmanagement komplexere und automatisierbare Tools wie die Windows PowerShell voraus. Bild 6 unterstreicht dies und gibt einen Überblick über die Installations- und Verwaltungsoptionen für Apps unter Windows 10. Neben den Klassikern wie Installation und Deinstallation finden sich hier auch diverse andere Funktionen, Eigenschaften und Einstellungen. Die Darstellung beantwortet auch die Frage, welche Identifizierungsmerkmale (PackageFullName, PackageFamilyName oder PackagePath) für die unterschiedlichen Funktionen benötigt werden.
Installation und Verwaltungvon Apps mit Windows 10(Bild 6)
Autor
Die Installation von Apps ist seit jeher mit dem folgenden PowerShell-Befehl möglich:
PS C:\> Add-AppxPackage -Path [Path]
Die Bezeichnung des Befehls ist mittlerweile irritierend, da damit die Installation von APPX-Paketen und nicht von MSIX-Paketen suggeriert wird. Da ein MSIX-Paket ja eine Weiterentwicklung eines APPX-Pakets ist, lässt sich mit diesem Befehl seit Windows 10 Version 1809 auch ein MSIX-Paket oder ein MSIX-Bundle installieren. Zur besseren Kennzeichnung existieren weitere PowerShell-Befehle mit identischer Implementierung, die mit generischeren Bezeichnungen für weniger Verwirrung sorgen sollen. Der Befehl Add-AppPackage ist somit synonym zu verwenden. Vermutlich wird Microsoft perspektivisch auch weiterhin beide Bezeichnungen pflegen, da die ursprüngliche Appx-Variante weit verbreitet in fertigen Skripten enthalten ist und das Entfernen zu erheblichem Mehraufwand bei den Nutzern führen würde.Am Anfang steht bekanntlich immer die Installation, die mit dem folgenden Befehl gestartet werden kann:
PS C:\> Add-AppPackage -Path "D:\MSIX\NativeNotepad_
2.0.8.0_x64.msix" [Volume]
Der eigentliche Installationsprozess ist in die beiden Phasen Staging und Registrierung unterteilt. Während der Staging-Phase werden alle Dateien des Anwendungspakets im Dateisystem abgelegt und die entsprechenden Zugriffssteuerlisten (ACL) konfiguriert. Detailliert betrachtet und bezogen auf das Beispiel wird zunächst der PackageFullName generiert. Hierzu werden die im Manifest definierten Identifizierungsmerkmale des MSIX-Pakets d:\msix\NativeNotepad_2.0.8.0_x64.msix herangezogen. Der vollständige Installationspfad wird aus dem Package-Volume und dem PackageFullName generiert. Ohne eine vorgenommene Konfigurationsänderung am Betriebssystem wird das System-Volume als Ziel verwendet, sodass sich folgender Installationspfad ergibt:
C:\Program Files\WindowsApps\NativeNotepadApp_2.0.8.0_
x64__yf5adtgdrdj2a
Wurde hingegen durch den Befehl Set-AppPackageDefaultVolume eine alternatives Standard-Volume festgelegt oder das Ziel-Volume dem Befehlsaufruf durch das Argument -Volume direkt übergeben, fungiert natürlich dieses als Installationsziel. Wie schon erläutert, verweist dann eine dem System-Volume hinzugefügte Verknüpfung vom Typ Junction auf das tatsächliche Zielverzeichnis. Im Weiteren werden die Zugriffssteuerlisten konfiguriert und die im MSIX-Paket enthaltenen Dateien in das Zielverzeichnis extrahiert.Auf die Staging-Phase folgt die Registrierungsphase, bei der die App für den aktuellen Benutzer registriert wird. Dabei werden alle nötigen Aktionen durchgeführt, um die App dem Benutzer zur Verfügung zu stellen und die entsprechenden Schnittstellen ins Betriebssystem zu integrieren, wie:
- Erstellen von benutzerbezogenen Dateiablagen beispielsweise für die virtuelle Systemregistrierung.
- Erstellen von Erweiterungspunkten wie Dateityp-Zuordnungen.
- Anlegen der App-Kacheln zum Starten der App.
var packageManager = new PackageManager();
packageManager.StagePackageAsync(new Uri(
inputPackageUri), null).AsTask();
packageManager.RegisterPackageByFullNameAsync(inputPackage
FullName, null, DeploymentOptions.None).AsTask();
Für das Staging wird hierzu der Pfad zum MSIX-Paket übergeben, der in einen URI umgewandelt wird. Die hierdurch vorgenommenen Modifikationen wirken sich auf den folgenden Ordner des Dateisystems aus:
%ProgramFiles%\WindowsApps\[PackageFullName]
Zur Registrierung für den Benutzer stehen mehrere Funktionen des PackageManagers bereit, die alle zum gleichen Ergebnis führen. Je nach Anwendungszweck sind der PackageFullName, der PackageFamilyName oder der Pfad zu der Manifestdatei zur Paketidentifizierung zu benutzen. Bei der Registrierung werden folgende Ordner erstellt oder verändert:
%LocalAppData%\Packages\[PackageFamilyName]
%ProgramData%\Packages\[PackageFamilyName]\[User-SID]
Wie zuvor schon angedeutet, können auch beiden Phasen mit dem PowerShell-Befehl Add-AppPackage getrennt voneinander durchlaufen werden. Um nur die Staging-Phase zu durchlaufen, ist dem Befehl das Argument -Stage anzufügen:
PS C:\> Add-AppPackage
-Path "D:\MSIX\NativeNotepad_2.0.8.0_x64.msix" -Stage
Zur Registrierung der App für den jeweiligen Benutzer ist hingegen das Argument -Register zu verwenden. Dieses Argument ist eher im Entwicklerumfeld bekannt und ermöglicht die Registrierung der Anwendungsdateien, ohne dass ein Installationspaket benötigt wird [10]. Diese Vorgehensweise ist Grundlage für einen effektiven Softwareentwicklungsprozess und erfordert den aktivierten Entwicklermodus.Dem Argument -Register ist der Pfad zur Manifest-Datei zu übergeben, wie das folgende Beispiel zeigt:
PS C:\> Add-AppPackage -Register
-Path "d:\Source\NativeNotepadApp\AppxManifest.xml"
Die Verwendung des Befehls mit Verweis auf die Manifestdatei eines Pakets, das bereits die Staging-Phase durchlaufen hat, führt aber zum nachfolgenden Fehler, der leider wenig Aussagekraft besitzt:
PS C:\> Add-AppPackage -Register -Path "C:\Program
Files\WindowsApps\NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a\AppxManifest.xml"
add-apppackage : Fehler bei Bereitstellung. HRESULT:
0x80073CF9, Fehler bei der Installation. Wenden Sie
sich an den Softwarehersteller. (Ausnahme von HRESULT:
0x80073CF9)
Eine Registrierungsanforderung von "AppxManifest.xml"
wurde abgelehnt, da die Manifestdatei nicht im
Paketstammverzeichnis vorhanden ist.
Die Behebung dieses Problems ist hingegen relativ simpel. Im Entwicklermodus haben ausschließlich Dateioperationen stattgefunden, die vom Entwickler und nicht vom PackageManager durchgeführt wurden. Die Ordner- und Dateistruktur ist dem PackageManager somit nicht bekannt. Bei einem Paket, das bereits die Staging-Phase durchlaufen hat, ist das natürlich anders, auch wenn die Ordner- und Dateistrukturen identisch sind. Das Stagen erfolgt durch den PackageManager, sodass dieses Paket im Gegensatz zum Entwicklerpaket auf dem System registriert und bekannt ist und durch Inventarisierungsfunktionen auch ermittelt werden kann. Aus diesem Grund muss dem Befehlsaufruf das Argument -DisableDevelopmentMode angefügt werden, wie der nachfolgende funktionierende Befehl auch zeigt:
PS C:\> Add-AppPackage -Register -Path "C:\Program
Files\WindowsApps\NativeNotepadApp_2.0.8.0_x64__yf5adt
gdrdj2a\AppxManifest.xml" -DisableDevelopmentMode
Die Aufteilung der Installation in zwei voneinander getrennt ausführbare Prozesse bietet somit einige Vorteile:
- Aktualisierte Apps lassen sich bereits herunterladen, während die Anwendung ausgeführt wird, ohne diese zu installieren. Dies ist unter anderem in Auto-Update-Szenarien gut zu beobachten. Steht ein Update zur Verfügung, wird es nach dem Anwendungsstart heruntergeladen, und das Staging erfolgt. Zu diesem Zeitpunkt existieren somit zwei Versionen der App auf dem System. Die eigentliche Registrierung für den Benutzer findet erst nach einem erneuten Start der App statt [9].
- Wenn zwei oder mehr Benutzer die gleiche App-Version auf dem Computer installieren, wird die Anwendung nicht zweimal heruntergeladen oder installiert. Stattdessen wird dieselbe Quelle verwendet, um die App beiden Benutzern zur Verfügung zu stellen, indem die App mit ihren jeweiligen Konten registriert wird. Auf diese Weise reduziert das Betriebssystem den Speicherbedarf und die Bandbreitenauslastung bei der Aktualisierung der App.
Systemweite Bereitstellung von Apps
Dies ist jedoch so nicht korrekt, denn auch mit dem MSIX kann eine App systemweit und ohne Benutzerinteraktion bereitgestellt oder, anders ausgedrückt, vorinstalliert werden, wie das auch bei diversen Microsoft-Apps wie Fotos oder Windows Store der Fall ist. Diese Form der App-Installation wird als Bereitstellung oder App-Provisioning bezeichnet.Analog zu der sogenannten einfachen Installation wird hierbei ebenfalls die Staging-Phase durchlaufen. Es werden die Inhalte des MSIX-Pakets extrahiert und im voreingestellten Zielverzeichnis abgelegt. Die Registrierungsphase ist ebenfalls für jeden Benutzer erforderlich. Sie wird aber in diesem Fall automatisch ausgeführt. Dies geschieht durch den Systemdienst App-Vorbereitung (AppReadiness), der für alle vorinstallierten Apps die Registrierung automatisch auslöst, sobald sich ein Benutzer das erste oder das nächste Mal am System anmeldet. Auf den ersten Blick ähnelt die Vorgehensweise dem Windows Installer, doch das ist nur scheinbar so. Während sich beim Windows Installer die erforderliche Implementierung innerhalb des Pakets befindet und durch den Entwickler beeinflusst werden kann, obliegt sie beim MSIX der Steuerung und Überwachung durch das Betriebssystem.Das folgende Codefragment verdeutlicht die Zusammenhänge mit der „einfachen Installation“. Die Funktion StagePackageAsync() ist exakt identisch zu verwenden. Anstelle der Registrierung für den Benutzer durch RegisterPackageByFullNameAsync() erfolgt hierbei aber die systemweite Bereitstellung durch die Funktion ProvisionPackageForAllUsersAsync(), sodass der angesprochene Systemdienst die Benutzerregistrierung automatisch veranlassen kann. Im Gegensatz zur normalen Registrierung sind hierfür jedoch administrative Privilegien erforderlich.var packageManager = new PackageManager();
packageManager.StagePackageAsync(new Uri(
inputPackageUri), null).AsTask();
packageManager.ProvisionPackageForAllUsersAsync(
inputPackageFamilyName).AsTask();
Durch diese Methoden kann eine App systemweit bereitgestellt und somit ein identisches Installationsergebnis wie mit dem Windows Installer erreicht werden. Dieses ist jedoch nicht alles, denn MSIX kann durchaus mehr. So lässt sich die App nicht nur dem aktuellen System hinzufügen, sondern auch in ein Windows-Image integrieren.Beim Windows Imaging Format (WIM) handelt es sich um ein dateibasiertes Archivformat. Im Gegensatz zu gewöhnlichen Disk-Image-Formaten wie .ISO bildet eine WIM-Datei keine physikalischen Sektoren ab, sondern enthält wie ein Archiv eine Anzahl von Dateien und Metadaten, die ein Dateisystem konstituieren. In einer WIM-Datei können zudem mehrere OS-Images enthalten sein, sodass mit einer Datei mehrere Betriebssysteminstallationen möglich sind. Die Dateiendung WIM für dieses Dateiformat ist nicht zwingend, denn es gibt unterschiedliche Ausprägungen. Die ESD-Datei (Electronic Software Distribution) ist eine stark komprimierte Image-Datei, die hierdurch effektivere Downloads ermöglicht. Bei der SWM-Datei (Splitted Windows Image) handelt es sich um ein Image, das in mehrere Teilarchive aufgeteilt ist. Ein Aufteilen wird erforderlich, um WIM-Dateien, die größer als 4 GByte sind, vom Stick im UEFI-Modus installieren zu können.
Bereitstellung im aktuellen System
Zur systemweiten Bereitstellung von Apps stehen zusätzlich zu den zuvor dargestellten Implementierungen des PackageManagers auch PowerShell-Funktionen zur Verfügung. Auch hier ist zu berücksichtigen, dass zur Ausführung administrative Privilegien nötig sind. Der folgende Befehl fügt ein Anwendungspaket dem aktuellen System hinzu und stellt es allen Benutzern zur Verfügung:PS C:\> Add-AppProvisionedPackage -PackagePath "D:\MSIX\
NativeNotepad_2.0.8.0_x64.msix" -Online -SkipLicense
Der aktuelle Benutzer kann die App sofort ohne Neuanmeldung nutzen. Allen weiteren Nutzern des Systems wird sie durch den App-Vorbereitungsdienst mit der nächsten Anmeldung zur Verfügung gestellt. Der Parameter -Online kennzeichnet bei allen diesbezüglichen PowerShell-Funktionen das aktuelle System.Bei der Bereitstellung von Anwendungspaketen ist eine Lizenzierungsoption zwingend anzugeben. Existiert eine XML-Lizenzdatei, so ist sie über das Argument -LicensePath anzugeben. Somit lässt sich eine App aus dem Microsoft Business Store zur Offline-Verwendung herunterladen und systemweit bereitstellen. Im Business Store [10] kann ebenfalls die Lizenz generiert und heruntergeladen werden, wie in Bild 7 zu sehen ist. Die unverschlüsselte Lizenz hat das erforderliche Format und kann hierfür verwendet werden.

Herunterladen einer Appaus dem Business Store(Bild 7)
Autor
Falls für die bereitzustellende App keine Lizenzdatei erforderlich ist, ist das Argument -SkipLicense zu verwenden.Eine so bereitgestellte App kann der Benutzer wieder deinstallieren. Auch wenn sich der Benutzer danach wieder am System anmeldet, findet keine erneute Auto-Registrierung statt, und der Benutzer müsste die App auf klassische Art erneut installieren. Je nach Anwendungsfall ist es somit erforderlich, dies zu beeinflussen und die Deinstallationsmöglichkeit durch den Benutzer zu unterbinden, was mit dem folgenden Befehl seit Windows 10 Version 1809 möglich ist:
PS C:\> Set-NonRemovableAppsPolicy -NonRemovable 1
-PackageFamilyName NativeNotepadApp_yf5adtgdrdj2a -Online
Unter Verwendung dieses Befehls lässt sich eine Paketfamilie in einen permanenten Zustand versetzen, wobei der Parameter -NonRemovable die Steuerung übernimmt und folgende Werte aufnehmen kann:
- 0: Deinstallation ist möglich.
- 1: Deinstallation ist nicht möglich.
PS C:\> Get-NonRemovableAppsPolicy -Online
Value
-----
NativeNotepadApp_yf5adtgdrdj2a
Der Versuch, ein auf diese Weise geschütztes Paket zu deinstallieren, wird mit der in Bild 8 dargestellten Fehlermeldung quittiert. Zur Deinstallation muss die Richtlinieneinschränkung aufgehoben werden, wozu der Parameter -NonRemovable auf 0 zu setzen ist.

Die Deinstallationeines Pakets wird verhindert(Bild 8)
Autor
Zum Entfernen eines provisionierten Pakets steht der Befehl Remove-AppProvisionedPackage zur Verfügung.
PS C:\> Remove-AppProvisionedPackage -PackageName
NativeNotepadApp_2.0.8.0_x64__yf5adtgdrdj2a -Online
[-AllUsers]
Eine besondere Bedeutung kommt dem Argument -AllUsers zu. Wird dieses Argument nicht verwendet, so wird lediglich die Bereitstellung der App aufgehoben, also die Auto-Registrierung für die App entfernt. Den Benutzern, die sich danach erstmalig am System anmelden, wird die App somit nicht mehr zur Verfügung gestellt. Wurde die App bisher für keinen Benutzer registriert, werden auch die Staged-Dateien entfernt. Auf die Benutzer, denen die App bereits zur Verfügung gestellt wurde, hat der Befehl keinen Einfluss, und die App verbleibt im funktionsfähigen Zustand.Kommt hingegen das Argument -AllUsers zum Einsatz, so wird die Registrierung der App zusätzlich aus allen Benutzerkonten entfernt, sodass die Stage-Dateien ebenfalls entfernt werden und die App im Anschluss daran physisch nicht mehr vorhanden ist.
Offline-Bereitstellung
Die gerade dargestellten Beispiele zielten ausnahmslos auf das aktuelle System ab. Wie bereits angedeutet, können Apps auch in ein Offline-Windows-Image integriert werden. Hierzu muss auf den Parameter -Online verzichtet und stattdessen das Image über den Parameter -Path referenziert werden. Das setzt jedoch voraus, dass das Image bereits in das aktuelle System eingebunden ist. Ist das noch nicht der Fall, muss zunächst bestimmt werden, in welches Image das App-Paket integriert werden soll. In einer WIM-Datei können mehrere Windows-Images enthalten sein, die sich mit dem Befehl Get-WindowsImage ermitteln lassen, wie das auch Listing 3 zeigt.Listing 1: Generierung des PackageFullName und des PackageFamilyName
public static string GetPackageFullName(string name, <br/> Version version, string publisher, string <br/> resourceId, PackageArchitecture architecture) <br/>{ <br/> string publisherId = GetPublisherIdFromPublisher(<br/> publisher); <br/> return ($"{name}_{version.ToString()}_{architecture.<br/> ToString()}_{resourceId}_{publisherId}"); <br/>} <br/><br/>public static string GetPackageFamilyName(string name,<br/> string publisher) <br/>{ <br/> string publisherId = GetPublisherIdFromPublisher(<br/> publisher); <br/> return ($"{name}_{publisherId}"); <br/>} <br/><br/>public static string GetPublisherIdFromPublisher(<br/> string publisher) <br/>{ <br/> using (SHA256 sha256Hash = SHA256.Create()) <br/> { <br/> byte[] data = sha256Hash.ComputeHash(<br/> Encoding.Unicode.GetBytes(publisher)); <br/> return Crockbase32.Encode(data, 0, 8).ToLower(); <br/> } <br/>}
Die Referenzierung des zu verwendenden Images kann anschließend über den ImageName oder den ImageIndex erfolgen. Mit dem folgenden Befehl wird das Image von Windows 10 Pro unter Verwendung der Indexangabe in das aktuelle System eingebunden. Der Inhalt des Images kann fortan über den Ordner d:\W10Pro angesprochen werden:
PS C:\> Mount-WindowsImage -ImagePath m:\sources\
install.wim -Index 6 -Path d:\W10Pro
Das entsprechende Anwendungspaket lässt sich durch den bereits bekannten Befehl Add-AppProvisionedPackage dem Image hinzufügen, indem der verknüpfte Ordner über das Argument -Path bestimmt wird. Anschließend sind die Änderungen noch zu persistieren.
PS C:\> Add-AppProvisionedPackage -Path d:\W10Pro
-PackagePath "D:\MSIX\NativeNotepad_2.0.8.0_x64.msix"
-SkipLicense
PS C:\> Save-WindowsImage –Path d:\W10Pro
Der vorherige Speichervorgang durch Save-WindowsImage ist nicht zwingend erforderlich, denn mithilfe des Schalters -Save werden die Änderungen beim Aufheben der Verknüpfung ebenfalls persistiert:
PS C:\> Dismount-WindowsImage -Path d:\W10Pro -Save
Sollen die Änderungen hingegen verworfen werden, ist der Schalter -Discard zu verwenden.
Inventarisierung der Apps
Unabhängig davon, ob die App über die gerade geschilderten Varianten des Sideloadings auf das System gekommen sind oder ob dies über andere Verteilmethoden wie den Windows Store erfolgte, ist eine professionelle Verwaltung der Apps unerlässlich. Nur hierdurch ist es möglich, einen Überblick über die Anzahl, Versionen und Ausprägungen der bereitgestellten Apps sowie der Nutzer zu gewinnen, um in Fehlersituationen entsprechend reagieren zu können.Die für den aktuellen Benutzer installierten Apps lassen sich mit dem PowerShell-Befehl Get-AppPackage abrufen. Über die Parameter -Name, -Publisher und -Volume können diverse Suchkriterien vorgegeben werden, die Jokerzeichen * und ? werden unterstützt. Die gefundenen Apps werden mit den in Bild 6 dargestellten Metainformationen angezeigt:PS C:\> Get-AppPackage -Name Native*
Name : NativeNotepadApp
Publisher : CN=AK
Architecture : X64
ResourceId :
Version : 2.0.8.0
PackageFullName : NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a
InstallLocation : C:\Program Files\WindowsApps\
NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a
IsFramework : False
PackageFamilyName : NativeNotepadApp_yf5adtgdrdj2a
PublisherId : yf5adtgdrdj2a
IsResourcePackage : False
IsBundle : False
IsDevelopmentMode : False
NonRemovable : False
IsPartiallyStaged : False
SignatureKind : Developer
Status : Ok
Bei einer großen Anzahl von Apps ist eine solche Darstellung innerhalb der PowerShell-Konsole eher ungeeignet. Passender ist hierfür eine tabellarische Darstellung, die sich mit dem generischen PowerShell-Argument Out-GridView realisieren lässt, wie das auch in Bild 9 skizziert ist. Zusätzlich zu der übersichtlicheren Darstellung ermöglicht diese Variante ein nachträgliches Filtern der Daten.

Tabellarische Darstellungder gefundenen Apps(Bild 9)
Autor
Unabhängig von den individuell festgelegten Suchkriterien ist das Suchergebnis standardmäßig eingeschränkt, da nur Pakete vom Typ Main und Framework angezeigt werden. Der Parameter -PackageTypeFilter lässt sich verwenden, um den Paket-Typ bei der Suche zu berücksichtigen. Die gültigen Werte sind in Tabelle 2 aufgeführt. Mehrere Werte können durch Kommas getrennt angefügt werden.
PS C:\> Get-AppPackage -Name Native* -PackageTypeFilter
Framework,Main,Optional
Sollen auch Apps für andere Benutzer sichtbar sein, so muss der Befehl Get-AppPackage mit administrativen Privilegien ausgeführt werden. Dem Argument -User ist hierfür der entsprechende Benutzer zuzuweisen, wozu sich die folgenden Formate verwenden lassen:
- Domäne\Benutzername
- Benutzername@fqn.domain.tld
- Benutzername
- SID-Zeichenfolge
PS C:\> Get-AppPackage -Name Native* -AllUsers
(...)
PackageUserInformation : {S-1-5-21-1722224311-169382814-
4001482406-1072 [MSIXTest]: Installed, S-1-5-21-172222
4311-169382814-4001482406-1001 [AK]: Installed}
(...)
Wurde für die App bisher nur die Staging-Phase durchlaufen und steht die Registrierung für einen Benutzer noch aus, so wird dieses ebenfalls durch diese Eigenschaft verdeutlicht:
PackageUserInformation : {S-1-5-18 [S-1-5-18]: Staged}
Verfügt ein Paket über Abhängigkeiten, so werden diese in der Eigenschaft Dependencies angezeigt:
Dependencies : {NativeNotepadConfigFile_1.0.0.
0_x64__yf5adtgdrdj2a}
Bei optionalen Paketen liefert Get-AppPackage keinen Hinweis auf das Hauptpaket. Hier und in anderen Situationen ist die Auswertung der Manifest-Datei einer App nützlich. Zur Bestimmung des Hauptpakets verhilft der folgende Befehl:
PS C:\> (Get-AppPackageManifest -Package
NativeNotepadConfigFile_2.0.8.0_x64__yf5adtgdrdj2a).
Package.Dependencies.MainPackageDependency
Name Publisher
---- ---------
NativeNotepadApp CN=AK
Man kann die provisionierten, also bereitgestellten Pakete auch mit dem Befehl Get-AppxProvisionedPackage ermitteln:
PS C:\> Get-AppxProvisionedPackage -Online
DisplayName : NativeNotepadApp
Version : 2.0.8.0
Architecture : x64
ResourceId :
PackageName : NativeNotepadApp_2.0.8.0_x64__
yf5adtgdrdj2a
Regions :
Der Parameter -Online kennzeichnet wie zuvor erläutert das aktive System. Der Befehl kann analog zu den sonstigen Bereitstellungsbefehlen auch auf Offline-Images abzielen.
Entfernen von Paketen
Am Ende des Lebenszyklus einer App steht gewöhnlich die Deinstallation. Systemweit bereitgestellte Pakete lassen sich durch den Befehl Remove-AppProvisionedPackage entfernen. Nur wenn hierbei auch der Parameter -AllUsers zum Einsatz kommt, erfolgt auch eine vollständige Deinstallation der App für alle Benutzer und ein physisches Löschen der Stage-Daten. Wurde -AllUsers nicht verwendet, wird nur die automatische Registrierung entfernt; die eigentliche Deinstallation ist auf Benutzerebene separat anzustoßen.Der Befehl Remove-AppPackage entfernt die App aus dem spezifizierten Benutzerkonto, unabhängig von der Vorgehensweise der Installation. Der Befehl entfernt auch die zugeordneten Pakete, die dieses Paket als Hauptpaket im Manifest definiert haben. Wird die App von keinem weiteren Benutzer verwendet, werden die Staging-Daten ebenfalls entfernt. Das zu deinstallierende Paket ist hierbei über den PackageFullName zu qualifizieren. Mithilfe des Arguments -User ist die Deinstallation der App auch aus einem anderen Benutzerprofil möglich. Abweichend von Get-AppPackages kann der Benutzername hierbei ausschließlich als SID-Zeichenfolge angegeben werden. Seit Windows 10 Version 1809 steht das Argument -AllUsers zum vollständigen Entfernen der App vom System zur Verfügung. Die Verwendung dieses Arguments oder die Spezifizierung eines anderen Benutzers erfordert administrative Privilegien für die Ausführung.PS C:\> Remove-AppPackage -Package NativeNotepadApp_
2.0.8.0_x64__yf5adtgdrdj2a -AllUsers
Fazit
Die Verwaltung von MSIX-Paketen obliegt der Steuerung und der Überwachung durch das Betriebssystem. Durch diesen zentralen Kontrollmechanismus sind Anforderungen wie Konsistenz der Daten, Stabilität und rückstandsfreie Deinstallation hervorragend umsetzbar. Die Verwendung der Windows PowerShell als zentrales Administrations- und Verwaltungsinstrument ist sehr mächtig und innovativ, sie geht gegenüber den rudimentären Verwaltungsmechanismen des Windows Installers als klarer Punktsieger vom Platz.Fussnoten
- PackageManager Class, http://www.dotnetpro.de/SL2007MSIX1
- Install Windows 10 apps with App Installer, http://www.dotnetpro.de/SL2007MSIX2
- MSIX Deployment Options, http://www.dotnetpro.de/SL2007MSIX3
- Andreas Kerl, MSI + APPX = MSIX, Das Ende einer Ära, dotnetpro 2/2019, Seite 86 ff., http://www.dotnetpro.de/A1902MSIX
- Sysinternals Junction, http://www.dotnetpro.de/SL2007MSIX4
- Douglas Crockford’s Base 32, http://www.dotnetpro.de/SL2007MSIX5
- Crockbase32, http://www.dotnetpro.de/SL2007MSIX6
- App-Installer, http://www.dotnetpro.de/SL2007MSIX7
- Andreas Kerl, MSIX im Unternehmen, Finales Tuning, dotnetpro 10/2019, Seite 58 ff., http://www.dotnetpro.de/A1910MSIXDeveloper
- Microsoft Store für Unternehmen, https://businessstore.microsoft.com