Search code examples
powershellforeachevent-viewer

PowerShell not printing to console


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:

  1. Why won't PowerShell print anything in this location?
  2. What is wrong with my comparison that checks if AccountName is not equal to an account like "LOCAL SERVICE"? It always evaluates to false, thus allowing it to get added to the list
  3. This one is a little off topic but is there a name for what I am doing with the whole $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
            }
        }
    }

Solution

    1. 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.

    2. 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.

    3. 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