如何搜索一个 PowerShell 对象数组并获取匹配字符串的索引?

3
我需要搜索一个自定义的PowerShell对象数组(包含来自AD和Exchange的数据 - 5列:邮件,dn,extensionAttribute7,TotalItemSize,Count)。我每天收集这些数据(对于总项目大小>指定大小的每个用户),并使用Export-Clixml将其导出到XML文件中,以便在随后的几天中引用数据。每天我都会执行新的搜索,查找大于指定大小的邮箱,并保存有关匹配邮箱的数据,但我需要交叉引用现有的用户数组。如果用户已经在我的数组中,则我想将PS对象中的计数属性增加1,否则我想将用户作为新的PS自定义对象添加到我的数组中。这样我就可以跟踪邮箱始终超过指定大小的用户并相应地采取行动(这是客户要求)。
我遇到困难的部分是在我的自定义PS对象数组中搜索匹配项,以确定是否需要将用户添加为新对象或仅递增用户的计数器,因为它们已经在我的数组中。最初,我认为可以使用.IndexOf或-Contains在我的数组中找到匹配项,但它们似乎不适用于包含PS对象的数组。我唯一能够使其正常工作的方式如下:
#Check to see if this user is already in our master mbxlist array from previous days
$ndx = 0..($mbxlist.length - 1) | Where-Object {$mbxlist[$_].mail -eq $($m.mail)}

$ndx 是在我的数组中匹配对象的索引,如果没有匹配,则为$null。但这似乎不是很高效,特别是当我需要每天检查每个单独用户的数组中有1000多个对象时。肯定有更好的方法来解决这个问题?我考虑创建一个单独的字符串数组,仅包含用户的邮件地址,然后使用indexof来检查是否匹配。我可以推断出匹配的PS对象将具有与我的字符串数组相同的索引号,然后相应地更新ps对象数组中的计数:

# Create an array of strings based on the mail attribute in my PS object array
foreach ($m in $mbxlist) {[array]$lookup += $m.mail.ToString()}

#Search the lookup array for matching email address using IndexOf
$ndx=[array]::indexof($lookup,"joe.bloggs@mydomain,com")

#If ndx > 0 I've got a match so increment the count in the corresponding PS object
If ($ndx -ge 0)
{
    $mbxlist[$ndx].Count = ($mbxlist[$ndx].Count) + 1
}

这样做是否更有效率,因为IndexOf比为每个用户执行Where-Object要快?
我已经搜索和测试了好几天,但还是无法弄清楚。我相对而言比较新手,所以可能会错过一些非常明显的东西。谢谢!
2个回答

3

不确定这是否有所帮助,但您可以尝试使用电子邮件地址作为键将对象加载到哈希表中,然后通过该键进行引用(未经过测试):

$ht = @{}
import-clixml mbxdata.xml |
 foreach {$ht[$_.mail] = $_}

$mailboxes = get-mailbox -resultsize unlimited |
  select -ExpandProperty PrimarySMTPAddress

foreach ($mbx in $mailboxes){
 if ($ht[$mbx] -eq $null)
   {
     $ht[$mbx] = new-object PSObject #Create and add new object here
   }

  if ((get-mailboxstatistics $mbx).totalitemsize -gt '<some value>')
    {
      $ht[$mbx].count ++
    }
 }

$ht.Values | export-clixml mbxdata.xml

非常感谢mjolinor。我认为这正是我要找的。我以前没有真正使用过哈希表。您知道是否存在性能提升,与仅使用普通数组和::indexof搜索数组相比?我仍然无法相信没有一种内置方法或cmdlet可以定位/修改自定义ps对象数组。 - stukey
尚未测试,但哈希表操作非常高效,我预计这比任何数组搜索都要快得多。如果所有键都是唯一的,则只能使用哈希表,在此应用中它们将是唯一的。通常要在数组中定位对象,您会使用where-object。 - mjolinor
@stukey,在mjolinor的答复中补充一点,哈希表将会提高搜索索引。在.NET Framework中有一个用于哈希的算法,每当您使用索引($ht[$mbx],在这种情况下),它就会使用该算法,而不是迭代地在基础数据结构中搜索项,因此它可以根据已知信息引用它(几乎像在字典中查找定义的页码一样),以便更快地返回数据。不过我建议所有比较都使用小写执行,因为“Mbx”与“mbx”不同。只是提供信息。 - PSGuy

0
如果我正确理解了您的问题,您只需要比较前一个对象和当前对象,并挑选出差异即可。
您可以使用Compare-Object来完成这个任务,并指定您想要比较的属性。
下面是一个比较两个对象并找出仅存在于$object2中的差异的示例。
  $object1 = @()
  $object2 = @()
  $FirstNames = ("Jane","James","Jen","Jim")

Foreach($fn in $FirstNames){

    $object1 += New-Object PSObject -Property @{
    Firstname = $fn
    LastName  = "Doe"
    }

}

$object2 += New-Object PSObject -Property @{
           Firstname = "Jimmy"
           LastName  = "Doe"
           }

$object2 += New-Object PSObject -Property @{
           Firstname = "Jane"
           LastName  = "Doe"
           }


Compare-Object $object1 $object2 -Property  'FirstName' | ? { $_.SideIndicator -eq "=>" }

你可以将结果管道传递给 foreach,根据找到的差异执行某些操作。

Compare-Object $object1 $object2 -Property  'FirstName' | ? { $_.SideIndicator -eq "=>" } | %{Write-Host $_.FirstName }

请注意,在使用Sort-Object cmdlet比较对象之前,您可能需要对它们进行排序。

非常感谢您的回复,但不幸的是那不是我想要做的。我不想比较对象。我想查看特定的字符串(电子邮件地址)是否已经在我的对象数组中。如果是,我想增加数组中匹配对象的“count”属性。如果它不在数组中,我想添加一个新的PS对象到我的数组中,其中包含电子邮件地址和其他属性。我不认为我可以用Compare-Object来实现这个? - stukey
根据我的理解,我认为值得深入研究。Compare-Object也可以给你匹配项,并输出一个对象,你可以迭代它来执行你所描述的对第一个对象的更新。 - malexander
再次感谢您。我会研究Compare-Object命令。 - stukey
没问题,记得在比较之前按照电子邮件属性对两个对象进行排序,如果这些对象具有不同的属性,则需要指定要比较的相似属性(例如,如果您只想比较该属性,请使用-Property 'EmailAddress')。 - malexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接