SysLog на PowerShell

Источник

Для приема логов на сервере Wndows 2008 от маршрутизатора нашел вот такой замечательные скрипт, который работает у меня уже несколько лет.


# SysLog.ps1
#
# A basic SysLog server. Behaviour should be fairly consistent with
# RFC 3164 (http://www.ietf.org/rfc/rfc3164.txt).
 
# Network Configuration
 
$SysLogPort = 514                  # Default SysLog Port
$Buffer = New-Object Byte[] 1024   # Maximum SysLog message size
 
# Server Configuration
 
$EnableMessageValidation = $True   # Enable check of the PRI and Header
$EnableRelay = $True               # Enable relay to $RelayTargetIP
$EnableLocalLogging = $True        # Enable local logging of received messages
$EnableConsoleLogging = $False     # Enable logging to the console
$EnableHostNameLookup = $True      # Lookup hostname for connecting IP
$EnableHostNamesOnly = $True       # Uses Host Name only instead of FQDNs
 
$RelayTargetIP = "10.0.0.1"        # Must be an IP Address
$LogFolder = "C:SysLogLogFiles"  # Path must exist
 
# Global variables used to store day and date-stamp for log roll-over
 
$Day = (Get-Date).Day
$DateStamp = (Get-Date).ToString("yyyy.MM.dd")
 
# Relay Initialisation
 
If ($EnableRelay)
{
  $RelayTarget = [Net.IPAddress]::Parse($RelayTargetIP)
  $RelayTargetEndPoint = New-Object Net.IPEndPoint($RelayTarget, $SysLogPort)
}
 
# A launcher for the process
#
# Caller: Manual / Script
 
Function Start-SysLog
{
  $Socket = CreateSocket
  StartReceive $Socket
}
 
# Create and bind to the socket
#
# Caller: Start-SysLog
 
Function CreateSocket
{
  $Socket = New-Object Net.Sockets.Socket(
    [Net.Sockets.AddressFamily]::Internetwork,
    [Net.Sockets.SocketType]::Dgram,
    [Net.Sockets.ProtocolType]::Udp)
 
  $ServerIPEndPoint = New-Object Net.IPEndPoint(
    [Net.IPAddress]::Any,
    $SysLogPort)
 
  $Socket.Bind($ServerIPEndPoint)
 
  Return $Socket
}
 
# Recieve a single message
#
# Caller: Start-SysLog
 
Function StartReceive([Net.Sockets.Socket]$Socket)
{
  # Placeholder to store source of incoming packet
  $SenderIPEndPoint = New-Object Net.IPEndPoint([Net.IPAddress]::Any, 0)
  $SenderEndPoint = [Net.EndPoint]$SenderIPEndPoint
 
  $ServerRunning = $True
  While ($ServerRunning -eq $True)
  {
    $BytesReceived = $Socket.ReceiveFrom($Buffer, [Ref]$SenderEndPoint)
    $Message = $Buffer[0..$($BytesReceived - 1)]
 
    $Message = ValidateMessage $Message $SenderEndPoint.Address.IPAddressToString
 
    If ($EnableRelay)
    {
      RelayMessage $Socket $Message
    }
  }
}
 
# Relay the message to an upstream SysLog server. Either basic forwarding,
# or full validation.
#
# Caller: StartReceive
 
Function RelayMessage([Net.Sockets.Socket]$Socket, [Byte[]]$Message)
{
  [Void]$Socket.SendTo($Message, $RelayTargetEndPoint)
}
 
# Check the validity of the message (if option is enabled). Adjust message
# according to recommendations in RFC 3164.
#
# Caller: StartReceive
 
Function ValidateMessage([Byte[]]$Message, [String]$HostName)
{
  If ($EnableMessageValidation)
  {
    $MessageString = [Text.Encoding]::ASCII.GetString($Message)
 
    If (IsValidPRI($MessageString))
    {
      If (!(IsValidDateTime($MessageString)))
      {
        $PRI = [Int]($MessageString -Replace "<|>.*")
        $HostName = GetHostName $HostName
        $MessageString = "<$PRI>$(NewDateTimeString) $HostName $MessageString"
        $Message = EncodeMessage $MessageString
      }
    }
    Else
    {
      $HostName = GetHostName $HostName
      $MessageString = "$(NewDateTimeString) $HostName $MessageString"
      $Message = EncodeMessage $MessageString
    }
  }
  If ($EnableLocalLogging -Or $EnableConsoleLogging)
  {
    If ($MessageString -eq $Null)
    {
      $MessageString = [Text.Encoding]::ASCII.GetString($Message)
    }
    If ($EnableLocalLogging) { WriteToLog $MessageString $HostName }
    If ($EnableConsoleLogging) { Write-Host $MessageString }
  }
  Return $Message
}
 
