Step 1: Setup Server
- Install a log aggregation server is out of scope of this document

Step 2: Setup Client
- Download and install NXLog Client:
  - Latest edition: https://nxlog.co/downloads/nxlog-ce
  - Automated install: choco install -y nxlog (version 2.10.2150 as of August 2021)
- Readme File content:
    Please edit the configuration file after installation. This file is
    located in the `conf` directory where NXLog was installed (default
    `C:\Program Files (x86)\nxlog\conf\nxlog.conf` on 64-bit Windows). If
    you chose a custom installation directory, you will need to update the
    ROOT directory specified in the configuration file before the NXLog
    service will start.

    The NXLog service can be started from the Services console (run
    `services.msc`) or will be started automatically at the next
    boot. Alternatively, the service can be started by executing
    `nxlog.exe`, located in the installation directory. The `-f` command
    line argument can be used to run NXLog in the foreground.

    By default, NXLog will write its own messages to the log file named
    `nxlog.log` in the `data` directory (default `C:\Program Files
    (x86)\nxlog\data\nxlog.log` on 64-bit Windows). If you have trouble
    starting or running NXLog, check that file for errors.

    See the NXLog Reference Manual for details about configuration and
    usage. The Reference Manual is installed in the `doc` directory
    (default `C:\Program Files (x86)\nxlog\doc` on 64-bit Windows) and
    should also be available online at <https://nxlog.co/resources>.
- Configure:
  - How to configure: https://nxlog.co/page/eventlog-to-syslog.html
  - Edit the file at C:\Program Files (x86)\nxlog\conf\nxlog.conf  

# Uncomment these line if using Graylog
#<Extension _gelf>
#    Module xm_gelf
#</Extension>

# How to generate query: https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/advanced-xml-filtering-in-the-windows-event-viewer/ba-p/399761
# Please note that indentation is important!
<Input im_msvistalog>
    Module      im_msvistalog
    Query   <QueryList>\
        	<Query Id="0">\
                # This is an example of Windows logon RDP mode 10
            		<Select Path="Security">*[System[(EventID=4624)]] and *[EventData[(Data=10)]]</Select>\
        	</Query>\
    	</QueryList>
</Input>

<Output om_udp>
  Module  om_udp
  Host  [IPADDRESSHERE]
  Port  514
  Exec  to_syslog_snare(); # Use this if Graylog: OutputType  GELF
</Output>

<Route out>
  Path  im_msvistalog  => om_udp
</Route>

- Confirm whether remote host port is reachable from client
  PS C:\Windows\system32> test-netconnection syslog-server -port 514
  ComputerName           : syslog-server
  RemoteAddress          : x.x.x.x
  RemotePort             : 514
  InterfaceAlias         : Ethernet 2
  SourceAddress          : x.x.x.x
  PingSucceeded          : True
  PingReplyDetails (RTT) : 1 ms
  TcpTestSucceeded       : True

# Success
PS C:\Windows\system32> portqry -n syslog-server -p udp -e 514
Querying target system called:
 syslog-server
Attempting to resolve name to IP address...
Name resolved to x.x.x.x
querying...
UDP port 514 (syslog service): LISTENING or FILTERED

# Success
PS C:\Windows\system32> portqry -n syslog-server -p udp -e 514
Querying target system called:
 syslog-server
Attempting to resolve name to IP address...
Name resolved to x.x.x.x
querying...
--- some response data ---
UDP port 514 (syslog service): LISTENING

# Failure
PS C:\Windows\system32> portqry -n syslog-server -p udp -e 514
Querying target system called:
 localhost
Attempting to resolve name to IP address...
Name resolved to x.x.x.x
querying...
UDP port 514 (syslog service): NOT LISTENING

- Start NXLog client service
  PS C:\Windows\system32> start-service NXLog

- Troubleshooting
  - Sample problem:
    PS C:\Windows\system32> start-service nxlog
    start-service : Service 'nxlog (nxlog)' cannot be started due to the following error: Cannot start service nxlog on
    computer '.'.
    At line:1 char:1
    + start-service nxlog
    + ~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service],
      ServiceCommandException
        + FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand

    PS C:\Windows\system32> &"C:\Program Files (x86)\nxlog\nxlog.exe" -c "C:\Program Files (x86)\nxlog\conf\nxlog.conf"
    Expected </Input> but saw </Query> at C:\Program Files (x86)\nxlog\conf\nxlog.conf:53
  - Resolution to error message above is to fix the indentation of the config file

- Check service connections
  PS C:\Windows\system32> netstat -nbt| select-string -Pattern "nxlog" -Context 2
    [rstudio.exe]
      TCP    127.0.0.1:61682        127.0.0.1:61683        ESTABLISHED
  >  [nxlog.exe]
      TCP    127.0.0.1:61683        127.0.0.1:61682        ESTABLISHED

- Check server for established tcp connections
  [thanos@syslog-server thanos] #
  remoteIP=x.x.x.x
  match=$null
  while [ -z "$match" ]
  do
    clear
    echo "Checking for incoming connection from $remoteIP"
    match=$(netstat -na|grep $remoteIP)
    [[ ! -z "$match" ]] && echo "$match" || sleep 1
  done

- check which daemons & owners listen to which ports
  [thanos@syslog-server thanos] # netstat -elpt
  Active Internet connections (only servers)
  Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name
  tcp        0      0 0.0.0.0:sunrpc          0.0.0.0:*               LISTEN      root       7956       1/systemd
  tcp        0      0 0.0.0.0:33427           0.0.0.0:*               LISTEN      root       13042      -
  tcp        0      0 localhost:domain        0.0.0.0:*               LISTEN      systemd-resolve 8111       673/systemd-resolve
  tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN      root       12384      1162/sshd: /usr/sbi
  tcp        0      0 localhost.localdom:smtp 0.0.0.0:*               LISTEN      root       9157       787/master
  tcp        0      0 0.0.0.0:46463           0.0.0.0:*               LISTEN      rpcuser    12960      1275/rpc.statd
  tcp        0      0 0.0.0.0:shell           0.0.0.0:*               LISTEN      root       11650      1252/rsyslogd
  tcp        0      0 localhost.localdom:smux 0.0.0.0:*               LISTEN      root       9674       811/snmpd

- Check RDP logging activities
  client=SYSLOGCLIENT
  year=$(date +"%Y")
  clientlog=/var/log/rsyslog/hosts/$client/$year/messages
  rdpLogFilter=".*Source Port:  \w+"
  tail -f $clientlog | grep -oP $rdpLogFilter
  cat $clientlog | grep -oP $rdpLogFilter

- Certain expected logging (such as logons and logoffs) not being sent to server
# on client Windows machine, turn on auditing of logon and logoff events
auditpol /set /category:"Logon/logoff" /failure:enable
auditpol /set /category:"Logon/logoff" /success:enable
# To persist settings for domain joined computers, it's necessary to create a GP with this configuration: Computer Configuration > Policies > Windows Settings > Security Settings > Advanced Audit Policy Configuration > Audit Policies > Logon/Logoff

Configuration Example 1:

Panic Soft
#NoFreeOnExit TRUE

define ROOT     C:\Program Files (x86)\nxlog
define CERTDIR  %ROOT%\cert
define CONFDIR  %ROOT%\conf
define LOGDIR   %ROOT%\data
define LOGFILE  %LOGDIR%\nxlog.log
LogFile %LOGFILE%

Moduledir %ROOT%\modules
CacheDir  %ROOT%\data
Pidfile   %ROOT%\data\nxlog.pid
SpoolDir  %ROOT%\data

<Extension _syslog>
    Module      xm_syslog
</Extension>

<Extension _charconv>
    Module      xm_charconv
    AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>

<Extension _exec>
    Module      xm_exec
</Extension>

<Extension _fileop>
    Module      xm_fileop

    # Check the size of our log file hourly, rotate if larger than 5MB
    <Schedule>
        Every   1 hour
        Exec    if (file_exists('%LOGFILE%') and \
                   (file_size('%LOGFILE%') >= 5M)) \
                    file_cycle('%LOGFILE%', 8);
    </Schedule>

    # Rotate our log file every week on Sunday at midnight
    <Schedule>
        When    @weekly
        Exec    if file_exists('%LOGFILE%') file_cycle('%LOGFILE%', 8);
    </Schedule>
</Extension>

<Extension _gelf>
    Module xm_gelf
</Extension>

# How to generate query: https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/advanced-xml-filtering-in-the-windows-event-viewer/ba-p/399761
# Please note that indentation is important!
<Input from_eventlog>
    Module      im_msvistalog
    <QueryXML>
        <QueryList>
            <Query Id="0">
                <Select Path="Security">
                    *[System[Level=0 and (EventID=4624 or EventID=4647)]]
                </Select>
            </Query>
        </QueryList>
    </QueryXML>
</Input>

# Source: https://docs.nxlog.co/userguide/configure/forwarding-logs.html
<Output om_udp>
    Module      om_udp # OR om_tcp (depending on server listening port discovered in http://{graylog.server.url}/system/inputs)
    Host        10.10.10.88
    Port        12222
    OutputType  GELF_UDP # OR GELF_TCP OR Exec to_syslog_ietf(); OR to_syslog_snare(); OR Binary OR to_json(); 
</Output>

<Route out>
    Path    from_eventlog  => out
</Route>

Configuration Example 2:

Panic Soft
#NoFreeOnExit TRUE
 
define ROOT     C:\Program Files (x86)\nxlog
define CERTDIR  %ROOT%\cert
define CONFDIR  %ROOT%\conf
define LOGDIR   %ROOT%\data
define LOGFILE  %LOGDIR%\nxlog.log
LogFile %LOGFILE%
 
Moduledir %ROOT%\modules
CacheDir  %ROOT%\data
Pidfile   %ROOT%\data\nxlog.pid
SpoolDir  %ROOT%\data
 
<Extension _syslog>
    Module      xm_syslog
</Extension>
 
<Extension _charconv>
    Module      xm_charconv
    AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>
 
<Extension _exec>
    Module      xm_exec
</Extension>
 
<Extension _fileop>
    Module      xm_fileop
 
    # Check the size of our log file hourly, rotate if larger than 5MB
    <Schedule> 
        Every   1 hour
        Exec    if (file_exists('%LOGFILE%') and \
                   (file_size('%LOGFILE%') >= 5M)) \
                    file_cycle('%LOGFILE%', 8);
    </Schedule>
 
    # Rotate our log file every week on Sunday at midnight
    <Schedule>
        When    @weekly
        Exec    if file_exists('%LOGFILE%') file_cycle('%LOGFILE%', 8);
    </Schedule>
</Extension>
 
<Extension _gelf>
    Module xm_gelf
</Extension>
 
<Input im_msvistalog>
    Module      im_msvistalog
    Query   <QueryList>\
        	<Query Id="0">\
					<Select Path="System">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\
            		<Select Path="Application">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\
					<Select Path="Security">*[System[Level=0 and (EventID=4624 or EventID=4647)]]</Select>\
        	</Query>\
    	</QueryList>
</Input>

<Output send_graylog>
    Module      om_tcp
    Host        10.10.10.88
    Port        12201
    OutputType  GELF_TCP
</Output>

<Processor norepeat>
	Module pm_norepeat
	CheckFields Message
</Processor>

<Route out>
    Path    im_msvistalog  => norepeat => send_graylog
</Route>

Example 3:

Panic Soft
#NoFreeOnExit TRUE
 
define ROOT     C:\Program Files (x86)\nxlog
define CERTDIR  %ROOT%\cert
define CONFDIR  %ROOT%\conf
define LOGDIR   %ROOT%\data
define LOGFILE  %LOGDIR%\nxlog.log
LogFile %LOGFILE%
 
Moduledir %ROOT%\modules
CacheDir  %ROOT%\data
Pidfile   %ROOT%\data\nxlog.pid
SpoolDir  %ROOT%\data
 
<Extension _syslog>
    Module      xm_syslog
</Extension>
 
<Extension _charconv>
    Module      xm_charconv
    AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>
 
<Extension _exec>
    Module      xm_exec
</Extension>
 
<Extension _fileop>
    Module      xm_fileop
 
    # Check the size of our log file hourly, rotate if larger than 5MB
    <Schedule> 
        Every   1 hour
        Exec    if (file_exists('%LOGFILE%') and \
                   (file_size('%LOGFILE%') >= 5M)) \
                    file_cycle('%LOGFILE%', 8);
    </Schedule>
 
    # Rotate our log file every week on Sunday at midnight
    <Schedule>
        When    @weekly
        Exec    if file_exists('%LOGFILE%') file_cycle('%LOGFILE%', 8);
    </Schedule>
</Extension>
 
<Extension _gelf>
    Module xm_gelf
</Extension>

# This example would filter the Windows Event Logs to capture only Network and Interactive logons
# Sources:
# - https://docs.nxlog.co/integrate/windows-eventlog.html
# - https://eventlogxp.com/blog/logon-type-what-does-it-mean/
<Input winEvents>
    Module      im_msvistalog
    Query   <QueryList>\
        	<Query Id="0">\
					<Select Path="Security">*[System[Level=0 and (EventID=4624 or EventID=4647)]]</Select>\
        	</Query>\
    	</QueryList>
	<Exec>
        if ($TargetUserName == "SYSTEM" OR $LogonType in ("4", "5", "7", "9"))
		drop();
    </Exec>
</Input>

<Output send_graylog>
    Module      om_tcp
    Host        0.0.100.88
    Port        12201
    OutputType  GELF_TCP
</Output>

<Processor norepeat>
	Module pm_norepeat
	CheckFields Message
</Processor>

<Route out>
    Path    winEvents => norepeat => send_graylog
</Route>