Using the POSH-SYSLOG PowerShell module for logging

In my home network, I run a Graylog Syslog instance in Docker for logging network and Linux events. But you can also log events from PowerShell scripts to Syslog for easy filtering or correlation. In this blog post, I will show you how that works.

What is Syslog?

“In computingsyslog (/ˈsɪslɒɡ/) is a standard for message logging. It allows separation of the software that generates messages, the system that stores them, and the software that reports and analyzes them. Each message is labeled with a facility code, indicating the type of system generating the message, and is assigned a severity level.

Computer system designers may use syslog for system management and security auditing as well as general informational, analysis, and debugging messages. A wide variety of devices, such as printers, routers, and message receivers across many platforms, use the syslog standard. This permits the consolidation of logging data from different types of systems in a central repository. Implementations of syslog exist for many operating systems.

When operating over a network, syslog uses a client-server architecture where a syslog server listens for and logs messages coming from clients.”

Source: https://en.wikipedia.org/wiki/Syslog

What does the POSH-SYSLOG module do?

“A module for sending SYSLOG messages from PowerShell.

The module supports RFC5424 and RFC3164, and can send messages via TCP and UDP.

Authored by Kieran Jacobsen

Source: https://github.com/poshsecurity/Posh-SYSLOG

How to use

Installation

You can install it from the PowerShell gallery using this:

Install-Module -Name Posh-SYSLOG

Or, when you have PSResourceGet installed:

Install-PSResource -Name Posh-SYSLOG

After installation, you will have this Cmdlet available:

Parameters

    -Server <String>
        Destination SYSLOG server that message is to be sent to.

        Required?                    true
        Position?                    named
        Default value
        Accept pipeline input?       false
        Aliases
        Accept wildcard characters?  false

    -Message <String>
        Our message or content that we want to send to the server. This is option in RFC 5424, the CMDLet still has this
        as a madatory parameter, to send no message, simply specifiy '-' (as per RFC).

        Required?                    true
        Position?                    named
        Default value
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -Severity
        Severity level as defined in SYSLOG specification, must be of ENUM type Syslog_Severity

        Required?                    true
        Position?                    named
        Default value
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -Facility
        Facility of message as defined in SYSLOG specification, must be of ENUM type Syslog_Facility

        Required?                    true
        Position?                    named
        Default value
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -Hostname <String>
        Hostname of machine the message is about, if not specified, RFC 5425 selection rules will be followed.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       false
        Aliases
        Accept wildcard characters?  false

    -ApplicationName <String>
        Specify the name of the application or script that is sending the mesage. If not specified, will select the ScriptName,
        or if empty, powershell.exe will be sent. To send Null, specify '-' to meet RFC 5424.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -Timestamp <DateTime>
        Time and date of the message, must be of type DateTime. Correct format will be selected depending on RFC requested.
        If not specified, will call get-date to get appropriate date time.

        Required?                    false
        Position?                    named
        Default value                (Get-Date)
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -Port <UInt16>
        SYSLOG UDP (or TCP) port to which to send the message. Defaults to 514, if not specified.

        Required?                    false
        Position?                    named
        Default value                514
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -Transport
        Transport protocol (TCP or UDP or TCP with TLS) over which the message will be sent. Default is UDP.
        [ValidateSet('UDP','TCP', 'TCPwithTLS')]
        [String]

        Required?                    false
        Position?                    named
        Default value                UDP
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -ProcessID <String>
        ProcessID or PID of generator of message. Will automatically use $PID global variable. If you want to override
        this and send null, specify '-' to meet RFC 5424 rquirements.

        Required?                    false
        Position?                    named
        Default value                $PID
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -MessageID <String>
        Error message or troubleshooting number associated with the message being sent. If you want to override this and
        send null, specify '-' to meet RFC 5424 rquirements.

        Required?                    false
        Position?                    named
        Default value                -
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -StructuredData <String>
        Key Pairs of structured data as a string as defined in RFC5424. Default will be '-' which means null.

        Required?                    false
        Position?                    named
        Default value                -
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -FramingMethod <String>
        Framing method used for the message, default is 'Octet-Counting' (see RFC6587 section 3.4). This only applies when
        TCP is used for transport (no effect on UDP messages).

        Required?                    false
        Position?                    named
        Default value                Octet-Counting
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -SslProtocols
        SSL/TLS Protocols to be used when connecting to server. Default is TLS1.2.

        Required?                    false
        Position?                    named
        Default value                Tls12
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -DoNotValidateTLSCertificate [<SwitchParameter>]
        Do not validate the SSL/TLS certificate presented by the server.

        Required?                    false
        Position?                    named
        Default value                False
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    -RFC3164 [<SwitchParameter>]
        Send an RFC3164 fomatted message instead of RFC5424.

        Required?                    true
        Position?                    named
        Default value                False
        Accept pipeline input?       true (ByPropertyName)
        Aliases
        Accept wildcard characters?  false

    <CommonParameters>
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer, PipelineVariable, and OutVariable. For more information, see
        about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216).

Facility and Severity level

You can specify more details using the -Facility and -Severity Parameters, following the standards described in the Wiki link above. You can auto-complete, CTRL+Space them, but these are the ones that you can use with the details:

and

Examples

Line in script

You can use the Cmdlet in your script so that instead of writing output to a log file or screen, you can send it to your Syslog server like this:

Send-SyslogMessage -Server 192.168.168.192 -Message "PowerShell is fun!" -Severity Critical -Facility user -ApplicationName PowerShell -Port 1514 -Transport UDP -Hostname P16SG2 -MessageID 1

The message will look like this in your SYSLOG server (In my case, Graylog):

As a Function

You can use the Send-SyslogMessage in a small Function, which makes it easier to use in larger scripts. For example:

# You need to install the POSH-SYSLOG module first
# https://www.powershellgallery.com/packages/Posh-SYSLOG/4.1.5
function Write-Log {
    param (
        [Parameter(Mandatory = $true)][string]$Message,
        [Parameter(Mandatory = $false)][validateset('Emergency', 'Alert', 'Critical', 'Error', 'Warning', 'Notice', 'Info', 'Debug')][string]$Severity = 'Info',
        [Parameter(Mandatory = $false)][validateset('auth', 'clock', 'daemon', 'kern', 'local1', 'local3', 'local5', 'local7', 'logaudit', 'mail', 'ntp', 'user', 'authpriv', 'cron', 'ftp', 'local0', 'local2', 'local4', 'local6', 'logalert', 'lpr', ' news', 'syslog', 'uucp')][string]$Facility = 'User'    
    )
    Send-SyslogMessage -Server 192.168.168.192 -Port 1514 -Transport UDP -Message $Message -Severity $Severity -Facility $Facility -Hostname $env:COMPUTERNAME -Timestamp (Get-Date) -ProcessID $PID -MessageID 1
}

This will look like this after running Write-Log -Message “PowerShell is fun!”

Because I didn’t use the -Facility or -Severity Parameter, it used the defaults (User and Info). The timestamp was from Get-Date, the Process ID was from VSCode’s PID, the ComputerName from $ENV:COMPUTERNAME, and the nice thing is… It also logs the script that it was run from (That’s the -ApplicationName Parameter from the Send-SysLogMessage Cmdlet)

Wrapping up

And that’s how you log messages into your SYSLOG server using the POSH-SYSLOG module. I showed how you can use it from the command line or as a nice, small function for easy usage. Have a lovely weekend!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.