Solved

PowerShell format-table with $Host.UI.RawUI.ForegroundColor issues

Posted on 2016-07-20
9
71 Views
Last Modified: 2016-07-21
Good morning,

I am having an issue colorizing within format-table using an expression and $Host.UI.RawUI.ForegroundColor.  I populated an array using garbage populated data and it works great:

$arrNetVirtLookupRecords = @()
100..150|%{
	$objNetVirtLookupRecord = $null
	$objNetVirtLookupRecord = New-Object PSObject -Property @{
		VMHost = $null;
		VSID = $null;
		VMName = $null;
		CustomerAddress = $null;
		ProviderAddress = $null;
		CustomerMAC = $null;
	}
	$objNetVirtLookupRecord.VMHost = If($_ % 2 -eq 0){"server101"} Else{"server102"}
	$objNetVirtLookupRecord.VSID = "1234567"
	$objNetVirtLookupRecord.VMName = "WINDOWS$_"
	$objNetVirtLookupRecord.CustomerAddress = "192.168.1.$_"
	$objNetVirtLookupRecord.ProviderAddress = "192.168.1.$_"
	$objNetVirtLookupRecord.CustomerMAC = "000000000$_"
	$arrNetVirtLookupRecords += $objNetVirtLookupRecord
}

$objOriginalColor = $Host.UI.RawUI.ForegroundColor
$arrNetVirtLookupRecords | Sort-Object VMHost, VMName | Format-Table @{
	Name="VMHost"
	Expression={
		If($_.VMHost -eq 'server102'){$Host.ui.rawui.ForegroundColor = "cyan"; $_.VMHost}
		Else{$Host.UI.RawUI.ForegroundColor = $objOriginalColor; $_.VMHost}
	}
}, VSID, VMName, CustomerAddress, ProviderAddress, CustomerMAC
$Host.UI.RawUI.ForegroundColor = $objOriginalColor

Open in new window


However when I run it against the real data it does not change the color.  When I run it against the real data and change the script to:

$objOriginalColor = $Host.UI.RawUI.ForegroundColor
$arrNetVirtLookupRecords | Sort-Object VMHost, VMName | Format-Table @{
	Name="VMHost"
	Expression={
		If("$($_.VMHost)" -eq 'server101'){$Host.ui.rawui.ForegroundColor = "cyan"; "Match)"}
		Else{$Host.UI.RawUI.ForegroundColor = $objOriginalColor; "No Match"}
	}
}, VSID, VMName, CustomerAddress, ProviderAddress, CustomerMAC
$Host.UI.RawUI.ForegroundColor = $objOriginalColor

Open in new window


Match and No Match are populated in the field appropriately but the color doesn't change.  Also if I print out the $Host.UI.RawUI.ForegroundColor in the expression it displays what the color should be, but the console doesn't display it.

Thanks for any assistance!
0
Comment
Question by:omnipower321
  • 4
  • 4
9 Comments
 
LVL 39

Expert Comment

by:footech
ID: 41721096
You're not running in the ISE are you?  That behaves different than a console.
0
 

Author Comment

by:omnipower321
ID: 41721099
I am not.  Straight up console.
0
 
LVL 39

Expert Comment

by:footech
ID: 41721543
I might have gotten somewhere with this.
What version of PS are you running?  Are you running everything on the same machine?

What I saw was with PS 5.0 that the color used was whatever the first object displayed used.  So if the first object was set to be cyan, then everything that followed was too.  With PS 4.0 the color changed according to the match.  I believe this is due to the change in PS 5.0 as to how Format-Table works.  If I changed the command to Format-List I observed the color change.

◦When you use the Format-Table command, table columns are now automatically formatted by evaluating the first 300ms of data that passes through the stream.
0
 

Author Comment

by:omnipower321
ID: 41721649
Thank you for the responses!  I am running these 2 tests from the same machine and am using PowerShell version 4.

I get the same behavior with Format-List:
$objOriginalColor = $Host.UI.RawUI.ForegroundColor
$arrNetVirtLookupRecords | Sort-Object VMHost, VMName | Format-List @{
	Name="VMHost"
	Expression={
		If("$($_.VMHost)" -eq 'server101'){$Host.ui.rawui.ForegroundColor = "cyan"; "$($_.VMHost) $($Host.UI.RawUI.ForegroundColor)"}
		Else{$Host.UI.RawUI.ForegroundColor = $objOriginalColor; "$($_.VMHost) $($Host.UI.RawUI.ForegroundColor)"}
	}
}, VSID, VMName, CustomerAddress, ProviderAddress, CustomerMAC
$Host.UI.RawUI.ForegroundColor = $objOriginalColor

Open in new window



VMHost          : server101 Cyan
VSID            : 1234567
VMName          : WINDOWS101
CustomerAddress : 192.168.1.x
ProviderAddress : 192.168.1.x
CustomerMAC     : 00000000101

VMHost          : server102 DarkYellow
VSID            : 1234567
VMName          : WINDOWS102
CustomerAddress : 192.168.1.x
ProviderAddress : 192.168.1.x
CustomerMAC     : 0000000000102

But the console color never changes.
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 83

Accepted Solution

by:
oBdA earned 300 total points
ID: 41721897
For the fun of it, here's a function. It expects an additional property '__Color' containing a hashtable with the fore- and/or background color the respective line should have (this hashtable will be splatted and used as argument for Write-Host).
-AutoSize and -HideTableHeaders are supported, and it works in the ISE as well.
Function Format-TableColored {
[CmdletBinding()]
Param(
	[Parameter(ValueFromPipeline=$true, Position=0)]
	[PSObject]$InputObject,
	[Switch]$AutoSize,
	[Switch]$HideTableHeaders,
	[String]$ColorProperty = "__Color"
)
	Begin {
		$Output = @()
		$Colors = @()
		$FirstValue = ''
		$StartColor = $False
		$ColorArgs = @{}
	}
	Process {
		If (!$FirstValue) {$FirstValue = [regex]::Escape(($InputObject.psobject.Properties | Select-Object -ExpandProperty Value -First 1))}
		$Colors += If ($InputObject.$ColorProperty -is [hashtable]) {$InputObject.$ColorProperty} Else {@{}}
		$Output += $InputObject | Select-Object -Property * -ExcludeProperty $ColorProperty
	}
	End {
		[void]$PSBoundParameters.Remove('ColorProperty')
		$PSBoundParameters['InputObject'] = $Output
		$i = 0
		(Format-Table @PSBoundParameters | Out-String) -split "`r`n" | ForEach-Object {
			If (!$StartColor -and ($_ -match "\s*$($FirstValue)")) {$StartColor = $True}
			If ($StartColor -and $_) {
				$ColorArgs = $Colors[$i++]
			} Else {
				$ColorArgs.Clear()
			}
			Write-Host -Object $_ @ColorArgs
		}
	}
}

Open in new window

Sample call:
Get-ChildItem C:\Windows\*.exe |
	Select-Object -Property `
		Name,
		Extension,
		LastWriteTime,
		@{Name='__Color'; Expression={
			Switch ($_.BaseName) {
				'Explorer'	{@{Fore='Black';Back='Yellow'}}
				'regedit'	{@{Back='Blue';Fore='White;}}
				'notepad'	{@{Back='DarkGray'}}
				'write'		{@{Fore='Magenta'}}
			}
		}} |
	Format-TableColored -AutoSize

Open in new window

In your case, this should work:
$arrNetVirtLookupRecords |
	Select-Object VMHost, VSID, VMName, CustomerAddress, ProviderAddress, CustomerMAC, @{Name='__Color'; Expression={If ($_.VMHost -eq 'server101') {@{Fore='Cyan'}}}} |
	Sort-Object VMHost, VMName | Format-TableColored

Open in new window

1
 
LVL 39

Assisted Solution

by:footech
footech earned 200 total points
ID: 41721921
Sorry, I can't think of any possible cause, unless there's a clue in the actual code you're running to gather data (but it seems unlikely).

One option which I found works with PS 5.0 (just using test data), is to specify the -GroupBy parameter of Format-Table.  However, if that that won't work for you, given what I found with PS 5.0, I'd pursue another route if I were you.  It doesn't seem to be a great idea to design something that will break when run on a new version of PS.
0
 
LVL 39

Expert Comment

by:footech
ID: 41722222
@oBdA - I like what you did with your function.  I was thinking about Format-Table > Out-String > Write-Host as an alternative but hadn't fleshed it out yet.
0
 

Author Comment

by:omnipower321
ID: 41722963
The function worked like a charm!  Thanks a bunch footech and oBdA.

I was going down a nasty path of Write-Hosts that was far less elegant.
0
 

Author Closing Comment

by:omnipower321
ID: 41722967
Thanks again for all of the help!
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

"Migrate" an SMTP relay receive connector to a new server using info from an old server.
A procedure for exporting installed hotfix details of remote computers using powershell
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now