Create an array of pscustomobjects which include a hasthable for export

28 Views Asked by At

I create a custom object

$ToExport = [pscustomobject]@{
           "samAccountName" = ''
           "forwarded" = @{
                "ForwardTo" = ""
                "RedirectTo" = ""
                "Enabled" = ""
                "Description" = ""
           }
}  

The i parse through mailboxes and their forwarding rules, fill the properties and try to put the object into an array:

$Testarray = @()

foreach($m in $mbx){
    $ToExport.samAccountName = $m.SamAccountName    
    $rule = Get-InboxRule -Mailbox $m.SamAccountName
    foreach($r in $rule){
        if(($r.ForwardTo) -OR ($r.RedirectTo)){
            if($r.ForwardTo -like "*smtp*" -and ($AcceptedDomains | %{"$($r.ForwardTo)" -like "*$_*"}) -notcontains $true){
                $ToExport.forwarded.ForwardTo += $r.ForwardTo}
            if($r.RedirectTo -like "*smtp*" -and ($AcceptedDomains | %{"$($r.RedirectTo)" -like "*$_*"}) -notcontains $true){
                $ToExport.forwarded.RedirectTo += $r.RedirectTo}
            $ToExport.forwarded.Description += $r.Description
            $ToExport.forwarded.enabled += $r.Enabled
        }
    }
    Write-Host($ToExport.samAccountName)
    if($ToExport.forwarded.ForwardTo -ne $null -or $ToExport.forwarded.RedirectTo -ne $null){
       $Testarray += $ToExport
    }
    
    $ToExport.forwarded.ForwardTo = $null
    $ToExport.forwarded.RedirectTo = $null
    $ToExport.forwarded.Enabled = $null
    $ToExport.forwarded.Description = $null 
}

The Problem is when i then check the content of the array all Objects in it have the same samAccountName and when i ope forwarded all properties in there are empty. I dont see where i either overwrite the name of all existing array objects or delete the content under the object: forwarded

$Testarray

samAccountName forwarded                                    
-------------- ---------                                    
Name1       {RedirectTo, ForwardTo, Description, Enabled}
Name1        {RedirectTo, ForwardTo, Description, Enabled}
Name1        {RedirectTo, ForwardTo, Description, Enabled}
Name1        {RedirectTo, ForwardTo, Description, Enabled}

$Testarray[0].forwarded

Name                           Value                                                                                                                                                                                                                                                                                                                      
----                           -----                                                                                                                                                                                                                                                                                                                      
RedirectTo                                                                                                                                                                                                                                                                                                                                                
ForwardTo                                                                                                                                                                                                                                                                                                                                                 
Description                                                                                                                                                                                                                                                                                                                                               
Enabled                              

I want to put it all into one array so i can later on export it as a json or xml file.

1

There are 1 best solutions below

0
Mathias R. Jessen On BEST ANSWER

When $ToExport is a reference-type object and you do:

$Testarray += $ToExport

What you're really doing is adding a reference to $ToExport to $TestArray, not a copy of it.

So when you then subsequently update property values on $ToExport or one of it's members (like forwarded), it's reflected by all references to said object.

You've essentially added the same object to the array 4 times, overwriting the property values every time.

Instead, create a new [ordered] dictionary on each loop iteration - when you subsequently convert the hashtable to a custom object, PowerShell will copy the properties to a new, distinct object, and you'll no longer see the behavior observed:

$Testarray = @()

foreach($m in $mbx){
    $forwarded = [ordered]@{
        'ForwardTo'   = @()
        'RedirectTo'  = @()
        'Enabled'     = @()
        'Description' = @()
    }
    
    $rule = Get-InboxRule -Mailbox $m.SamAccountName
    foreach($r in $rule){
        if(($r.ForwardTo) -OR ($r.RedirectTo)){
            if($r.ForwardTo -like "*smtp*" -and ($AcceptedDomains | %{"$($r.ForwardTo)" -like "*$_*"}) -notcontains $true){
                $forwarded.ForwardTo += $r.ForwardTo}
            if($r.RedirectTo -like "*smtp*" -and ($AcceptedDomains | %{"$($r.RedirectTo)" -like "*$_*"}) -notcontains $true){
                $forwarded['RedirectTo'] += $r.RedirectTo}
            $forwarded['Description'] += $r.Description
            $forwarded['Enabled'] += $r.Enabled
        }
    }
    Write-Host($m.samAccountName)
    if($forwarded['ForwardTo'].Length -or $forwarded['RedirectTo'].Length){
        # create new object
        $Testarray += [pscustomobject]@{
            'samAccountName' = $m.SamAccountName
            # convert ordered hashtable to object
            'forwarded'      = [pscustomobject]$forwarded
        }
    }
    
    # no need to clean object template, it'll get recreated
}

If your goal is to export the list of forwarding rules to a flat format (like CSV), then I'd suggest attaching the SAMAccountName value to each rule, and then export those:

$testArray = foreach($m in $mbx){
    Get-InboxRule -Mailbox $m.SamAccountName |Where-Object {
        $r = $_
        ($r.ForwardTo -like "*smtp*" -and ($AcceptedDomains | %{"$($r.ForwardTo)" -like "*$_*"}) -notcontains $true) -or 
        $r.RedirectTo -like "*smtp*" -and ($AcceptedDomains | %{"$($r.RedirectTo)" -like "*$_*"}) -notcontains $true
    } |Select -Property @{Name='SamAccountName';Expression={$m.SamAccountName}} RedirectTo,ForwardTo,Description,Enabled
}

$testArray |Export-Csv path\to\forward_rules_export.csv -NoTypeInformation

Piping to Select-Object -Property will also cause the creation of a new, distinct object instance, once again preempting the problematic behavior you describe.