-
Notifications
You must be signed in to change notification settings - Fork 0
/
Send-STSplunkMessage.ps1
152 lines (141 loc) · 7.54 KB
/
Send-STSplunkMessage.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#requires -version 2
# Author: Joakim Borger Svendsen, 2016-present.
# Svendsen Tech. MIT license.
# Send-STSplunkMessage. GitHub here: https://github.com/EliteLoser/Send-SplunkMessage
# I make an attempt at semantic versioning...
$Script:Version = "1.0.0" # 2021-05-31
function GetDomain {
$ErrorActionPreference = "Stop"
$Domain = 'unknown_domain'
try {
# Previously used method, would occasionally fail and is resource-expensive and slow, I think.
#$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().Forest.ToString()
# Will fail on non-Windows PS. Will then be set to 'unknown_domain'.
$Domain = Get-WmiObject -Class Win32_ComputerSystem -Property Domain -ErrorAction Stop |
Select-Object -ExpandProperty Domain -ErrorAction Stop
}
catch {
$Domain = 'unknown_domain'
Write-Warning "Couldn't retrieve domain. Domain set to: '$Domain'."
}
$ErrorActionPreference = "Continue"
return $Domain
}
function Send-STSplunkMessage {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)] $InputObject,
#[String] $Severity = "Information",
[String] $Source = 'powershell.splunkmessage',
[String] $SourceType = 'powershell.splunkmessage.testing',
[String] $Index = 'test',
[String] $SplunkHECToken = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
[String[]] $SplunkUri = @(),
[Switch] $VerboseJSONCreation = $false,
[Switch] $CoerceNumberStrings = $false,
[Switch] $Proxy = $false
)
Begin {
if (($PSVersionTable.PSVersion.Major -eq 2) -or $CoerceNumberStrings) {
# PSv2-compatible "$PSScriptRoot".
$MyHome = Split-Path -Path $MyInvocation.MyCommand.Path -Parent
try {
$ErrorActionPreference = 'Stop'
# ConvertTo-STJson, https://github.com/EliteLoser/ConvertTo-Json
# Svendsen Tech. MIT License. Copyright Joakim Borger Svendsen / Svendsen Tech. 2016-present.
. "$MyHome\ConvertTo-STJson.ps1"
}
catch {
Write-Error -ErrorAction Stop -Message "This script depends on 'ConvertTo-STJson.ps1' in the same folder as the calling script on PowerShell version 2 - and also if you specify the parameter -CoerceNumberStrings. See https://github.com/EliteLoser/ConvertTo-Json"
}
$ErrorActionPreference = 'Continue'
}
if ($SplunkUri.Count -eq 0) {
# Using default list.
Write-Verbose -Message "No Splunk forwarder URI specified. Using default list if one has been hardcoded in the source code."
$SplunkUri = @() # list of strings with URLs to Splunk forwarders... I know this is esoteric, but kind of "real world"?
}
if ($SplunkUri.Count -eq 0) {
# Fail and halt if no Splunk forwarders are specified (or hardcoded above).
Write-Error -ErrorAction Stop -Message "No Splunk forwarder URI specified. No default list hardcoded in source code. Exiting. Please specify splunk forwarder(s) using the parameter -SplunkUri."
}
Write-Verbose -Message "Choosing from the following Splunk URI(s):`n$($SplunkUri -join ""`n"")"
$Domain = GetDomain
[Bool] $GotGoodForwarder = $False
}
Process {
Write-Verbose -Message "Trying to log to splunk. Source: '$Source'. SourceType: '$SourceType'. Index: '$Index'."
# Code for PSv2 and up ...
# http://www.powershelladmin.com/wiki/Convert_between_Windows_and_Unix_epoch_with_Python_and_Perl # using diff logic
:FORWARD while ($True) {
try {
$ErrorActionPreference = "Stop"
if ($GotGoodForwarder -eq $False) {
if ($SplunkUri.Count -eq 0) {
Write-Warning -Message "None of the Splunk forwarders worked. Last recorded error message in system buffer is: $(
$Error[0].Exception.Message)"
break FORWARD
}
$CurrentSplunkUri = $SplunkUri | Get-Random -Count 1
$SplunkUri = $SplunkUri | Where-Object { $_ -ne $CurrentSplunkUri } # pop...
Write-Verbose -Message "Splunk URIs left:`n$($SplunkUri -join ""`n"")"
}
if (($PSVersionTable.PSVersion.Major -eq 2) -or $CoerceNumberStrings) {
$Json = ConvertTo-STJson -InputObject $InputObject -Verbose:$VerboseJSONCreation -CoerceNumberStrings:$CoerceNumberStrings
}
else {
$Json = ConvertTo-Json -InputObject $InputObject -Verbose:$VerboseJSONCreation
}
if (-not (Get-Variable -Name STSplunkWebClient -ErrorAction SilentlyContinue)) {
$STSplunkWebClient = New-Object -TypeName System.Net.WebClient -ErrorAction Stop
$STSplunkWebClient.Headers.Add([System.Net.HttpRequestHeader]::Authorization, "Splunk $SplunkHECToken")
$STSplunkWebClient.Headers.Add("Content-Type", "application/json")
$STSplunkWebClient.Encoding = [System.Text.Encoding]::UTF8
if (-not $Proxy) {
# Do not use the proxy specified in browser/registry settings.
$STSplunkWebClient.Proxy = [System.Net.GlobalProxySelection]::GetEmptyWebProxy()
}
}
$Result = $STSplunkWebClient.UploadString($CurrentSplunkUri, "POST", @"
{
"time": $([Math]::Floor(([DateTime]::Now - (Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0)).TotalSeconds)),
"host": "$env:ComputerName.$Domain",
"source": "$Source",
"sourcetype": "$SourceType",
"index": "$Index",
"event": $Json
}
"@.Trim()
)
if ($Result -match ':\s*"Success"') {
"Successfully sent event JSON to '$CurrentSplunkUri'."
$GotGoodForwarder = $True
break FORWARD
}
else {
Write-Warning -Message "It might not have gone well sending to '$CurrentSplunkUri'. Result looks like this: $Result. Last error in system buffer is: $($Error[0].Exception.Message -replace '[\r\n]+', ' ')"
Write-Verbose -Message "This is the 'event JSON' we tried:`n$Json"
#$GotGoodForwarder = $False # infinite loop with malformed data, etc., so we can't do that. -Joakim
#break FORWARD
}
}
catch {
Write-Warning -Message "[$([DateTime]::Now.ToString('yyyy\-MM\-dd HH\:mm\:ss'))]. Send-SplunkMessage failed to connect to '$CurrentSplunkUri' with the following error: '$($_ -replace '[\r\n]+', '; ')'"
Write-Verbose -Message "This is the 'event' JSON we tried:`n$Json"
# This makes it try another forwarder if a good one suddenly goes bad. Won't retry the formerly good one.
# For that functionality I need a "once good forwarder cache" and it seems overkill for an obscure scenario?
$GotGoodForwarder = $False
}
}
Write-Verbose -Message "This is the 'event JSON' we tried:`n$Json"
$ErrorActionPreference = "Continue"
}
End {
# Do some house-keeping.
if (Get-Variable -Name STSplunkWebClient -ErrorAction SilentlyContinue) {
$STSplunkWebClient.Dispose()
$STSplunkWebClient = $null
}
[System.GC]::Collect()
}
}