Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell - Output Color for certain results

Tags:

powershell

I am running the code below and it works. What I am trying to do is, in the results when Enabled properties is True I would like to the text 'True' foreground color to be green otherwise if 'false' color Red.

The same with the Password never expires properties, if the result is 'True' I would like to the text 'True' foreground color to be Red otherwise if its 'False' color green.

I am trying to fit an if-else statement into the code but have not been successfull.

Code:

Get-ADUser "user name"  -Properties Enabled,LockedOut,DisplayName,GivenName, SurName,Mail,LastLogon, Created,passwordlastset,Passwordneverexpires,msDS-UserPasswordExpiryTimeComputed, Description, office, Canonicalname | `
        Select-Object Enabled, 
        @{Expression={$_.LockedOut};Label='Locked';}, 
        @{Expression={$_.DisplayName};Label='Display Name';},
        @{Expression ={$_.GivenName};Label='Name';}, `
        @{Expression ={$_.SurName}; Label='Last Name'; }, 
        Mail, 
        @{Expression ={[DateTime]::FromFileTime($_.LastLogon)}; Label='Last Logon';}, 
        @{Expression={$_.Created};Label='Date Created';}, 
        @{Expression={$_.passwordlastset};Label='PW Last Reset';}, 
        @{Expression={$_.Passwordneverexpires};Label='PW Never Expires';},
        @{Name="PW Exp Date";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}  ,
        Description, 
        Office,
        Canonicalname 
        Format-list

enter image description here

Any suggestions?

like image 216
Lou Mal Avatar asked Sep 02 '17 18:09

Lou Mal


2 Answers

Find advanced function Out-HostColored below, to which you can pipe any command and color its output selectively based on regular expressions / literal substrings.

Applied to your case, with simulated input:

@'
Enabled          : True
Locked           : False
Display Name     : foo
Name             : bar
Last Name        : baz
Mail             : [email protected]
Last Logon       : 9/1/2017 7:33:30 PM
Date Created     : 11/21/2014 6:04:54 AM
PW Last Reset    : 9/2/2015
PW Never Expires : False
Description      : Technician
Office           : IT
Canonical Name   : CORPORATE.LOCAL/foo Users/bar
'@ |
  Out-HostColored '(?<=Enabled\s+: )True', '(?<=PW Never Expires\s+: )False' Green

Two regular expressions are passed that match only the tokens of interest and color them greenOriginally, only a single regex was supported. Tip of the hat to @SamHasler for the suggestion to accept an array..
Note the use of look-behind assertions ((?<=...)) to match the proper context without including it in the match.

The above yields:

sample output

Out-HostColored features:

  • You can pipe any command - whether you rely on its implicit formatting or whether you pipe it to a Format-* cmdlet explicitly first.

  • Matching is restricted to a single line at a time, but coloring multiple matches on a given line is supported.

  • You can specify both a foreground color (-ForegroundColor) and (-BackgroundColor) explicitly if desired; by default, matches are colored green.

  • To color the entire line if a match is found, pass -WholeLine

  • To pass literal substrings to match rather than regular expressions, use -SimpleMatch.


Out-HostColored source code (PSv2+):

