#Requires -Version 5.1
<#
.SYNOPSIS
Shows a WPF notification popup for the OBS Replay Buffer tool.
Must be launched via Start-Process with powershell.exe -STA.
.PARAMETER Type
'BufferStarted' — shown at logon when the replay buffer is active.
'ReplaySaved' — shown after a successful replay save.
#>
param(
[Parameter(Mandatory)]
[ValidateSet('BufferStarted', 'ReplaySaved')]
[string]$Type,
[string]$ContactNumber = '',
[int]$BufferMinutes = 0,
[string]$FileName = '',
[double]$FileSizeMB = 0
)
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class GdiHelper {
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
}
"@
$hBitmap = [System.Drawing.SystemIcons]::Shield.ToBitmap().GetHbitmap()
$wpfShield = [System.Windows.Interop.Imaging]::CreateBitmapSourceFromHBitmap(
$hBitmap, [IntPtr]::Zero, [System.Windows.Int32Rect]::Empty,
[System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()
)
[GdiHelper]::DeleteObject($hBitmap) | Out-Null
$hBitmap = [System.Drawing.SystemIcons]::Warning.ToBitmap().GetHbitmap()
$wpfWarning = [System.Windows.Interop.Imaging]::CreateBitmapSourceFromHBitmap(
$hBitmap, [IntPtr]::Zero, [System.Windows.Int32Rect]::Empty,
[System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()
)
[GdiHelper]::DeleteObject($hBitmap) | Out-Null
if ($Type -eq 'BufferStarted') {
[xml]$xaml = @"
"@
$window = [System.Windows.Markup.XamlReader]::Load([System.Xml.XmlNodeReader]::new($xaml))
$imgHeader = $window.FindName('ImgHeader')
$imgTray = $window.FindName('ImgTray')
$txtBody = $window.FindName('TxtBody')
$txtContact = $window.FindName('TxtContact')
$btnOK = $window.FindName('BtnOK')
$imgHeader.Source = $wpfWarning
$imgTray.Source = $wpfShield
$txtContact.Text = "Questions? Contact IT at $ContactNumber"
$txtBody.Inlines.Add("Your screen is being recorded into a rolling $BufferMinutes-minute replay buffer. Nothing is saved until you request it.`n`n")
$bold0 = New-Object System.Windows.Documents.Run('Open the application you want to capture on this screen.')
$bold0.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold0)
$txtBody.Inlines.Add("`n`nTo save a clip, ")
$bold1 = New-Object System.Windows.Documents.Run('right-click the shield icon')
$bold1.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold1)
$txtBody.Inlines.Add(' in your system tray (bottom-right of your screen) and select ')
$bold2 = New-Object System.Windows.Documents.Run('Save Replay')
$bold2.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold2)
$txtBody.Inlines.Add('.')
} else {
[xml]$xaml = @"
"@
$window = [System.Windows.Markup.XamlReader]::Load([System.Xml.XmlNodeReader]::new($xaml))
$imgHeader = $window.FindName('ImgHeader')
$txtBody = $window.FindName('TxtBody')
$txtContact = $window.FindName('TxtContact')
$btnOK = $window.FindName('BtnOK')
$imgHeader.Source = $wpfShield
$txtContact.Text = "Questions? Contact IT at $ContactNumber"
$txtBody.Inlines.Add("Your replay has been saved ($FileSizeMB MB):`n")
$bold1 = New-Object System.Windows.Documents.Run($FileName)
$bold1.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold1)
$txtBody.Inlines.Add("`n`nIT can retrieve this file if needed for a support case.")
}
if ($Type -eq 'ReplaySaved') {
# Countdown timer — auto-dismisses after 30 seconds
# Use a hashtable for shared state so the closure captures it by reference correctly
$state = @{ Tick = 30 }
$btnOK.Content = 'OK (30)'
$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromSeconds(1)
$timer.Add_Tick({
$state.Tick--
$btnOK.Content = "OK ($($state.Tick))"
if ($state.Tick -le 0) {
$timer.Stop()
$window.Close()
}
}.GetNewClosure())
$timer.Start()
$btnOK.Add_Click({ $timer.Stop(); $window.Close() }.GetNewClosure())
} else {
$btnOK.Content = 'OK'
$btnOK.Add_Click({ $window.Close() }.GetNewClosure())
}
# Center on the primary monitor (the one OBS is recording)
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
$window.Add_Loaded({
$window.Left = $screen.Left + ($screen.Width - $window.ActualWidth) / 2
$window.Top = $screen.Top + ($screen.Height - $window.ActualHeight) / 2
}.GetNewClosure())
$window.ShowDialog() | Out-Null