比较对象返回无效结果
Compare-Object Returning Invalid Results
首先 post 到 Whosebug,如果我错过了社会规范,请提前致歉。
我在 PowerShell 中有一个数组,其中包含数千个对象。标准的东西,每个对象都具有用户名、登录时间、他们登录的计算机等属性。然后我从第一个数组中分离出少量对象,用户名以 A:
开头
$Array2 = $Array1 | where-object Username -like '*\a*'
这按预期工作。
我想构建第三个数组,它只包含 $Array1 中不在 $Array2 中的对象。或者换句话说,一个只有用户名不以 A 开头的用户的数组。
这似乎是要走的路:
$Array3 = compare-object $Array1 $Array2 | select-object -expandproperty InputObject
期望:
$Array3 | where-object Username -like '*\a*'
结果一无所有returned
我得到的结果很多。奇怪的是,如果我查看每个数组的 .count,数学就会计算出来。 Array1 减去 Array2 等于 Array3。所以它删除了正确数量的对象,而不是预期的对象。我在这里做错了什么?由于我正在从我正在比较的确切数组中进行拉取,因此我想不出它会搜索的任何其他条件 return 意外匹配。在比较之前,我还尝试按相同的 属性 对每个数组进行排序,因为我正在掌握但正如预期的那样并没有解决它。
提前致谢!
简单的方法是做相同的 -like
赋值,但使用相反的运算符 -notlike
例如:
$Array2 = $Array1 | where-object Username -like 'a*'
$Array3 = $Array1 | where-object Username -notlike 'a*'
注:
(不确定是否是匹配问题中的错字:'*\a*'
),匹配应该是 a*
,在“a
”之后只有一个星号特点。您想要匹配所有 starting 与“a
”和“*
”之后的任何内容(例如只匹配 "Alex",而不匹配 "Brad").
比较对象的工作方式很有趣。对于对象,您通常需要指定属性。我很惊讶文档没有这方面的例子。不幸的是,-属性 不接受通配符。我认为如果没有“-属性”,除非有特殊的 compareto() 或 equals() 方法,否则它将比较对象的字符串版本。我认为对于 get-aduser 输出,它将比较字符串(专有名称)。
$a = @([pscustomobject]@{name='joe'})
$b = @([pscustomobject]@{name='joey'})
compare-object $a $b # no output, they're equal!
compare-object $a $b -property name
name SideIndicator
---- -------------
joey =>
joe <=
正在试用日期时间。它使用字符串以外的东西进行比较。
$a = get-date; sleep -Milli 500; $b = get-date
$a.tostring(); $b.tostring()
4/23/2020 6:33:56 PM
4/23/2020 6:33:56 PM
$a -eq $b
False
compare-object $a $b
InputObject SideIndicator
----------- -------------
4/23/2020 6:33:56 PM =>
4/23/2020 6:33:56 PM <=
您可以通过取反 Where-Object
操作数(-notlike
而不是 -like
)来解决此问题:
$Array2 = $Array1 |Where-Object Username -like *\a*
$Array3 = $Array1 |Where-Object Username -notlike *\a*
... 或者,您可以利用 .Where()
扩展方法的 "Split" 模式,并在单个赋值中完成:
$Array2,$Array3 = $Array1.Where({$_.Username -like '*\a*'}, 'Split')
我认为Compare-Object
内部使用ToString()
方法来比较对象。
class foo {
[string]$str
foo($str) {
$this.str = $str
}
}
class bar {
[string]$str
bar($str) {
$this.str = $str
}
[string] ToString() { return $this.str }
}
"== Compare foo object =="
$fooA = [foo]::new("a")
$fooB = [foo]::new("b")
compare $fooA $fooB -IncludeEqual | ft
"== Compare bar object =="
$barA = [bar]::new("a")
$barB = [bar]::new("b")
compare $barA $barB -IncludeEqual | ft
输出:
== Compare foo object ==
InputObject SideIndicator
----------- -------------
foo ==
== Compare bar object ==
InputObject SideIndicator
----------- -------------
b =>
a <=
我的结论是,某些命令行开关以破坏比较对象的方式构建数组。我仍然不确定这个神秘的 "way" 是什么,但问题在使用 Citrix 的 Get-BrokerSession 时出现,而在使用 Get-AdUser 时则没有。
长答案
对于那些真正想要使用比较对象的人,这里是我让它工作的方式:
compare-object $Array1 $Array2 -Property Username -PassThru
-PassThru 对我来说是灵光一现的时刻。
我的问题具体是关于 how/why 比较对象没有按我预期的方式工作。根据我的解释,所有答案都只提供了解决问题的不同方法,并没有真正回答问题。特别感谢@js2010 继续与我一起完成它。
首先 post 到 Whosebug,如果我错过了社会规范,请提前致歉。
我在 PowerShell 中有一个数组,其中包含数千个对象。标准的东西,每个对象都具有用户名、登录时间、他们登录的计算机等属性。然后我从第一个数组中分离出少量对象,用户名以 A:
开头$Array2 = $Array1 | where-object Username -like '*\a*'
这按预期工作。
我想构建第三个数组,它只包含 $Array1 中不在 $Array2 中的对象。或者换句话说,一个只有用户名不以 A 开头的用户的数组。 这似乎是要走的路:
$Array3 = compare-object $Array1 $Array2 | select-object -expandproperty InputObject
期望:
$Array3 | where-object Username -like '*\a*'
结果一无所有returned
我得到的结果很多。奇怪的是,如果我查看每个数组的 .count,数学就会计算出来。 Array1 减去 Array2 等于 Array3。所以它删除了正确数量的对象,而不是预期的对象。我在这里做错了什么?由于我正在从我正在比较的确切数组中进行拉取,因此我想不出它会搜索的任何其他条件 return 意外匹配。在比较之前,我还尝试按相同的 属性 对每个数组进行排序,因为我正在掌握但正如预期的那样并没有解决它。
提前致谢!
简单的方法是做相同的 -like
赋值,但使用相反的运算符 -notlike
例如:
$Array2 = $Array1 | where-object Username -like 'a*'
$Array3 = $Array1 | where-object Username -notlike 'a*'
注:
(不确定是否是匹配问题中的错字:'*\a*'
),匹配应该是 a*
,在“a
”之后只有一个星号特点。您想要匹配所有 starting 与“a
”和“*
”之后的任何内容(例如只匹配 "Alex",而不匹配 "Brad").
比较对象的工作方式很有趣。对于对象,您通常需要指定属性。我很惊讶文档没有这方面的例子。不幸的是,-属性 不接受通配符。我认为如果没有“-属性”,除非有特殊的 compareto() 或 equals() 方法,否则它将比较对象的字符串版本。我认为对于 get-aduser 输出,它将比较字符串(专有名称)。
$a = @([pscustomobject]@{name='joe'})
$b = @([pscustomobject]@{name='joey'})
compare-object $a $b # no output, they're equal!
compare-object $a $b -property name
name SideIndicator
---- -------------
joey =>
joe <=
正在试用日期时间。它使用字符串以外的东西进行比较。
$a = get-date; sleep -Milli 500; $b = get-date
$a.tostring(); $b.tostring()
4/23/2020 6:33:56 PM
4/23/2020 6:33:56 PM
$a -eq $b
False
compare-object $a $b
InputObject SideIndicator
----------- -------------
4/23/2020 6:33:56 PM =>
4/23/2020 6:33:56 PM <=
您可以通过取反 Where-Object
操作数(-notlike
而不是 -like
)来解决此问题:
$Array2 = $Array1 |Where-Object Username -like *\a*
$Array3 = $Array1 |Where-Object Username -notlike *\a*
... 或者,您可以利用 .Where()
扩展方法的 "Split" 模式,并在单个赋值中完成:
$Array2,$Array3 = $Array1.Where({$_.Username -like '*\a*'}, 'Split')
我认为Compare-Object
内部使用ToString()
方法来比较对象。
class foo {
[string]$str
foo($str) {
$this.str = $str
}
}
class bar {
[string]$str
bar($str) {
$this.str = $str
}
[string] ToString() { return $this.str }
}
"== Compare foo object =="
$fooA = [foo]::new("a")
$fooB = [foo]::new("b")
compare $fooA $fooB -IncludeEqual | ft
"== Compare bar object =="
$barA = [bar]::new("a")
$barB = [bar]::new("b")
compare $barA $barB -IncludeEqual | ft
输出:
== Compare foo object ==
InputObject SideIndicator
----------- -------------
foo ==
== Compare bar object ==
InputObject SideIndicator
----------- -------------
b =>
a <=
我的结论是,某些命令行开关以破坏比较对象的方式构建数组。我仍然不确定这个神秘的 "way" 是什么,但问题在使用 Citrix 的 Get-BrokerSession 时出现,而在使用 Get-AdUser 时则没有。
长答案 对于那些真正想要使用比较对象的人,这里是我让它工作的方式:
compare-object $Array1 $Array2 -Property Username -PassThru
-PassThru 对我来说是灵光一现的时刻。
我的问题具体是关于 how/why 比较对象没有按我预期的方式工作。根据我的解释,所有答案都只提供了解决问题的不同方法,并没有真正回答问题。特别感谢@js2010 继续与我一起完成它。