Where am i going wrong ? Psobject & Foreach

This topic contains 8 replies, has 3 voices, and was last updated by  Mark Prior 6 months, 1 week ago.

  • Author
    Posts
  • #68482

    Mark Prior
    Participant

    A little confused,

    so i want to retreive all mailboxes and output them to an array which is working fine code below

    
    $MBDatabases = Get-MailboxDatabase | where {$_.name -like "*EU*"} | select name
    
    
    $outarray = @()
    
    foreach ($MBDatabase in $MBDatabases)
    {
        $Users = Get-MailboxStatistics -Database $MBDatabase.name | where {$_.ObjectClass -eq “Mailbox”}
       
       
    
        foreach ($user in $users)
    
        {
            $properties = @{Name = $User.Displayname
                            MBSize = $User.TotalItemSize
                            ItemCount = $User.ItemCount
                            Database = $user.Database
                            Servername = $user.ServerName
                                  
    
                            }
    
        $Obj = New-Object -TypeName psobject -Property $properties
    $outarray  += $obj 
                         }
       
    }
    
    $outarray | Out-GridView
    
    

    now i also want to include the 'title' & 'samAccountname' attribute in the object, to get the details im using

    
    $user2 = $user | select -ExpandProperty displayname
    
        $adusers = get-aduser -filter {displayname -eq $user2} -Properties title | select title, samaccountname
    
    

    i want to combine the two commands so i output one array of objects

    
    $properties = @{Name = $User.Displayname
                            MBSize = $User.TotalItemSize
                            ItemCount = $User.ItemCount
                            Database = $user.Database
                            Servername = $user.ServerName
                            Title = $aduser.title
                            SamAccountName = $aduser.samaccountname
                                  }
    
    

    i know im going wrong somewhere but lost as to where ? last method i tried was below but seems to only give me the last result of each DB, HEEEELLLP!

    
    $MBDatabases = Get-MailboxDatabase | where {$_.name -like "*EU*"} | select name
    
    
    $outarray = @()
    
    foreach ($MBDatabase in $MBDatabases)
    {
        $Users = Get-MailboxStatistics -Database $MBDatabase.name | where {$_.ObjectClass -eq “Mailbox”}
       
     
    
        foreach ($user in $users)
    
        {
    
        $user2 = $user | select -ExpandProperty displayname
    
        $adusers = get-aduser -filter {displayname -eq $user2} -Properties title | select title, samaccountname
        foreach ($aduser in $Adusers)
        {
            
        
            $properties = @{Name = $User.Displayname
                            MBSize = $User.TotalItemSize
                            ItemCount = $User.ItemCount
                            Database = $user.Database
                            Servername = $user.ServerName
                            Title = $aduser.title
                            SamAccountName = $aduser.samaccountname
                                  }
    
                                  }
                            }
    
        $Obj = New-Object -TypeName psobject -Property $properties
    $outarray  += $obj 
                         }
       
    
    
    $outarray | Out-GridView
    
    
  • #68494

    Max Kozlov
    Participant

    for each MailBoxStatistic object you easily can get mailbox or user with

    Get-Mailbox -Identity $user.LegacyDN
    Get-User -Identity $user.LegacyDN

    and do something like

    # [...]
    $Users = Get-MailboxStatistics -Database $MBDatabase.name | where {$_.ObjectClass -eq “Mailbox”}
    foreach ($user in $users)
    $mb = Get-MailBox $user.LegacyDN
    $us = Get-User $user.LegacyDN
    #Do not use "$obj =" here, let it flow thru pipeline
    [PSCustomObject]@{
                            MBSize = $User.TotalItemSize
                            ItemCount = $User.ItemCount
                            Database = $user.Database
                            Servername = $user.ServerName
                            Title = $us.title
                            SamAccountName = $us.samaccountname
    }
    

    and please do not use accumulator like "$outarray += $obj"
    you can

    foreach ($MBDatabase in $MBDatabases)
    {
    # [...]
    } | Out-GridView
    
  • #68530

    Mark Prior
    Participant

    Much appreciated Max, will give this a shot first thing tomorrow

  • #68556

    Mark Prior
    Participant

    Hi Max gave this a shot today, but it reports the last line in wrong

    
    $MBDatabases = Get-MailboxDatabase | where {$_.name -like "*EU*"} | select name
    
    
    
    
    foreach ($MBDatabase in $MBDatabases)
    {
        $Users = Get-MailboxStatistics -Database $MBDatabase.name | where {$_.ObjectClass -eq “Mailbox”}
       
       
    
        foreach ($user in $users)
    
        {
    
        $mb = Get-MailBox $user.LegacyDN
        $us = Get-User $user.LegacyDN
        
    [PSCustomObject]@{
                            MBSize = $User.TotalItemSize
                            ItemCount = $User.ItemCount
                            Database = $user.Database
                            Servername = $user.ServerName
                            Title = $us.title
                            SamAccountName = $us.samaccountname
                                  
    
                            }
                         }
       
    }| Out-GridView -Wait
    
    
    At H:\EAA\Powers Shell Commands\get all mb sizes.ps1:31 char:2
    + }| Out-GridView -Wait
    +  ~
    An empty pipe element is not allowed.
        + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
        + FullyQualifiedErrorId : EmptyPipeElement
    
  • #68574

    Max Kozlov
    Participant

    sorry, I'm misinform you
    this way works

    $output = foreach ($MBDatabase in $MBDatabases)
    {
    # [...]
    }
    $output | Out-GridView
    
  • #68575

    Mark Prior
    Participant

    Thanks max, just another quick Q

    out of interest whats the benefit of this over adding objects to an array ?

  • #68635

    Curtis Smith
    Participant

    Hey Mark,
    Both methods result in an array.

    Example

    $numlist = 1..10
    $addarray = @()
    $returnedarray = foreach ($num in $numlist) {
        $psobj = [pscustomobject]@{
            num = $num
        }
        $addarray += $psobj
        $psobj
    }

    In the above example we are using both methods. One to add the custom PS object to $addarray using +=, and the other to return the custom PS object so that it is included in $returnedarray as a return value.

    With these two variables now populated with values, the same values, we can check out what they are using Get-Member

    (Get-Member -InputObject $addarray).GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                                      
    -------- -------- ----                                     --------                                                                                                      
    True     True     Object[]                                 System.Array
    (Get-Member -InputObject $returnedarray).GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                                      
    -------- -------- ----                                     --------                                                                                                      
    True     True     Object[]                                 System.Array

    As you can see both BaseTypes are System.Array

    The difference is that collecting the objects into an array as they are returned seems to be faster than adding them to an array using +=.

    $numlist = 1..10000
    $addarray = @()
    
    Measure-Command {
        $returnedarray = foreach ($num in $numlist) {
            [pscustomobject]@{
                num = $num
            }
        }
    } | Select-Object -ExpandProperty TotalSeconds
    
    Measure-Command {
        foreach ($num in $numlist) {
            $addarray += [pscustomobject]@{
                num = $num
            }
        }
    } | Select-Object -ExpandProperty TotalSeconds
    
    0.141293
    6.5053623
  • #68637

    Max Kozlov
    Participant

    In addition to @Curtis explanation

    "+=" also memory expensive

    for array with 10000 elements after "$array += 1"
    you have two arrays in memory: named $array with 10001 element and unnamed (old) with 10000 elements
    it falls under GarbageCollection after that but still exists some time...

  • #68638

    Mark Prior
    Participant

    Thanks both, have a much better understanding now

You must be logged in to reply to this topic.