TransWikia.com

(PowerShell) How do I filter usernames with Get-EventLog

Stack Overflow Asked by Jeremiah Williams on January 5, 2022

I’m working on a Powershell script to get all users who have logged in/out of a server in the past 7 days, where their name is not like "*-organization". The below works, but no matter what I try I’m not able to filter names

$logs = get-eventlog system -ComputerName $env:computername -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7)
$res = @()
ForEach ($log in $logs)
{
    if($log.instanceid -eq 7001){
        $type = "Logon"
    }
    Elseif ($log.instanceid -eq 7002){
        $type = "Logoff"
    }
    Else { Continue } 
    
    $res += New-Object PSObject -Property @{Time = $log.TimeWritten; "Event" = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
$res

I’ve tried adding this line in various places and ways, but no matter what I can’t get it to filter. It either fails and tells me my operator must have a property and value, or it runs fine and ignores any username filtering.

| Where-Object $_.User -notlike "*-organization"

Is it even possible to filter the login username with this method? If so, what am I doing wrong? If it’s not possible, is there another way I can get what I need?

3 Answers

You can do this with the -FilterXPath parameter like below:

$filter = "(*[System/EventID=7001] or *[System/EventID=7002]) and *[System/Provider[@Name='Microsoft-Windows-Winlogon']]"
$result = Get-WinEvent -LogName System -FilterXPath $filter | ForEach-Object {
    # convert the event to XML and grab the Event node
    $eventXml = ([xml]$_.ToXml()).Event
    $eventData = $eventXml.EventData.Data

    $userSID = ($eventData | Where-Object { $_.Name -eq 'UserSid' }).'#text'
    $userName = [System.Security.Principal.SecurityIdentifier]::new($userSID).Translate([System.Security.Principal.NTAccount])

    # you can add username filtering here if you like.
    # remember the $userName is in formal DOMAINLOGONNAME
    # if ($username -notlike "*-organization") {
        # output the properties you need
        [PSCustomObject]@{
            Time     = [DateTime]$eventXml.System.TimeCreated.SystemTime
            Event    = if ($eventXml.System.EventID -eq 7001) { 'LogOn' } else { 'LogOff' }
            UserName = $userName
            UserSID  = $userSID
            Computer = $eventXml.System.Computer

        }
    # }
}

# output on screen
$result

# output to CSV file
$result | Export-Csv -Path 'X:TheOutputFile.csv' -NoTypeInformation

Note, I have commented out the username filtering in the code. It is just there to give you an idea of where to put it. Of course, you can also filter the $result afterwards:

$result | Where-Object { $_.UserName -notlike "*-organization" }

Answered by Theo on January 5, 2022

Adding to @js2010's helpful answer, and with the assumption you're using PowerShell 5.1. I usually identify the property array index and use Select-Object to create a custom property as needed.

$WinEvents = 
get-winevent @{logname='system'; providername='Microsoft-Windows-Winlogon'} | 
Select-Object @{Name = 'Time'; Expression = {$_.TimeCreated}},
    @{Name = 'Event'; Expression = { If($_.ID -eq 7001){'Logon'} ElseIf($_.ID -eq 7002){ 'Logoff' } } },
    @{Name = 'User'; Expression = { [System.Security.Principal.SecurityIdentifier]::new( $_.Properties[1].Value ).Translate([System.Security.Principal.NTAccount]) } }

In your case this should add a property called User with a value like DomainNameUserName to the objects. I also added expressions to derive the other properties you were adding to your custom objects. Select-Object emits custom objects as well so this should give the result you're looking for.

Let me know if this helps.

Update

Respectfully, the other 2 answers make the assumption that you are looking for logon/off events for a specific user. That's not how I read the question; in particular:

"get all users who have logged in/out of a server"

While PowerShell 7+ does let you directly cite UserID in the FilterHashtable, it's not very useful here because we're not seeking events for a specific user. Furthermore, it seems unhelpful for the ultimate output as by default it echoes as a SID. It would still need to be translated, not only for display but for further filtering. I'm also not positive that UserID will always be the same as Properties[1], there's certainly some variance when looking at other event IDs.

The XML work is very cool, but I don't think it's called for here.

There were some issues with my answer as well. I overlooked filtering the event IDs & dates up front. I also realized we don't need to instantiate [System.Security.Principal.SecurityIdentifier] class because the property is already typed as such. Along with some readability improvements I corrected those issues below.

# Should be the 1st line!
using NameSpace System.Security.Principal

$ResolveEventType = @{ 7001 = 'Logon'; 7002 = 'Logoff' }
$FilterHashTable  =
    @{
        LogName      = 'system'
        ProviderName = 'Microsoft-Windows-Winlogon'
        ID           = 7001,7002
        StartTime    = (Get-Date).AddDays(-7)
    }

[Array]$WinEvents = 
Get-WinEvent -FilterHashtable $FilterHashTable | 
Select-Object @{ Name = 'Time'; Expression = { $_.TimeCreated } },
    @{ Name = 'Event'; Expression = { $ResolveEventType[ $_.ID ] } },
    @{ Name = 'User'; Expression = { $_.Properties[1].Value.Translate( [NTAccount] ) } }

$WinEvents | 
Where-Object{ $_.UserName -notlike "*-organization" } | 
Format-Table -AutoSize

This tested good in PowerShell 5.1 & 7.0. I added Format-Table to display the output, but you can just change that out for an Export-Csv command as needed

Note: The last 2 pipelines can be combined, but I thought this was a little more readable.

Let me know if this helps.

Answered by Steven on January 5, 2022

There would have to be a property named 'user' for that to work. Get-eventlog is actually obsolete now, and replaced by get-winevent. Unfortunately, you have to get into the xml to filter by usersid. I've included a time filter.

$a = get-winevent @{logname='system';
  providername='Microsoft-Windows-Winlogon'} -MaxEvents 1
$e = $a.ToXml() -as 'xml'
$e.event.EventData

Data
----
{TSId, UserSid}

get-winevent @{logname='system';providername='Microsoft-Windows-Winlogon';
  data='S-2-6-31-1528843147-473324174-2919417754-2001';starttime=(Get-Date).AddDays(-7);
  id=7001,7002}

In powershell 7 you can refer to the eventdata named data fields directly:

get-winevent @{logname='system';providername='Microsoft-Windows-Winlogon';
  usersid='S-2-6-31-1528843147-473324174-2919417754-2001'}

The get-winevent docs say you can use "userid" in the filterhashtable, but I can't get that to work.

EDIT: Actually this works. But without limiting it too much, at least for me.

get-winevent @{logname='system';userid='js2010'}
get-winevent @{providername='Microsoft-Windows-Winlogon';userid='js2010'}

Answered by js2010 on January 5, 2022

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP