Grouping data from Active Directory - powershell

wondering if i could get some help with my powershell script. I am halfway (or maybe even 3/4 of the way there) but im just struggling to get my groups grouped on one line per user....
Ill explain
Right now i'm able to get ALL users from Multiple AD groups, took a bit of playing around but i got there in the end...
However it displays CSV like this:
first_name,last_name,email,group_list
John,Smith,JSmith#email.com,Group1
John,Smith,JSmith#email.com,Group2
Emily,Rogers,ERogers#email.com,Group1
Emily,Rogers,ERogers#email.com,Group3
Whilst thats OK, i would really like to format the data like this:
first_name,last_name,email,group_list
John,Smith,JSmith#email.com,Group1~Group2
Emily,Rogers,ERogers#email.com,Group1~Group3
This is my code so far
## Define the groups, This includes a wildcard which gets all users in groups with that pattern
$Groups = (Get-AdGroup -filter * | Where {$_.name -like "GroupName*"} | select name -expandproperty name)
## Var for array, empty
$Array = #()
## Var for data
$Data = [ordered]#{
}
## For Each loop to get members of each group
Foreach ($Group in $Groups)
{
## Define the search criteria for AD Search
$Members = Get-ADGroupMember -identity $Group | Get-ADUser -Properties * | select givenName,sn,sAMAccountName,mail
foreach ($Member in $Members)
{
$Data."first_name" = $Member.givenName
$Data."last_name" = $Member.sn
$Data."email" = $Member.mail
$Data."group_list" = $Group
## Store in PSObject
$DataPSObject = New-Object PSObject -property $Data
## Add to array so it is no longer empty
$Array += $DataPSObject
}
}
## Export array into CSV
$Array | export-csv "C:\temp\DataFromArray.csv" -NoTypeInformation
As the email is the unique identifier, i tried to Group-Object on the email property but the output is not useful for me
## Export array into CSV
$Array | Group-Object -Property email | export-csv "C:\temp\DataFromArray.csv" -NoTypeInformation
Also i tried to join the groups using a defined separator -join '~' but this just seemed to create one long string of joined groups (makes sense when i put it that way)
Hoping anyone has some ideas?
Thanks

You need to do a little more processing on the output of Group-Object, but you're almost there!
$Array |Group-Object -Property email |ForEach-Object {
[pscustomobject]#{
first_name = $_.Group[0].first_name
last_name = $_.Group[0].last_name
email = $_.Group[0].email
groups = $_.Group.group_list -join '~' # join all the group names together
}
} |Export-Csv "C:\temp\DataFromArray.csv" -NoTypeInformation

Just a quick thingy to get what you want:
## Define the groups, This includes a wildcard which gets all users in groups with that pattern
$Groups = Get-AdGroup -Filter 'Name -like "GroupName*"' | Select-Object -ExpandProperty Name
## For Each loop to get members of each group
$Array = foreach ($Group in $Groups) {
## Define the search criteria for AD Search and capture in variable $Array
Get-ADGroupMember -Identity $Group |
Get-ADUser -Properties GivenName,Surname,SamAccountName,EmailAddress |
Select-Object #{Name = 'first_name'; Expression = {$_.GivenName}},
#{Name = 'last_name'; Expression = {$_.Surname}},
#{Name = 'email'; Expression = {$_.EmailAddress}},
#{Name = 'GroupName'; Expression = {$Group}}
}
$out = $Array | Group-Object email | ForEach-Object {
# join the GroupName property of this user to get a delimited string
$grouplist = $_.Group.GroupName -join '; '
# output a new object with the 'group_list' property
# this will create duplicates objects, so we need Select-Object * -Unique at the end
$_.Group | Select-Object first_name, last_name, email, #{Name = 'group_list'; Expression = {$grouplist}}
} | Select-Object * -Unique
$out | Export-Csv "C:\temp\DataFromArray.csv" -NoTypeInformation
Hope that helps

Related

pscustomobject multiple lines per row

