Skip to content

Instantly share code, notes, and snippets.

@Geogboe
Last active September 10, 2018 21:49
Show Gist options
  • Save Geogboe/77fc7828595e386127586f1f83de9832 to your computer and use it in GitHub Desktop.
Save Geogboe/77fc7828595e386127586f1f83de9832 to your computer and use it in GitHub Desktop.
function Write-LogMessage {
<#
.SYNOPSIS
Console logging helper function.
.DESCRIPTION
For a given set of parameters, will create a standardized log message that can be written to any of
the various output streams.
For more documentation on the available output streams see this:
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-6
.EXAMPLE
PS C:\> Write-LogMessage -Message "Test Message Numbers: {0},{1}" -Values "Test1","Test2" -Type "output"
LOG: 6/4/2018 4:21 PM - MSG: Test Message Numbers: Test1,Test2
In this example a string is printed that substitutes the {} placeholder for the values in the list, in order.
.EXAMPLE
PS C:\> Write-LogMessage -Values "Test1","Test2" -Type "output"
LOG: 6/4/2018 4:22 PM - MSG: Test1,Test2
In this example the message paramter is ommited so the values in the values list are joined together with a comma
.EXAMPLE
PS C:\> Write-LogMessage -InputHashtable @{ prop1 = "value1"; prop2 = "value2" } -Type "output"
LOG: 6/4/2018 4:23 PM - MSG: Hashtable object enumeration:
prop2:value2
prop1:value1
In this example the InputHashtable parameter is used an automatically prints the values and values of the hashtable
This is useful for debugging.
.EXAMPLE
PS C:\> Write-LogMessage -Message "Test: {0}" -IncludeDetails -Type Output
LOG: 6/4/2018 4:19 PM - MSG: Test: - Invocation Details: <No file>
In the above example we can add the arg -IncludeDetails which appends the script and command and lin number that
Invoke write log message. This can be useful for debugging.
.INPUTS
None
.OUTPUTS
None
.NOTES
General notes
v0.0.2 - George
Roadmap
- Add writing to text files and event logs
#>
[CmdletBinding( PositionalBinding, DefaultParameterSetName = "NormalInput" )]
param (
# String text that needs to be displayed
# You can insert variable values using {} placeholders
# By default this will just join all your values
[Parameter( ParameterSetName = "NormalInput", Position = 0 )]
[string]
$Message = ( $Values -join $SeperatorChar ),
# A list of values that will replaces the {} placeholders in the message.
# If the message field isn't specified, these values will just be joined together.
# using the default join operator.
[Parameter( ParameterSetName = "NormalInput", Position = 1)]
[string[]]
$Values,
# Why type of message stream to write to.
# Defaults to host stream which, on PS5 is the equivalent to
# info with informationaction = Continue
[Parameter( Position = 2)]
[ValidateSet( "Info", "Verbose", "Debug", "Host", "Error", "Warning", "Throw", "Output")]
[Alias("Type")]
[string]
$OutputStream = "Host",
# Will indicate that a banner will be printed marking the start of the curently running function
[Parameter( Mandatory = $false, ParameterSetName = "PrintFunctionHeaderBanner" )]
[switch]
$PrintFunctionHeaderBanner,
# Will indicate that a banner will be printed marking the end of the curently running function
[Parameter( Mandatory = $false, ParameterSetName = "PrintFunctionFooterBanner" )]
[switch]
$PrintFunctionFooterBanner,
# Specifies a hashtable that is printed inline
# The hashtable keys and properties will be printed and join using
# the seperatator listed below
[Parameter( Mandatory = $false, ParameterSetName = "InputHashtableSet" )]
[hashtable]
$InputHashtable,
# If values are being joined, this will be used as the separator.
# This defaults to a comma
[Parameter( ParameterSetName = "InputHashtableSet" )]
[string]
$SeperatorChar = ",",
# Include additional details about the invocation.
[Parameter( Mandatory = $false )]
[switch]
$IncludeDetails = $false,
# Determines whether or not the date will be printed
[Parameter( Mandatory = $false )]
[switch]
$ExcludeDate = $false,
# Prefix to use at the begining of the message string.
[Parameter( DontShow )]
[string]
$MessagePrefix = "LOG: ",
# The date
[Parameter( DontShow )]
[string]
$LogDate = ( Get-Date -Format g ).ToString()
)
begin {
$ErrorActionPreference = "Stop"
Set-StrictMode -Version 2.0
}
process {
# Put all our values in an object for organization
$Log = [PSCustomObject]@{
CallingFunctionName = ( Get-PSCallStack ).Location[1] # ( Get-PSCallStack )[1].Command
PrintCallingFunction = $IncludeDetails
OutputString = [string]
Prefix = $MessagePrefix
Suffix = $null
ExcludeDate = $ExcludeDate
Date = $LogDate + ": "
Strings = @()
InnerText = $null
}
# Add the date to the log if not excluded then update the prefix to include the date
if ( $ExcludeDate -eq $false ) { $Log.Prefix += $Log.Date }
# Set the message content to the keys and values of the provided hashtable
if ( $PSCmdlet.ParameterSetName -eq "InputHashtableSet" ) {
$Log.InnerText += Invoke-HashtableEnumeration -Hashtable $InputHashtable -StringSeparator $SeperatorChar
}
# Display a banner indicating the function header
if ( $PSCmdlet.ParameterSetName -eq "PrintFunctionHeaderBanner" ) {
$Log.InnerText = "------------- Entering Function: " + $Log.CallingFunctionName
$OutputStream = "Debug"
}
# Display a banner indicating the function footer
if ( $PSCmdlet.ParameterSetName -eq "PrintFunctionFooterBanner" ) {
$Log.InnerText = "------------- Exiting Function: " + $Log.CallingFunctionName
$OutputStream = "Debug"
}
# If a message has been provided create that
if ( $PSCmdlet.ParameterSetName -eq "NormalInput" ) {
$Log.InnerText = ( $Message -f $Values )
}
# Print the calling function and line if debug is the output stream
if (
$OutputStream -eq "Debug" -OR
$Log.PrintCallingFunction -AND
!(
$PSCmdlet.ParameterSetName -eq "PrintFunctionHeaderBanner" -OR
$PSCmdlet.ParameterSetName -eq "PrintFunctionFooterBanner"
)
) {
$Log.Suffix += "[ " + $Log.CallingFunctionName + " ]"
}
# Build the log string array
$Log.Strings += $Log.Prefix
$Log.Strings += $Log.InnerText
$Log.Strings += $Log.Suffix
$Log.OutputString = $Log.Strings -join ''
switch ( $OutputStream ) {
"Info" { Write-Information $Log.OutputString }
"Output" { Write-Output $Log.OutputString }
"Host" { Write-Host $Log.OutputString }
"Verbose" { Write-Verbose $Log.OutputString }
"Debug" { Write-Debug $Log.OutputString }
"Error" { Write-Error $Log.OutputString }
"Warning" { Write-Warning $Log.OutputString }
"Throw" { throw $Log.OutputString }
}
}
}
function Invoke-HashtableEnumeration {
<#
.SYNOPSIS
Enumerates the keys and values of a hashtable into a single string
.DESCRIPTION
Loops through the keys and values of a given
hashtable and joined these keys and values into a string
separated by the provided string separator.
This is especially useful for debugging
#>
[CmdletBinding()]
param (
[hashtable]
$Hashtable,
[string]
$StringSeparator
)
$OutputString = "Hashtable object enumeration:`n"
$InputHashtable.GetEnumerator() | ForEach-Object {
$KeyValuePair = " - " + $_.Name + ": " + $_.Value + "`n"
$OutputString += $KeyValuePair
}
return $OutputString
}
<#
Poor Mans Pester Tests
Import-Module <Module> -Force
InModuleScope <Module> {
Describe "Write-LogMessage" {
$DebugPreference = "Continue"
$VerbosePreference = "Continue"
It "Writes a function header to the debug stream" {
Write-LogMessage -PrintFunctionHeaderBanner
}
It "Writes a function footer the debug stream" {
Write-LogMessage -PrintFunctionFooterBanner
}
It "Writes a string to the host stream" {
Write-LogMessage -Message "Hello World"
}
It "Writes a string with value substitutions the host stream" {
Write-LogMessage -Message "Value 1: {0}, Value 2: {1}" -Values "Hello", "World"
}
It "Write the enumerated values of a hastable to the verbose stream" {
Write-LogMessage -InputHashtable @{ Hello = "World" } -OutputStream Verbose
}
It "Writes a message to throw a terminating error" {
{ Write-LogMessage -Message "Hello World" -OutputStream throw } | Should -Throw
}
}
}
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment