PowerShell:列出 CSV 文件行,其中第 3 列和最后一列之间的至少一个值等于“0”或“1”
PowerShell: list CSV file rows where at least one value between the 3rd and last column is equal to "0" or "1"
在我的 PowerShell 脚本中,我正在处理一个 CSV 文件,它看起来像这样(有许多行和列可以变化,但总是至少有 headers 和前 2 列):
OS;IP;user0;user1;user3
Windows;10.0.0.1;;;
Linux;hostname2;0;;1
Linux;10.0.0.3;;0;0
Linux;hostname4;;;
Windows;hostname5;1;1;1
我基本上在第一列列出服务器,在第一行列出用户 (CSV header)。这表示服务器的用户 "access granting" 矩阵("give access" 为 1,"remove access" 为 0,"don't change" 为空)。
我正在寻找一种方法来仅提取在第 3 列和最后一列之间(包括)包含等于“1”或“0”的值的行。 (= 最终获得应更改访问权限的服务器列表)
以上面的例子为例,我只想返回以下几行:
Linux;hostname2;0;;1
Linux;10.0.0.3;;0;0
Windows;hostname5;1;1;1
有什么提示可以实现吗?或者相反(得到没有任何 0 或 1 的那些)?
即使这意味着使用 "Get-Content" 而不是 "Import-CSV"。我不关心第一 (headers) 行;我知道如何排除它。
谢谢!
--- 最终解决方案,感谢@Tomalak 的回答:
$AccessMatrix = Import-CSV $CSVfile -delimiter ';'
$columns = $AccessMatrix | Get-Member -MemberType NoteProperty | Select-Object -Skip 2 -ExpandProperty Name
$AccessMatrix = $AccessMatrix | ForEach-Object {
$row = $_
foreach ($col in $columns) {
if ($row.$col.trim() -eq "1" -OR $row.$col.trim() -eq "0") {
$row # this pushes the $row onto the pipeline
break
}
}
}
以下使用Get-Member
到select前两列之后的所有列的名称。
然后,使用 ForEach-Object
,我们可以只输出那些在任何这些列中有值的行。
$data = ConvertFrom-Csv "OS;IP;user0;user1;user3
Windows;10.0.0.1;;;
Linux;hostname2;0;;1
Linux;10.0.0.3;;0;0
Linux;hostname4;;;
Windows;hostname5;1;1;1" -Delimiter ";"
$columns = $data | Get-Member -MemberType NoteProperty | Select-Object -Skip 2 -ExpandProperty Name
$data | ForEach-Object {
$row = $_
foreach ($col in $columns) {
if ($row.$col -ne "") {
$row # this pushes the $row onto the pipeline
break
}
}
}
break
语句停止执行内部 foreach
循环,因为一旦找到具有任何值的第一列就没有进一步检查的意义。
这相当于上面的,如果你更喜欢Where-Object
:
$data | Where-Object {
$row = $_
foreach ($col in $columns) {
if ($row.$col -ne "") {
return $true
}
}
}
在我的 PowerShell 脚本中,我正在处理一个 CSV 文件,它看起来像这样(有许多行和列可以变化,但总是至少有 headers 和前 2 列):
OS;IP;user0;user1;user3
Windows;10.0.0.1;;;
Linux;hostname2;0;;1
Linux;10.0.0.3;;0;0
Linux;hostname4;;;
Windows;hostname5;1;1;1
我基本上在第一列列出服务器,在第一行列出用户 (CSV header)。这表示服务器的用户 "access granting" 矩阵("give access" 为 1,"remove access" 为 0,"don't change" 为空)。
我正在寻找一种方法来仅提取在第 3 列和最后一列之间(包括)包含等于“1”或“0”的值的行。 (= 最终获得应更改访问权限的服务器列表)
以上面的例子为例,我只想返回以下几行:
Linux;hostname2;0;;1
Linux;10.0.0.3;;0;0
Windows;hostname5;1;1;1
有什么提示可以实现吗?或者相反(得到没有任何 0 或 1 的那些)? 即使这意味着使用 "Get-Content" 而不是 "Import-CSV"。我不关心第一 (headers) 行;我知道如何排除它。
谢谢!
--- 最终解决方案,感谢@Tomalak 的回答:
$AccessMatrix = Import-CSV $CSVfile -delimiter ';'
$columns = $AccessMatrix | Get-Member -MemberType NoteProperty | Select-Object -Skip 2 -ExpandProperty Name
$AccessMatrix = $AccessMatrix | ForEach-Object {
$row = $_
foreach ($col in $columns) {
if ($row.$col.trim() -eq "1" -OR $row.$col.trim() -eq "0") {
$row # this pushes the $row onto the pipeline
break
}
}
}
以下使用Get-Member
到select前两列之后的所有列的名称。
然后,使用 ForEach-Object
,我们可以只输出那些在任何这些列中有值的行。
$data = ConvertFrom-Csv "OS;IP;user0;user1;user3
Windows;10.0.0.1;;;
Linux;hostname2;0;;1
Linux;10.0.0.3;;0;0
Linux;hostname4;;;
Windows;hostname5;1;1;1" -Delimiter ";"
$columns = $data | Get-Member -MemberType NoteProperty | Select-Object -Skip 2 -ExpandProperty Name
$data | ForEach-Object {
$row = $_
foreach ($col in $columns) {
if ($row.$col -ne "") {
$row # this pushes the $row onto the pipeline
break
}
}
}
break
语句停止执行内部 foreach
循环,因为一旦找到具有任何值的第一列就没有进一步检查的意义。
这相当于上面的,如果你更喜欢Where-Object
:
$data | Where-Object {
$row = $_
foreach ($col in $columns) {
if ($row.$col -ne "") {
return $true
}
}
}