I have some code so far, but would like it to result in a table with multiple lines for users per group.
Currently, it creates a table like this:
Group
Users
abcgroup1
Alice
abcgroup1
Bob
abcgroup2
Bob
abcgroup2
Jason
abcgroup3
Eve
I would like it to instead create a table like this:
Group
Users
abcgroup1
AliceBob
abcgroup2
BobJason
abcgroup3
Eve
$Groups = get-adgroup -Filter 'name -like "*abc*"'
$Results = foreach( $Group in $Groups ){
Get-ADGroupMember -Identity $Group | foreach {
[pscustomobject]#{
Group = $Group.Name
Users = $_.Name
}
}
}
$Results
$Results | Export-Csv C:\abc_search.txt -NoTypeInformation
You can use -join operator concatenating by CRLF `r`n. This will result in a multiline string:
$Groups = Get-ADGroup -Filter "name -like '*abc*'"
$Results = foreach($Group in $Groups)
{
[pscustomobject]#{
Group = $Group.Name
Members = (Get-ADGroupMember -Identity $Group).Name -join "`r`n"
}
}
$Results | Format-Table -Wrap -Autosize
$Results | Export-Csv C:\abc_search.csv -NoTypeInformation
Note that I'm using -Wrap on Format-Table, needed to correctly display multiline strings on the console.
The other option you could use is Out-String thought that would also require the use of .TrimEnd() method to get rid of the trailing new line:
Members = ((Get-ADGroupMember -Identity $Group).Name | Out-String).TrimEnd()

How to iterate through user's group membership and return user if they are a member of a list of groups

I have a large number of samAccountNames in a csv that I need to write a script that checks each user and sees if they are a member of any of 3 AD groups. I tried a script that searches through the groups and then finds the user, but I run into issues where the groups contain too many members which throws an error.
I tried looping through each user and pulling group membership, but I think I don't know how to properly search for a value in an array, or at least I think that is my problem
This is what I want:
#Groups to look for
$groups = 'Group1', 'Group2', 'Group3'
#Import users to check from a csv file
Import-Csv "$PSScriptroot\Users.csv" | ForEach-Object {
#define users variable
$users = $_."samAccountName"
foreach ($user in $users) {
#Get all groups that the $user is a member of
$membership = Get-ADPrincipalGroupMembership $user | select name
foreach ($group in $groups) {
#Check if $group is in $membership
}
}
}
#export a new csv of all $users who were found to be in an $groups
Looking for any help on how to accomplish this. Thanks!
Considering it's your intent to re-export to CSV, you need to think about adding Boolean columns (properties) that represent the user's membership in a given group.
I didn't test this, but it's an idea:
# Groups to look for
$groups = 'Group1', 'Group2', 'Group3'
# Import users to check from a csv file
Import-Csv "$PSScriptroot\Users.csv" |
ForEach-Object {
# Get all groups that the $user is a member of
$membership = (Get-ADPrincipalGroupMembership $_.samAccountName).Name
$_ |
Select-Object *,
#{Name = 'Group1'; Expression = { 'Group1' -in $membership }},
#{Name = 'Group2'; Expression = { 'Group2' -in $membership }},
#{Name = 'Group3'; Expression = { 'Group3' -in $membership }}
} |
Export-Csv -Path "$PSScriptroot\Users_New.csv" -NoTypeInformation
In this case, we're adding properties to the objects produced by Import-Csv. Property's value will be True/False respective to the membership received from Get-ADUserPrincipalGroupMembership. Then, immediately create a new CSV file.
You could also go in the other direction by preloading the membership of the groups and checking the users against those stored lists. Again untested bu that may look something like:
$Members =
#{
Group1 = (Get-ADGroupMember 'Group1').samAccountName
Group2 = (Get-ADGroupMember 'Group2').samAccountName
Group3 = (Get-ADGroupMember 'Group3').samAccountName
}
Import-Csv "$PSScriptroot\Users.csv" |
Select-Object *,
#{Name = 'Group1'; Expression = { $_.samAccountName -in $Members['Group1'] }},
#{Name = 'Group2'; Expression = { $_.samAccountName -in $Members['Group2'] }},
#{Name = 'Group3'; Expression = { $_.samAccountName -in $Members['Group3'] }} |
Export-Csv -Path "$PSScriptroot\Users_New.csv" -NoTypeInformation
This has the added advantage of being able to interrogate the group membership recusively. Simply add the -Recursive switch parameter to the Get-ADGroupMember command.

Exporting AD group memberships of users in PowerShell

