Tyler Southard
Tyler Southard

Reputation: 165

How to provision a UWP app using powershell from a non-elevated .NET app

I have a .NET 4.6.2 app that needs to add a provisioned UWP app. The current plan is to use Process.Start() to launch powershell. Assume the UWP app is present at the exe path as "test.appx".

Here's the code:

var psi = new ProcessStartInfo
{
    UseShellExecute = true,
    CreateNoWindow = false,
    Arguments = "Add-AppxProvisionedPackage -Online -PackagePath test.appx -SkipLicense",
    WindowStyle = ProcessWindowStyle.Hidden,
    FileName = "powershell.exe",
    Verb = "runas"
};

var proc = Process.Start(psi);

I'm using the runas verb because provisioning commands require elevation.

The process starts without throwing, but the app does not get provisioned, and if I use proc.WaitForExit() and check the ExitCode, it returns error code 1.

If I use a manifest to require the host app to have elevated rights, it does work, but I would prefer to not require elevation to run the host app.

I'm wondering if there's something wrong with how I'm setting up the ProcessStartInfo? Or otherwise if there's a way to temporarily elevate the host process?

Upvotes: 0

Views: 290

Answers (2)

Mitch
Mitch

Reputation: 22251

You can also add the package by directly calling the undocumented DismAddProvisionedAppxPackage API. (Standard warnings about using undocumented API's apply).

P/Invoke:

[DllImport("dismapi.dll", PreserveSig = false)]
public static extern void DismAddProvisionedAppxPackage(
    uint Session,
    [MarshalAs(UnmanagedType.LPWStr)] string AppPath, 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr, SizeParamIndex=3)] string[] DependencyPackages, 
    uint DependencyPackageCount, 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr, SizeParamIndex=5)] string[] OptionalPackages, 
    uint OptionalPackageCount, 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr, SizeParamIndex=7)] string[] LicensePaths, 
    uint LicensePathCount, 
    bool SkipLicense, 
    [MarshalAs(UnmanagedType.LPWStr)] string CustomDataPath, 
    [MarshalAs(UnmanagedType.LPWStr)] string Regions, 
    int stubPackageOption
);

This is also available from ManagedDism (MIT License, Nuget)

using var sess = DismApi.OpenOnlineSession();
DismApi.AddProvisionedAppxPackage(sess, @"c:\foo\bar.appx", null, null, null!);

Upvotes: 0

Julien
Julien

Reputation: 447

When you run powershell.exe as an admin, it does not use the current folder as its starting folder, but instead goes under C:\WINDOWS\system32.

Therefore, it's impossible to find the test.appx file.

This should work:

        var pathToAppx = Path.Combine(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "test.msixbundle");
        var psi = new ProcessStartInfo
        {
            UseShellExecute = true,
            CreateNoWindow = false,
            Arguments = $@"-NoExit &""Add-AppxProvisionedPackage -Online -PackagePath {pathToAppx} -SkipLicense;""",
            WindowStyle = ProcessWindowStyle.Normal,
            FileName = "powershell.exe",
            Verb = "runas"
        };

        var proc = Process.Start(psi);

        proc.WaitForExit();

In my example I used an msixbundle that I already had at my disposal, but it should not impact.

Upvotes: 1

Related Questions