Save-Screenshot.ps1

function Save-Screenshot
{
    <#
    .Synopsis
        Saves a screenshot of a UI element
    .Description
        Saves a screenshot of a WPF UI element to many different file formats
    .Example
        New-Button -FontFamily "Webdings" -Content ([char]0xcf) -FontSize 36 |
            Save-Screenshot -AsPng -outputPath .\LockButton.jpg
    #>

    [CmdletBinding(DefaultParameterSetName='Jpeg')]
    [OutputType([Byte[]], [IO.FileInfo])]
    param(
    # The inputObject
    [Parameter(ValueFromPipeline=$true)]
    [Windows.Media.Visual]
    $InputObject,        
    
    # the pixel format used to save the image
    [Windows.Media.PixelFormat]
    $pixelFormat = [Windows.Media.PixelFormats]::Default,
    
    # The JPEG Quality
    [Parameter(ParameterSetName='Jpeg')]
    [int]$JpegQuality = 100,

    # The dots per inch
    [Alias('DPI')]
    [int]$DotsPerInch = 96,
        
    # If set, will save as a jpeg
    [Parameter(ParameterSetName='Jpeg')]
    [Alias('AsJpg', 'Jpg', 'Jpeg')]
    [switch]
    $AsJpeg,

    # If set, will save as a png
    [Parameter(ParameterSetName='Png')]
    [Alias('Png')]
    [switch]
    $AsPng,
    
    # If set, interlaces the output PNG
    [Parameter(ParameterSetName='Png')]
    [switch]
    $Interlace,
    
    # If set, outputs a BMP
    [Parameter(ParameterSetName='Bmp')]
    [Alias('Bmp')]
    [switch]
    $AsBmp,
    
    # If set, outputs a GIF
    [Parameter(ParameterSetName='Gif')]
    [Alias('Gif')]
    [switch]
    $AsGif,
    
    # If set, outputs a TIFF
    [Parameter(ParameterSetName='Tiff')]
    [Alias('Tiff', 'Tif')]
    [switch]
    $AsTiff,
    
    # Changes the Tiff Compression
    [Parameter(ParameterSetName='Tiff')]
    [Windows.Media.Imaging.TiffCompressOption]
    $TiffCompression ='Zip',
    
    # If set, outputs HDPhoto
    [Parameter(ParameterSetName='Wmp')]
    [Alias('Wmp', 'HDPhoto')]
    [switch]
    $AsWmp,
    
    # If set, returns the item as a frame
    [Parameter(ParameterSetName='Frame')]
    [switch]
    $AsFrame,
    
    # The output path. If this is not set, it will be saved to a randomly named file in the
    # current directory.
    [string]$OutputPath,
    
    # If set, will output bytes instead of a file
    [switch]$InMemory,
    
    # The amount of time to wait before closing the window
    [Timespan]
    $ScreenShotTimer = 10
    )
    
    process {
        #region Process Parameters Before Launching UI
        if ($psCmdlet.ParameterSetName -eq 'Jpeg') {
            $psBoundParameters.AsJpeg = $true
            $asJpeg = $true
        } 
        $psBoundParameters."As$($psCmdlet.ParameterSetName)" = $true
        if (-not $psBoundParameters.PixelFormat) {
            $psBoundParameters.PixelFormat  = $pixelFormat
        }
        if (-not $psBoundParameters.DotsPerInch) {
            $psBoundParameters.DotsPerInch  = $DotsPerInch
        }
        if (-not $psBoundParameters.JpegQuality) {
            $psBoundParameters.JpegQuality = $jpegQuality
        }
        if (-not $psBoundParameters.TiffCompression) {
            $psBoundParameters.TiffCompression = $tiffCompression 
        }
        
        if (-not $psBoundParameters.OutputPath) {
            if ($asJpeg) {
                $psBoundParameters.OutputPath = Join-Path $pwd "Screenshot.$(Get-Random).jpeg"
            } elseif ($asPng) {
                $psBoundParameters.OutputPath = Join-Path $pwd "Screenshot.$(Get-Random).png"
            } elseif ($asbmp) {
                $psBoundParameters.OutputPath = Join-Path $pwd "Screenshot.$(Get-Random).bmp"
            } elseif ($astiff) {
                $psBoundParameters.OutputPath = Join-Path $pwd "Screenshot.$(Get-Random).tiff"
            } elseif ($aswmp) {
                $psBoundParameters.OutputPath = Join-Path $pwd "Screenshot.$(Get-Random).wmp"
            } elseif ($asgif) {
                $psBoundParameters.OutputPath = Join-Path $pwd "Screenshot.$(Get-Random).gif"
            } elseif ($asFrame) {
                $psBoundParameters.OutputPath = $null
            } elseif ($InMemory) {
                $psBoundParameters.OutputPath = $null
            }
            
        } else {
            $psBoundParameters.OutputPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($psBoundParameters.OutputPath)
            
        }
        #endregion
        
        foreach ($kv in $psBoundParameters.GetEnumerator()) {
            $inputObject.Resources[$kv.Key] = $kv.Value
        }


        if ($Window) {
            # Already in ShowUI

        } else {

        $inputObject.Resources['ScreenshotTimer'] = $screenShotTimer
        $inputObject |
            Add-EventHandler -EventName On_SizeChanged -Handler {
            if ($_.PreviousSize.Width -eq 0 -and $_.PreviousSize.Height -eq 0) {
                
                $visual = $This
                $window | Add-EventHandler -EventName On_LocationChanged -Handler { $window.Close() } 
                $waitScript = [ScriptBlock]::Create("
                    Start-Sleep -Milliseconds $($ScreenshotTimer.TotalMilliseconds); `$true
                "
)
                
                $this.DataContext = Get-PowerShellDataSource -On_OutputChanged {
                    $visual = $This
                    if (-not $visual.Background -and 
                        -not ($AsPng -or $AsGif)) {
                        if ($visual -and $visual.GetType().GetProperty("Background")) {
                            try {
                                # $visual.Background = "White"
                            } catch {
                            
                            }
                        }
                    }
                    if (-not $DotsPerInch) { $DotsPerInch  = 72 } 
                    $visual.UpdateLayout()
                    $actualWidth = $visual.ActualWidth
                    $actualHeight = $visual.ActualHeight
                    #$visual | select *height* | Out-Host
                    #$actualWidth, $actualHeight, $DotsPerInch | Out-Host
                    $renderBitmap = 
                        New-Object Windows.Media.Imaging.RenderTargetBitmap $actualWidth , $actualHeight, $DotsPerInch, $DotsPerInch, ([Windows.Media.PixelFormats]::Pbgra32)
                    $sourceBrush = New-Object Windows.Media.VisualBrush $visual
                    #$sourceBrush | Out-Host
                    $drawingVisual = New-Object Windows.Media.DrawingVisual 
                    
                    $drawingContext = $drawingVisual.RenderOpen()
                    $rect = New-Object Windows.Rect ((New-Object Windows.Point),(
                        New-Object Windows.Point $actualWidth, $actualHeight
                    ))
                    
                    $drawingContext.DrawRectangle($sourceBrush, $null, $rect)

                    $drawingContext.Close()
                    $renderBitmap.Render($drawingVisual)
                    $frame =[Windows.Media.Imaging.BitmapFrame]::Create($renderBitmap)

                    $fileOrInMemory = {
                        param($this, $encoder, $inMemory, $outputPath) 
                        $null = $encoder.Frames.Add($frame)          
                        if ($InMemory) {                        
                            $memStream = New-Object IO.MemoryStream
                            $encoder.Save($memStream) 
                            $memStream.Seek(0,0)
                            $bytes = New-Object Byte[] $memStream.Length
                            $memStream.Read($bytes, 0, $memStream.Length)                        
                            $this.Parent.Tag = $bytes
                        } else {
                            $fileStream = [IO.File]::Create($outputPath)                               
                            $encoder.Save($fileStream) 
                            $fileStream.Close()               
                        }
                    }
                    
                    if ($AsJpeg) {
                        $jpegEncoder = New-Object Windows.Media.Imaging.JpegBitmapEncoder
                        $jpegEncoder.QualityLevel = $jpegquality                    
                        & $fileOrInMemory $this $jpegEncoder $inMemory $outputPath                    
                    } elseif ($AsPng) {                    
                        $pngEncoder = New-Object Windows.Media.Imaging.PngBitmapEncoder
                        if ($interlace) {
                            $pngEncoder.Interlace = 'On'
                        }
                        & $fileOrInMemory $this $pngEncoder $inMemory $outputPath                                                            
                    } elseif ($AsBmp) {                    
                        $bmpEncoder = New-Object Windows.Media.Imaging.BmpBitmapEncoder                    
                        & $fileOrInMemory $this $bmpEncoder $inMemory $outputPath      
                    } elseif ($asTiff) {
                        $TiffEncoder = New-Object Windows.Media.Imaging.TiffBitmapEncoder
                        $TiffEncoder.Compression = $TiffCompression
                        & $fileOrInMemory $this $TiffEncoder $inMemory $outputPath      
                    } elseif ($asgif) {
                        $GifEncoder = New-Object Windows.Media.Imaging.GifBitmapEncoder
                        & $fileOrInMemory $this $GifEncoder $inMemory $outputPath      
                    } elseif ($aswmp) {
                        $WmpEncoder = New-Object Windows.Media.Imaging.WmpBitmapEncoder
                        & $fileOrInMemory $this $WmpEncoder $inMemory $outputPath      
                    } elseif ($AsFrame) {
                        $frame
                        $this.Parent.Tag = $frame
                    } 


                    $window.Close()
                } -Script $waitScript
            }
        }
        
        $bytes = $inputObject | Show-Window -WindowProperty @{Sizetocontent='WidthAndHeight'; Top = -10000; Left = -10000}
        }
        if ($byteS -and ($InMemory -or $asFrame)) { 
            $bytes
        }
        
        $params = $psBoundParameters     
        if ($psBoundparameters.OutputPath) {   
            Get-Item -ErrorAction SilentlyContinue $psBoundParameters.OutputPath                        
        }
    }
}