I need to export a list of all groups a user is assigned to. This command works fine for my needs:
Get-ADPrincipalGroupMembership username | select name | Export-Csv filepath
However I have to review about 100 users in my company, so I would like to to merge those CSVs in an Excel spreadsheet. My problem is that when I merge the CSVs, I just have a random list of AD groups.
A solution for this problem would be to export a CSV with two columns while column 1 consists of the AD username and column 2 of the AD groupname, eg.
User A | Group A; User A | Group B; User A | Group C
I already have figured out that this probably won't be possible with Get -ADPrincipalGroupMembership but unfortunately I haven't found any solution yet.
The format you're considering is terrible for both viewing and processing. Either build a list mapping the user to each group (one mapping per line)
$users = 'userA', 'userB', ...
foreach ($user in $users) {
$groups = Get-ADPrincipalGroupMembership $user |
Select-Object -Expand Name
$groups | ForEach-Object {
New-Object -Type PSObject -Property #{
'User' = $user
'Group' = $_
}
}
} | Export-Csv 'output.csv' -NoType
or join the list of groups with a secondary delimiter and map a user to all of its groups like that:
$users = 'userA', 'userB', ...
foreach ($user in $users) {
$groups = Get-ADPrincipalGroupMembership $user |
Select-Object -Expand Name
New-Object -Type PSObject -Property #{
'User' = $user
'Group' = $groups -join '|'
}
} | Export-Csv 'output.csv' -NoType

New-object, property "disappears"

I'm trying to make a script returning AD users ID, Display Name and Group memberships based on an input file and export the result to another file.
However, the group membership information seems to get lost in the process.
Any ideas?
My current script:
$Result = #()
ForEach ($_ in gc userlist.csv)
{
$User = Get-ADUser $_ -Properties DisplayName, SamAccountName, LastLogonDate | Select DisplayName, SamAccountName, LastLogonDate
$Groups = Get-ADPrincipalGroupMembership $_ | Select Name
# So far it seems to work
$Properties = #{
UserID = (#($User.SamAccountName) -join ',')
Name = (#($User.DisplayName) -join ',')
LastLogonDate = (#($User.LastLogonDate) -join ',')
Groups = (#($Groups.Name) -join ',')
}
# By this time, Groups doesn't return any information
$Result += New-Object psobject -Property $Properties
}
$Result | Select-Object Name, UserID, Groups, LastLogonDate | Export-Csv -NoTypeInformation -Path output.csv
Here's what I think might work:
$Result = #()
ForEach ($User in gc userlist.csv) {
$UserDetails = Get-ADUser $User -Properties DisplayName, SamAccountName, LastLogonDate | Select DisplayName, SamAccountName, LastLogonDate
$Groups = Get-ADPrincipalGroupMembership $User | Select Name
$Properties = #{
UserID = $UserDetails.SamAccountName
Name = $UserDetails.DisplayName
LastLogonDate = $UserDetails.LastLogonDate
Groups = ($Groups.Name -join '; ')
}
$Result += New-Object psobject -Property $Properties
}
$Result | Select-Object Name, UserID, Groups, LastLogonDate | Export-Csv -NoTypeInformation -Path output.csv
Per my comment, although using $_ will probably work its not particularly good practice to manually set that variable so i've changed it to $user.
I've therefore changed your $user to $userdetails.
I removed your casting as an array #() for each of the properties as well as your joining them with ,. I'm not sure why this is necessary, except perhaps with the Groups property, but in order to then not confuse the CSV result, i've joined these with a ; instead.

Simple Script - Export Groups and nested Objects into file (dynamic)

I'm quite new to powershell and I'm trying to create a simple script, that exports groups and underlying objects to a csv file. It all works fine if I would access the data staticly, by for example indexing the values from the array but how can I change all that, to be dynamic?
$Groups = Get-QADGroup
$Result = #()
$Groups | ForEach-Object {
$Group = $_
$Members = Get-QADGroupMember $Group -Indirect
$Obj = '' | Select-Object -Property Name, Members #, members2
$Obj.Name = $Group.Name
#$Obj.Members = $Members[0].Name ----would work, but should be dynamic
#$Obj.members2 = $Members[1].Name ----would work, but should be dynamic
$Result += $Obj
}
$Result | Export-Csv -Path C:\Temp\groups.csv -NoTypeInformation -Encoding Unicode -Delimiter ";"
So that I just can write something like $Obj.Members = $Members but this doesn't work and gives me this output:
"Name";"Members"
"RootGroup01";"System.Object[]"
"RootGroup02";"System.Object[]"
"RootGroup03";"System.Object[]"
But I'd like something like this (example data):
"Name";"Members"
"RootGroup01";"Subuser01";"Subuser02";"SubGroup01"
"RootGroup02";"SubGroup02"
"RootGroup03";"SubGroup03";"Subuser02";"Subuser03";"Subuser04";
...
All the subgroups/subusers are in the $Members variable
You're nearly there actually. All you need is to iterate $Members and select the property you need and (as #TheMadTechinian suggested) join the array:
$Obj.Members = ($Members | Select-Object -ExpandProperty "Name") -join ';'