0

I have two Powershell objects, one with yesterdays failed servers, another with todays failed servers.

I want to compare the two objects and only return the servers that are present in todays list but not in yesterdays list, ignoring any that appear in both lists and ignoring any that appear in yesterdays list but not todays list.

Only way I've found to do this is by using filtering using Where-Object as below:

Compare-Object -ReferenceObject $YesterdayData -DifferenceObject $TodaysData -Property Server -PassThru | Where-Object {$_.SideIndicator -like '=>'}

I feel there must be another way of doing this without the Where-Object filter?

  • Do you need to filter? You only need the WHERE if you are getting more results than what you need. – jdweng Feb 17 '23 at 10:19
  • @jdweng if I don't apply the filter then it also shows me servers that are in yesterdays list but not in todays list which i dont want to see. I only need to see servers that are in todays list but not in yesterdays list – TripToBelize Feb 17 '23 at 10:37
  • [`Compare-Object`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/compare-object) is indeed probably best native PowerShell approach, at the hand you want to try this [`Join-Object script`](https://www.powershellgallery.com/packages/Join)/[`Join-Object Module`](https://www.powershellgallery.com/packages/JoinModule) (see also: [In Powershell, what's the best way to join two tables into one?](https://stackoverflow.com/a/45483110/1701026)): `$TodaysData |LeftJoin $YesterdaysData -on Server -Name 'Today','Yesteday'` which is generally faster and (I hope) more intuitive. – iRon Feb 17 '23 at 10:57

1 Answers1

1

That's a good approach regarding Compare-Object and I would only do a few minor improvements:

Compare-Object -ReferenceObject $YesterdayData -DifferenceObject $TodaysData -Property Server -PassThru |
    Where-Object SideIndicator -eq '=>'
  • As you are only filtering on a single property, the Where-Object call can use simplified argument syntax.
  • Although -like works, -eq better expresses intentions as you are actually looking for an exact match and don't need the pattern-matching ability of -like.

An alternative to Compare-Object, which will be significantly faster if you are dealing with large number of input objects (i. e. more than a few thousands), is to make use of a Hashset. A Hashset basically is a hashtable that only consists of keys and can be used for fast lookup (much less dependent on the number of input objects).

# Turn yesterdays server names into a Hashset for fast lookup
$YesterdayServers = [Collections.Generic.Hashset[string]] $YesterdayData.Server

# Now filter todays servers to only output new servers (which are not contained in yesterdays servers)
$TodaysData.Where{ -not $YesterdayServers.Contains( $_.Server ) }
  • The .Where method is an intrinsic method that PowerShell adds to most objects. It can be used similar to Where-Object but is more efficient if you are working with data objects such as arrays. In a pipeline, the Where-Object command is usually preferred as it outputs elements one-by-one, lettings you see results immediately as they arrive. See this answer for a few more details.
  • The .Contains method is specific to Hashset and takes advantage of the internal structure of the data to do a very fast lookup.
zett42
  • 25,437
  • 3
  • 35
  • 72