How may my Hyper-V host remotely execute an elevated program on its guest running Windows 11?
I’m authoring some tooling to manage a GUI test program on a Hyper-V guest running Windows 11. Ideally this VM will not have network access so I’m trying to avoid approaches such as installing a service on the VM that will listen for commands over the network.
I’ve discovered that Microsoft has PowerShell commands specifically for Hyper-V and so far I’ve been able to manage everything else I’ve needed about the VM. I’ve also had good success using Windows UI Automation for the GUI testing locally. But I’ve been having a difficult time executing the GUI test program remotely on the VM. The root of the difficulty appears to be the fact that administrator privileges on the remote target are required in order to remotely launch an application that can interact with the input desktop on the remote target. And so I believe that I need a way to establish a remote PowerShell session into the VM with administrator rights on the VM.
The most promising approach I’ve tried so far is to copy PsExec onto the VM, then on the host run the PowerShell command New-PSSession
, then pass that session object into the Enter-Session
command, then execute PsExec
in that session. But that fails because “The requested operation requires elevation”:
PS> New-PSSession -VMName "Windows 11" | Enter-PSSession
[Windows 11]: PS C:UsersuserDocuments> .PsExec.exe .test.exe -i -h -accepteula
PsExec could not start test.exe:
The requested operation requires elevation.
I see that New-PSSession
has a -RunAsAdministrator
parameter, but that parameter is only valid with the -ContainerId
parameter which is a Docker thing. After digging into Microsoft’s source code I can see that ultimately boils down to telling vmcompute.dll
to create a process with "RestrictedToken": false
. So that won’t work here.
I’ve also tried connecting a different way. Microsoft’s PowerShell SDK has a VMConnectionInfo
class that can be used as the connection info for a call to RunspaceFactory.CreateRunspace
. From there I can construct a PowerShell
object in C#:
// Thanks, Microsoft, for making this constructor be internal
var constructorInfo = typeof(VMConnectionInfo).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
[ typeof(PSCredential), typeof(Guid), typeof(string), typeof(string) ]
) ?? throw new Exception("Cannot find the constructor");
var connectionInfo = (VMConnectionInfo)constructorInfo.Invoke([
credential, // A PSCredential object constructed with the username and password of an administrator account on the VM
vmId, // The VM's GUID
null, // The VM's name. Null here since I'm using the GUID
null // "configurationName: Configuration name of the VM session"
]);
using var runspace = RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
using var ps = PowerShell.Create(runspace);
…and once I have the PowerShell
object I can run commands like Start-Process
to launch PsExec.exe
on the VM with the parameters shown above.
But I still get the same error from PsExec:
PsExec could not start test.exe:
The requested operation requires elevation.
I’m unfamiliar with the Hyper-V WMI provider. Would this be possible to achieve through those interfaces?