Reputation: 73
I have the below code which retrieves the last users to login after a certain number of days. I want to stop logins that I don't care about from appearing in the list, such as when it shows that "LOCAL SERVICE" or "NETWORK SERVICE" has logged in. I also designed it so that repeats will be excluded.
While trying to figure out why Powershell never thought $Matches.AccountName
equaled "LOCAL SERVICE" or any of the other checks, I realized that powershell was refusing to print anything after this line
[void]($event.Message -match 'Account Name:\s{1,}(?<AccountName>.+)')
So I have three questions:
$result = foreach($event in $events)
thing? I don't quite understand how it works or how it knows what to set each index of $result
equal to{
$computer = $env:ComputerName
if ($Days -eq $null) {
$Days = Read-Host -prompt "Enter the number of days to go back"
}
$startDate = (Get-Date) - (New-TimeSpan -Day $Days)
$events = Get-WinEvent -Computer $computer -FilterHashtable @{Logname='Security';ID=4672;StartTime=$startDate}
[System.Collections.ArrayList]$arr = @()
$result = foreach ($event in $events) {
[void]($event.Message -match 'Account Name:\s{1,}(?<AccountName>.+)')
$Matches.AccountName.gettype()
$Matches.AccountName
"SYSTEM"
$h = Read-Host -prompt "Stop here to see if anything printed"
if ((-not ($arr.Contains($Matches.AccountName))) -and ($Matches.AccountName -ne "SYSTEM") -and ($Matches.AccountName -ne "LOCAL SERVICE") -and ($Matches.AccountName -ne "NETWORK SERVICE") -and ($Matches.AccountName -ne "Local Administrator")) {
$arr.Add($Matches.AccountName) > $null;
[PSCustomObject]@{
AccountName = $Matches.AccountName;
Time = $event.timeCreated
}
}
}
Upvotes: 0
Views: 2850
Reputation: 3154
$result
, hence nothing is printed to the console$arr
is an empty array, I don't see any reason to use an array here. Also the comparison is just so long that's difficult to find a flaw. You can do much much simpler, as I'll show in a second.PSCustomObject
.You can solve your problem much easier and readable by using the -contains
or -notcontains
operator, which checks whether or not an element exists in an array.
So, simply create an array of accounts which you want to filter out, check if the found account is part of the filter list and proceed. By doing so you also have no hassle to extend the list or even make the list part of the input of a function.
$FilteredAccounts = 'LOCAL SERVICE', 'NETWORK SERVICE'
$AccountRegEx = 'Account Name:\s{1,}(?<AccountName>.+)'
foreach ($Event in $Events) {
[void]($Event.Message -match $AccountRegEx)
if ($FilteredAccounts -notcontains $Matches.AccountName.Trim()) {
[PSCustomObject]@{
AccountName = $Matches.AccountName
Time = $Event.TimeCreated
}
}
}
Upvotes: 0
Reputation: 7479
No print output
you were capturing that to the $Results
collection. anything on a line by itself is sent to the output stream ... and you were capturing it all.
Your comparison failed because your regex left a CR
on the end of your $Matches.AccountName
. I can't figure out how to fix the regex, so I simply used .Trim()
on it. after that, things worked.
However, you used an overly complex IF cascade. I switched to using -notin $ExcludedAccountList
for a simpler test.
Sending stuff from the foreach
to the $Results
variable
Anything that is sent to the output stream can be assigned to a $Var
. In this case, the custom object was sent to the output stream ... and PoSh gathered all of that output, held it until the loop ended, and then stuffed the objects into the $Var
on the left of the =
.
Here is a slightly different way to get the info.
There is something wrong with your regex - it includes the line-ending CR
. I was unable to fix that, so I simply used .Trim()
on it.
your if
cascade was too twisty, so I simplified that to test for -notin
an excluded account list.
#Requires -RunAsAdministrator
$ExcludedAccountList = @(
# I only have the "system" account listed
# commented this out so I could see something
#'SYSTEM'
'LOCAL SERVICE'
'NETWORK SERVICE'
'Local Administrator'
)
$computer = $env:ComputerName
$Days = ''
if ($Days -eq '')
{
[int]$Days = Read-Host -prompt "Enter the number of days to go back"
}
$startDate = (Get-Date).AddDays(-$Days)
$FilterHashtable = @{
Logname = 'Security'
ID = 4672
StartTime = $startDate
}
$EventList = Get-WinEvent -Computer $computer -FilterHashtable $FilterHashtable
$DupeCheck = [System.Collections.Generic.List[string]]::New()
# force the $Var to be an array even if only one item is returned
[array]$Results = foreach ($Event in $EventList)
{
$null = $event.Message -match 'Account Name:\s{1,}(?<AccountName>.+)'
# get rid of trailing non-printing char [hex = "0d" - carriage return]
$AccountName = $Matches.AccountName.Trim()
# check if we already have that account name
# then exclude the unwanted account names
if (-not $DupeCheck.Contains($AccountName) -and
$AccountName -notin $ExcludedAccountList)
{
$DupeCheck.Add($AccountName)
[PSCustomObject]@{
AccountName = $AccountName
Time = $event.timeCreated
}
}
#>
}
$Results
With the $Days
set to 1, the $Results
collection contains this:
AccountName Time ----------- ---- SYSTEM 2019-02-10 1:11:52 AM
Upvotes: 2