Using a UWP API Namespace in PowerShell

I was looking for how to use a namespace for working with the Windows 10 lock screen in PowerShell and came across this answer: https://superuser.com/a/1062551/700258, however it doesn't say anything about how to import or add that namespace to PowerShell for use. I tried looking for the referenced DLL files for the assemblies and they weren't on my computer. When I see they are part of the Windows Desktop Extensions API, I went out and downloaded the Windows 10 SDK, but the DLL files were not within that either. How can I use this LockScreen Class from the Windows.System.UserProfile namespace in a PowerShell script?


Solution 1:

First you need to tell PowerShell that you want to use a UWP class:

[Windows.System.UserProfile.LockScreen,Windows.System.UserProfile,ContentType=WindowsRuntime] | Out-Null

The first part is the class name, the second is the UWP namespace, and the third just says that it's a UWP class. After the type is loaded, you can refer to the type by its name (just the first part: [Windows.System.UserProfile.LockScreen] in this case.)

The next trick is that Windows Runtime methods are asynchronous and use a different async task class than .NET Framework methods. Calling them from PowerShell requires a little extra infrastructure that I originally developed for another answer:

Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
    $asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
    $netTask = $asTask.Invoke($null, @($WinRtTask))
    $netTask.Wait(-1) | Out-Null
    $netTask.Result
}
Function AwaitAction($WinRtAction) {
    $asTask = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and !$_.IsGenericMethod })[0]
    $netTask = $asTask.Invoke($null, @($WinRtAction))
    $netTask.Wait(-1) | Out-Null
}

Await can be used to call functions that return an IAsyncOperation, i.e. those that produce a value. It takes the WinRT task object and the type of the output. AwaitAction can be used to call functions that return an IAsyncAction, i.e. those that just do something without returning a result. It takes only the WinRT task object.

For this application, we're going to need the StorageFile type accessible too:

[Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime] | Out-Null

Now we can start calling some functions. First we use GetFileFromPathAsync to get an IStorageFile instance of the desired lock screen image:

$image = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync('C:\path\to\image.ext')) ([Windows.Storage.StorageFile])

Finally, we pass that image to SetImageFileAsync to set the lock screen background:

AwaitAction ([Windows.System.UserProfile.LockScreen]::SetImageFileAsync($image))

Changes should take effect immediately.