比较对象返回无效结果

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 继续与我一起完成它。