PwSh.Fw.Log.psm1
<#
.NOTES Author: Charles-Antoine Degennes <cadegenn@gmail.com> Version: 0.0.1 Changelog: 2018.09.24, DCA - inital version Manifest created with command line: New-ModuleManifest PwSh.Log.psd1 -RootModule PwSh.Log.psm1 -ModuleVersion "0.0.1" -Author "Charles-Antoine Degennes <cadegenn@gmail.com>" #> <# .SYNOPSIS Print a message into a log file .DESCRIPTION Print a message into a log file .PARAMETER Append Append message to the log file. Do not overwrite it. Append = $true is the default. If you want to overwrite or initiate the file, call Write-ToLogFile -message "Logfile initialized" -Append:$false .PARAMETER NoNewline Do not append a new line at the end of file. .PARAMETER NoHeader Do not print header informations : "date hostname scriptname". Usefull to append text to an existing line. .EXAMPLE Write-ToLogFile -message "a log entry" -append #> function Write-ToLogFile() { [CmdletBinding()]param( [switch]$Append, [switch]$NoNewLine, [switch]$NoHeader, [string]$message, [string]$logFile ) # if we specified -trace AND -log on command line, pwsh uses Start-Transcript to log things. So we disable Write-ToLogFile() if ($Global:TRACE) { return } $date = Get-Date -UFormat %c if ($NoHeader) { $msg = $message } else { $msg = "`n" + $date + " " + $env:computername + " " + $Global:BASENAME + " " + $message } if ($logFile) { $msg | Out-File $logFile -Append:$Append -NoNewLine:$NoNewLine -Encoding utf8 } } <# .SYNOPSIS Send a message to a syslog server. .DESCRIPTION Send a message to a syslog server. Currently, only UDP is supported. .EXAMPLE $message = "This is a test" SendTo-SysLog aa.bb.cc.dd "local7" "notice" $message $env:computername "myapp" #> function Send-ToSysLog () { [CmdletBinding()]Param ( [string]$Server = "127.0.0.1", [string]$Port = 514, [ValidateSet('TCP', 'UDP', IgnoreCase = $true)] [string]$Protocol = "UDP", [switch]$TCP, [switch]$UDP, [ValidateSet('kern', 'user', 'mail', 'daemon', 'auth', 'syslog', 'lpr', 'news', 'uucp', 'cron', 'authpriv', 'ftp', 'ntp', 'logaudit', 'logalert', 'clock', 'local0', 'local1', 'local2', 'local3', 'local4', 'local5', 'local6', 'local7', IgnoreCase = $true)] [string]$Facility = "local7", [ValidateSet('Emergency', 'Alert', 'Critical', 'Error', 'Warning', 'Notice', 'Info', 'Debug', IgnoreCase = $true)] [string]$Severity = "Notice", [string]$Message = "Your payload...", [string]$FromHost = $env:computername, [string]$Tag = "PowerShell" ) Begin { # eenter($MyInvocation.MyCommand) if ($UDP) { $Protocol = "UDP" } if ($TCP) { $Protocol = "TCP" } } Process { switch ($Facility.ToLower()) { 'kern' {$iFacility = 0 * 8 ; break } 'user' {$iFacility = 1 * 8 ; break } 'mail' {$iFacility = 2 * 8 ; break } 'system' {$iFacility = 3 * 8 ; break } 'auth' {$iFacility = 4 * 8 ; break } 'syslog' {$iFacility = 5 * 8 ; break } 'lpr' {$iFacility = 6 * 8 ; break } 'news' {$iFacility = 7 * 8 ; break } 'uucp' {$iFacility = 8 * 8 ; break } 'cron' {$iFacility = 9 * 8 ; break } 'authpriv' {$iFacility = 10 * 8 ; break } 'ftp' {$iFacility = 11 * 8 ; break } 'ntp' {$iFacility = 12 * 8 ; break } 'logaudit' {$iFacility = 13 * 8 ; break } 'logalert' {$iFacility = 14 * 8 ; break } 'clock' {$iFacility = 15 * 8 ; break } 'local0' {$iFacility = 16 * 8 ; break } 'local1' {$iFacility = 17 * 8 ; break } 'local2' {$iFacility = 18 * 8 ; break } 'local3' {$iFacility = 19 * 8 ; break } 'local4' {$iFacility = 20 * 8 ; break } 'local5' {$iFacility = 21 * 8 ; break } 'local6' {$iFacility = 22 * 8 ; break } 'local7' {$iFacility = 23 * 8 ; break } default {$iFacility = 23 * 8 } #Default is local7 } switch ($Severity.ToLower()) { 'emergency' {$iSeverity = 0 ; break } #Emergency 'alert' {$iSeverity = 1 ; break } #Alert 'critical' {$iSeverity = 2 ; break } #Critical 'error' {$iSeverity = 3 ; break } #Error 'warning' {$iSeverity = 4 ; break } #Warning 'notice' {$iSeverity = 5 ; break } #Notice 'info' {$iSeverity = 6 ; break } #Informational 'debug' {$iSeverity = 7 ; break } #Debug default {$iSeverity = 5 } #Default is Notice } $pri = "<" + ($iFacility + $iSeverity) + ">" # Note that the timestamp is local time on the originating computer, not UTC. # if ($(get-date).day -lt 10) { $timestamp = $(get-date).tostring("MMM d HH:mm:ss") } else { $timestamp = $(get-date).tostring("MMM dd HH:mm:ss") } # comply with RFC3164 §4.1.2 @url https://tools.ietf.org/html/rfc3164#page-10 if ((Get-Culture).Name -eq "en-US") { $timestamp = (get-date).tostring("MMM dd HH:mm:ss") } else { # check if Use-Culture exist (bundled with PowerShellCookBook module) if (Get-Command Use-Culture -ErrorAction SilentlyContinue) { $timestamp = Use-Culture en-US { (get-date).tostring("MMM dd HH:mm:ss") } } else { eerror "Use-Culture cmdlet not found on this system. Please install PowerShellCookBook module." return $false } } # Hostname does not have to be in lowercase, and it shouldn't have spaces anyway, but lowercase is more traditional. # The name should be the simple hostname, not a fully-qualified domain name, but the script doesn't enforce this. $header = $timestamp + " " + $FromHost.tolower().replace(" ","").trim() + " " #Cannot have non-alphanumerics in the TAG field or have it be longer than 32 characters. if ($tag -match '[^a-z0-9]') { $tag = $tag -replace '[^a-z0-9]','' } #Simply delete the non-alphanumerics if ($tag.length -gt 32) { $tag = $tag.substring(0,31) } #and truncate at 32 characters. $msg = $pri + $header + $tag + ": " + $Message # Convert message to array of ASCII bytes. $bytearray = $([System.Text.Encoding]::ASCII).getbytes($msg) # RFC3164 Section 4.1: "The total length of the packet MUST be 1024 bytes or less." # "Packet" is not "PRI + HEADER + MSG", and IP header = 20, UDP header = 8, hence: if ($bytearray.count -gt 996) { $bytearray = $bytearray[0..995] } # Send the message... switch ($Protocol) { 'UDP' { $UdpClient = New-Object System.Net.Sockets.UdpClient try { # $Server # $Port $UdpClient.Connect($Server,$Port) $UdpClient.Send($ByteArray, $ByteArray.length) | out-null } catch { eerror "Failed to send syslog message via UDP. More Info: $_" } finally { $UdpClient.Close() } } 'TCP' { $TcpClient = New-Object System.Net.Sockets.TcpClient try { # $Server # $Port $TcpClient.Connect($Server,$Port) $TcpStream = $TcpClient.GetStream() $TcpWriter = New-Object System.IO.StreamWriter($TcpStream) $TcpWriter.AutoFlush = $true $TcpWriter.Write($ByteArray, 0, $ByteArray.length) } catch { eerror "Failed to send syslog message via TCP. More Info: $_" } finally { $TcpClient.Close() } } } } End { # eleave($MyInvocation.MyCommand) } } function Write-LogMessage { [CmdletBinding()]Param ( [Parameter(Mandatory = $true,ValueFromPipeLine = $true)][string]$Message, [ValidateSet('kern', 'user', 'mail', 'daemon', 'auth', 'syslog', 'lpr', 'news', 'uucp', 'cron', 'authpriv', 'ftp', 'ntp', 'logaudit', 'logalert', 'clock', 'local0', 'local1', 'local2', 'local3', 'local4', 'local5', 'local6', 'local7', IgnoreCase = $true)] [string]$Facility = "local7", [ValidateSet('Emergency', 'Alert', 'Critical', 'Error', 'Warning', 'Notice', 'Info', 'Debug', 'Devel', IgnoreCase = $true)] [string]$Severity = "Notice" ) Begin { # eenter($Script:NS + '\' + $MyInvocation.MyCommand) } Process { return $Message } End { # eleave($Script:NS + '\' + $MyInvocation.MyCommand) } } |