Author Posts

August 22, 2017 at 4:06 am

I have an array that is full of firewall rules objects. These objects all have properties associated with firewall rules. Many of these properties are multi-value, for example the Source IP field could have multiple IP Addresses and Groups. The source zone the same. The same with Destination Zone, Destination IP, Service, Application, etc...

With that said, how can I show all the expanded results of all my multi-value properties on the console? How about when exporting to a text file? How about when exporting to a CSV?

Thanks in Advance,

DJ

August 22, 2017 at 5:29 am

Try setting $FormatEnumerationLimit to -1 before dumping out your objects.

For example:

$FormatEnumerationLimit = -1
$FirewallObjects | fl

August 22, 2017 at 8:47 am

How exactly do you need the output ? For example, do you want to have a single source IP field, and then if an object has multiple Source IPs each one gets listed on it's own line? Or would fields like SourceIP1, SourceIP2.. SourceIPN format work?

Since you can't do an -expandproperty on multiple properties, the only thing I can think of is to iterate the object (essentially an array of arrays), and "flatten" it out, storing that in a new object, and exporting that.

Here's a simple example, the dependentservices property could contain 0 or more services, I just took 3 as an example.

$Services = get-service CryptSvc, BITS


function Expand-DependentServices
{    
    [OutputType([PSObject])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline = $true,
                   Position=0)]
        $service
    )

    Process
    {
      $name = $service.name
      $depends = $service | select -ExpandProperty dependentservices
      if ($depends){
      
      
        $props =[ordered] @{'Name' =$name
                'Depends on 1' =$depends[0]
                'Depends on 2' =$depends[1]
                'Depends on 3' =$depends[2]
                }
      }else {
        $props =[ordered] @{'Name' =$name
                'Depends on 1' =$null
                'Depends on 2' =$null
                'Depends on 3' =$null
                }
      }
      $obj = New-Object -TypeName PSObject -Property $props
    Write-Output $obj
    }
    
}
$Services | Expand-DependentServices

Name     Depends on 1 Depends on 2  Depends on 3
----     ------------ ------------  ------------
BITS                                            
CryptSvc AppIDSvc     applockerfltr 

August 22, 2017 at 7:52 pm

This was very helpful for when displaying the results in the console, or just dumping to a text file. Thanks!

August 22, 2017 at 7:56 pm

Let me provide some more context with sample data:

Get-UnusedAddresses | Select Name
Name
—-
CFG-LOP-IP-1
CFG-LOP-IP-2
CFG-LOP-IP-3
CFG-LOP-IP-4
CFG-LOP-IP-5

Get-UnusedAddressGroups | Select Name
Name
—-
CFG-OFC
OPP-OFC
JAK-LOTS

Get-UnusedServices | Select Name
Name
—-
TCP-555
TCP-139
TCP-445
TCP-389
TCP-88
UDP-88
TCP-636
TCP-123
TCP-53
UDP-53

All 3 of these functions return Objects of: System.Management.Automation.PSCustomObject

I've also saved out these results to variables of Type: System.String as shown below

$unusedAddresses
CFG-LOP-IP-1
CFG-LOP-IP-2
CFG-LOP-IP-3
CFG-LOP-IP-4
CFG-LOP-IP-5

$unusedAddressGroups
CFG-OFC
OPP-OFC
JAK-LOTS

$unusedServices
TCP-555
TCP-139
TCP-445
TCP-389
TCP-88
UDP-88
TCP-636
TCP-123
TCP-53
UDP-53

I want to export these Strings or PSCustomObjects into a CSV similar to below. There's no telling how many items will be in each array.

Column1 = UnusedAddresses
Column2 = UnusedAddressGroups
Column3 = UnusedServices

Essentially these arrays have NOTHING to do with each other. Its just for presentation. Aside from CSV, I would like this as HTML too.

August 22, 2017 at 10:01 pm

See if this helps. I tested with an array of strings, but you can work with your PSCustomObjects as well.

$UnusedAddresses = 'CFG-LOP-IP-1','CFG-LOP-IP-2','CFG-LOP-IP-3','CFG-LOP-IP-4','CFG-LOP-IP-5'
$UnusedAddressGroups = 'CFG-OFC','OPP-OFC','JFK-LOTS'
$UnusedServices = 'TCP-555','TCP-139','TCP-445','TCP-389','TCP-88','UDP-88','TCP-636','TCP-123','TCP-53','UDP-53'
$LargestListCount = ($UnusedAddresses.Count,$UnusedAddressGroups.Count,$UnusedServices.Count | Measure-Object -Maximum).Maximum

For($i = 0;$i -lt $LargestListCount;$i++)
{
  If($i -lt $UnusedAddresses.Count)
  {
    $UA = $UnusedAddresses[$i]
  }
  Else
  {
    $UA = ''
  }

  If($i -lt $UnusedAddressGroups.Count)
  {
    $UAG = $UnusedAddressGroups[$i]
  }
  Else
  {
    $UAG = ''
  }

  If($i -lt $UnusedServices.Count)
  {
    $US = $UnusedServices[$i]
  }
  Else
  {
    $US = ''
  }

  $Props = [ordered] @{
                        UnusedAddresses = $UA;
                        UnusedAddressGroups = $UAG;
                        UnusedServices = $US
                      }

  $Obj = New-Object -TypeName PSObject -Property $Props
  $ObjArray += $Obj
}

Write-Output $ObjArray
$ObjArray | Export-Csv -Path 'C:\data\obj.csv' -NoTypeInformation
$ObjArray | ConvertTo-Html | Out-File -FilePath 'C:\data\obj.html'

I get the following output, for the Write-Output command at the bottom of the code. When I do the export to CSV or conversion/export of the html, it looks good to me. I'm sure there's a better solution, but this worked for me.

UnusedAddresses UnusedAddressGroups UnusedServices
————— ——————- ————–
CFG-LOP-IP-1 CFG-OFC TCP-555
CFG-LOP-IP-2 OPP-OFC TCP-139
CFG-LOP-IP-3 JFK-LOTS TCP-445
CFG-LOP-IP-4 TCP-389
CFG-LOP-IP-5 TCP-88
UDP-88
TCP-636
TCP-123
TCP-53
UDP-53

August 22, 2017 at 10:33 pm

I edited my above code to put the columns in the order you were mentioning.

August 23, 2017 at 3:06 am

BTW, don't trust how the Write-Output looks in my above post. It's just the way this forum formats it. It looks the way it should, on the screen and in the files, when you run the code.

August 27, 2017 at 2:23 am

Kevyn, thanks for the help. I hadn't had time to respond back to you. This worked better than what I was able to come up with. As an FYI, I essentially created an empty CSV file, and then using Add-Content I manually added entries to the CSV file with comma delimiters, using a for loop with index. Its similar, but the code you showed looked cleaner, and lets me remain standardized on export-csv. Thanks!

August 27, 2017 at 2:45 am

You're welcome. Glad it worked for you. 🙂

August 27, 2017 at 5:41 pm

My nuclear option to expand everything is

$object | fc *

You can also export it to xml or json (-depth 100)...