Kabompo.Logging.ps1
# # Kabompo.Logging.ps1 # function Register-KabompoLogging { <# .SYNOPSIS Starts logging of KABOMPO module. .DESCRIPTION Initializes the logging to the KABOMPO logfile in the subdirectory "log". Please be sure, that the executing user has write access to this folder. The log file will be generated as a CMTrace (see Microsoft SCCM) compatible file. .PARAMETER LoggingPath Optional. Path of the folder where the log file is located. Default is "$($PSScriptRoot)\log". Fallback is "$($env:TEMP)\KABOMPO" (if path is not accessible or due to invalid characters given) .PARAMETER Name Optional. Base name of the log file. Default is "kabompo" .PARAMETER Extension Optional. Extension of the log file without a leading dot. Default is "log" .PARAMETER MaxSize Optional. Maximum size (bytes) of a log file at the time of the registration. Default: 5000000 - Min: 200 - Max: 2147483647 (i.e. 2GB) If a file "$LoggingPath\$Name.$Extension" exists and its size exceeds $MaxSize, then it will be renamed according to the pattern "$Name_[1-9][0-9]*.$Extension" - i.e. the next free number is added to the base name of the log file. Note: No size check is done during the logging, only at the begin of the logging .PARAMETER MaxAge Optional. All log files (i.e. matching the pattern "$LoggingPath\*.log") older than $MaxAge days will be deleted prior to the registrating of the current log file. Default: 60 - Min: 1 - Max: 32676 (i.e. more than 89 years) .PARAMETER LogDetailLevel Optional. The log's detail level. Default: 1 - Allowed values: 0 = Debug, 1 = Normal, 2 = Minimalistic Warnings and Errors will be logged whatever detail level is set. Logs of type 1 ("Normal") will be logged only if the log level matches the log's detail level (i.e. if the log level equals or exceeds the log's detail level). .EXAMPLE Register-Logging .EXAMPLE Register-Logging -Name "MyLog" -Extension "log" -MaxSize 5000000 -MaxAge 60 .EXAMPLE Register-Logging -Name "MyLog" -Extension "log" -LogDetailLevel 2 .NOTES .LINK https://marketplace.matrix42.com #> Param ( [Parameter(Mandatory=$false)] [string]$LoggingPath="$($PSScriptRoot)\log", #path to logging file (just the folder) [Parameter(Mandatory=$false)] [string]$Name="kabompo", #basename of the logging file [Parameter(Mandatory=$false)] [string]$Extension="log", #extension of the logging file [Parameter(Mandatory=$false)] [ValidateRange([uint32]200,[uint32]2147483647)] #max 2^31-1 bytes (or 2GB) [uint32]$MaxSize=5000000, #max log file size at start of logging - not checked during logging! [Parameter(Mandatory=$false)] [ValidateRange(1,32767)] #max 2^15-1 days (or more than 89 years) [int]$MaxAge=60, #remove all log files older than $MaxAge days [Parameter(Mandatory=$false)] [ValidateSet(0,1,2)] #log detail level: 0 = Debug, 1 = Normal, 2 = Minimalistic [int] $LogDetailLevel=0 #logging will be done for every message with log level greater or equal this detail level ) try { # should we do a verbose registration of logging module $DoVerbose = ($PSBoundParameters['Verbose'] -eq $true) # remove the current logfile store $global:kabompoLog = $null if ([string]::IsNullOrWhiteSpace($LoggingPath)) { $LoggingPath = "$($PSScriptRoot)\log" } # Check if path exist if(!(Test-Path "$LoggingPath")) { try { $logPath = (New-Item -Path "$LoggingPath" -ItemType directory -ErrorAction Stop).FullName } catch { $logPath = (New-Item -Path "$($env:TEMP)" -Name KABOMPO -ItemType directory -Force -ErrorAction Stop).FullName } } else { $logPath = "$LoggingPath" } # define the absolute path of the logfile $logFile = "{0}\{1}.{2}" -f $logPath, $Name, $Extension # get files based on lastwrite filter and specified folder $Files = @(Get-ChildItem $logPath -Filter "*.$Extension" -ErrorAction Stop | where { $_.LastWriteTime -le ((Get-Date).AddDays(-$MaxAge))}) # Delete all files older than $MaxAge days foreach ($File in $Files) { Remove-Item $File.FullName -Verbose:$DoVerbose | Out-Null } # Is logfile size more than size $MaxSize bytes $log = @(Get-ChildItem $logPath -Filter "$Name.$Extension" -ErrorAction Stop | where { $_.Length -ge $MaxSize }) if($log -ne $null) { # Find the next free logfile-name $logCount=1 while ($targetLogName -eq $null) { $testLogName = "{0}_{1}.{2}" -f $Name, $logCount, $Extension if(!(Test-Path "$logPath\$testLogName")) { $targetLogName = $testLogName } else { $logCount++ } } # Rename logfile Rename-Item -Path $logFile -NewName $targetLogName -Verbose:$DoVerbose } # Define logfile-name $global:kabompoLog = $logFile # Set LogLevel $global:LogDetailLevel = $LogDetailLevel # do an initial logging Add-KabompoLogLine -Message "----------------- New logfile worker initialized. Start logging ----------------- " -Component Register-KabompoLogging -Type 1 -Verbose:$DoVerbose } catch { throw $_.Exception } } function Add-KabompoLogLine { <# .SYNOPSIS Add a line to the KABOMPO logfile. .DESCRIPTION Add a line to the registered KABOMPO logfile in a CMTrace (see Microsoft SCCM) compatible format. Please be sure, that the executing user has write access to file. .PARAMETER Message Mandatory. The message describing the event being logged. May be given as $null or empty string if -ErrorMessage parameter is given. Note: If neither $Message nor $ErrorMessage is given ($null or empty string) no logging will be done. .PARAMETER ErrorMessage Optional. Meant for errors - overwrites parameter -Type with value 3 (Error) if not null and not empty. If both $Message and $ErrorMessage are given then the CMTrace message is build from both parameters according to the pattern "$Message. Details: $ErrorMessage". Note: If neither $Message nor $ErrorMessage is given ($null or empty string) no logging will be done. .PARAMETER Component Optional. Fills the "component" field of the CMTrace log. Component "KABOMPO" is used if $Component is $null or empty. .PARAMETER Type Mandatory. Fills the "type" field of the CMTrace log (representing 1 for "Normal", 2 for "Warning" and 3 for "Error"). The type will be overwritten by 3 ("Error") if a non-empty -ErrorMessage parameter is provided. .PARAMETER LogLevel Optional. Log level of the message provided. Default: 1 - Allowed values: 0 = Debug, 1 = Normal, 2 = Minimalistic The log level is only obeyed for events of type 1 ("Normal"), all other types (2 for "Warning" and 3 for "Error") are always logged. Logs of type 1 ("Normal") will be logged only if the log level matches the log's detail level (i.e. if the log level equals or exceeds the log's detail level). .PARAMETER Context Optional. Fills the "context" field of the CMTrace log. Default: "" (i.e. empty string) .PARAMETER Thread Optional. Fills the "thread" field of the CMTrace log. Default: "" (i.e. empty string) .PARAMETER File Optional. Fills the "file" field of the CMTrace log. Default: "" (i.e. empty string) .PARAMETER Verbose Optional. The bound PS parameter is used to do an additional output to the host. Some pretty printing is done by using $global:LogIndentationStep for defining indentation steps (i.e. a user of this logging tool as to maintain $global:LogIndentationStep him- or herself for pretty printing) .EXAMPLE Add-KabompoLogLine -Message "Some message" -Component My-CurrentFunction -Type 1 .EXAMPLE Add-KabompoLogLine -Message "Some message" -ErrorMessage "My detailed error message" -Component My-CurrentFunction -Type 3 .EXAMPLE Add-KabompoLogLine -Message "Also output to host" -ErrorMessage "My detailed error message" -Component My-CurrentFunction -Type 3 -Verbose .NOTES .LINK https://marketplace.matrix42.com #> Param ( [Parameter(Mandatory=$true)] [string]$Message, [Parameter(Mandatory=$false)] [string]$ErrorMessage="", #ErrorMessage overwrites Type (i.e. if set the logging type will always be 3 (Error - red)) [Parameter(Mandatory=$false)] [string]$Component="", [Parameter(Mandatory=$true)] [ValidateSet(1,2,3)] #Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red) [int]$Type, [Parameter(Mandatory=$false)] [ValidateSet(0,1,2)] #Log Level: 0 = Debug, 1 = Normal, 2 = Minimalistic [int]$LogLevel = 1, [Parameter(Mandatory=$false)] [string]$Context="", [Parameter(Mandatory=$false)] [string]$Thread="", [Parameter(Mandatory=$false)] [string]$File="" ) # Exit when logging is disabled for unit testing if($global:LogDetailLevel -eq 99) { return } # Exit function when given loglevel is less than configured loglevel if($LogLevel -lt $global:LogDetailLevel -and $Type -eq 1) { return } # Exit function if idention level is too high for minimalistic loglevel if($global:LogIndentationStep -ge 1 -and $global:LogDetailLevel -eq 2 -and $Type -eq 1) { return } # Exit function if idention level is too high for normal loglevel if($global:LogIndentationStep -ge 2 -and $global:LogDetailLevel -eq 1 -and $Type -eq 1) { return } # exit function if logging is switched off if($LogLevel -eq 3) { return } # Exit function if no message is given if([string]::IsNullOrEmpty($Message) -and [string]::IsNullOrEmpty($ErrorMessage)) { return } # Use Errormessage as message when message is empty elseif([string]::IsNullOrEmpty($Message) -and ![string]::IsNullOrEmpty($ErrorMessage)) { $Message = $ErrorMessage } # Combine Errormessage and Message when both are given elseif(![string]::IsNullOrEmpty($Message) -and ![string]::IsNullOrEmpty($ErrorMessage)) { $Message = "{0}. Details: {1}" -f $Message, $ErrorMessage } # Generate Date and Time string for CMTrace and Console Log $TimeString = Get-Date -Format "HH:mm:ss.ffffff" $DateString = Get-Date -Format "MM-dd-yyyy" # If errormessage is given, set message type to error if (![string]::IsNullOrEmpty($ErrorMessage)) { $Type = 3 } # Set default comonent string when not given if ([string]::IsNullOrEmpty($Component)) { $Component = "KABOMPO" } # Configure Log Message output string $LogMessage = "<![LOG[{0}]LOG]!><time=""{1}"" date=""{2}"" component=""{3}"" context=""{4}"" type=""{5}"" thread=""{6}"" file=""{7}"">" -f $Message, $TimeString, $DateString, $Component, $Context, $Type, $Thread, $File $LogMessage | Out-File -Append -Encoding UTF8 -FilePath $global:kabompoLog # Write output also to host when enabled and PS-Host is Console or ISE if($PSBoundParameters['Verbose'] -eq $true) { Write-KabompoLogToHost -Message $Message -Component $Component -Type $Type -DateString $DateString -TimeString $TimeString } } function Write-KabompoLogToHost { <# .SYNOPSIS Output a line to the Powershell console. .DESCRIPTION Output a line to the Powershell console. This function is just for internal use and not published in the module. .PARAMETER Message Mandatory. The message as provided to the CMTrace log entry .PARAMETER Component Mandatory. The component as provided to the "component" field of the CMTrace log entry .PARAMETER Type Mandatory. The type as provided to the "type" field of the CMTrace log entry .PARAMETER DateString Mandatory. The date as provided to the "date" field of the CMTrace log entry .PARAMETER TimeString Mandatory. The date as provided to the "time" field of the CMTrace log entry .EXAMPLE Write-KabompoLogToHost -Message "Some message" -Component My-CurrentFunction -Type 1 -DateString 2016-05-06 -TimeString 12:39:33.698623 .NOTES .LINK https://marketplace.matrix42.com #> Param ( [Parameter(Mandatory=$true)] [string]$Message, [Parameter(Mandatory=$true)] [string]$Component, [Parameter(Mandatory=$true)] [ValidateSet(1,2,3)] #Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red) [int]$Type, [Parameter(Mandatory=$true)] [string]$DateString, [Parameter(Mandatory=$true)] [string]$TimeString ) $indent = (37 - $Component.Length) + ($global:LogIndentationStep * 2) # Output information line to the console with the normal powershell console colors $indentMessage = $Message.PadLeft($Message.Length + $indent, " ") if($Type -eq 1) { $HostMessage = "{0}_{1} I [{2}] {3}" -f $DateString, $TimeString, $Component, $indentMessage Write-Host -Object $HostMessage } # Output warning line to the console in yellow elseif($Type -eq 2) { $HostMessage = "{0}_{1} W [{2}] {3}" -f $DateString, $TimeString, $Component, $indentMessage Write-Host -Object $HostMessage -ForegroundColor Yellow } # Output error line to the console in red elseif($Type -eq 3) { $HostMessage = "{0}_{1} E [{2}] {3}" -f $DateString, $TimeString, $Component, $indentMessage Write-Host -Object $HostMessage -ForegroundColor Red } } # SIG # Begin signature block # MIINJAYJKoZIhvcNAQcCoIINFTCCDRECAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUgInjZSnVH8VIlhC8YXSLvdbW # yo6gggpZMIIE+DCCA+CgAwIBAgIQXWihGXfS4Od7/8YeI88pIDANBgkqhkiG9w0B # AQsFADB/MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRp # b24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxMDAuBgNVBAMTJ1N5 # bWFudGVjIENsYXNzIDMgU0hBMjU2IENvZGUgU2lnbmluZyBDQTAeFw0xNTAyMDMw # MDAwMDBaFw0xODA0MDMyMzU5NTlaMGAxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZI # ZXNzZW4xEjAQBgNVBAcTCUZyYW5rZnVydDEVMBMGA1UEChQMTWF0cml4IDQyIEFH # MRUwEwYDVQQDFAxNYXRyaXggNDIgQUcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw # ggEKAoIBAQDHZNuFnBatHdyRnMUJ2Y1P6k49MjD04t9S7ukWj8upP/B6wPRYzzQf # 6QVMPKzMhNTPfIXaIEzi/jhT0jjwnXC0O9hF2rwTpDRnVOnVJemaqd2XsSDVEBUY # yhH7QZ82Zwi1nnSgo69WL694L3f74ge6bRiRIJ/IoZawj+74NL/9B93kGKH89sew # VtqPoDwSklJmzc86Qlgw6X/WXenHw8n6k/htEIjkHpiE6iGkDZp1gAPBERIV/qi/ # HyIZpvsO3g9RvcWEDvRvq6ZsIPfAvtlOnVWPrvik96pEDugHKPtvyjuAQtJtxw42 # zsYbB7lQxCo7khjhuZKYrzjv/l79BnC1AgMBAAGjggGNMIIBiTAJBgNVHRMEAjAA # MA4GA1UdDwEB/wQEAwIHgDArBgNVHR8EJDAiMCCgHqAchhpodHRwOi8vc3Yuc3lt # Y2IuY29tL3N2LmNybDBmBgNVHSAEXzBdMFsGC2CGSAGG+EUBBxcDMEwwIwYIKwYB # BQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkMF2h0 # dHBzOi8vZC5zeW1jYi5jb20vcnBhMBMGA1UdJQQMMAoGCCsGAQUFBwMDMFcGCCsG # AQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDovL3N2LnN5bWNkLmNvbTAmBggr # BgEFBQcwAoYaaHR0cDovL3N2LnN5bWNiLmNvbS9zdi5jcnQwHwYDVR0jBBgwFoAU # ljtT8Hkzl699g+8uK8zKt4YecmYwHQYDVR0OBBYEFAAbz15M7iRhPipVPcQDgb2D # MWA5MBEGCWCGSAGG+EIBAQQEAwIEEDAWBgorBgEEAYI3AgEbBAgwBgEBAAEB/zAN # BgkqhkiG9w0BAQsFAAOCAQEAScMz5dR4/qoFzikf7Dj15lRfGWNY1IZ50GPxhhqo # aMM8Vb8oyO3Z0J9bRuX/gwV80NaaKuC1MX2b/5yVLqTpZXvVAO4uwxNq5/BXywi5 # 7Wb6V2ld9Fey9TsSQHZLwbyYua1+yPGAnI7hcc/I9TAsHXIjx0kclwJm8FYMUh8+ # NnEnt7PTV3Z0ytUsR/oS7Kq5TYNhxKUpTP2vZfdYnM7yf4oglandpdsA0tJATc2r # Gw/tdUEqOyynzPG5OI49SDkypSdFTdEnN70CwrHUcIplwY3Ro7hWWtHA4drT2bgh # 1KsFyPjq3rDQD6xWAIuiFlBAwnr1DzdGFi2jMZfKLWNpXTCCBVkwggRBoAMCAQIC # ED141/l2SWCyYX308B7KhiowDQYJKoZIhvcNAQELBQAwgcoxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 # c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDIwMDYgVmVyaVNpZ24sIEluYy4gLSBG # b3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3Mg # MyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc1MB4X # DTEzMTIxMDAwMDAwMFoXDTIzMTIwOTIzNTk1OVowfzELMAkGA1UEBhMCVVMxHTAb # BgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBU # cnVzdCBOZXR3b3JrMTAwLgYDVQQDEydTeW1hbnRlYyBDbGFzcyAzIFNIQTI1NiBD # b2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCX # gx4AFq8ssdIIxNdok1FgHnH24ke021hNI2JqtL9aG1H3ow0Yd2i72DarLyFQ2p7z # 518nTgvCl8gJcJOp2lwNTqQNkaC07BTOkXJULs6j20TpUhs/QTzKSuSqwOg5q1PM # IdDMz3+b5sLMWGqCFe49Ns8cxZcHJI7xe74xLT1u3LWZQp9LYZVfHHDuF33bi+Vh # iXjHaBuvEXgamK7EVUdT2bMy1qEORkDFl5KK0VOnmVuFNVfT6pNiYSAKxzB3JBFN # YoO2untogjHuZcrf+dWNsjXcjCtvanJcYISc8gyUXsBWUgBIzNP4pX3eL9cT5Dio # hNVGuBOGwhud6lo43ZvbAgMBAAGjggGDMIIBfzAvBggrBgEFBQcBAQQjMCEwHwYI # KwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wEgYDVR0TAQH/BAgwBgEB/wIB # ADBsBgNVHSAEZTBjMGEGC2CGSAGG+EUBBxcDMFIwJgYIKwYBBQUHAgEWGmh0dHA6 # Ly93d3cuc3ltYXV0aC5jb20vY3BzMCgGCCsGAQUFBwICMBwaGmh0dHA6Ly93d3cu # c3ltYXV0aC5jb20vcnBhMDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9zMS5zeW1j # Yi5jb20vcGNhMy1nNS5jcmwwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMD # MA4GA1UdDwEB/wQEAwIBBjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50 # ZWNQS0ktMS01NjcwHQYDVR0OBBYEFJY7U/B5M5evfYPvLivMyreGHnJmMB8GA1Ud # IwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEBCwUAA4IBAQAT # hRoeaak396C9pK9+HWFT/p2MXgymdR54FyPd/ewaA1U5+3GVx2Vap44w0kRaYdtw # b9ohBcIuc7pJ8dGT/l3JzV4D4ImeP3Qe1/c4i6nWz7s1LzNYqJJW0chNO4LmeYQW # /CiwsUfzHaI+7ofZpn+kVqU/rYQuKd58vKiqoz0EAeq6k6IOUCIpF0yH5DoRX9ak # JYmbBWsvtMkBTCd7C6wZBSKgYBU/2sn7TUyP+3Jnd/0nlMe6NQ6ISf6N/SivShK9 # DbOXBd5EDBX6NisD3MFQAfGhEV0U5eK9J0tUviuEXg+mw3QFCu+Xw4kisR93873N # Q9TxTKk/tYuEr2Ty0BQhMYICNTCCAjECAQEwgZMwfzELMAkGA1UEBhMCVVMxHTAb # BgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBU # cnVzdCBOZXR3b3JrMTAwLgYDVQQDEydTeW1hbnRlYyBDbGFzcyAzIFNIQTI1NiBD # b2RlIFNpZ25pbmcgQ0ECEF1ooRl30uDne//GHiPPKSAwCQYFKw4DAhoFAKB4MBgG # CisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC # AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYE # FDEcCGonv9lK0mshQPrQE0YN5sqeMA0GCSqGSIb3DQEBAQUABIIBAHAeRFKYvOAR # /yCmTDjPl6B9JU4WpxSMC6DV0z9OGJ7KA/w3TeoOEFHvOeNYgNH+ugWalyl1I1D3 # 0gCxG3cXMspxzVsURVOHnBwj/RwUxSyf0Scbp+RDlFUasee20MxtQrpsYH3AoY5I # 8HF2NiT25WUQsVtvGhHOnM2ttKETWioUJLf1ppdT/5AtPQDjH+fXmnWFEIG7/yNZ # x2aHwd+KQ+PNNFua7eN7VZ/sNUrCcxYqTSN4FEo4QeGKbALOc/C0jdNMod11EcwW # N6yGYvRtHf7cPPVFMoK85gGj8tcDW5iI4uJQIrFyWEUf6D1W7V+z6RlY+xeavw5k # 84Olql4utO8= # SIG # End signature block |