# Validate the PRI (Priority Field - Facility and Severity)
# No parsing is performed. No network prioritisation is implemented
#
# Caller: ValidateMessage
 
Function IsValidPRI([String]$MessageString)
{
  If ($MessageString.SubString(0, 1) -ne "<") { Return $False } If (!$MessageString.SubString(2, 3).Contains(">"))
  {
    Return $False
  }
 
  $PRI = [Int]($MessageString -Replace "<|>.*")
  # PRI = (Facility * 8) + Severity. Maximum and minimum values from RFC 3164
  If ($PRI -lt 1 -Or $PRI -gt 191)
  {
    Return $False
  }
  Return $True
}
 
# Validate the TimeStamp formatting
#
# Caller: ValidateMessage
 
Function IsValidDateTime([String]$MessageString)
{
  $IsValid = $False
  If ($MessageString -Match "(?<=>)w{3}ss?d{1,2}s(dd:){2}dd(?=s)")
  {
    $Date = New-Object DateTime
    ForEach ($Format in @("MMM  d hh:mm:ss", "MMM dd hh:mm:ss"))
    {
      $Date = New-Object DateTime
      $IsValid = [DateTime]::TryParseExact(
        $Matches[0],
        $Format,
        [Globalization.CultureInfo]::InvariantCulture,
        [Globalization.DateTimeStyles]::AssumeUniversal,
        [Ref]$Date)
      If ($IsValid) { Return $True }
    }
  }
  Return $False
}
 
# Create a new DateTime String
#
# Caller: ValidateMessage
 
Function NewDateTimeString
{
  $Date = (Get-Date).ToUniversalTime()
  If ($Date.Day -lt 10)
  {
    Return $Date.ToString("MMM  d HH:mm:ss")
  }
  Return $Date.ToString("MMM dd HH:mm:ss")
}
 
# Attempt to lookup the HostName if an IP value was passed.
# [Net.Dns]::GetHostEntry fails to return if a Forward Lookup record
# does not exist. NsLookup as a simple alternative.
#
# Caller: ValidateMessage
 
Function GetHostName([String]$HostName)
{
  If (!$EnableHostNameLookup) { Return $HostName }
  If ([Net.IPAddress]::TryParse($HostName, [Ref]$Null))
  {
    $Temp = (nslookup -q=ptr $HostName | ?{ $_ -Like "*name = *" })
    $Temp = $Temp -Replace ".*name = "
    If ($Temp -ne [String]::Empty) { $HostName = $Temp }
  }
  If ($EnableHostNamesOnly)
  {
    Return $HostName.Split(".")[0]
  }
  Return $HostName
}
 
# Returns a Byte Array representation of the original message.
# If the length is greater than 1024 Bytes the array is truncated
# as stipulated under RFC 3164.
#
# Caller: ValidateMessage
 
Function EncodeMessage([String]$MessageString)
{
  $Message = [Text.Encoding]::ASCII.GetBytes($MessageString)
  If ($Message.Length -gt 1024)
  {
    Return $Message[0..1023]
  }
  Return $Message
}
 
# Maintain a per-host log file in the $LogFolder
# Script does not clean up old log files
#
# Caller: ValidateMessage
 
Function WriteToLog([String]$MessageString, [String]$HostName)
{
  # Simple time based roll-over check
  If ((Get-Date).Day -ne $Day)
  {
    $Day = (Get-Date).Day
    $DateStamp = (Get-Date).ToString("yyyy.MM.dd")
  }
 
  $LogFile = "$LogFolder$HostName-$DateStamp.log"
  $MessageString >> $LogFile
}
 
# Start the server
 
Start-SysLog