Reputation: 1
I'm trying to compare an hashtable to multiple output from Pipeline, in he shortest way ( one line if possible).
Each output will contains at minimum same Property as Key in hashtable, but could have more Property that I don't care.
An example ( not exactly what I need but for the idea ):
$hash = @{
Name = Name1
CreationTime = DateC1
LastWriteTime = DateW1
}
$Result = Get-Item -Path "Path to Check"
Output1 :
Name : Name1
CreationTime : DateC1
LastWriteTime : DateW1
Mode :
LinkType :
Target :
Output2 :
Name : Name1
CreationTime : DateC1
LastWriteTime : DateW2
Mode :
LinkType :
Target :
Output3 :
Name : Name1
CreationTime : DateC2
LastWriteTime : DateW1
Mode :
LinkType :
Target :
Output4 :
Name : Name2
CreationTime : DateC1
LastWriteTime : DateW1
Mode :
LinkType :
Target :
How to return only the first output that match hashtable ?
I tryed the basic way, compare each Property like :
Get-Item -Path "Path to Check" | ?{ ($_.Name -eq $hash.Name) -and ($_.CreationTime -eq $hash.CreationTime) -and ($_.LastWriteTime -eq $hash.LastWriteTime) }
But I think there must be other solutions, especially if there are more properties
Upvotes: 0
Views: 84
Reputation: 2845
Bit late but here my solutions.
Using the variable names $HashParagon
for the hashtable you use as... well, paragon, and $ResultList
for whatever collection you are going to check.
For every item of the collection, check if it has all the Properties equivalent to the Keys in the hashtable and if so if they have the same value of the hashtable.
If any comparison returns false, it skips to the next item of the collection.
Solution 1: in-line
$ResultList | Where-Object {
foreach ($key in $HashParagon.Keys) {
if ($key -notin $_.psobject.Properties.Name -or
$HashParagon.$key -ne $_.$key) {
return $false
}
}
$true
} | Select-Object -First 1
Solution 2: offline with Labeled Foreach() I know there is some stigma over labels, but they are a useful tools and this seems the perfect situation to use it.
:ResultListLoop foreach ($Item in $ResultList) {
foreach ($key in $HashParagon.Keys) {
if ($key -notin $item.psobject.Properties.Name -or
$HashParagon.$key -ne $Item.$key ) {
continue ResultListLoop
}
}
return $item
}
Upvotes: 0
Reputation: 174760
Use the Where-Object
script block to iterate over each entry in the hashtable - as soon as you encounter an entry with no matching property on the input value you can return $false
and ignore the item. Then use Select-Object -First 1
to only select the first matching item:
Get-ChildItem -Path path\to\files |Where-Object {
$item = $_
return $hash.psbase.Keys.Where({$hash[$_] -ne $item.$_}, 'First').Count -eq 0
} |Select-Object -First 1
Here we safely enumerate the hashtable keys with .psbase.Keys
, and then use the intrinsic .Where({})
method to filter the keys - we only want the ones not matching the values of the input file - and if any is found, we'll return $false
from the Where-Object
filter block, thus filtering out all files with non-matching properties, leaving you only with matching files.
If you want case-sensitive string comparisons, use -cne
instead of -ne
inside .Where({...})
Upvotes: 2