4

I have a few unusual, relatively complex/large PowerShell scripts where it outputs colorized text via Write-Host. I want to copy the entire text output to the Windows clipboard WITHOUT losing tab characters (with windows Control-C, clipboard copy) or alternative. If I highlight all the text after the script runs in a PowerShell.exe console Window, then, press control-C (to copy to the Windows clipboard) the tab characters are converted to spaces.

If I try to use Set-Clipboard cmdlet below to pipe entire output of my script, there are too many components in my script (mainly Write-Host lines) which aren't compatible with further PS pipeline processing; so, Set-Clipboard below is completely ignored (only displaying output to to local host console).

PS: I've also tried Start-Transcript\Stop-Transcript.. However, that doesnt capture tabs either. It converts tabs to spaces.

I was hoping someone had a clever, quick way to clipboard capture the text I get from cmdlets that need write-host THAT ALSO CAPTURE `t tab characters.

invoke-myscript -Devicename "WindowsPC" | Set-Clipboard
function Set-Clipboard {

param(
    ## The input to send to the clipboard
    [Parameter(ValueFromPipeline = $true)]
    [object[]] $InputObject
)

begin
{
    Set-StrictMode -Version Latest
    $objectsToProcess = @()
}

process
{
    ## Collect everything sent to the script either through
    ## pipeline input, or direct input.
    $objectsToProcess += $inputObject
}

end
{
    ## Launch a new instance of PowerShell in STA mode.
    ## This lets us interact with the Windows clipboard.
    $objectsToProcess | PowerShell -NoProfile -STA -Command {
        Add-Type -Assembly PresentationCore

        ## Convert the input objects to a string representation
        $clipText = ($input | Out-String -Stream) -join "`r`n"

        ## And finally set the clipboard text
        [Windows.Clipboard]::SetText($clipText)
    }
}
MKANET
  • 573
  • 6
  • 27
  • 51
  • 1
    Why not just write output as HTML output to file? or some other rich text. It really sounds like you just want the colour more than anything and are trying to fix the wrong problem. Namely that Write-Host does not use the output stream so you would get nothing in the pipe.CSS enabled HTML output sounds more versatile – Matt Dec 22 '15 at 18:45
  • Hey Matt. Thanks so much for the suggestion. Any ideas how to convert a script that has tons of lines like write-host -NoNewline -ForegroundColor "Gray" "Circuit:`t`t`t"; write-host -ForegroundColor "DarkYellow" " $Circuit" – MKANET Dec 22 '15 at 20:50
  • You need to use @name to respond to people. I didn't know you responded. Like I said I think you sould try a different approach. Can you show a sample of what you want your output to be like and how you generate `$circut` this should be easy enough to replace. It's a matter of being efficient. – Matt Dec 31 '15 at 02:16
  • Are you able to use the powershell_ise to run your scripts? The console does lose tabs but the ISE does not. – Sam Jan 05 '16 at 19:01

2 Answers2

3

I think the answer you will find is that using Write-Host will most always take you down a path you do not want. Jeffrey Snover discusses this in his blog. It might be worth the hit to change your scripts to change Write-Host to Write-Output and maybe even use the colors to decide if you should change some of those to Write-Verbose and/or Write-Warning.

If you do this, then you have other options at your disposal like using -OutVariable to capture output precisely for further processing (automation).

Example below to demonstrate how such a change could benefit you.

function print-with-tab {
  [cmdletbinding()]
  Param()

  Write-Host "HostFoo`t`t`tHostBar"
  Write-Output "OutFoo`t`t`tOutBar"
  Write-Warning "You have been warned."
}

print-with-tab -OutVariable outvar -WarningVariable warnvar

Write-Output "Out -->"
$outvar
# proof there's tabs in here
$outvar -replace "`t", "-"
Write-Output "Warn -->"
$warnvar

Output

HostFoo         HostBar
OutFoo          OutBar
WARNING: You have been warned.
Out -->
OutFoo          OutBar
OutFoo---OutBar
Warn -->
You have been warned.

Last Thought

Last thought is if you know you do not have any strings with 4 spaces in them (if that is what your tabs turn into), then take your output, replace all occurrences of 4 spaces, back into a tab character, then add to clipboard. Hacky, but per my previous point about the paths you take with Write-Host and further automation...this just might work for you.

In that case, I think you could use something like:

$objectsToProcess += $inputObject -replace "    ", "`t"
Kory Gill
  • 6,993
  • 1
  • 25
  • 33
  • @Keri Gill.. Thanks so much this would really help when making new scripts. In my case, it might be easier to make my own write-host function in the script. That way I dont need to change every single line that has a write-host. I just need to figure out how to handle NoNewLine switch. – MKANET Dec 31 '15 at 12:22
  • Is there a copy of a write-host function I can copy from somewhere so I dont have to make it from scratch? I can then add ability to make a compatible for windows clipboard with tabs. – MKANET Dec 31 '15 at 12:42
  • Search for "powershell override write-host". http://stackoverflow.com/questions/14470953/powershell-how-to-capture-or-suppress-write-host, https://byteonmyside.wordpress.com/2012/04/25/how-to-capture-or-redirect-write-host-output-in-powershell/. etc. – Kory Gill Dec 31 '15 at 17:30
  • I hate to say this; despite the solutions offered here. I still think it's best (for my case) to create my own write-host cmdlet (to include with my script(s)) that has an append output text-file switch. This would allow me to only add an extra switch to all existing write-host lines with a single search&replace; keeping all functionality intact; while adding an extra option. – MKANET Jan 04 '16 at 16:52
  • 1
    @MKANET Write-Host should not be overloaded as it would be misleading. It is not meant to create output just console text. I think you should be using a logging function with a variable that that you can splat so that you can decide at execution where the data is going. Also could convert to write-debug?. Either way it seems you are misusing write-host and should, for your own sake, replace it anyway. find-replace is not a hard task. It also seems your tab question is not your real issue. – Matt Jan 05 '16 at 17:08
  • @Matt, agree. If a refactor of the scripts to replace Write-Host is not possible, I thought my suggestions were the next best thing. – Kory Gill Jan 05 '16 at 17:23
  • 1
    Thanks for the valid points. Refactoring with a simple search\replace is the easiest solution (in my case). I can just name my custom write-host something like, 'Write-Host2'. Then, just add Write-Host2 function to my script(s). It will be backwards compatible with most Write-Host arguments; plus, copy-paste and tab character compatible with color output to local console. – MKANET Jan 06 '16 at 17:51
0

Going against expert recommendations.. I still feel my solution is the easiest (and ideal) one for my circumstance. I don't take this decision lightly; especially when people spent considerable time trying to help me. So sorry Matt! If I didn't have a million write-host lines in my gigantic script already, I would use your solution.

Refactoring with a simple search\replace is the easiest solution (in my case). I can just name my custom write-host something like, 'Write-Host2'. Then, just add Write-Host2 function to my script(s). It will be backwards compatible with most Write-Host arguments; plus, copy-paste and tab character compatible with color output to local console.

MKANET
  • 573
  • 6
  • 27
  • 51