【问题标题】:Compare-Object Returning Invalid Results比较对象返回无效结果
【发布时间】:2020-08-07 02:18:13
【问题描述】:

第一次在stackoverflow上发帖,如果我错过了社会规范,请提前道歉。

我在 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*'

没有返回任何东西

我得到的是很多结果。奇怪的是,如果我查看每个数组的 .count ,数学就可以解决。 Array1 减去 Array2 等于 Array3。所以它正在删除正确数量的对象,而不是预期的对象。我在这里做错了什么?由于我正在从我正在比较的确切数组中提取数据,因此我想不出任何其他标准,它将搜索将返回意外匹配。我还尝试在比较之前按相同的属性对每个数组进行排序,因为我正在掌握但正如预期的那样并没有解决它。

提前致谢!

【问题讨论】:

  • 您在 array1 前面缺少一个美元符号:$Array2 = Array1 | where-object Username -like '*\a*'。我使用 get-aduser 但使用 name 属性进行了尝试,它对我有用。我没有用户名属性,也没有包含反斜杠的名称。如果不分配 $array3,比较对象的输出看起来正确吗?
  • 用户名中只有一个反斜杠对吗? dom/joe/abel Compare-object 查看 aduser 对象或 DistinguishedName 的字符串版本。它不是在查看用户名属性。

标签: arrays powershell compare compareobject


【解决方案1】:

简单的方法是执行相同的-like 赋值,但使用相反的运算符-notlike 例如:

$Array2 = $Array1 | where-object Username -like 'a*'
$Array3 = $Array1 | where-object Username -notlike 'a*'

注意:

(不确定是否是匹配问题中的拼写错误:'*\a*'),匹配应为a*,“a”字符后只有一个星号。您希望将开始的所有内容与“a”和“*”匹配(例如,仅匹配“Alex”,而不是“Brad”)。

【讨论】:

  • 对不起,我应该解释一下,因为它确实看起来像一个错字。 *\ 是因为我在我的用户名属性中处理多个域。所以我抓住了 domain1\a* 和 domain2\a* 用户。
【解决方案2】:

您可以通过取反 Where-Object 操作数(-notlike 而不是 -like)来解决此问题:

$Array2 = $Array1 |Where-Object Username -like *\a*
$Array3 = $Array1 |Where-Object Username -notlike *\a*

...或者,您可以利用.Where() 扩展方法的“拆分”模式,并在单个分配中完成:

$Array2,$Array3 = $Array1.Where({$_.Username -like '*\a*'}, 'Split')

【讨论】:

  • 第一个例子对我有用。您缺少引号:{$_ -like 'a*'}
  • 我觉得这几乎可以解释它,但我认为失败在我这边。如果我对您的理解正确,那么数学部分与我所看到的不符。在您的示例中 $Array1.count 将是六, $Array2.count 将是二,并且比较两个不同的对象(您的中间行)将导致计数为五个不匹配。但我看到的是 $Array1.count 减去 $Array2.count 是四个而不是五个。我仍然错过了它的工作原理。
  • 所以经过一些试验和错误后,它起作用了:'compare-object $Array1 $Array2 -Property Username -PassThru' 虽然我仍然不知道为什么,这很麻烦。
  • 不,我的解释完全错误,它可以与-Property Username一起使用是有道理的
  • 希望它对我有用!无论如何,感谢您的尝试解释。就答案而言,我不会将其中任何一个标记为答案,因为我的问题是为什么 compare-object 不能像我认为的那样工作,而不是如何构建不同的解决方案来获得我需要的东西。跨度>
【解决方案3】:

比较对象以一种有趣的方式工作。对于对象,您通常需要指定属性。我很惊讶文档没有这样的例子。不幸的是, -property 不接受通配符。我认为没有“-property”,除非有特殊的 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 <=

【讨论】:

  • 但是如果我直接从第一个数组中提取对象,每个属性都应该是相同的。它显然是在比较两个数组并成功计算出两者之间有多少不同。那么这不是证明它可以比较对象而不仅仅是属性吗?
  • 除非对象的字符串版本不同,否则我看不到这一点。你能举个例子吗?
  • 我不确定如何构建一个其他人可以在不访问我的数据的情况下尝试的示例。如果我可以用 get-aduser 重新创建它,你能在你这边重新创建吗?
  • 即使使用 get-aduser,compare-object 所做的只是在每个对象上运行 $obj.tostring(),然后比较字符串。
  • 有人告诉我 compare-object 可能会先尝试 .compareto() 或 .equals() 方法,然后再使用 .tostring()。但是 aduser 对象没有比较对象。日期时间就可以了。
【解决方案4】:

我认为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           <=  

【讨论】:

  • 是的。这就是文档中的流程对象示例所做的。
  • 这可能会回答我的问题,但我不是一个强大的 PowerShell 人,无法从解释引擎如何工作到知道为什么我的车无法启动。 ELI 5 呢?
【解决方案5】:

我的结论是,一些命令行开关以破坏比较对象的方式构建数组。我仍然不确定这种神秘的“方式”是什么,但问题在使用 Citrix 的 Get-BrokerSession 时会出现,而在使用 Get-AdUser 时不会出现。

长答案 对于那些真正想使用 compare-object 的人来说,这是我让它工作的方式:

compare-object $Array1 $Array2 -Property Username -PassThru

-PassThru 对我来说是一个灵光乍现的时刻。

我的问题特别是关于 compare-object 如何/为什么没有按我预期的方式工作。根据我的解释,所有答案只提供了解决问题的不同方法,并没有真正回答问题。特别感谢 @js2010 继续与我合作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    相关资源
    最近更新 更多