Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing [System.Windows.Forms.Application]::EnableVisualStyles() # ========== Native SendInput (Keyboard / Scancode) ========== Add-Type -Language CSharp @' using System; using System.Runtime.InteropServices; public static class ScanInput { [StructLayout(LayoutKind.Sequential)] public struct INPUT { public uint type; public InputUnion U; } [StructLayout(LayoutKind.Explicit)] public struct InputUnion { [FieldOffset(0)] public MOUSEINPUT mi; [FieldOffset(0)] public KEYBDINPUT ki; [FieldOffset(0)] public HARDWAREINPUT hi; } [StructLayout(LayoutKind.Sequential)] public struct MOUSEINPUT { public int dx, dy; public uint mouseData, dwFlags, time; public IntPtr dwExtraInfo; } [StructLayout(LayoutKind.Sequential)] public struct KEYBDINPUT { public ushort wVk, wScan; public uint dwFlags, time; public IntPtr dwExtraInfo; } [StructLayout(LayoutKind.Sequential)] public struct HARDWAREINPUT { public uint uMsg; public ushort wParamL, wParamH; } private const uint INPUT_KEYBOARD = 1; private const uint KEYEVENTF_SCANCODE = 0x0008; private const uint KEYEVENTF_KEYUP = 0x0002; private const uint KEYEVENTF_EXTENDEDKEY = 0x0001; private const uint MAPVK_VK_TO_VSC_EX = 0x04; [DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); [DllImport("user32.dll")] private static extern short VkKeyScanExW(char ch, IntPtr dwhkl); [DllImport("user32.dll")] private static extern uint MapVirtualKeyEx(uint code, uint mapType, IntPtr dwhkl); [DllImport("user32.dll")] private static extern IntPtr GetKeyboardLayout(uint threadId); public static bool TryGetScanAndMods( char ch, out ushort scan, out bool needShift, out bool needLCtrl, out bool needRAltExt, out bool ext, out bool isDeadKey) { scan = 0; needShift = false; needLCtrl = false; needRAltExt = false; ext = false; isDeadKey = false; IntPtr hkl = GetKeyboardLayout(0); short result = VkKeyScanExW(ch, hkl); if (result == -1) return false; byte vk = (byte)(result & 0xFF); byte sh = (byte)((result >> 8) & 0xFF); needShift = (sh & 1) != 0; bool ctrl = (sh & 2) != 0; bool alt = (sh & 4) != 0; needLCtrl = ctrl || alt; needRAltExt = alt; uint scEx = MapVirtualKeyEx(vk, MAPVK_VK_TO_VSC_EX, hkl); if (scEx == 0) return false; ext = (scEx & 0x100) != 0; scan = (ushort)(scEx & 0xFF); if (ch == '^' || ch == '`') isDeadKey = true; return true; } private static void SendKey(ushort scan, bool ext, bool up) { INPUT[] inp = new INPUT[1]; inp[0].type = INPUT_KEYBOARD; inp[0].U.ki.wVk = 0; inp[0].U.ki.wScan = scan; uint flags = KEYEVENTF_SCANCODE; if (ext) flags |= KEYEVENTF_EXTENDEDKEY; if (up) flags |= KEYEVENTF_KEYUP; inp[0].U.ki.dwFlags = flags; inp[0].U.ki.time = 0; inp[0].U.ki.dwExtraInfo = IntPtr.Zero; uint sent = SendInput(1, inp, Marshal.SizeOf(typeof(INPUT))); if (sent == 0) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } public static void ModDown_LCtrl() { SendKey(0x1D, false, false); } public static void ModUp_LCtrl() { SendKey(0x1D, false, true); } public static void ModDown_LShift() { SendKey(0x2A, false, false); } public static void ModUp_LShift() { SendKey(0x2A, false, true); } public static void ModDown_RAlt() { SendKey(0x38, true, false); } public static void ModUp_RAlt() { SendKey(0x38, true, true); } public static void SendCharByScan(char ch, int delayMs) { ushort scan; bool needShift, needLCtrl, needRAltExt, ext, isDeadKey; if (!TryGetScanAndMods(ch, out scan, out needShift, out needLCtrl, out needRAltExt, out ext, out isDeadKey)) throw new InvalidOperationException("Char not representable in current layout: " + ch); if (needLCtrl) ModDown_LCtrl(); if (needRAltExt) ModDown_RAlt(); if (needShift) ModDown_LShift(); if (isDeadKey) { SendKey(scan, ext, false); SendKey(scan, ext, true); SendKey(0x39, false, false); SendKey(0x39, false, true); } else { SendKey(scan, ext, false); SendKey(scan, ext, true); } if (needShift) ModUp_LShift(); if (needRAltExt) ModUp_RAlt(); if (needLCtrl) ModUp_LCtrl(); } } '@ # ========== Clipboard helpers (native Win32, kein STA erforderlich) ========== # Klassenname WinClip — eindeutig, kollidiert nicht mit alten Add-Type-Caches if (-not ('WinClip' -as [type])) { Add-Type -Language CSharp @' using System; using System.Runtime.InteropServices; public static class WinClip { // ── Read ────────────────────────────────────────────────────────────────── [DllImport("user32.dll", SetLastError=true)] public static extern bool OpenClipboard(IntPtr h); [DllImport("user32.dll", SetLastError=true)] public static extern bool CloseClipboard(); [DllImport("user32.dll", SetLastError=true)] public static extern IntPtr GetClipboardData(uint format); [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern uint RegisterClipboardFormat(string name); [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr GlobalLock(IntPtr h); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool GlobalUnlock(IntPtr h); [DllImport("kernel32.dll", SetLastError=true)] public static extern UIntPtr GlobalSize(IntPtr h); // ── Write ───────────────────────────────────────────────────────────────── [DllImport("user32.dll", SetLastError=true)] public static extern bool EmptyClipboard(); [DllImport("user32.dll", SetLastError=true)] public static extern IntPtr SetClipboardData(uint format, IntPtr hMem); [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes); public const uint CF_UNICODETEXT = 13; public const uint GMEM_MOVEABLE = 0x0002; } '@ } function Get-ClipboardRaw { $text = "" if ([WinClip]::OpenClipboard([IntPtr]::Zero)) { $h = [WinClip]::GetClipboardData([WinClip]::CF_UNICODETEXT) if ($h -ne [IntPtr]::Zero) { $p = [WinClip]::GlobalLock($h) if ($p -ne [IntPtr]::Zero) { $text = [Runtime.InteropServices.Marshal]::PtrToStringUni($p) [WinClip]::GlobalUnlock($h) | Out-Null } } [WinClip]::CloseClipboard() | Out-Null } return $text } function Set-ClipboardMultiFormat { # Schreibt mehrere Clipboard-Formate auf einmal via natives Win32. # Exakte Encodings: # CF_UNICODETEXT → UTF-16LE + Null # Rich Text Format → ANSI (Default) + Null # HTML Format → UTF-8 + Null ← WinForms DataObject macht das falsch (UTF-16) param( [string]$PlainText = "", [string]$RtfString = "", [string]$HtmlString = "" ) # Bytes in GMEM_MOVEABLE-Block schreiben, Handle zurückgeben function AllocBlock([byte[]]$bytes) { $hMem = [WinClip]::GlobalAlloc([WinClip]::GMEM_MOVEABLE, [UIntPtr][uint64]$bytes.Length) if ($hMem -eq [IntPtr]::Zero) { return [IntPtr]::Zero } $ptr = [WinClip]::GlobalLock($hMem) if ($ptr -eq [IntPtr]::Zero) { return [IntPtr]::Zero } [Runtime.InteropServices.Marshal]::Copy($bytes, 0, $ptr, $bytes.Length) [WinClip]::GlobalUnlock($hMem) | Out-Null return $hMem } if (-not [WinClip]::OpenClipboard([IntPtr]::Zero)) { return $false } [WinClip]::EmptyClipboard() | Out-Null if (![string]::IsNullOrEmpty($PlainText)) { $bytes = [System.Text.Encoding]::Unicode.GetBytes($PlainText + [char]0) $hMem = AllocBlock $bytes if ($hMem -ne [IntPtr]::Zero) { [WinClip]::SetClipboardData([WinClip]::CF_UNICODETEXT, $hMem) | Out-Null } } if (![string]::IsNullOrEmpty($RtfString)) { $bytes = [System.Text.Encoding]::Default.GetBytes($RtfString + [char]0) $fmt = [WinClip]::RegisterClipboardFormat("Rich Text Format") $hMem = AllocBlock $bytes if ($hMem -ne [IntPtr]::Zero) { [WinClip]::SetClipboardData($fmt, $hMem) | Out-Null } } if (![string]::IsNullOrEmpty($HtmlString)) { # CF_HTML muss UTF-8 sein $bytes = [System.Text.Encoding]::UTF8.GetBytes($HtmlString + [char]0) $fmt = [WinClip]::RegisterClipboardFormat("HTML Format") $hMem = AllocBlock $bytes if ($hMem -ne [IntPtr]::Zero) { [WinClip]::SetClipboardData($fmt, $hMem) | Out-Null } } [WinClip]::CloseClipboard() | Out-Null return $true } function Get-ClipboardFormat { # Liest ein beliebiges benanntes Clipboard-Format als String. # RTF → ANSI (Encoding = "Default") # HTML → UTF-8 (Encoding = "UTF8") param( [Parameter(Mandatory=$true)][string]$FormatName, [string]$Encoding = "Default" ) $result = "" $fmt = [WinClip]::RegisterClipboardFormat($FormatName) if ($fmt -eq 0) { return $result } if ([WinClip]::OpenClipboard([IntPtr]::Zero)) { $h = [WinClip]::GetClipboardData($fmt) if ($h -ne [IntPtr]::Zero) { $p = [WinClip]::GlobalLock($h) if ($p -ne [IntPtr]::Zero) { $size = [WinClip]::GlobalSize($h).ToUInt64() if ($size -gt 0) { $bytes = New-Object byte[] ([int]$size) [Runtime.InteropServices.Marshal]::Copy($p, $bytes, 0, [int]$size) $nullIdx = [Array]::IndexOf($bytes, [byte]0) if ($nullIdx -gt 0) { $bytes = $bytes[0..($nullIdx - 1)] } $enc = if ($Encoding -eq "UTF8") { [System.Text.Encoding]::UTF8 } ` else { [System.Text.Encoding]::Default } $result = $enc.GetString($bytes) } [WinClip]::GlobalUnlock($h) | Out-Null } } [WinClip]::CloseClipboard() | Out-Null } return $result } # ========== Keyboard helpers ========== function Type-Char { param([Parameter(Mandatory=$true)][char]$Char, [int]$DelayMs = 15) [ScanInput]::SendCharByScan($Char, $DelayMs) if ($DelayMs -gt 0) { Start-Sleep -Milliseconds $DelayMs } } function Type-ScancodeText { param([Parameter(Mandatory=$true)][string]$Text, [int]$DelayMs = 15) if ([string]::IsNullOrEmpty($Text)) { return } $normalized = $Text -replace "`r`n","`n" -replace "`r","`n" foreach ($c in $normalized.ToCharArray()) { switch ($c) { "`n" { [ScanInput]::SendCharByScan([char]0x0D, $DelayMs); if ($DelayMs -gt 0) { Start-Sleep -Milliseconds $DelayMs }; continue } "`t" { [ScanInput]::SendCharByScan([char]0x09, $DelayMs); if ($DelayMs -gt 0) { Start-Sleep -Milliseconds $DelayMs }; continue } "`b" { [ScanInput]::SendCharByScan([char]0x08, $DelayMs); if ($DelayMs -gt 0) { Start-Sleep -Milliseconds $DelayMs }; continue } default { Type-Char -Char $c -DelayMs $DelayMs } } } } # ========== HTML-Hilfsfunktionen ========== function New-CfHtml { # Baut einen gültigen CF_HTML-String mit korrekten UTF-8-Byte-Offsets im Header. # OneNote, Outlook etc. erwarten exakt dieses Format. param([string]$HtmlFragment) $enc = [System.Text.Encoding]::UTF8 $pre = "
" $post = "" # Dummy-Header gleicher Länge zum Messen $hdrDummy = "Version:0.9`r`nStartHTML:0000000000`r`nEndHTML:0000000000`r`nStartFragment:0000000000`r`nEndFragment:0000000000`r`n" $hdrLen = $enc.GetByteCount($hdrDummy) $preLen = $enc.GetByteCount($pre) $fragLen = $enc.GetByteCount($HtmlFragment) $postLen = $enc.GetByteCount($post) $startHtml = $hdrLen $startFrag = $hdrLen + $preLen $endFrag = $startFrag + $fragLen $endHtml = $endFrag + $postLen $header = "Version:0.9`r`nStartHTML:{0:D10}`r`nEndHTML:{1:D10}`r`nStartFragment:{2:D10}`r`nEndFragment:{3:D10}`r`n" ` -f $startHtml, $endHtml, $startFrag, $endFrag return $header + $pre + $HtmlFragment + $post } function Convert-RichBoxToHtmlFragment { # Liest Farbe + Fett/Kursiv zeichenweise aus einem RichTextBox aus # und erzeugt ein HTML-Fragment mit Inline-Styles. # Ergebnis ist der...-Block, ohne CF_HTML-Header. param([System.Windows.Forms.RichTextBox]$Rtb) $len = $Rtb.TextLength if ($len -eq 0) { return "" } $sb = New-Object System.Text.StringBuilder $sb.Append("
") | Out-Null
$prevColor = $null
$prevBold = $false
$spanOpen = $false
for ($i = 0; $i -lt $len; $i++) {
$Rtb.SelectionStart = $i
$Rtb.SelectionLength = 1
$color = $Rtb.SelectionColor
$font = $Rtb.SelectionFont
$bold = $font -and $font.Bold
if (($color -ne $prevColor) -or ($bold -ne $prevBold)) {
if ($spanOpen) { $sb.Append("") | Out-Null }
$hex = "#{0:X2}{1:X2}{2:X2}" -f $color.R, $color.G, $color.B
$style = "color:$hex;" + $(if ($bold) { "font-weight:bold;" } else { "" })
$sb.Append("") | Out-Null
$spanOpen = $true
$prevColor = $color
$prevBold = $bold
}
$ch = $Rtb.Text[$i]
switch ($ch) {
'<' { $sb.Append("<") | Out-Null }
'>' { $sb.Append(">") | Out-Null }
'&' { $sb.Append("&") | Out-Null }
'"' { $sb.Append(""") | Out-Null }
"`r" { } # CR überspringen, nur LF verwenden
default { $sb.Append($ch) | Out-Null }
}
}
if ($spanOpen) { $sb.Append("") | Out-Null }
$sb.Append("") | Out-Null
return $sb.ToString()
}
# ========== WinForms-UI ==========
$MIN_LINES = 4
$RTF_BOX_HEIGHT = 92 # ~5 Zeilen sichtbar, Rest scrollbar
function Show-TextWithCopyButtons {
param(
[string[]]$InputText,
# Vollständiger RTF-String für die Preview-Box (leer = kein RTF verfügbar)
[string]$RtfContent = "",
# HTML Format-String (CF_HTML), z.B. von PS ISE – für OneNote & Co.
[string]$HtmlContent = "",
# Plaintext-Fallback für die Preview-Box
[string]$PlainContent = ""
)
# Einzelzeilen normalisieren und auf MIN_LINES auffüllen
$lines = @()
if ($InputText) {
foreach ($item in $InputText) { $lines += ($item -split "`r?`n") }
}
while ($lines.Count -lt $MIN_LINES) { $lines += "" }
# Layout-Konstanten
$textboxWidth = 300
$buttonWidth = 75
$padding = 10
$lineHeight = 35
$logBoxHeight = 120
$formHeight = $lines.Count * $lineHeight + $RTF_BOX_HEIGHT + $logBoxHeight + 110
$formHeight = [Math]::Min($formHeight, 1050)
$form = New-Object System.Windows.Forms.Form
$form.Text = "TextCopyHelper v7"
$form.Size = New-Object System.Drawing.Size(440, $formHeight)
$form.StartPosition = "CenterScreen"
$form.AutoScroll = $true
$form.TopMost = $true
# Log-Box (wird später positioniert)
$logBox = New-Object System.Windows.Forms.TextBox
$logBox.Multiline = $true
$logBox.ScrollBars = "Vertical"
$logBox.ReadOnly = $true
$logBox.Size = New-Object System.Drawing.Size(400, $logBoxHeight)
$y = 10
# ── Einzeilige Textboxen ──────────────────────────────────────────────────
foreach ($line in $lines) {
$textBox = New-Object System.Windows.Forms.RichTextBox
$textBox.Multiline = $false
$textBox.AcceptsTab = $false
$textBox.ShortcutsEnabled = $true
$textBox.BorderStyle = 'Fixed3D'
$textBox.ScrollBars = 'None'
$textBox.Text = $line
$textBox.Location = New-Object System.Drawing.Point($padding, $y)
$textBox.Size = New-Object System.Drawing.Size($textboxWidth, 20)
$form.Controls.Add($textBox)
$btn = New-Object System.Windows.Forms.Button
$btn.Text = "Copy"
$btn.Location = New-Object System.Drawing.Point(($padding + $textboxWidth + 10), ([int]$y - 1))
$btn.Size = New-Object System.Drawing.Size($buttonWidth, 23)
$curTb = $textBox
$curLog = $logBox
$btn.Add_Click({
$t = $curTb.Text
if (![string]::IsNullOrWhiteSpace($t)) {
[System.Windows.Forms.Clipboard]::SetText($t)
$curLog.AppendText("Copied: $t`r`n")
} else {
$curLog.AppendText("Nothing to copy (empty line).`r`n")
}
}.GetNewClosure())
$form.Controls.Add($btn)
$y += $lineHeight
}
# ── Paste-Button ─────────────────────────────────────────────────────────
$pasteButton = New-Object System.Windows.Forms.Button
$pasteButton.Text = "Paste clipboard as keyboard input"
$pasteButton.Size = New-Object System.Drawing.Size(250, 28)
$pasteButton.Location = New-Object System.Drawing.Point($padding, ($y + 5))
$curForm = $form
$curLog2 = $logBox
$pasteButton.Add_Click({
try {
$curLog2.AppendText("Reading clipboard...`r`n")
$clipText = Get-ClipboardRaw
} catch {
$curLog2.AppendText("Failed to read clipboard: $($_.Exception.Message)`r`n")
return
}
if ([string]::IsNullOrEmpty($clipText)) {
$curLog2.AppendText("Clipboard is empty. Nothing to type.`r`n")
return
}
$curLog2.AppendText("Read: $clipText`r`n")
$curLog2.AppendText("Minimizing window and typing...`r`n")
$curForm.WindowState = 'Minimized'
Start-Sleep -Seconds 2
Type-ScancodeText -text $clipText
$curForm.WindowState = 'Normal'
$curLog2.AppendText("Done typing.`r`n")
}.GetNewClosure())
$form.Controls.Add($pasteButton)
$y += 40
# ── Trennlinie + Label ────────────────────────────────────────────────────
$sep = New-Object System.Windows.Forms.Label
$sep.Text = "── Clipboard preview ──────────────────────"
$sep.AutoSize = $true
$sep.Location = New-Object System.Drawing.Point($padding, ($y + 2))
$sep.ForeColor = [System.Drawing.Color]::Gray
$form.Controls.Add($sep)
$y += 22
# ── Mehrzeilige RTF-Box ───────────────────────────────────────────────────
$richBox = New-Object System.Windows.Forms.RichTextBox
$richBox.Multiline = $true
$richBox.AcceptsTab = $true
$richBox.ShortcutsEnabled = $true
$richBox.ScrollBars = 'Vertical'
$richBox.BorderStyle = 'Fixed3D'
$richBox.Location = New-Object System.Drawing.Point($padding, $y)
$richBox.Size = New-Object System.Drawing.Size(($textboxWidth + 10), $RTF_BOX_HEIGHT)
# RTF laden — mit Fallback auf Plaintext
if (![string]::IsNullOrEmpty($RtfContent)) {
try {
$richBox.Rtf = $RtfContent
# PS ISE fügt manchmal ein führendes Leerzeichen ein — entfernen
$leadingSpaces = $richBox.Text.Length - $richBox.Text.TrimStart().Length
if ($leadingSpaces -gt 0) {
$richBox.SelectionStart = 0
$richBox.SelectionLength = $leadingSpaces
$richBox.SelectedText = ""
}
}
catch { $richBox.Text = $PlainContent }
} elseif (![string]::IsNullOrEmpty($PlainContent)) {
$richBox.Text = $PlainContent
}
# CF_HTML aus dem gerenderten Inhalt generieren.
# PS ISE legt kein HTML Format ins Clipboard — wir erzeugen es selbst,
# damit OneNote (und andere HTML-only-Ziele) die Formatierung bekommen.
$generatedHtml = ""
if ($richBox.TextLength -gt 0) {
try {
$fragment = Convert-RichBoxToHtmlFragment -Rtb $richBox
$generatedHtml = New-CfHtml -HtmlFragment $fragment
} catch { $generatedHtml = "" }
}
$form.Controls.Add($richBox)
# Buttons rechts neben der RTF-Box
$curRichBox = $richBox
$curLog3 = $logBox
$btnX = $padding + $textboxWidth + 20
# Button 1: Plaintext kopieren
$rtfCopyTextBtn = New-Object System.Windows.Forms.Button
$rtfCopyTextBtn.Text = "Copy text"
$rtfCopyTextBtn.Location = New-Object System.Drawing.Point($btnX, $y)
$rtfCopyTextBtn.Size = New-Object System.Drawing.Size($buttonWidth, 23)
$rtfCopyTextBtn.Add_Click({
$t = $curRichBox.Text
if (![string]::IsNullOrWhiteSpace($t)) {
[System.Windows.Forms.Clipboard]::SetText($t)
$curLog3.AppendText("Copied RTF-box content (plain text).`r`n")
} else {
$curLog3.AppendText("RTF-box is empty.`r`n")
}
}.GetNewClosure())
$form.Controls.Add($rtfCopyTextBtn)
# Button 2: Als Rich Text kopieren — DataObject mit ALLEN Originalformaten
# (RTF + HTML Format + Plaintext), damit OneNote, Word etc. das beste Format wählen können
$rtfCopyRtfBtn = New-Object System.Windows.Forms.Button
$rtfCopyRtfBtn.Text = "Copy RTF"
$rtfCopyRtfBtn.Location = New-Object System.Drawing.Point($btnX, ($y + 28))
$rtfCopyRtfBtn.Size = New-Object System.Drawing.Size($buttonWidth, 23)
$storedRtf = $RtfContent
# HtmlContent käme von einer Quelle die bereits CF_HTML liefert (selten).
# Fallback: das eben aus dem RichTextBox generierte CF_HTML.
$storedHtml = if (![string]::IsNullOrEmpty($HtmlContent)) { $HtmlContent } else { $generatedHtml }
$storedPlain = $PlainContent
$rtfCopyRtfBtn.Add_Click({
if ([string]::IsNullOrWhiteSpace($storedPlain) -and
[string]::IsNullOrEmpty($storedRtf)) {
$curLog3.AppendText("RTF-box is empty.`r`n")
return
}
$ok = Set-ClipboardMultiFormat -PlainText $storedPlain -RtfString $storedRtf -HtmlString $storedHtml
$formats = @()
if (![string]::IsNullOrEmpty($storedRtf)) { $formats += "RTF" }
if (![string]::IsNullOrEmpty($storedHtml)) { $formats += "HTML" }
if (![string]::IsNullOrEmpty($storedPlain)) { $formats += "Text" }
if ($ok) { $curLog3.AppendText("Copied rich text ($($formats -join ' + ')).`r`n") }
else { $curLog3.AppendText("Failed to set clipboard.`r`n") }
}.GetNewClosure())
$form.Controls.Add($rtfCopyRtfBtn)
$y += $RTF_BOX_HEIGHT + 10
# ── Log-Box ───────────────────────────────────────────────────────────────
$logBox.Location = New-Object System.Drawing.Point($padding, $y)
$form.Controls.Add($logBox)
$form.ShowDialog() | Out-Null
}
# ── Start ─────────────────────────────────────────────────────────────────────
try { $plainText = Get-ClipboardRaw -ErrorAction Stop } catch { $plainText = "" }
try { $rtfText = Get-ClipboardFormat -FormatName "Rich Text Format" -Encoding "Default" -ErrorAction Stop } catch { $rtfText = "" }
try { $htmlText = Get-ClipboardFormat -FormatName "HTML Format" -Encoding "UTF8" -ErrorAction Stop } catch { $htmlText = "" }
Show-TextWithCopyButtons -InputText $plainText -RtfContent $rtfText -HtmlContent $htmlText -PlainContent $plainText