- Dwarfsoft [GPA] - http://www.dwarfsoft.com/blog -

PowerShell PowerISE Copy-Script Add-On

One of the most useful things I get to use in day to day scripting is Copy-Script. It is a script that I originally picked up from this msdn blog [1]. I have since made a couple of modifications to allow me to reload it with the rest of my profile, as well as my most recent addition: Converting the Formatted Text to Word Document format.

The reason I needed to use Word Document format was due to OneNote and Lync not taking the RTF formatted data until it had been pasted and copied out of Microsoft Word. Therefore I added the following process into the end of the script:

    #...
    [Windows.Clipboard]::SetDataObject($dataObject, $true)
    
    $word = New-Object -ComObject Word.Application
    $doc = $word.Documents.Add()
    $a = $word.Selection.Paste()
    $word.Selection.Start = 0
    $a = $word.Selection.Copy()
    $a = $doc.Undo()
    $wdNoSave = [microsoft.office.interop.word.WdSaveOptions]::wdDoNotSaveChanges
    
    $doc.Close([ref]$wdNoSave)
    $doc = $null
 
    $word.Quit([ref]$wdNoSave)
    $word = $null
    'The script has been copied to clipboard.'
    #...

The Full Text of the Script is as follows:

##############################################################################################################
# Copy-Script.ps1
#
# The script entire contents of the currently selected editor window to system clipboard.
# The copied data can be pasted into any application that supports pasting in UnicodeText, RTF or HTML format.
# Text pasted in RTF or HTML format will be colorized.
#
 
 
# Create RTF block from text using named console colors.
#
function Append-RtfBlock ($block, $tokenColor)
{
    $colorIndex = $rtfColorMap.$tokenColor
    $block = $block.Replace('\','\\').Replace("`r`n","\cf1\par`r`n").Replace("`t",'\tab').Replace('{','\{').Replace('}','\}')
    $null = $rtfBuilder.Append("\cf$colorIndex $block")
}
 
# Generate an HTML span and append it to HTML string builder
#
function Append-HtmlSpan ($block, $tokenColor)
{
  if ($tokenColor -eq 'NewLine')
  {
    $null = $htmlBuilder.Append("
") } else { $block = $block.Replace('&','&').Replace('>','>').Replace('<','<') if (-not $block.Trim()) { $block = $block.Replace(' ', ' ') } $htmlColor = $psise.Options.TokenColors[$tokenColor].ToString().Replace('#FF', '#') $null = $htmlBuilder.Append("$block") } } function Copy-Script { if (-not $psise.CurrentFile) { Write-Error 'No script is available for copying.' return } if ($psise.CurrentFile.Editor.SelectedText -eq "") { $text = $psise.CurrentFile.Editor.Text } else { $text = $psise.CurrentFile.Editor.SelectedText } trap { break } # Do syntax parsing. $errors = $null $tokens = [system.management.automation.psparser]::Tokenize($Text, [ref] $errors) # Set the desired font and font size $fontName = 'Lucida Console' $fontSize = 10 # Initialize HTML builder. $htmlBuilder = new-object system.text.stringbuilder $null = $htmlBuilder.AppendLine("

") # Initialize RTF builder. $rtfBuilder = new-object system.text.stringbuilder # Append RTF header $null = $rtfBuilder.Append("{\rtf1\fbidis\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 $fontName;}}") $null = $rtfBuilder.Append("`r`n") # Append RTF color table which will contain all Powershell console colors. $null = $rtfBuilder.Append("{\colortbl ;") # Generate RTF color definitions for each token type. $rtfColorIndex = 1 $rtfColors = @{} $rtfColorMap = @{} [Enum]::GetNames([System.Management.Automation.PSTokenType]) | % { $tokenColor = $psise.Options.TokenColors[$_]; $rtfColor = "\red$($tokenColor.R)\green$($tokenColor.G)\blue$($tokenColor.B);" if ($rtfColors.Keys -notcontains $rtfColor) { $rtfColors.$rtfColor = $rtfColorIndex $null = $rtfBuilder.Append($rtfColor) $rtfColorMap.$_ = $rtfColorIndex $rtfColorIndex ++ } else { $rtfColorMap.$_ = $rtfColors.$rtfColor } } $null = $rtfBuilder.Append('}') $null = $rtfBuilder.Append("`r`n") # Append RTF document settings. $null = $rtfBuilder.Append('\viewkind4\uc1\pard\f0\fs20 ') $position = 0 # Iterate over the tokens and set the colors appropriately. foreach ($token in $tokens) { if ($position -lt $token.Start) { $block = $text.Substring($position, ($token.Start - $position)) $tokenColor = 'Unknown' Append-RtfBlock $block $tokenColor Append-HtmlSpan $block $tokenColor } $block = $text.Substring($token.Start, $token.Length) $tokenColor = $token.Type.ToString() Append-RtfBlock $block $tokenColor Append-HtmlSpan $block $tokenColor $position = $token.Start + $token.Length } # Append HTML ending tag. $null = $htmlBuilder.Append("

") # Append RTF ending brace. $null = $rtfBuilder.Append('}') # Copy console screen buffer contents to clipboard in three formats - text, HTML and RTF. # $dataObject = New-Object Windows.DataObject $dataObject.SetText([string]$text, [Windows.TextDataFormat]"UnicodeText") $rtf = $rtfBuilder.ToString() $dataObject.SetText([string]$rtf, [Windows.TextDataFormat]"Rtf") $html = $htmlBuilder.ToString() $dataObject.SetText([string]$html, [Windows.TextDataFormat]"Html") [Windows.Clipboard]::SetDataObject($dataObject, $true) $word = New-Object -ComObject Word.Application $doc = $word.Documents.Add() $a = $word.Selection.Paste() $word.Selection.Start = 0 $a = $word.Selection.Copy() $a = $doc.Undo() $wdNoSave = [microsoft.office.interop.word.WdSaveOptions]::wdDoNotSaveChanges $doc.Close([ref]$wdNoSave) $doc = $null $word.Quit([ref]$wdNoSave) $word = $null 'The script has been copied to clipboard.' } #$psise.CustomMenu.Submenus.Add("Copy Script", {Copy-Script}, $null) if ($psise.PowerShellTabs[0].DisplayName -eq "PowerShell 1") { $tabs = [Microsoft.PowerShell.Host.ISE.PowerShellTab]$psise.PowerShellTabs[0] $menu = [Microsoft.PowerShell.Host.ISE.ISEMenuItem]$tabs.AddOnsMenu $ret = $menu.Submenus.Add("Copy Script",{Copy-Script},$null) } else { $ret = $psise.CustomMenu.Submenus.Add("Copy Script", {Copy-Script}, $null) }

Cheers, Chris