0

I have written a logging function for my PowerShell Script, which will log the Input to the file, at the same time also display the same onto the output screen. While displaying the output on the screen, depending on different matching conditions, the Output will be displayed in different colors. I have used switch statement to compare the input to a set of conditions and then display the output.

However I feel that this approach is not efficient, considering there are over 20 condition that are to be met, each will have its own formatting. Can anyone suggest an alternative approach or any optimal change that can be done in this approach ?

Below is a sample code :

    [String] WriteLog([string]$LogString)
    {
        
        #Logging to File
        If (!(Test-Path $this.LogFile)) {New-Item -Path $this.LogFile -Force}
        Add-content $this.LogFile -value $LogString

        #Printing on Console
        switch -CaseSensitive -Wildcard ($LogString)
        {
            '*PASSED*'
            {
                Write-host $LogString -fore Green -nonewline
                break
            }               
            
            '*Warnings.*'
            {
                Write-host $LogString -fore Yellow -nonewline
                break
            }
            
            
            '*Fail*'
            {
                Write-host $LogString -fore Red-nonewline
                break
            }

            '*Run*'
            {
                Write-Host $LogString  -NoNewline -fore Red -BackgroundColor White -nonewline
            }
            default
            {
                Write-Host "       " $LogString 
            }
        }
 }

Prateek Jaiswal
  • 145
  • 2
  • 15
  • 1
    It's unusual for a logger to determine the message level by parsing the log message - in your case, what happens if it's logging the message "INVALID PARAMETER PASSED"? (Hint it gets processed through the ```*PASSED*``` case!). It would make more sense to have a "level" parameter of some sort and let the *caller* decide the status - e.g. ```WriteLog -LogString "my message" -Level Warning``` or switch parameters for each level like ```WriteLog -LogString "my message" -Warning```, then your ```switch``` just has to output based on the level. – mclayton Apr 13 '22 at 08:11
  • @mclayton Thank you for the suggestion. There is one big problem though, there are 20 such conditions, and expected to increase in coming time. In this case the ever increasing switch block is the concern. – Prateek Jaiswal Apr 13 '22 at 10:01

1 Answers1

1

If you would have just a wildcard string to check and a foreground color depending on the wildcard, you could use a hashtable with key & value:

# Hashtable for foreground color
$foregroundColorHT = @{
    '*PASSED*' = 'Green'
    '*Warnings.*' = 'Yellow'
    '*Fail*' = 'Red'
    '*Run*' = 'Red'
}

function WriteLog([string]$LogString)
{
    #Logging to File
    If (!(Test-Path $this.LogFile)) {New-Item -Path $this.LogFile -Force}
    Add-content $this.LogFile -value $LogString

    # Get the foregound color
    $foregroundColorKey = $foregroundColorHT.Keys | Where-Object { $LogString -clike $_ }

    # Printing on Console
    if ($foregroundColorKey) {
        # If a wildcard value exists in the hashtable
        $foregroundColorValue = $foregroundColorHT.$($foregroundColorKey)
        Write-host $LogString -fore $foregroundColorValue -nonewline

    } else {
        # If no match was found in the hashtable
        Write-Host "       " $LogString
    }
}

WriteLog -LogString "Testcase Failed!!"

In your case you have also a background color depending to the wildcard string, so as an alternative to your switch statement you could use a psobject array:

# PSObject array for foreground and background colors
$colorArray = @()

$colorArray += New-Object psobject -Property @{ Wildcard = '*PASSED*'; FGC = 'Green'; BGC = $null}
$colorArray += New-Object psobject -Property @{ Wildcard = '*Warnings.*'; FGC = 'Yellow'; BGC = $null}
$colorArray += New-Object psobject -Property @{ Wildcard = '*Fail*'; FGC = 'Red'; BGC = $null}
$colorArray += New-Object psobject -Property @{ Wildcard = '*Run*'; FGC = 'Red'; BGC = 'White'}

function WriteLog([string]$LogString)
{
    #Logging to File
    If (!(Test-Path $this.LogFile)) {New-Item -Path $this.LogFile -Force}
    Add-content $this.LogFile -value $LogString

    # Get the color
    $color = $colorArray | Where-Object { $LogString -clike $_.Wildcard }
    
    # Printing on Console
    if ($color) {
        # If a wildcard value exists in the psobject array
        $foregroundColor = $color.FGC
        $backgroundColor = $color.BGC

        if ($backgroundColor) {
            Write-host $LogString -fore $foregroundColor -BackgroundColor $backgroundColor -nonewline
        } else {
            Write-host $LogString -fore $foregroundColor -nonewline
        }
    } else {
        # If no match was found in the psobject array
        Write-Host "       " $LogString
    }
}

WriteLog -LogString "Testcase Running!!"
fabrisodotps1
  • 117
  • 1
  • 10
  • Thank you @pwsh.exe for this approach. I can certainly include this in my script where just the Text color is involved. However, unfortunately there are some other actions as well that are to be performed, depending on the wild card string . For Ex : If we encounter PASS, Print "The Action was successful". Seems like I will have to stick to Switch case only :( – Prateek Jaiswal Apr 13 '22 at 10:12