Note:

  • The function below is now also available as an MIT-licensed Gist - only the latter will be maintained going forward.

  • The Gist additionally supports a -CaseSensitive switch and pattern-specific coloring, via a dictionary of per-pattern colorsTip of the hat to @not2qubit for the inspiration; e.g.:

    # Prints "easy" and "green" in green, "being" in black on yellow.
    'It ain''t easy being green.' | Out-HostColored @{ 
      ('easy', 'green') = 'green'
      '\bbe.+?\b' = 'black,yellow' 
    }
    
  • In PSv3+, you can install the function directly from the Gist as follows (while I personally assure you that doing so is safe, it's generally a good idea to check the source first):

    irm https://gist.github.com/mklement0/243ea8297e7db0e1c03a67ce4b1e765d/raw/Out-HostColored.ps1 | iex
    
<#
.SYNOPSIS
Colors portions of the default host output that match given patterns.

.DESCRIPTION
Colors portions of the default-formatted host output based on either
regular expressions or a literal substrings, assuming the host is a console or
supports colored output using console colors.

Matching is restricted to a single line at a time, but coloring multiple
matches on a given line is supported.

Note: Since output is sent to the host rather than the pipeline, you cannot
      chain calls to this function.

.PARAMETER Pattern
One or more search patterns specifying what parts of the formatted 
representations of the input objects should be colored.

 * By default, these patterns are interpreted as regular expressions.

 * If -SimpleMatch is also specified, the patterns are interpreted as literal
   substrings.

.PARAMETER ForegroundColor
The foreground color to use for the matching portions.
Defaults to green.

.PARAMETER BackgroundColor
The optional background color to use for the matching portions.

.PARAMETER WholeLine
Specifies that the entire line containing a match should be colored,
not just the matching portion.

.PARAMETER SimpleMatch
Interprets the -Pattern argument(s) as a literal substrings to match rather
than as regular expressions.

.PARAMETER InputObject
The input object(s) whose formatted representations to color selectively.
Typically provided via the pipeline.

.NOTES
Requires PSv2 or above.
All pipeline input is of necessity collected first before output is produced.

.EXAMPLE
Get-Date | Out-HostColored '\b\p{L}+\b' red white

Outputs the current date with all words composed of letters (p{L}) only in red
on a white background.

.EXAMPLE
Get-ChildItem | select Name | Out-HostColored -WholeLine -SimpleMatch .exe

Highlight all executable file names in green.

.EXAMPLE
'apples', 'kiwi', 'pears' | Out-HostColored '^a', 's$' blue

Highlight all As at the beginning and Ss at the end of lines in blue.
#>
Function Out-HostColored {
  # Note: The [CmdletBinding()] and param() block are formatted to be PSv2-compatible.
  [CmdletBinding()]
  param(
    [Parameter(Position = 0, Mandatory = $True)] [string[]] $Pattern,
    [Parameter(Position = 1)] [ConsoleColor] $ForegroundColor = 'Green',
    [Parameter(Position = 2)] [ConsoleColor] $BackgroundColor,
    [switch] $WholeLine,
    [switch] $SimpleMatch,
    [Parameter(Mandatory = $True, ValueFromPipeline = $True)] $InputObject
  )

  # Wrap the pattern / literal in an explicit capture group.
  # Fail, if the given regex is syntactically invalid.
  try {
    $re = [regex] ('(?<sep>{0})' -f $(if ($SimpleMatch) { 
          ($Pattern | ForEach-Object { [regex]::Escape($_) }) -join '|'
        } 
        else { 
          ($Pattern | ForEach-Object { '(?:{0})' -f $_ }) -join '|'
        }))
  }
  catch { Throw }

  # Build a parameters hashtable specifying the colors, to be use via
  # splatting with Write-Host later.
  $htColors = @{
    ForegroundColor = $ForegroundColor
  }
  if ($BackgroundColor) {
    $htColors.Add('BackgroundColor', $BackgroundColor)
  }

  # Use pipeline input, if provided (the typical case).
  if ($MyInvocation.ExpectingInput) { $InputObject = $Input }

  # Apply default formatting to each input object, and look for matches to
  # color line by line.
  $InputObject | Out-String -Stream | ForEach-Object {
    $line = $_
    if ($WholeLine) {
      # Color the whole line in case of match.
      if ($line -match $re) {
        Write-Host @htColors $line
      }
      else {
        Write-Host $line
      }
    }
    else {
      # Split the line by the regex and include what the regex matched.
      $segments = $line -split $re, 0, 'ExplicitCapture'
      if ($segments.Count -eq 1) {
        # no matches -> output line as-is
        Write-Host $line
      }
      else {
        # at least 1 match, as a repeating sequence of <pre-match> - <match> pairs
        $i = 0
        foreach ($segment in $segments) {
          if ($i++ % 2) {
            # matching part
            Write-Host -NoNewline @htColors $segment
          }
          else {
            # non-matching part
            Write-Host -NoNewline $segment
          }
        }
        Write-Host '' # Terminate the current output line with a newline.
      }
    }
  }
}
like image 169
mklement0 Avatar answered Nov 17 '22 01:11

mklement0


Here's a possible solution:

$Highlight = @{
    True = 'Red'
    False = 'Green'
}

$User = Get-ADUser "user name"  -Properties Enabled,LockedOut,DisplayName,GivenName,SurName,Mail,LastLogon,Created,passwordlastset,Passwordneverexpires,msDS-UserPasswordExpiryTimeComputed, Description, office, Canonicalname |
        Select-Object Enabled, 
        @{Expression={$_.LockedOut};Label='Locked';}, 
        @{Expression={$_.DisplayName};Label='Display Name';},
        @{Expression ={$_.GivenName};Label='Name';}, `
        @{Expression ={$_.SurName}; Label='Last Name'; }, 
        Mail, 
        @{Expression ={[DateTime]::FromFileTime($_.LastLogon)}; Label='Last Logon';}, 
        @{Expression={$_.Created};Label='Date Created';}, 
        @{Expression={$_.passwordlastset};Label='PW Last Reset';}, 
        @{Expression={$_.Passwordneverexpires};Label='PW Never Expires';},
        @{Name="PW Exp Date";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}},
        Description, 
        Office,
        Canonicalname | Format-list | Out-String

$User -split "`n" | ForEach-Object {
    $Output = $False
    If ($_ -match 'Enabled|PW Never Expires') {
        ForEach ($Entry in $Highlight.Keys){
            $Text = $_ -split $Entry
            If ($Text.count -gt 1) { 
                Write-Host $Text[0] -NoNewline
                Write-Host $Entry -ForegroundColor $Highlight.$Entry
                $Output = $true
                Break
            }
        }
    }

    If (-not $Output) { Write-Host $_ }
}

Note that this should work for the sort of output you get with Format-List in particular but isn't a particularly well thought out highlighting function otherwise: e.g this won't handle words that might appear multiple times in the same line of text.

Also FYI working with PowerShell in this way isn't generally best practice. You should consider writing PowerShell tools that output to the pipeline and not via Write-Host, that way you can manipulate the results in other commands, or transform it (e.g to CSV etc.).

like image 24
Mark Wragg Avatar answered Nov 17 '22 01:11

Mark Wragg