Reputation: 11
I'm new to scripting and struggling with implementing some concepts. I've got a PowerShell script working that will take in input from the user and store it into several variables. It will then look at a .csv file and only output rows where the several inputs from the user is not like the value in a specified column.
For example, if I've got a .csv file that contains:
value1, value2, value3
data1, data2, data3
data1, data2, data3
data1, data5, data3
data1, data2, data3
And I ask to output the rows where value2 is not like data5 I get the following as output:
value1, value2, value3
data1, data2, data3
data1, data2, data3
data1, data2, data3
Here's the current code I have that is working:
$path = Read-Host 'What is the file share path?'
$filteredvalue = Read-Host 'What value would you like to filter out?'
$filteredvalue2 = Read-Host 'What second value would you like to filter out?'
$filteredvalue3 = Read-Host 'What second value would you like to filter out?'
$filteredvalue4 = Read-Host 'What second value would you like to filter out?'
$filteredvalue5 = Read-Host 'What second value would you like to filter out?'
$filteredvalue6 = Read-Host 'What second value would you like to filter out?'
$filteredvalue7 = Read-Host 'What second value would you like to filter out?'
$file1 = $path
$filtered = Import-Csv -Path $file1 | where {$_.IdentityReference -notlike $filteredvalue -and $_.IdentityReference -notlike $filteredvalue2 -and $_.IdentityReference -notlike $filteredvalue3 -and $_.IdentityReference -notlike $filteredvalue4 -and $_.IdentityReference -notlike $filteredvalue5 -and $_.IdentityReference -notlike $filteredvalue6 -and $_.IdentityReference -notlike $filteredvalue7}
$file2 = "${path}_filtered.csv"
$filtered | Export-Csv -Path $file2 -NoTypeInformation
This works but is not the best solution as I have to specify in the code how many values I'll be filtering out. I would like to use arrays to prevent having to create all the variables for the values.
Here's what I've tried so far but no luck:
$path = Read-Host 'What is the file share path?'
$Reponse = 'Y'
$filteredvalue = $Null
$filteredvalues = @()
Do
{
$filteredvalue = Read-Host 'What value would you like to filter out?'
$Response = Read-Host 'Would you like to filter out additional values? (y/n)'
$filteredvalues += $filteredvalue
}
Until ($Response -eq 'n')
$file1 = $path
$filtered = Import-Csv -Path $file1 | where {for($i = 0; $i -le $filteredvalues.GetUpperBound(0); $i++) {$_.IdentityReference -ne $filteredvalues[$i]}}
$file2 = "${path}_filtered.csv"
$filtered | Export-Csv -Path $file2 -NoTypeInformation
The output remains the same and nothing gets filtered out.
Upvotes: 1
Views: 115
Reputation: 440317
PowerShell offers array-containment comparison operators -contains
and, since v3, also -in
- they differ only in whether the input array goes on the LHS (-contains
) or RHS (-in
).
As most operators in PowerShell, they also exist in negated form, i.e. -notcontains
and -notin
.
Applied to your code:
$filtered = Import-Csv $file1 | Where-Object IdentityReference -notin $filteredValues
As for what you tried:
As an aside: it's easier to use $filteredvalues.Count - 1
instead of $filteredvalues.GetUpperBound(0)
.
where
(Where-Object
) selects (passes through) input objects based on whether the output from the script block { ... }
evaluates to $true
.
Your for
-loop code returns an array of Booleans, indicating for each filter value whether the input object's .IdentityReference
matches that value.
Therefore, with 2 or more filter values, you'll end up with an array that contains at least 1 $true
value, and any such array is invariably interpreted as $true
overall.
For instance:
PS> [bool] ($false, $true)
True
For an overview of how PowerShell implicitly evaluates object as Booleans (to-Boolean conversion), see the bottom half of this answer.
For your loop approach to have worked, you would have had to return $false
as a scalar as soon as a filter value matched, and default to $true
otherwise (note the use of foreach
to enumerate the array elements more conveniently):
$filtered = Import-Csv -Path $file1 | where {
foreach ($filteredValue in $filteredValues) {
if ($_.IdentityReference -eq $filteredValue) { return $false }
}
return $true
}
Upvotes: 1