-
-
Save BenjaminArmstrong/e6e4c771b5553b6c15788a3406feb934 to your computer and use it in GitHub Desktop.
$VMName = "VM 1" | |
$BMPName = "C:\Users\benja\Desktop\test.bmp" | |
Add-Type -AssemblyName "System.Drawing" | |
$VMCS = Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -Filter "ElementName='$($VMName)'" | |
# Get the resolution of the screen at the moment | |
$video = $VMCS.GetRelated("Msvm_VideoHead") | |
$xResolution = $video.CurrentHorizontalResolution[0] | |
$yResolution = $video.CurrentVerticalResolution[0] | |
function getVMScreenBMP { | |
param | |
( | |
$VM, | |
$x, | |
$y | |
) | |
$VMMS = Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_VirtualSystemManagementService | |
# Get screenshot | |
$image = $VMMS.GetVirtualSystemThumbnailImage($VMCS, $x, $y).ImageData | |
# Transform into bitmap | |
$BitMap = New-Object System.Drawing.Bitmap -Args $x,$y,Format16bppRgb565 | |
$Rect = New-Object System.Drawing.Rectangle 0,0,$x,$y | |
$BmpData = $BitMap.LockBits($Rect,"ReadWrite","Format16bppRgb565") | |
[System.Runtime.InteropServices.Marshal]::Copy($Image, 0, $BmpData.Scan0, $BmpData.Stride*$BmpData.Height) | |
$BitMap.UnlockBits($BmpData) | |
return $BitMap | |
} | |
(getVMScreenBMP $VMCS $xResolution $yResolution).Save($BMPName) |
Good point - I have updated to code to be cleaner on scoping
I have an error with a new version of the script:
"A Using variable cannot be retrieved. A Using variable can be used only with Invoke-Command, Start-Job, or InlineScript in the script workflow. When it is used with Invoke-Command, the Using variable is valid only if the script block is invoked on a remote computer."
I have Powershell v5.0.10586.117 on the host (2012 R2) and 2012 R2 guest from Image Factory (https://github.com/BenjaminArmstrong/Hyper-V-PowerShell/tree/master/Image-Factory)
Gah! Okay, take three. This one should work.
Perfect! Thank you.
Awesome, works great still on Server 2019 :)
This is supposed to be run on the host machine, not inside the guest machine, right?
I can confirm this works on Windows PowerShell, but not modern PowerShell (powershell.exe
, not pwsh.exe
), at least on my machine. This is awesome!
EDIT (18 June 2024): The code as-is only works in Windows PowerShell, but that's because there are newer APIs for using WMI/CIM in modern PowerShell.
For my purposes, I used runspaces to continue using the old APIs, but you can see a modern implementation in strawgate's HyperV-OCR project (a friend found that for me).
Runspace alternative:
$s = New-PSSession -UseWindowsPowerShell
Invoke-Command -Session $s -ScriptBlock {
# Call above code, basically.
#
# If you want to reference external variables:
# $MyVar becomes $using:MyVar
}
As a PowerShell best practice you shouldn't really reference variables outside the function scope. Here's my fork of your script, although I'm still testing a few things. https://gist.github.com/jdhitsolutions/78d71ceeefb54675a7c53a13ac861780