How do I search an array of PowerShell objects and the retrieve index to a matching string?

15,877

Not sure if this helps or not, but you can try loading your objects into a hash table using the email address as the key, then reference it by that (not tested):

$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
Share:
15,877
stukey
Author by

stukey

Updated on June 04, 2022

Comments

  • stukey
    stukey almost 2 years

    I need to search a custom PowerShell array of objects (which consists of data from both AD and Exchange - 5 columns: mail, dn, extensionAttribute7, TotalItemSize, Count). I gather this data daily (for each user whose total item size > specified size) and export it to an XML file using Export-Clixml so that I can reference the data in subsequent days. Each day I perform a new search for mailboxes > specified size and save data about the matching mailboxes, but I need to cross-reference my existing array of users. If the user is already in my array, then I want to increment the count attribute in my PS object by 1, otherwise I want to add the user to my array as a new PS custom object. That way I can track users whose mailboxes are consistently exceeding the specified size and act accordingly (this is a customer requirement).

    The piece I am struggling with is searching my array of custom PS objects for a match in order to determine whether I need to add the user as a new object or just increment the counter for a user because they are already in my array. In the beginning I thought I could use .IndexOf or -Contains to find a match in my array but they don't appear to work on arrays containing PS Objects. The only way I have been able to get this to work is as follows:

    #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 is then set to the index of the matching object in my array or is $null if there's no match. But this doesn't seem very efficient, especially when I am searching through an array of 1000s of objects for each separate user that I am checking on a daily basis. Surely there must be a better way to do this? I did think of creating a separate string array containing just the users' mail address and then using indexof to check for a match. I could infer that the matching PS object would have the same index number as my array of strings and then update the count in corresponding ps object array accordingly:

    # 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
    }
    

    Would this be more efficient because IndexOf is quicker than performing a Where-Object for each user I am searching for?

    I have searched and tested for days and I can't figure this out. I am relatively new to PowerShell so I am probably missing something really obvious. Thanks!