Where-Object - Matching any integer in an array

Hi PS.org! Looking forward to getting involved here!

Am trying to write a fairly simple script to pull out specific Event IDs from a set of System event logs (on domain controllers), but I can’t quite figure out how to get it to match any of the values within an array that holds the event IDs I want.

I have a variable ($EventIDs) that is an array of 5 or 6 integers, and one for the domain controller objects ($DCs):

When I do something simple, such as search for { $_.EventID -eq ‘1234’), it works fine. However, I can’t figure out how to get this to search for any ID that is in the array $EventIDs:

 

Invoke-Command -ComputerName $DCs.Name -ScriptBlock {

Get-EventLog -LogName System | Where-Object { $_.EventID -in $EventIDs } | Select-Object machinename,eventid,timegenerated

}

(I know the above is wrong as it stands!)

I’ve gone through a number of articles today about this and can’t seem to work it out. Would really appreciate a pointer or two!

Best to all,

J

In your script $_.EventID is NOT an integer. It is an EventLogEntry object. If you run the following you will see what I mean:

Get-EventLog -LogName System | select -First 1 | GM

Get-EventLog -LogName System | select -First 1 | Select EventID | GM

You will also see that EventLogEntry objects have a property of EventID that is an integer and what you are trying to filter. So you would actually need to re-write as:

Get-EventLog -LogName System | where {$_.EventID.EventID -in $EventIDs}

Having said all that it is more efficient to just use the InstanceID parameter of the Get-EventLog command so you are not paying the performance penalty of a pipe. Like this:

Get-EventLog -LogName System -InstanceId $EventIDs

 

The code looks OK to me and works locally. I think this might be a scoping problem. If you’re declaring $EventIDs outside of your ScriptBlock you need to make sure it’s passed through to Invoke-Command.

Invoke-Command -ComputerName $DCs.Name -ScriptBlock {

Get-EventLog -LogName System | Where-Object { $_.EventID -in $Using:EventIDs } | Select-Object machinename,eventid,timegenerated

}

 

Hi Mike,

 

I know $_.EventID is not an integer, I meant that my array is an array of integers (suppose I could have just said ‘numbers’!)

 

Thanks for that, I’ll give it a try.

 

J

Hi Matt,

Ah, that makes sense! I’ve done that and it works perfectly!

Do you think it’s best practice to put an array/variable like this within the script block itself, or does it not really matter if you just use $USING: ?

Many thanks,

J

What I meant is you were comparing <EventLogEntry> to <Int> in your script and not <int> to <int> like you might think. Also, I forgot you are doing this in a script block for Invoke-Command so Matt is right about scoping. Local variables in your script are not accessible inside the Invoke-Command script block unless you force it with $using: or pass it in as a parameter value.

[quote quote=271012]What I meant is you were comparing <EventLogEntry> to <Int> in your script and not <int> to <int> like you might think. Also, I forgot you are doing this in a script block for Invoke-Command so Matt is right about scoping. Local variables in your script are not accessible inside the Invoke-Command script block unless you force it with $using: or pass it in as a parameter value.

[/quote]

I see what you mean!

I think either way is acceptable as long as your code is consistent.

I’m aware of problems with $Using if you’re developing with Pester but in most (all?) other cases passing local variables with $Using should be fine.

Thanks to you both for your input and help!

 

J

One more question on this:

I’ve been using a particular event ID/set of IDs that I know exist to test this; the script is actually going to be used to check for events that don’t generally exist but we need to know if they get logged.

 

When I change the variable $EventIDs to the actual numbers I want to search for, it fails. Why would this be? I’m not sure which ‘-’ operator the error is referring to - nothing in the syntax has changed, only the contents of the array I am using…

You must provide a value expression on the right-hand side of the ‘-’ operator.
+ CategoryInfo : ParserError: (:slight_smile: [], ParseException
+ FullyQualifiedErrorId : ExpectedValueExpression
+ PSComputerName : TESTSERVER

 

Invoke-Command -ComputerName $DCs.Name -ScriptBlock {

Get-EventLog -LogName System | Where-Object { $_.EventID -in $Using:EventIDs } | Select-Object machinename,eventid,timegenerated

} | Format-Table -OutVariable EventResults

 

What OS and PS version is your TESTSERVER? I am unable to duplicate your results using Server 2019 / Windows PS Version 5.1 as a target machine. This error is on the remote machine which is why you don’t see line numbers and a PSCOMPUTERNAME property in the error.

Hi Mike,

The test server is Server 2008 R2 and version info is as follows:

Name Value
---- -----
CLRVersion     2.0.50727.8806
BuildVersion   6.1.7601.23403
PSVersion        2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1

This only occurs when I put the actual IDs I want to use into the array. If I change the array contents back to the values I was using to test with (i.e. event IDs I know for certain are present in the logs), it runs through all machines’ logs fine with zero errors.

 

Many thanks,

 

J

That is a very old version of PS. If you can upgrade, I would. Since I can’t duplicate it in my environment, my guess is that version of PS does not handle piping a null value across the pipe to where-object or could be it can’t handle $null -in EventIDs. Do you have another host with at least PS version 3 that you can try?

Hi Mike,

There are other servers I COULD use, but as the purpose of it is to search domain controller logs, it probably doesn’t matter whether it works without errors on another machine!

The thing is: it brings up that above error for 2 machines (DCs), and then continues on its merry way, and actually then finds some of those events on some other machines - so it’s not a critical failure that leads to the script stopping or anything.

I’m just confused as to why simply changing the values in the array would cause the error on the same machine(s)? If it’s able to make a remote connection using Invoke-Command to the machine, and find one set of event IDs, why would another set of IDs be any different?

 

Many thanks,

 

J

I agree with Mike that you should try and upgrade those servers. The -in operator was introduced in version 3.0 so this is likely to be version related.

Those will be upgraded at some point. However, I’m just trying to understand (from a learning perspective), why one number in an array doesn’t produce the error, but another one DOES? Surely that can’t be to do with that version it’s on, right?

Also, the other DCs are the same, and they don’t error - which is why I’m confused!

[quote quote=271099]Also, the other DCs are the same, and they don’t error – which is why I’m confused!

[/quote]
Interesting. To troubleshoot, I would probably start an interactive session (ISE) with the server that causes the errors to troubleshoot. Once established you can try the commands one at a time to narrow down and perhaps generate a more helpful error message.

Are you sure the PS version on the other servers is the same?

A quick check running powershell -version 2.0 confirms that the error is the same. I can’t get it to return anything different.

PS E:\temp> powershell -version 2.0
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.

PS E:\temp> '1' -in '1','2','3'
- : You must provide a value expression on the right-hand side of the '-' operator.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedValueExpression

 

 

I rarely run into terminating errors with the standard cmdlets, most errors are non-terminating, so it makes since that it keeps working. If -in was not introduced until PS version 3 then the error message makes perfect sense because the interpreter would recognize the - but not the in. If you just use the -InstanceID parameter in your Get-EventLog call this would be moot since you wouldn’t need to pipe the output to where-object. The -InstanceID parameter will take an array of integers and will filter for EventID. Just change you code to this:

Invoke-Command -ComputerName $DCs.Name -ScriptBlock { 
    Get-EventLog -LogName System -InstanceID $Using:EventIDs | 
        Select-Object machinename,eventid,timegenerated 
} | Format-Table -OutVariable EventResults