Question

I hit a common problem with my scripting lately and decided to throw it into the wild to see how other people deal with this problem.

tl;dr; I want to export objects which have a varying number of properties. eg; object 1 may have 3 IP address but object 2 has 7 IP addresses.

I've evolved to creating a new object with custom properties and then injecting these objects into an array as my method of catching results - happy to hear if there is a better way but this is how I roll. This method works 100% when outputting to the screen as the objects are shown in list format - I've tried a number of export/out-file methods to no avail when I want to capture and store the output for reading in something like Excell.

The following is an example of me building an object and storing it (the function of the code is not important here - just the results it generates):

add-pssnapin Quest.ActiveRoles.ADManagement
$Groups = get-qadgroup AmbigousGroupNameHere-
$UserInfo = @()

ForEach ( $Group in $Groups ) {
    $CurrentGroupMembers = get-qadgroupmember $Group
    write-host "Processing group:" $Group
    ForEach ( $GroupMember in $CurrentGroupMembers ) {
        If ( $GroupMember.type -eq "User" ) {
            $counter = 1
            write-host "Processing member:" $GroupMember
            $UserObject = get-qaduser $GroupMember | select SamAccountName,FirstName,LastName

            $objUserInfo = New-Object System.Object
            $objUserInfo | Add-Member -MemberType NoteProperty -Name SamAccountName -Value $UserObject.SamAccountName
            $objUserInfo | Add-Member -MemberType NoteProperty -Name FirstName -Value $UserObject.FirstName
            $objUserInfo | Add-Member -MemberType NoteProperty -Name LastName -Value $UserObject.LastName

            $GroupMembership = get-qadgroup -ContainsMember $GroupMember | where name -like "AmbigousGroupNameHere-*"

            ForEach ( $GroupName in $GroupMembership ) {
                $objUserInfo | Add-Member -MemberType NoteProperty -Name CtxGroup$counter -Value $GroupName.SamAccountName
                $counter++
            }
            $UserInfo += $objUserInfo
        } else {
            write-host "This is a group - we are ignoring it."
        }
    }
}

$UserInfo | Export-Csv UsersOutput.csv -NoType

From the above - you can see I scale the object property name by 1 for each group. CtxGroup$counter allows me to scale an object for the correct number of groups each user has. Confirmed this works great when outputting to the screen by default. The object is listed and I can see a new property for each group that matches for that user.

Now for the problem. When I export-csv or out-file the file is generated with enough headers based off the first object - so it creates the headings based on the amount of properties the first object has. So lets say the first user has 3 matching groups, it will create heading CtxGroup1, CtxGroup2, CtxGroup3. Great! No.

If the next user has 5 matching groups - only the first three are included in the output and the additional 2 are discarded as we don't have headings for CtxGroup4, CtxGroup5.

How on earth do other people deal with this?

side note; I considered creating my first object as a dummy with a massive amount of object (and hence headings) but well - that is not cool and really makes me feel inefficient.

Was it helpful?

Solution

You can obtain what you want ordering $UserInfo array by the number of properties, it can be done, but it's not so simple, in your case I would add another propertie with the count of groups added:

...
ForEach ( $GroupName in $GroupMembership ) {
                $objUserInfo | Add-Member -MemberType NoteProperty -Name CtxGroup$counter -Value $GroupName.SamAccountName
                $counter++
            }
$objUserInfo | Add-Member -MemberType NoteProperty -Name NbCtxGroup -Value ($counter - 1)
$UserInfo += $objUserInfo
...

And then order descending the array on this propertie :

$UserInfo | Sort-Object -Property NbCtxGroup -Descending | Export-Csv .\F.csv

It's not so nice but it will do the trick.

Have a look at :

$objUserInfo.psobject.Properties | Measure-Object
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top