Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

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

Posted on 2016-07-20
9
Medium Priority
?
288 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 41

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 41

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
Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

 

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
 
LVL 85

Accepted Solution

by:
oBdA earned 1200 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 41

Assisted Solution

by:footech
footech earned 800 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 41

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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

A brief introduction to what I consider to be the best editor for PowerShell.
In this post we will be converting StringData saved within a text file into a hash table. This can be further used in a PowerShell script for replacing settings that are dynamic in nature from environment to environment.
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…
Screencast - Getting to Know the Pipeline

877 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