tags:

views:

1396

answers:

5

Hi, I'm trying to read the event log for security audit for all users except two, but is it possible to do that with the -notlike operator? It's something like that:

Get-EventLog -LogName Security | where {$_.UserName -notlike @("*user1","*user2")}

I have it working for a single user, like:

Get-EventLog -LogName Security | where {$_.UserName -notlike "*user1"}

Thanks, Pascal

A: 

Hey Pascal,

Yep, but you have to put the array first in the expression:

... | where { @("user1","user2") -notlike $_.username }

-Oisin

x0n
I tried, but it didn't have the excepted results.. check below if I did anything stupid, because both users appeared, along with everyone else:Get-EventLog -LogName Security | where {@("*user1", "*user2") -notlike $_.UserName} | Format-Table -Property EventID,Category,EntryType,TimeGenerated,UserName
Pascal
Right, this wont work because no matter what the username is, it will also be notlike one of the items in the list. So the condition is always true. These array comparisons are always OR and not AND.
JasonMArcher
silly me. i was concentrating on the syntactic rather than semantic error.
x0n
+3  A: 

V2 at least contains the -username parameter that takes a string[], and supports globbing.

V1 you want to expand your test like so:

Get-EventLog Security | ?{$._UserName -notlike "user1" -and $_.UserName -notlike "*user2"}

Or you could use "-notcontains" on the inline array but this would only work if you can do exact matching on the usernames.

... | ?{@("user1","user2") -notcontains $_.username}

slipsec
The missing ___ was treated as wiki markup for italics ;)
x0n
Thanks.. that did it!
Pascal
You can also reference the list of usernames to filter out via a variable: ?{$users -notcontains $_.username}
JasonMArcher
A: 
$listOfUsernames = @("user1", "user2", "etc", "and so on")
Get-EventLog -LogName Security | 
    where { $_.Username -notmatch (
        '(' + [string]::Join(')|(', $listOfUsernames) + ')') }

It's a little crazy I'll grant you, and it fails to escape the usernames (in the unprobable case a username uses a Regex escape character like '\' or '(' ), but it works.

As "slipsec" mentioned above, use -notcontains if possible.

Peter Seale
Thanks Peter.. That's also a great alternative!
Pascal
+1  A: 

I think Peter has the right idea. I would use a regular expression for this along with the -notmatch operator.

Get-EventLog Security | ?{$_.Username -notmatch '^user1$|^.*user$'}
+1  A: 

In order to support "matches any of ..." scenarios, I created a function that is pretty easy to read. My version has a lot more to it because its a PowerShell 2.0 cmdlet but the version I'm pasting below should work in 1.0 and has no frills.

You call it like so:

Get-Process | Where-Match Company -Like '*VMWare*','*Microsoft*'
Get-Process | Where-Match Company -Regex '^Microsoft.*'

filter Where-Match($Selector,[String[]]$Like,[String[]]$Regex) {

    if ($Selector -is [String]) { $Value = $_.$Selector }
    elseif ($Selector -is [ScriptBlock]) { $Value = &$Selector }
    else { throw 'Selector must be a ScriptBlock or property name' }

    if ($Like.Length) {
        foreach ($Pattern in $Like) {
            if ($Value -like $Pattern) { return $_ }
        }
    }

    if ($Regex.Length) {
        foreach ($Pattern in $Regex) {
            if ($Value -match $Pattern) { return $_ }
        }
    }

}

filter Where-NotMatch($Selector,[String[]]$Like,[String[]]$Regex) {

    if ($Selector -is [String]) { $Value = $_.$Selector }
    elseif ($Selector -is [ScriptBlock]) { $Value = &$Selector }
    else { throw 'Selector must be a ScriptBlock or property name' }

    if ($Like.Length) {
        foreach ($Pattern in $Like) {
            if ($Value -like $Pattern) { return }
        }
    }

    if ($Regex.Length) {
        foreach ($Pattern in $Regex) {
            if ($Value -match $Pattern) { return }
        }
    }

    return $_

}
Josh Einstein
Great script. Thanks!
Pascal