Creating a logging framework in PowerShell – Part 3


In Part-1, we looked at why logging was important, established a set of guidelines or targets that we need to keep in mind while designing the framework and defined few variables that we will be using. 

In Part-2, we expanded on the basics created a few more variables and created a function ‘Write-Log’, which as the name suggests writes messages to the log file.

In this part we will look at managing the logs that we will generate. What I mean is, we will need a way to archive the log files. For this we need a couple of functions:

  • Add-BackSlashToPath, this function adds a backslash to a path.
  • Switch-LogFile, this function archives the log files that are created for a script.

First let us look at Add-BackSlashToPath. The reason why we need this function is because PowerShell does not always return paths with a backslash appended at the end. So, we append it to the end of the path.

Function Add-BackSlashToPath ($Path){
 <#
  .SYNOPSIS
     Add a backslash to any given path if it is missing.
  .DESCRIPTION
Powershell usually returns path without a backslash.
	This function takes care of that.
	We need not expose this to the environment.
  .EXAMPLE
Add-BackSlashToPath -Path "C:\Test-PS-1"
	C:\Test-PS-1\
  .EXAMPLE
	Add-BackSlashToPath -Path C:\Windows\System32\
	C:\Windows\System32\
  .EXAMPLE
	Add-BackSlashToPath -Path \\comp1\C$\Windows\System32
	\\comp1\C$\Windows\System32\
 #>
	if(Test-Path -Path $Path -IsValid){
		if($Path -match "\\$"){
			$strPath = $Path
		}else{
			$strPath = $Path + "\"
		}
	} else{
		$strPath = ".\"
	}
	$strPath
}


The second function archives the log files. The assumption is that the log file name will be scriptname.log. So, when the program finds a log with the name scriptname.log it will rename the existing log file to scriptname.001.log and then creates a new file with the scriptname.log name. This process will continue until we have as many log files as defined by the number of archives parameter. Once, this limit is reached the function will delete the last log file and update the names for all existing log files in the folder.

Function Switch-LogFile {
<#
  .SYNOPSIS
     Archive the log files for the script.
  .DESCRIPTION
The number of archive files we maintain is determined by the numArch parameter.
	Log file name is ProgramName.log.
  .EXAMPLE
Switch-LogFile -Name "C:\Test-PS-1\First.log" -Arch 10
#>
  Param (
  	[Parameter(Mandatory=$true)][string]$Name,
    [Parameter(Mandatory=$false)][int]$Arch
  )
	try{
		$pathToFile = [System.IO.Path]::GetDirectoryName($Name)
if ( ! (Test-Path -Path "$pathToFile")) {
$pathToFile = New-Item -Path "$pathToFile" -type directory
        }
$pathToFile = Resolve-Path $pathToFile #Get full path for paths passed like '.\filename'
		$pathToFile = Add-BackSlashToPath $pathToFile.Path.ToString()
		$isValidPath = Test-Path -Path "$pathToFile" -IsValid
		Write-Debug $isValidPath
		if(!$Arch){
			$Arch = $NumOfArchives
		}
		if($isValidPath){

			#Get path that can be used by Get-ChildItem (gci) and Test-Path
			$gciLogPath = $pathToFile + "*"
			$Name = $Name.Substring($Name.LastIndexOf('\') + 1)
			$logName = $Name.Substring(0,$Name.Length - 4)
			Write-Debug $gciLogPath
			#Test if the logfile exists
			$defaultLogExists = Test-Path -Path $gciLogPath -include $Name

			#If the default log i.e. "ScriptName.Log" exists
			if($defaultLogExists){
				$dirContent = Get-ChildItem $gciLogPath -Filter "$logName*.log" |Sort-Object -Property Name -Descending| Select-Object Name
				ForEach($fileName in $dirContent){
					if($fileName.Name -match "^*`.\d{3}")
					{
						$matchVal = $Matches[0]
						if(([int]$matchVal.SubString(1,$matchVal.Length-1)) -eq ($Arch))
						{
							Write-Debug "Deleting log file: $($fileName.Name)"
							$fileToDel = $pathToFile + "$($fileName.Name)"
							Remove-Item -LiteralPath $fileToDel
						}else{
							$logNum = $matchVal.SubString(1,$matchVal.Length-1)
							$logNum = "{0:D3}" -f (([int] $logNum) + 1)
							$newName = "$logName.$logNum.log"
							$fullPath = $pathToFile + "$($fileName.Name)"
							Rename-Item -Path $fullPath -NewName "$newName"
						}
					}
				}
				#we are done with all the preprocessing so we can now rename "Log.log"
				#as Log.001.log and create a new default log file.
				$fullPath = $pathToFile + $Name
				Write-Debug $fullPath
				Rename-Item -Path $fullPath -NewName "$logName.001.log"
				$newLogFile = New-Item -Path "$fullPath" -ItemType File -Force

			} else { #default log does not exist go ahead and create the log file.
				$fullPath = $pathToFile + $Name
				$newLogFile = New-Item -Path $fullPath -ItemType File -Force
			}
		}
	} catch{
		Write-Error $_
	}
}
# End Function Switch-LogFile


We now have a way of managing log files.

In the blog posts till now we have seen how to define a set of guidelines, define our variables based on these guidlines. We also, created a function that will log the data to a log file and created functions that will help us manage the log files that are generated.

In the next part we will tie all of this together and put them in a module so that we can use this as a standard way to log script actions.

Advertisements
About

By profession, I’m a SQL Server Database Administrator. I love to poke my nose into different corners and see how stuff looks in there. I keep looking for new things to do as my mind refuses to settle on one topic.

Tagged with: , , , ,
Posted in PowerShell

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: