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