I have performed a number of updates to the PowerShell SYSLOG module since this post. You can read the latest post. The module has been renamed to Posh-SYSLOG.
The GitHub location has been moved to https://github.com/poshsecurity/Posh-SYSLOG.
The module is now available on the PowerShell Gallery.
I had this need to send some SYSLOG messages from PowerShell, and there are many reasons why you might want to do this one, from notifications to logging, SYSLOG can be very handy.
I looked around online and could not find a really simple and easy to use piece of code. There were some examples out there, but they were all a little rough around the edges, and I knew I could clean them up and improve upon their design.
Before we get to the code, let us take a quick look at the SYSLOG protocol. According to Wikipedia, the SYSLOG protocol was originally developed in the 1980s by Eric Allman as part of Sendmail and is now standardized by IETF in RFC5424.
A standard SYSLOG message consists of four things:
- A priority - how bad is it?
- A Timestamp - when is this occurring
- A hostname - who is sending the message
- A Message - kind of obvious
One thing to note is that the priority is not that simple. The priority in the message is actually made of two things: the severity and the facility, or what the application or subsystem generating the message is. The levels are defined in the tables below:
Facility Number | Keyword | Facility Description |
---|---|---|
0 | kern | kernel messages |
1 | user | user-level messages |
2 | mail system | |
3 | daemon | system daemons |
4 | auth | security/authorization messages |
5 | syslog | messages generated internally by syslogd |
6 | lpr | line printer subsystem |
7 | news | network news subsystem |
8 | uucp | UUCP subsystem |
9 | clock daemon | |
10 | authpriv | security/authorization messages |
11 | ftp | FTP daemon |
12 | - | NTP subsystem |
13 | - | log audit |
14 | - | log alert |
15 | cron | clock daemon |
16 | local0 | local use 0 (local0) |
17 | local1 | local use 1 (local1) |
18 | local2 | local use 2 (local2) |
19 | local3 | local use 3 (local3) |
20 | local4 | local use 4 (local4) |
21 | local5 | local use 5 (local5) |
22 | local6 | local use 6 (local6) |
23 | local7 | local use 7 (local7) |
and
Code | Severity | Keyword | Description | General Description |
---|---|---|---|---|
0 | Emergency | emerg (panic) | System is unusable. | A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call. |
1 | Alert | alert | Action must be taken immediately. | Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection. |
2 | Critical | crit | Critical conditions. | Should be corrected immediately, but indicates failure in a secondary system, an example is a loss of a backup ISP connection. |
3 | Error | err (error) | Error conditions. | Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time. |
4 | Warning | warning (warn) | Warning conditions. | Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. |
5 | Notice | notice | Normal but significant condition. | Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required. |
6 | Informational | info | Informational messages. | Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required. |
7 | Debug | debug | Debug-level messages. | Info useful to developers for debugging the application, not useful during operations. |
Here are a few examples:
- Emergency Message from Kernel = (0 * 8) + 0 = 0
- Alert from User = (1 * 8) + 1 = 9
- Informational from mail = (2 * 8) + 6 = 22
When you look at a SYSLOG servers output, it probably has the severity levels and facilities nicely printed, all it is doing is reversing the process. For example, if we received a priority of 58, we would firstly divide 58 by 8, this comes out at 7.25, if we just take the whole number, we can see that this was a message from the NEWS facility, if we take 7*8 from 58, we get 2, and this, we know this was a critical severity message.
As you can see, the whole thing is rather easy. The SYSLOG protocol is brilliant in its simplicity.
So, back to PowerShell.
If we were going to write a PowerShell CMDLet to send a SYSLOG message, what would it look like?
Let us start with parameters. We are going to need to know the SYSLOG server we want to send the message to, we need a message to send, and we need to define the severity and facility that is sending the message. Optionally we might want to specify the hostname of the machine sending the message (we can get this if not specified), we might want to specify a timestamp (but we could get lazy) and finally our SYSLOG server might be running the service on a different port, so we should be able to specify the port if it is different from the default, UDP514.
How do we go about specifying the severity and facility levels? We donβt want to force users to remember 0 through to 7 and 0 through to 23? We need to make this easier! How about some sort of data type? Thankfully, we can use ENUM types within PowerShell to define some simple data types and simplify specifying these parameters. If you donβt know about ENUMs, I suggest you do some Googling, they are very handy and quite useful.
What would the ENUM definitions look like?
For those of you who don't know, each item in the ENUM is assigned a number, starting with 0. We will use these numbers as part of our calculation of the priority.
So once we have these data types defined, what's next? Let's take a look at parameters. Parameter's for a function are pretty straight forward, destination server, message, severity, facility, hostname, and date/time stamp are all we really need. In terms of mandatory parameters, only the first 4 are, we can determine the other two for the user.
What's next? Well, what about determining the priority to be sent based upon severity and facility?
The only other tricky part is the date/timestamp, but once again, that isn't too tricky. We just use Get-Date and a custom specified format.
Finally let's stick it all together:
Well we now have a message to send to the syslog server? Well all that is left to do is encode and send the message using a UDP client object.
The finished CMDLet looks like this:
You can also see the finished product on my GitHub. I built a module based upon my prefered structure here.
As you can see, this is all pretty simple stuff. Now we get to go off and user it in your scripts! Using this CMDLet is pretty simple, there is an example included in the comments. Simply specify the various details, and then check your SYSLOG server to see the results.
Stay tuned into my blog for a non-PowerShell post about some issues I recently faced with Windows Integrated Authentication.