0
votes

I'm using Powershell and trying to export a csv that includes a list of users and all the groups they belong to. Where I'm running into troubles is I want each group to be it's own column, making it easier to compare who belongs to what.

$OU = "OU=Company,DC=Domain,DC=local"
$out = @()
$users = Get-aduser -filter * -SearchBase $OU -properties memberof |  Where-Object { $_.enabled -eq "true" }
Foreach ( $user in $users ) {
    $group = ($user.memberof -replace 'CN=(.+?),(OU|DC|)=.+','$1') -split (", ")
    $obj = New-Object psobject
    $obj | Add-Member -membertype noteproperty -name Name -Value $user.name -force
    $obj | Add-Member -membertype noteproperty -name Dept -Value (($user.DistinguishedName -replace "CN=$($user.name),OU=") -replace ",OU(.+?),OU=Company,DC=Domain,DC=local") -force
    $obj | Add-Member -membertype noteproperty -name Loc -Value (($user.DistinguishedName -replace "CN=$($user.name),OU=(.+?),OU=") -replace ",OU=Company,DC=Domain,DC=local") -force
    $group | ForEach-Object { 
        $obj | Add-Member -membertype noteproperty -name $_ -Value "Y" -force 
    }
    $out += $obj
}

$out |export-csv C:\users.csv -NoTypeInformation

So it's going to search for all users, split the memberof groups and then I want to create a separate column for each group. The problem is the foreach-object loop for each group.

This is what I'm looking for. Say user1 belongs to Group1 and Group2, and user2 belongs to Group1 and Group3,

Name    Dept    Loc    Group1    Group2     Group3
User1   HR      CAN       Y        Y
User2   Sales   US        Y                   Y

This works for the first user, but it won't add anymore groups for each user after that, the output with be the following:

Name    Dept    Loc    Group1    Group2 
User1   HR      CAN       Y        Y
User2   Sales   US        Y

What am I missing here? Is this possible?

2
have you looked at the actual structure of the $Out variable? the way that Export-CSV works means that the first collection item defines the columns. any item with more than props than the 1st will be truncated. ///// the usual solution is to sort the collection by the number of props so that the 1st item has the max number of props OR determine the max number of props in advance and build ALL the items with all those props. - Lee_Dailey
So something like ` $users = Get-aduser -filter * -properties Memberof | Foreach-object { ` $count = @{ User = $_.name Count = ($_.memberof -replace 'CN=(.+?),(OU|DC|)=.+','$1') -split (", ")).count } | sort-object Count $obj = @{ Name= $count.name; $memberof = @{Get-aduser -filter * -properties Memberof }-replace 'CN=(.+?),(OU|DC|)=.+','$1') -split (", ")).count } }` - Solips
i can't read the garbled code in your comment. [blush] i would grab all the user accounts, grab all the .MemberOf items, split them by the delimiter used, add them all into one bunch, remove the dupes, and use that list for your group name property names. - Lee_Dailey

2 Answers

0
votes

This worked, I changed it to just include distribution lists:

$OU = "OU=Company,DC=Domain,DC=local"
$out = @()
$lists = (Get-ADGroup -Filter "groupcategory -eq 'Distribution'" -SearchBase $OU).name
$obj = New-Object psobject
$obj | Add-Member -membertype noteproperty -name Name -Value Notset
$obj | Add-Member -membertype noteproperty -name Dept -Value Notset
$obj | Add-Member -membertype noteproperty -name Loc -Value Notset
$lists | ForEach-Object { 
    $obj | Add-Member -membertype noteproperty -name $_ -Value Notset
}
$out += $obj
$users = Get-aduser -filter * -SearchBase $OU -properties memberof | Where-Object { $_.enabled -eq "true" }
Foreach ( $user in $users ) {
    $group = ($user.memberof -replace 'CN=(.+?),(OU|DC|)=.+','$1') -split (", ")
    $obj = New-Object psobject
    $obj | Add-Member -membertype noteproperty -name Name -Value $user.name -force
    $obj | Add-Member -membertype noteproperty -name Dept -Value (($user.DistinguishedName -replace "CN=$($user.name),OU=") -replace ",OU(.+?),OU=Company,DC=Domain,DC=local") -force
    $obj | Add-Member -membertype noteproperty -name Loc -Value (($user.DistinguishedName -replace "CN=$($user.name),OU=(.+?),OU=") -replace ",OU=Company,DC=Domain,DC=local") -force
    $group | ForEach-Object { 
        $obj | Add-Member -membertype noteproperty -name $_ -Value "Y" -force 
    }
    $out += $obj
}

$out |export-csv C:\users.csv -NoTypeInformation
0
votes

This is my first time to write out a response to the PowerShell community, so I'll do my best to give you the information that I can and in the proper format.

In my experience, Get-ADUser is better for getting and working with user properties, not so much user groups.Get-ADPrincipalGroupMembership works well with getting specific user membership and is what I use in my example.

I want to mention the Microsoft Documentation for these commands that I've mentioned thus far because the documentation has a lot of good information and examples that you should definitely check out.

Get-ADUser

Get-ADPrincipalGroupMembership

In my example, I use Get-ADUser and Get-ADPrincipalGroupMembership, which Get-ADPrincipalGroupMembership takes a parameter of -Identity and it's looking for an input of a users SamAccountName, to pull the groups for each user and it's found from Get-ADUser.

I also utilize hash tables in this example, which you could create and use an object, but I really like hash tables and they can sometimes improve the speed of your code. I'll link the official MS documentation, but I'll also list a more in depth article to Kevin Marquette's blog that has a ton of examples for hash tables.

about_Hash_Tables

Kevin Marquette - PowerShell: Everything You wanted to know about hashtables

$OU = 'OU=Company,DC=Domain,DC=local'

$users = Get-ADUser -Filter * -SearchBase $OU -Properties Department, Country | Where-Object {$_.Enabled -eq $true}

ForEach ($user in $users) {

    $groups = Get-ADPrincipalGroupMembership $user.SamAccountName

    $h = [ordered]@{
        'Name' = $user.SamAccountName
        'Department' = $user.Department
        'Location' = $user.Country
    }

    ForEach ($group in $groups) {
        $h.Add($group.Name,'Y')
    }

    $testObject = [pscustomobject]$h #Casting the hash table to a custom object

    $testObject | Export-Csv 'C:\test\test.csv' -Append -NoTypeInformation -Force
    #Must have append and force, just be sure to make a new csv file or delete the existing one when running this command multiple times since it will write the same info over and over again.

    $h.clear() #Cannot have duplicate values in hash tables so at the end of each loop through each user, we clear out the hash table so it can be rebuilt with the newly found user.
}