A simple logger using PowerShell Class

‘Sup PSHomies,

At our last DuPSUG meeting, Jaap Brassers did a short Demo on the latest addition to PowerShell Streams, Information. How did I miss this?

So what’s so great about the new Information stream? The Information stream solves the Write-Host issue of not sending output to a stream like: error;verbose;warning etc. As such we were told that Write-Host is evil and every time you use it a puppy dies… Who wants that on their conscious right?

Well with the Information stream Write-Host is allowed… no more puppy genocide!

Jaap showed us what the stream output looks like and how to write to the information stream. Here’s what the output looks like

informationstream

Here are a few properties we can play with: TimeGenerated,Source,User,Computer,Tags and MessageData. You get all of this by writing/redirecting to the information stream. The TimeGenerated property caught my eye, imagine creating a timeline of sorts. While googling (don’t act like it’s just me…) I came across a great article by Jeff Hicks on the subject (Seriously, how did I miss this?) In it he also talked about generating a timeline view… 😉

After I had some time to think about how to make use of this, it dawned on me… You know what else is native to PowerShell v5? Classes! When Classes were introduced in v5, they were another way to write DSC Resources. I’ve always thought that there’s more to classes than meets the eye.

If you’re interested in classes, Richard Siddaway has a great article taking you through each step, worth trying out.

Jaap’s demo gave me the idea to try my hand at a simple logger using classes. Here’s what I came up with…

Class WriteLog{
[string]$FileBaseName = 'Temp'
[string]$LogDirectory = 'C:\Scripts\export'
[string]$Preference = 'SilentContinue'
[bool]$Console = $true
[PSObject[]]$InfoMessages
#default constructor
WriteLog(){}
#constructor
WriteLog($fbn,$ld){
$this.FileBaseName = $fbn
$this.LogDirectory = $ld
}
WriteInformation($MessageData){
$info = $false
if ($this.Preference -eq 'Continue') { $Info = $true }
if ($Info) {
$this.InfoMessages += Write-Information -MessageData $MessageData 6>&1 | Select-Object *
}
if($this.Console){
Write-Information -MessageData $MessageData -InformationAction Continue
}
}
ExportToText(){
$this.InfoMessages |
Select TimeGenerated,MessageData |
Out-File "$($this.LogDirectory)\$($this.FileBaseName).txt" -Encoding utf8 -Force -Append -Width 1000
}
ExportToXML(){
$this.InfoMessages |
Export-Clixml -Path "$($this.LogDirectory)\$($this.FileBaseName).xml" -Encoding UTF8 -Force
}
}

Here’s a quick rundown:

construtors

The idea is to gather output from the Information stream. Constructors are a way of initiating an object for use (Shout out to Doug Finke for breaking this down for me!)

writeloginformation

I “borrowed” Jeff Hicks idea of validating the preference first. This way you can toggle between showing Write-Information and/or Write-Host data. You can use Write-Host for a more colorful experience. Did I already mention that Write-Host is cool again? :-P.  I also added the possibility to show data in the console if you choose to, a verbose action of sorts…

exportlogger

I also added two methods of exporting: text and xml. That’s where LogDirectory and FileBaseName come in. For the text export, I selected TimeGenerated and MessageData for a timeline view (I know I know Jeff Hicks did it first :-P). Export to xml saves InfoMessages in raw format.

Here’s some code to play with.

function Get-PowerShellProcess{
[cmdletbinding()]
param()

Write-Verbose "InformationPreference = $InformationPreference"
$Logger.Preference = $InformationPreference
$Logger.WriteInformation("Starting $($MyInvocation.MyCommand)")

Get-Process -Name *PowerShell*
$Logger.WriteInformation("Finishing $($MyInvocation.MyCommand)")
}

#region Main
#Initiate variable
$Logger = [WriteLog]::New('psProcess','C:\scripts\temp')

#Run with InformationAction. Information will be saved and not shown
Get-PowerShellProcess -InformationAction Continue -Verbose

#Run without InformationAction with Console set to $true
$Logger.Console = $true
Get-PowerShellProcess -Verbose

#Run without InformationAction with Console set to $false
$Logger.Console = $false
Get-PowerShellProcess -Verbose
#endregion

Here are some screenshots of the output

I initiated the object a FileBaseName value ‘psProcess’ and LogDirectory ‘C:\scripts\temp’. Default Preference is ‘SilentContinue’ and no ouput to the console

initiate

First up run with action set to continue

loggerinfoaction

$Logger.InfoMessages has redirected data.

loggerinfomessages

When console is set to true we’ll see the Information message without explicitly setting InformationAction to ‘continue’. Using InformationAction will save the Information data to InfoMessages property.

infostreamconsole

Setting the console preference back to $false stops displaying output to the console

infostreamconsolefalse

I hope that you were able to follow it all. 2016 was all about Operation Validation for me. I think classes are going to be mainstream in 2017! PowerShell + Classes will definitely give you an edge and not to mention make you feel more like a developer! 😉

The line between Dev and Ops is being blurred…

Hope it’s worth something to you…

Ttyl,

Urv

Advertisement

1 thought on “A simple logger using PowerShell Class

  1. Pingback: RoboCopy class | pshirwin

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s