Skip to content

Instantly share code, notes, and snippets.

@jmuders
Created January 19, 2021 08:41
Show Gist options
  • Select an option

  • Save jmuders/40654f042036226028dfe43bb33365ed to your computer and use it in GitHub Desktop.

Select an option

Save jmuders/40654f042036226028dfe43bb33365ed to your computer and use it in GitHub Desktop.
install NxLog
function Retry-Command {
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$true)]
[scriptblock]$ScriptBlock,
[Parameter(Position=1, Mandatory=$false)]
[int]$Maximum = 5,
[Parameter(Position=2, Mandatory=$false)]
[int]$Delay = 100
)
Begin {
$cnt = 0
}
Process {
do {
$cnt++
try {
$ScriptBlock.Invoke()
return
} catch {
Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
Start-Sleep -Milliseconds $Delay
}
} while ($cnt -lt $Maximum)
# Throw an error after $Maximum unsuccessful invocations. Doesn't need
# a condition, since the function returns upon successful invocation.
throw 'Execution failed.'
}
}
function Install-AdvancedLogging {
$file = "AdvancedLogging64.msi"
$url = "https://download.microsoft.com/download/9/6/5/96594C39-9918-466C-AFE0-920737351987/$file"
$output = "$env:USERPROFILE\Downloads\$file"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($url, $output)
Start-Process msiexec.exe -Wait -NoNewWindow -ArgumentList "/i $output /qb"
}
function Stop-NxLog {
$serviceName = "nxlog"
Write-Host "stop nxlog if exists"
if (Get-Service $serviceName -ErrorAction SilentlyContinue) {
Stop-Service $serviceName
}
}
function Install-NxLog {
Write-Host "download, extract and install NxLog"
$version = "nxlog-ce-2.10.2150"
$url = "https://nxlog.co/system/files/products/files/348/$version.msi"
$output = "$env:USERPROFILE\Downloads\$version.msi"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($url, $output)
Start-Process msiexec.exe -Wait -NoNewWindow -ArgumentList "/i $output /qn"
}
function Set-NxLogConfiguration($logsDir) {
Write-Host "configure nxlog"
$config = @'
define ROOT %SYSTEM_DRIVE%\Program Files (x86)\nxlog
Moduledir %ROOT%\modules
CacheDir %ROOT%\data
Pidfile %ROOT%\data\nxlog.pid
SpoolDir %ROOT%\data
LogFile %ROOT%\data\nxlog.log
<Extension gelf>
Module xm_gelf
ShortMessageLength 3000
</Extension>
<Extension fileop>
Module xm_fileop
</Extension>
<Extension w3c>
Module xm_csv
Fields $idate, $itime, $s_ip, $cs_method, $cs_uri_stem, $cs_uri_query, $s_port, $cs_username, $c_ip, $cs_user_agent, $cs_referer, $sc_status, $sc_substatus, $sc_win32_status, $time_taken, $true_client_ip, $x_cdn_cacherequester
FieldTypes string, string, string, string, string, string, integer, string, string, string, string, string, string, string, string, string, string
Delimiter ' '
QuoteChar '"'
EscapeControl FALSE
UndefValue -
</Extension>
<Input iis_in>
Module im_file
File "%SYSTEM_DRIVE%\\inetpub\\logs\\%LOGS_DIR%\\\**.log"
SavePos TRUE
Exec $FileName = file_name();
Exec if $raw_event =~ /^#/ drop(); \
else \
{ \
w3c->parse_csv(); \
$EventTime = parsedate($idate + "T" + $itime + "Z"); \
$SourceName = "IIS"; \
}
</Input>
<Output iis_out>
Module om_udp
Host logcollector.finanzennet.de
Port 12202
OutputType GELF
Exec $Hostname = hostname_fqdn();
#Use the following line for debugging (uncomment the fileop extension above as well)
#Exec file_write("F:\\nxlog_output.log", $idate + " " + $itime + " > " + $EventTime + " -- " + $Hostname + " - " + $raw_event + "\n");
</Output>
<Route IIS>
Path iis_in => iis_out
</Route>
'@
$config.Replace("%SYSTEM_DRIVE%", $env:SystemDrive).Replace("%LOGS_DIR%", $logsDir) | Out-File -encoding ASCII -FilePath "$env:SystemDrive\Program Files (x86)\nxlog\conf\nxlog.conf"
}
function Start-NxLog {
$serviceName = "nxlog"
Write-Host "stop nxlog if exists"
if (Get-Service $serviceName -ErrorAction SilentlyContinue) {
Start-Service $serviceName
}
}
function Install-LogCleaningJob {
Write-Host "Setup an daily cron job which cleans IIS logs"
Unregister-ScheduledJob -Name "Clean-IIS-Logs" -ErrorAction "SilentlyContinue"
$trigger = New-JobTrigger -Daily -At 1am -RandomDelay 00:05:00
Register-ScheduledJob -Name "Clean-IIS-Logs" -Trigger $trigger -MaxResultCount 1 -ScriptBlock {
Get-ChildItem -Path "$env:SystemDrive\inetpub\logs" -Recurse |
Where-Object {$_.lastwritetime -lt (get-date).addDays(-1)} |
Foreach-Object { Remove-Item $_.FullName -Recurse }
}
}
function Set-AdvancedLoggingConfiguration {
Write-Host "Configure advanced IIS logging module"
# see https://rafpe.ninja/2015/08/05/iis-advanced-logging-first-approach/
# and https://gist.githubusercontent.com/RafPe/5404350e56147a093049/raw/e509bf0bb987c4d1367c7d38c80a8755245d3fe7/Set-IisAdvLogging.ps1
# Array of fields we want to be logging
$AdvLogFields = "Date-UTC","Time-UTC","Server-IP","Method","URI-Stem","URI-Querystring","Server Port","UserName","Client-IP","User Agent","Referer","Status","Substatus","Win32Status","Time Taken","True-Client-IP","X-CDN-CACHEREQUESTER"
$BaseLogName = "%COMPUTERNAME%-FinServer"
$LogRotateFreq = "Hourly"
# removes True-Client-IPfrom Logging Field if exists
Clear-WebConfiguration "system.webServer/advancedLogging/server/fields/field[@id='True-Client-IP']"
Clear-WebConfiguration "system.webServer/advancedLogging/server/fields/field[@id='X-CDN-CACHEREQUESTER']"
#Add True-Client-ID to available logging fields
Add-WebConfiguration "system.webServer/advancedLogging/server/fields" -value @{id="True-Client-IP";sourceName="True-Client-IP";sourceType="RequestHeader";logHeaderName="True-Client-IP";category="Akamai";loggingDataType="TypeLPCSTR"}
Add-WebConfiguration "system.webServer/advancedLogging/server/fields" -value @{id="X-CDN-CACHEREQUESTER";sourceName="X-CDN-CACHEREQUESTER";sourceType="RequestHeader";logHeaderName="X-CDN-CACHEREQUESTER";category="Akamai";loggingDataType="TypeLPCSTR"}
# Reconfigure username property - this is to well known bug when this property is not logged in correctly
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/advancedLogging/server/fields/field[@id='UserName']" -name "sourceType" -value "BuiltIn"
# logging fields available on server
$availableFields = Get-WebConfiguration "system.webServer/advancedLogging/server/fields"
Clear-WebConfiguration "/system.webServer/advancedLogging/Server/logDefinitions"
# Add our own logging Definition
Add-WebConfiguration "/system.webServer/advancedLogging/Server/logDefinitions" IIS:\ -value @{ rollLogFileOnConfigChanges="true";baseFileName="$BaseLogName"; enabled="true"; logRollOption="Schedule"; schedule=$LogRotateFreq; publishLogEvent="false"}
# Delay commit of settings ( otherwise each time we would wait )
Start-WebCommitDelay
foreach( $singleField in $AdvLogFields)
{
# Check if collection contains this singlefield
if ( ($availableFields.Collection | Select-Object Id -ExpandProperty Id).Contains($singleField) )
{
$fieldDetails = ( $availableFields.Collection | Where-Object Id -eq $singleField)
# Add this required field on site level
Add-WebConfiguration "/system.webServer/advancedLogging/Server/logDefinitions/logDefinition[@baseFileName=""$BaseLogName""]/selectedFields" IIS:\ -value @{defaultValue="";required="false";logHeaderName=$($fieldDetails.logHeaderName);id=$($fieldDetails.id);}
}
}
#Stop delay
Stop-WebCommitDelay -Commit $true
# Disable standard logging
Set-WebConfigurationProperty -Filter "system.webServer/httpLogging" -PSPath "machine/webroot/apphost" -Name dontlog -Value true
# Enable advanced logging
Set-WebConfigurationProperty -Filter "system.webServer/advancedLogging/server" -PSPath "machine/webroot/apphost" -Name enabled -Value true
# iisreset /noforce
# iisreset /status
}
function Set-IISLoggingConfiguration {
Write-Host "Configure IIS logging"
& "$env:SystemDrive\windows\system32\inetsrv\appcmd" unlock config -section:system.webServer/httplogging
Import-Module WebAdministration
$sites = Get-ChildItem IIS:\Sites
foreach ($site in $sites) {
Set-ItemProperty $site.PSPath -Name logFile.directory -Value '%SystemDrive%\inetpub\logs\LogFiles'
Set-ItemProperty $site.PSPath -Name logFile.enabled -Value 'True'
Set-ItemProperty $site.PSPath -Name logFile.period -Value 4 # Hourly
Set-ItemProperty $site.PSPath -Name logfile -Value @{ logExtFileFlags = "Date,Time,ClientIP,UserName,ServerIP,Method,UriStem,UriQuery,HttpStatus,Win32Status,TimeTaken,ServerPort,UserAgent,Referer,HttpSubStatus" }
Set-WebConfigurationProperty $site.PSPath -filter "system.webServer/httpLogging" -name dontLog -value $false
}
Remove-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/siteDefaults/logFile/customFields" -name "." -AtElement @{logFieldName='True-Client-IP'};
Remove-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/siteDefaults/logFile/customFields" -name "." -AtElement @{logFieldName='X-CDN-CACHEREQUESTER'};
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/siteDefaults/logFile/customFields" -name "." -value @{logFieldName='True-Client-IP';sourceName='True-Client-IP';sourceType='RequestHeader'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/siteDefaults/logFile/customFields" -name "." -value @{logFieldName='X-CDN-CACHEREQUESTER';sourceName='X-CDN-CACHEREQUESTER';sourceType='RequestHeader'}
Set-WebConfigurationProperty -Filter "system.webServer/httpLogging" -PSPath "machine/webroot/apphost" -Name dontlog -Value false
}
# main
Stop-NxLog
Install-NxLog
$logsDir = "LogFiles"
$iisMajorVersion = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\InetStp).MajorVersion
if ($iisMajorVersion -le 7)
{
$logsDir = "AdvancedLogs"
Install-AdvancedLogging
Set-AdvancedLoggingConfiguration
} else {
Set-IISLoggingConfiguration
}
Set-NxLogConfiguration($logsDir)
Start-NxLog
Install-LogCleaningJob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment