PowerShell Logging Functions
I have been working on automating my organizations Active Directory/Exchange user provisioning, and needed a method to easily log what actions are taken. To accomplish this, I decided to write a couple PowerShell logging functions that I could integrate into my other functions for creating the user, creating the mailbox, generating approval emails, and assigning groups. The functions I came up with are Start-Log, Write-Log, and Stop Log.
My goal was to create a log file with some basic information (time, username, and machine calling the function) with Start-Log. Then, Write-Log will write a line to the file with a timestamp, username, and specified log message. Finally, Stop-Log will right a tail line with the same information as Start-Log. Here are the functions:
Start-Log:
FUNCTION Start-Log{ <# .SYNOPSIS Creates log file .DESCRIPTION Creates log file based on specified name and path, backs up existing log if exists .PARAMETER Path Requires a valid path .PARAMETER Name Requires a valid filename .EXAMPLE PS C:\> Start-Log -Path "C:\Temp" -Name "NewLog.log" .NOTES Author : Ryan DeVries Last Updated: 2015/05/19 Version : 1 #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter the path for the log directory",ValueFromPipeline)] [ValidateNotNullorEmpty()] [String]$Path, [Parameter(Position=1,Mandatory,HelpMessage="Enter the name of the log",ValueFromPipeline)] [ValidateNotNullorEmpty()] [String]$Name ) begin { Write-Verbose "Starting $($MyInvocation.Mycommand)" Write-Verbose "Detected parameter set $($PSCmdlet.ParameterSetName)" Write-Verbose ($PSBoundParameters | out-string) } process { try { $fullpath = $path + "\" + $name $bakpath = $fullpath + '.bak' Write-Verbose "Checking for existing log at $fullpath" if(Test-Path -Path $fullpath){ Move-Item -Path $fullpath -Destination $bakpath -Force -ErrorAction Stop Write-Verbose "Backed up existing log to $bakpath" } New-Item -Path $path -Name $name -ItemType file -ErrorAction Stop | Out-Null Write-Verbose "Created log at $fullpath" Add-Content -Path $fullpath -Value "Log started: at [$([DateTime]::Now)] by $env:USERNAME on $env:COMPUTERNAME" Add-Content -Path $fullpath -Value "--------------------------------------------------------------------`n" Write-Verbose "Started Log at $fullpath" } catch { Write-Error $_ } } end { Write-Verbose "Ending $($MyInvocation.Mycommand)" } }
Nothing super complex going on here. Here is the basic flow:
- Takes a couple strings as input, one as the path to store the log in, one as the name of the log file
- Checks if a file with that name already exists, renaming it with .bak if it does. If a .bak exists, it will overwrite it.
- Creates the log file and adds a header to it using environment variables
Write-Log:
FUNCTION Write-Log{ <# .SYNOPSIS Writes a line to a log file .DESCRIPTION Writes a line to the end of the specified log file, prepended with a timestamp .PARAMETER Path Specifies a valid log path .PARAMETER Line Specifies a line to add to the log .EXAMPLE PS C:\> Log-Write -Path "C:\Temp\NewLog.log" -Line "Test message please ignore." .NOTES Author : Ryan DeVries Last Updated: 2015/05/19 Version : 1 #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter the path of the log file",ValueFromPipeline)] [ValidateNotNullorEmpty()] [String]$Path, [Parameter(Position=1,Mandatory,HelpMessage="Enter the line to add to the log",ValueFromPipeline)] [ValidateNotNullorEmpty()] [String]$Line ) begin { Write-Verbose "Starting $($MyInvocation.Mycommand)" Write-Verbose "Detected parameter set $($PSCmdlet.ParameterSetName)" Write-Verbose ($PSBoundParameters | out-string) } process{ if(Test-Path -Path $path){ $timeline = "$([DateTime]::Now)" + "`t" + $env:USERNAME + "`t" + $line Write-Verbose "Writing $timeline to $path" Add-Content -Path $path -Value $timeline } else{ Write-Error "Log does not exist at $path " -Category ResourceUnavailable } } }
This one is even simpler, just takes a path and a message and writes a line, including a timestamp and username, if the file exists.
Stop-Log:
FUNCTION Stop-Log{ <# .SYNOPSIS Ends log file .DESCRIPTION Adds a closing line to a log file .PARAMETER Path Requires a valid log path .EXAMPLE PS C:\> Stop-Log -Path "C:\Temp\NewLog.log" .NOTES Author : Ryan DeVries Last Updated: 2015/05/19 Version : 1 #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter the path of the log file",ValueFromPipeline)] [ValidateNotNullorEmpty()] [String]$Path ) begin { Write-Verbose "Starting $($MyInvocation.Mycommand)" Write-Verbose "Detected parameter set $($PSCmdlet.ParameterSetName)" Write-Verbose ($PSBoundParameters | out-string) } process { if(Test-Path -Path $path){ Write-Verbose "Finalizing Log at $path" Add-Content -Path $Path -Value "`n--------------------------------------------------------------------" Add-Content -Path $Path -Value "Log ended: at [$([DateTime]::Now)] by $env:USERNAME on $env:COMPUTERNAME" } else{ Write-Error "Log does not exist at $path " -Category ResourceUnavailable } } end { Write-Verbose "Ending $($MyInvocation.Mycommand)" } }
This one is the same as Write-Log, except it only needs a path and writes a couple tail lines if the file exists.
Here is an example of what the output looks like:
Log started: at [05/21/2015 13:15:06] by rdevries on FNY-WS-XXXXXXXX -------------------------------------------------------------------- 05/21/2015 13:15:21 rdevries test message 1 05/21/2015 13:15:26 rdevries test message 2 -------------------------------------------------------------------- Log ended: at [05/21/2015 13:15:32] by rdevries on FNY-WS-XXXXXXXX
As usual, latest versions can be found on GitHub.