How can I serialize a complex Powershell array to disk for processing by a second Script?
Asked Answered
O

1

6

I am collecting statistics about an Exchange environment and need to collect statistics about all the DNS domains in use.

This is a long and intensive operation that can take a long time. I want to persist these values to disk, so I can run a post-processor on the summary.

How should I alter the script I wrote below so that I can run the post-processor?

$dict = @{}
$AcceptedDomains = Get-AcceptedDomain | select domainname
foreach($ad in $AcceptedDomains)
{
   $tmp = $dict[$ad.DomainName]
   if ($tmp -eq $null)
   {
       $obj1 = @{CountPrimary = 0; CountWindows =0; CountSecondary = 0; IsAcceptedDomain = 0; DNS_MX = ""; DNS_SRV= ""; SSL=""}
       $dict.Add($ad.DomainName.ToString(), $obj1)
   } 

   $dict[$ad.DomainName.ToString()].IsAcceptedDomain = 1
}



foreach($currentmb in get-mailbox -resultsize unlimited|select PrimarySMTPAddress, WindowsEmailAddress, EmailAddresses)
{
   $domName = $currentmb.PrimarySmtpAddress.ToString().Split("@")[1].ToString();
   $tmp = $dict[ $domName]
   if ($tmp -eq $null)
   {
       $obj1 = @{CountPrimary = 0; CountWindows =0; CountSecondary = 0; IsAcceptedDomain = 0; DNS_MX = ""; DNS_SRV= ""; SSL=""}
       $dict.Add( $domName, $obj1)
   } 
   $dict[$domName].CountPrimary+= 1



   $domName = $currentmb.WindowsEmailAddress.ToString().Split("@")[1].ToString();
   $tmp = $dict[ $domName]
   if ($tmp -eq $null)
   {
       $obj1 = @{CountPrimary = 0; CountWindows =0; CountSecondary = 0; IsAcceptedDomain = 0; DNS_MX = ""; DNS_SRV= ""; SSL=""}
       $dict.Add( $domName, $obj1)
   } 
   $dict[$domName].CountWindows += 1



   $secondaries = New-Object System.Collections.ArrayList($null)
   $currentMBSmtp = $currentMB.EmailAddresses | where {$_.PrefixString -eq "SMTP"} | select SMTPAddress
   foreach($smtp1 in $currentMBSmtp)
   {
        $smtp1Domain =     $smtp1.SmtpAddress.ToString().Split("@")[1].ToString()
        $secondaries.Add($smtp1Domain) 
   }
   foreach($domName1 in $secondaries | select -unique)
   {
    $tmp = $dict[ $domName1]
    if ($tmp -eq $null)
    {
            $obj1 = @{CountPrimary = 0; CountWindows =0; CountSecondary = 0; IsAcceptedDomain = 0; DNS_MX = ""; DNS_SRV= ""; SSL=""}
            $dict.Add( $domName1, $obj1)
    } 
    $dict[$domName1].CountSecondary += 1
   }
}

If you can tell from the placeholders, I intend to look at the MX records, SSL certs and other aspects of each DNS domain located.

The intent is to gain enough information about the domains in use so that each domain can be prioritized as needed.

The array $dict when sent to the screen looks like this: (domains truncated for privacy)

oup.com       {DNS_SRV, CountSecondary, CountWindows, IsAcceptedDomain, DNS_MX, SSL, CountPrimary}
isorygroup... {DNS_SRV, CountSecondary, CountWindows, IsAcceptedDomain, DNS_MX, SSL, CountPrimary}
ces.com       {DNS_SRV, CountSecondary, CountWindows, IsAcceptedDomain, DNS_MX, SSL, CountPrimary}
nc.net        {DNS_SRV, CountSecondary, CountWindows, IsAcceptedDomain, DNS_MX, SSL, CountPrimary}

An individual object looks like this:

[PS] C:\scripts>$dict["sol.com"]

Name                           Value
----                           -----
DNS_SRV
CountSecondary                 3
CountWindows                   0
IsAcceptedDomain               0
DNS_MX
SSL
CountPrimary                   0
Orrery answered 7/11, 2015 at 15:33 Comment(3)
Export-Clixml/Import-ClixmlLowndes
@PetSerAl - Awesome thanks!!Orrery
Please @PetSerAl put it as an answer.Zanthoxylum
O
6

You can use Export-CliXml to serialize and write the values to disk. Import-CliXml to deserialize it and bring it back in.

You may need to use the -Depth parameter if your objects are nested, I believe it defaults to 2 levels. Increasing the levels can vastly increase the time taken for serialization; especially if you have circular references.

If you want to serialize/deserialize in memory, you can use [System.Management.Automation.PSSerializer]::Serialize() and [System.Management.Automation.PSSerializer]::Deserialize() (these are used internally by the cmdlets, so it's the same representation).

Openandshut answered 7/11, 2015 at 21:59 Comment(2)
Thanks. do you have any tips on how I can make $dict appear nicer when I write to host? My hierarchy is a flat table, but I'm using a Dict + Object to add more columns. There is probably a better approach.Orrery
@LamonteCristo you can make your own object ([PSObject]) and add each "column" as a property. New-Object PSObject -Property @{ Key=Value ; Key2=Value2 }. The hashtable can be used like that for initial properties. You can use Add-Member to add additional properties after the object is created. Consider the psobject to be a single row; you would have an array of those. That would be the most versatile in terms of further formatting and transformation.Openandshut

© 2022 - 2024 — McMap. All rights reserved.