Powershell: Implementing Automated Screenshots

I needed screenshot functionality for my testing framework. Typically when something fails, I have most of the environment variables to investigate along with the error codes, but a screenshot gives additional context, particularly in my browser automation stuff. There is no native command to do this in Powershell v2.

So, I combined three different scripts I found while trying to sort out screenshot functionality to create some code that:

  1. Brings a existing process’s window to the foreground (can’t take a screenshot of it if we can’t see it obviously).
  2. Calculates the dimensions of the window.
  3. Uses the calculated dimensions to take a screenshot and write it to a file (C:\MyFancyScreenshot.bmp in this example).
$handle = (Get-Process -Name notepad).MainWindowHandle

You will need to narrow this down to make sure you get exactly what you want. It’s going to fail if you have multiple instances of notepad open. Take a look at these links if you’d like additional context.

https://blogs.technet.microsoft.com/heyscriptingguy/2015/12/26/weekend-scripter-manage-window-placement-by-using-pinvoke/
https://www.adminarsenal.com/blog/capturing-screenshots-with-powershell-and-net/
http://stackoverflow.com/questions/2556872/how-to-set-foreground-window-from-powershell-event-subscriber-action

Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    public class Window {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    }
 
    public struct RECT
    {
    public int Left;        // x position of upper-left corner
    public int Top;         // y position of upper-left corner
    public int Right;       // x position of lower-right corner
    public int Bottom;      // y position of lower-right corner
    }
"@
 
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@
 
$handle = (Get-Process -Name notepad).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($handle)
$Rectangle = New-Object RECT
[Window]::GetWindowRect($Handle,[ref]$Rectangle)
$File = "C:\MyFancyScreenshot.bmp"
Add-Type -AssemblyName System.Windows.Forms
Add-type -AssemblyName System.Drawing
# Gather Screen resolution information
$Screen = [System.Windows.Forms.SystemInformation]::VirtualScreen
$width = $rectangle.right - $rectangle.left
$height = $rectangle.bottom - $rectangle.top
$left = $rectangle.left
$top = $rectangle.top
# Create bitmap using the top-left and bottom-right bounds
$bitmap = New-Object System.Drawing.Bitmap $Width, $Height
# Create Graphics object
$graphic = [System.Drawing.Graphics]::FromImage($bitmap)
# Capture screen
$graphic.CopyFromScreen($Left, $Top, 0, 0, $bitmap.Size)
# Save to file
$bitmap.Save($File)
Write-Output "Screenshot saved to:"
Write-Output $File

Leave a Reply

Your email address will not be published. Required fields are marked *