Splunk String Search - powershell

I have a powershell command value for a process field that I am trying to match in my splunk search but I am getting
"Error in 'SearchParser': Subsearches are only valid as arguments to commands. Error at position '3271' of search query 'litsearch (index=notable ((sourcetype="WMI:LocalPr...{snipped} {errorcontext = andLine"=[[Decoded Ba}'.":
`macro` rule_name="rule-name" process="[[Decoded Base64]] -LogName Microsoft-Windows-Diagnostics-Performance/Operational
| Where-Object {$_.Id -eq 100 -and $_.TimeCreated -ge ((Get-Date) - (New-TimeSpan -Day 90))}
| Format-list ;<!LF!>$ImpersonatedUser.ImpersonationContext.Undo()<!LF!>"
I need a solution for grabbing every instance that this value occurs

Related

ForEach-Object changing result of SearchUnifiedAuditLog

I have a powershell script to retrieve the most recent login for guest users. It works fine.
(Based on https://gallery.technet.microsoft.com/office/Get-Guest-User-Last-Login-39f8237e)
$startDate = "{0:yyyy-MM-dd}" -f (get-date).AddDays(-365) #look 1 year back (not sure what the maximum is, but 1 year seems to work)
$endDate = "{0:yyyy-MM-dd}" -f (get-date) #current date.
$externalUserExtention = "*#EXT#*"
$filePath="c:\temp\guest_user_last_logins.txt"
function logtoText($filePath, $msg) {
$msg >> $filepath;
}
function find_last_login_date($user) {
$lastLoginDate = Search-UnifiedAuditLog -UserIds $user.UserPrincipalName -StartDate $startDate -EndDate $endDate| Foreach-Object {$_.CreationDate = [DateTime]$_.CreationDate; $_} | Group-Object UserIds | Foreach-Object {$_.Group | Sort-Object CreationDate | Select-Object -Last 1} | Select CreationDate
Write-Host "User " $user.UserPrincipalName "| Last Login Date -" $lastLoginDate.CreationDate
logtoText $filePath ($user.UserPrincipalName + "," + $lastLoginDate.CreationDate)
Write-Output $user.UserPrincipalName
}
Clear-Content $filePath
logtoText $filePath ('Username', 'Last Login DateTime')
#Get All External Users
$allExternalUsers = Get-MsolUser -All | Where-Object -FilterScript { $_.UserPrincipalName -Like $externalUserExtention }
ForEach($externalUser in $allExternalUsers) {
find_last_login_date($externalUser)
}
The output is as expected:
User user1#external.com#EXT##tenant.onmicrosoft.com | Last Login Date -
user1#external.com#EXT##tenant.onmicrosoft.com
User user2#external.com#EXT##tenant.onmicrosoft.com | Last Login Date - 11/04/2020 12:02:12
user2#external.com#EXT##tenant.onmicrosoft.com
...
User userNNNN#external.com#EXT##tenant.onmicrosoft.com | Last Login Date - 12/04/2020 14:22:25
userNNNN#external.com#EXT##tenant.onmicrosoft.com
...
The extra Write-Output inside find_last_login_date is just their for debugging this.
Now when I change it to ForEach-Object it does something weird. Probably it makes sense to the experts, but not to me :-)
Replace
ForEach($externalUser in $allExternalUsers) {
find_last_login_date($externalUser)
}
With
ForEach-Object -InputObject $allExternalUsers {
find_last_login_date($_)
}
And the output becomes
User userX#external.com#EXT##tenant.onmicrosoft.com | Last Login Date - 10/01/2021 14:05:36 05/01/2021 20:48:45 05/01/2021 16:09:25 04/01/2021 07:36:26 22/12/2020 08:01:07 19/12/2020 10:24:08 18/12/2020 14:20:51 18/12/2020 08:05:55 16/12/2020 17:32:28 14/12/2
020 08:20:56 13/12/2020 07:58:13 11/12/2020 10:58:58 10/12/2020 08:08:28
user1#external.com#EXT##tenant.onmicrosoft.com
user2#external.com#EXT##tenant.onmicrosoft.com
...
userNNNN#external.com#EXT##tenant.onmicrosoft.com
...
So it seems to trigger the script to only look for the last login date once and also the select top 1 fails, etc.
Any idea what I am doing wrong? At first I thought it was about the "nested" ForEach-Object but even with the code to do the search inside a function it keeps doing this.
Is it by default doing things in parallel and do I need to wait for completion of all tasks? Something telse?
I'm looking at ForEach-Object to parallelize the above script as it takes a very long time to run on a large tenant.
From the docs :
When you use the InputObject parameter with ForEach-Object, instead of piping command results to ForEach-Object, the InputObject value is treated as a single object. This is true even if the value is a collection that is the result of a command, such as -InputObject (Get-Process). Because InputObject cannot return individual properties from an array or collection of objects, we recommend that if you use ForEach-Object to perform operations on a collection of objects for those objects that have specific values in defined properties, you use ForEach-Object in the pipeline.
Change
ForEach-Object -InputObject $allExternalUsers {
find_last_login_date($_)
}
into
$allExternalUsers | ForEach-Object {
find_last_login_date($_)
}

Can't figure out Powershell Where-Object. SSAS Cube Processed State via Powershell,

I've created a powershell script to list the Processed State of a number of SSAS Cubes.
I'm puzzled why the Where-Object only produces the correct results when I use -like. I can't seem to use -eq. Anyone got any ideas ?
I'm using the Where-Object to zero in on the production Database.
The code i'm using is this..
Import-Module SQLASCmdlets -DisableNameChecking
$SSASServer = New-Object Microsoft.AnalysisServices.Server
$instanceName = "SSASSVR01"
$SSASServer.connect($instanceName)
$ProdCubes = $SSASServer.Databases.Cubes
$ProdCubes | Select Parent , State , Name `
| Where-Object { $_.Parent -like "DWProd*" }
I'd expect that -eq would work, but it doesn't
I don't get any response if the last line is written as...
$ProdCubes | Select Parent , State , Name `
| Where-Object { $_.Parent -eq "DWProd" }
I suspect it's whitespace, but how do you filter out the whitespace in powershell.

powershell Get-Winevent SWITCH MATCH issue

'm running this powershell command and saving the output in a csv.
powershell "Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=42}| SELECT-Object #{Label = 'TimeCreated'; Expression = {Get-Date $_.TimeCreated -Format 'yyyy-MM-dd HH:mm:ss'}},#{Label = 'DayOfWeek'; Expression = {(Get-Date $_.TimeCreated).DayOfWeek}},ID,#{l='ID Description';e={Switch ($_) { {$_.ID -eq '42'}{'Type=Sleep matched using EventID';break} {$_.MESSAGE -Match 'Sleep Reason: Application API'}{Type='Sleep matched using Message';break} }}},MESSAGE|ConvertTo-Csv -NoTypeInformation | %{ $_ -replace """`r`n""",',' } | select -Skip 1 | Out-File -Append c:\logs\timeline\TEMP_TimeLine.csv"
I get the expected results as below:
"2014-05-10 00:00:04","Saturday","42","Type=Sleep matched using EventID","The system is entering sleep.,,Sleep Reason: Application API"
"2014-05-09 00:00:02","Friday","42","Type=Sleep matched using EventID","The system is entering sleep.,,Sleep Reason: Application API"
"2014-05-08 00:00:02","Thursday","42","Type=Sleep matched using EventID","The system is entering sleep.,,Sleep Reason: Application API"
But, if i switch the positions of the two case statements inside the switch, i'm not getting the expected output(The derived field 'ID Description' is blank). I am trying to get mix of string matches on the message field and EventID field to be working together.
This is what i'm trying:
powershell "Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=42}| SELECT-Object #{Label = 'TimeCreated'; Expression = {Get-Date $_.TimeCreated -Format 'yyyy-MM-dd HH:mm:ss'}},#{Label = 'DayOfWeek'; Expression = {(Get-Date $_.TimeCreated).DayOfWeek}},ID,#{l='ID Description';e={Switch ($_) { {$_.MESSAGE -Match 'Sleep Reason: Application API'}{Type='Sleep matched using Message';break} {$_.ID -eq '42'}{'Type=Sleep matched using EventID';break} }}},MESSAGE|ConvertTo-Csv -NoTypeInformation | %{ $_ -replace """`r`n""",',' } | select -Skip 1 | Out-File -Append c:\logs\timeline\TEMP_TimeLine.csv"
The Message field clearly has the string 'Sleep Reason: Application API' as we can see from the first output. Wondering whats going on here... Any clues powershell experts?
Ok, two issues I see:
A) You're probably breaking your own script. I'll get to that in a sec.
B) You're missing a ' on the $_.Message line. Type='Sleep should be 'Type=Sleep
Ok, back to point A. I'll start with ;break. In 99% of cases don't do it, you'll make the scripting gods angry, and you wouldn't like them when they're angry. In most cases you want to use ;Continue instead. Break literally breaks out of things, and depending on where it's used it can break out of parent loops entirely stopping part way through a set of things. Continue on the other hand moves to the end of the current loop, skipping anything else. Same thing? Kinda, sorta, but Continue won't break a ForEach-Object loop like Break will.
So, with that said, let's try this in your switch:
Switch ($_) {
{$_.ID -eq '42'}{'Type=Sleep matched using EventID';continue}
{$_.MESSAGE -Match 'Sleep Reason: Application API'}{'Type=Sleep matched using Message';continue}
}
Ok, that's great, along with the whole ' issue in point B that would probably fix the code in general.
So, with that said, why are you running it like that? Dear lord, running an insanely long one liner is just crazy. Save it to a .PS1 file, and if you're calling it from a batch file then call the script file, but ug, that's just hard to work with in general, it's no wonder you missed the ' in the middle of that line. If you are calling it from a batch file, name it GetSleepLogs.ps1 (or whatever you want, just modify the file name in the command) and try this:
PowerShell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -File GetSleepLogs.ps1
Edit: I didn't like the convertto-CSV | select -skip 1 | %{ %_ -replace ...} | Out-File thing, it just seemed clunky to me. Also, all the impromptu hashtables on the Select command were a little hard to follow. Check out this alternative that creates 1 object with several properties, and then just pipes that to Export-CSV with the -append and -NoTypeInformation switches set which should just tack it to the bottom of an existing CSV file.
Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=42}| ForEach{[PSCustomObject][Ordered]#{
'TimeCreated' = Get-Date $_.TimeCreated -Format 'yyyy-MM-dd HH:mm:ss'
'DayOfWeek' = (Get-Date $_.TimeCreated).DayOfWeek
'ID' = $_.ID
'ID Description' = Switch($_){
{$_.ID -eq '42' -AND $_.Message -match 'Sleep Reason: Application API'}{'Type=Sleep matched using EventID and Message';continue}
{$_.ID -eq '42'}{'Type=Sleep matched using EventID';continue}
{$_.Message -match 'Sleep Reason: Application API'}{'Type=Sleep matched using Message';continue}}
'MESSAGE' = $_.Message.replace("`r`n`r`n","`r`n") -replace "((?<!`")`r`n|`n|`r)", ","
}}|Export-Csv C:\temp\TimeLine.csv -NoTypeInformation -append

Powershell: How can I extract time from the message field of eventlog?

I'm trying to get unexpected shutdown times of Windows Sever 2008 machines via Get-EventLog in Powershell. I can get close by searching for events with an EventID of 6008 and selecting only message, but I need to parse within the field to grab the time it occurred (not the time the event fired).
I've tried to use replacementstrings[x] but I can't find how to specify the field to use (messages) and can't get a result.
get-eventlog -LogName System -ComputerName svr-name | Where-Object {$_.EventID -eq 6008 -AND $_.timegenerated -gt (get-date).adddays(-30)}| select message
Produces this:
Message
-------
The previous system shutdown at 3:35:32 AM on ‎7/‎29/‎2014 was unexpected.
The previous system shutdown at 3:40:06 PM on ‎7/‎10/‎2014 was unexpected.`
Retrieving all events from a remote host and filtering them on the local machine ususally doesn't perform too well, because that way you transmit tons of unrelated events over the network, just to throw them away. Get-EventLog has options for filtering messages by Event ID or before/after a given timestamp on the source, so better use those for pre-selecting the messages you're actually interested in. The timestamp of the crash can be extracted from the Message field with a regular expression and parsed into a DateTime value via ParseExact():
$log = 'System'
$server = 'svr-name'
$id = [uint64]"0x80000000" + 6008
$date = (Get-Date).AddDays(-30)
$fmt = 'h:mm:ss tt on M\/d\/yyyy'
$culture = [Globalization.CultureInfo]::InvariantCulture
Get-EventLog -LogName $log -ComputerName $server -InstanceId $id -After $date | ? {
$_.Message -match 'at (\d+:\d+:\d+ [ap]m on \d+/\d+/\d+) was unexpected'
} | select MachineName, TimeGenerated,
#{n='Crashtime';e={[DateTime]::ParseExact($matches[1], $fmt, $culture)}}
The pipeline produces a list of objects with the properties MachineName, TimeGenerated and Crashtime (the last one being a calculated property). If you collect the output of the pipeline in a variable (e.g. $evt) you can access the Crashtime property of the third object like this:
$evt = .\script.ps1
$evt[2].Crashtime
Using regex, you can pull it out as such.
$Messages = (get-eventlog -LogName System -ComputerName svr-name | Where-Object {$_.EventID -eq 6008 -AND $_.timegenerated -gt (get-date).adddays(-30) }| select message)
$Messages | ForEach-Object {
$Matched = $_.Message -match "([0-9]{1,2}:.*[0-9]{4})"
if ($Matched) {
Write-Output "System rebooted at $($Matches[1])"
}
}
There might be a better way, but I do not know what :)
Example Output from my System
System rebooted at 4:34:30 PM on ‎4/‎20/‎2014
System rebooted at 1:48:38 PM on ‎1/‎21/‎2014
System rebooted at 1:37:12 PM on ‎1/‎21/‎2014
System rebooted at 1:22:01 PM on ‎1/‎21/‎2014
System rebooted at 4:41:21 PM on ‎11/‎22/‎2013
More easy
get-eventlog system | where-object {$_.EventID -eq "6008"} | fl

Powershell: filtering event logs

Ive written a small script to retreive event logs from application for the last 10 days but i receive the error. Any ideas why the error appear?
Where-Object : Cannot bind parameter 'FilterScript'. Cannot convert
value "False" to type "System.Management.Automation.ScriptBlock".
Error: "Invalid cast from 'System.Boolean' to
'System.Management.Automation.ScriptBlock'."
#Sets the application log to query
$Log ="Application"
$FilterHashTable = #{LogName=$Log}
#stores the computer name
$ComputerName = $env:COMPUTERNAME
#sets the date 10 days ago
$DeleteDate = Get-Date
$DeleteDate = $DeleteDate.AddDays(-10)
Write-Verbose $DeleteDate
#retrieve WMIevent and logs the information
$Winevent = Get-WinEvent -ComputerName $ComputerName -FilterHashTable $FilterHashTable -ErrorAction SilentlyContinue
# Filter on time
$Winevent | where-object ($_.timecreated -gt $DeleteDate)
Where-Object needs a scriptblock parameter - use curly braces {...} not parentheses (...) to contain your filter logic.
Currently PS is checking your criteria and returning a boolean, instead of applying it as a filter.