Solved

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

Posted on 2016-07-20
9
90 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
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

How to sign a powershell script so you can prevent tampering, and only allow users to run authorised Powershell scripts
"Migrate" an SMTP relay receive connector to a new server using info from an old server.
A short film showing how OnPage and Connectwise integration works.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

929 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

10 Experts available now in Live!

Get 1:1 Help Now