I have a list of users (their CN), and I want a list of the groups they are member of.
I already have a code which almost does the trick, but it shows as follows:
User1 - group1;group2
User2 - group1;group2;group3 etc...
Also, groups are shown as distinguished name (with container etc), so very long. I only want the name.
I want to show it as follows:
User1 - group1
User1 - group2
User2 - group1, etc
The code that shows the groups the users are member of, but not in the visual way i like is below:
Import-Csv -Path .\Input_CN.csv |
ForEach-Object {
$User = Get-ADUser -filter "CN -eq '$($_.CN)'" -properties memberof
[PSCustomObject]#{
SourceCN = $_.CN
MemberOf = $User.MemberOf -join ";"
}
} | Export-Csv -Path .\Output.csv -Delimiter ";" -NoTypeInformation
.\Output.csv
I have some other code that list the groups how I want, but I am unable to list it per user. And unable to combine it with the above code.
get-aduser -filter {cn -eq "Testuser"} -properties memberof |
Select -ExpandProperty memberof |
ForEach-Object{Get-ADGroup $_} |
Select -ExpandProperty Name
Thanks in advance :)
You could combine both code pieces like this:
Import-Csv -Path .\Input_CN.csv |
ForEach-Object {
$user = Get-ADUser -Filter "CN -eq '$($_.CN)'" -Properties MemberOf, CN -ErrorAction SilentlyContinue
foreach($group in $user.MemberOf) {
[PSCustomObject]#{
SourceCN = $user.CN
MemberOf = (Get-ADGroup -Identity $group).Name
}
}
} | Export-Csv -Path .\Output.csv -Delimiter ";" -NoTypeInformation
Edit
Although I have never seen an AD user to have no group membership at all (should have at least the default Domain Users in the MemberOf property), You commented that you would like to have a test for that aswell.
Import-Csv -Path .\Input_CN.csv |
ForEach-Object {
$user = Get-ADUser -Filter "CN -eq '$($_.CN)'" -Properties MemberOf, CN -ErrorAction SilentlyContinue
if (!$user) {
Write-Warning "No user found with CN '$($_.CN)'"
# skip this one and resume with the next CN in the list
continue
}
$groups = $user.MemberOf
if (!$groups -or $groups.Count -eq 0) {
[PSCustomObject]#{
SourceCN = $user.CN
MemberOf = 'No Groups'
}
}
else {
foreach($group in $groups) {
[PSCustomObject]#{
SourceCN = $user.CN
MemberOf = (Get-ADGroup -Identity $group).Name
}
}
}
} | Export-Csv -Path .\Output.csv -Delimiter ";" -NoTypeInformation
This is a bit clunky, but you can use nested loops:
Import-Csv -Path .\Input_CN.csv | ForEach-Object {
$user = Get-ADUser -filter "CN -eq '$($_.CN)'" -properties cn, memberof
$user | ForEach-Object {
$_.MemberOf |
ForEach-Object {
[PSCustomObject]#{
SourceCN = $user.CN
MemberOf = $_.split('[=,]')[1]
}
}
}
} | Where-Object {$null -ne $_.MemberOf} |
Export-Csv -Path .\Output.csv -Delimiter ";" -NoTypeInformation
UPDATE: Updated to show only the 'CN' part of the group name and to filter any users who are not a member of any group.
All in one line could be
Get-ADUser -filter {Enabled -eq $True} -Properties Name, Created | Select-Object Name, Created, #{Name="Groups";Expression={Get-ADPrincipalGroupMembership -Identity $_.SamAccountName | Where-Object {$_.GroupCategory -Eq 'Security'} | Join-String -Property Name -Separator ", "}}
Related
I want to get canonical name for each groups as well. how can I do that ?
Here is my script :
Get-ADUser -Filter {Enabled -eq $true} -Properties * | Select displayname ,#{Name="MemberOf";Expression={($_.MemberOf | %{(Get-ADGroup $_).sAMAccountName}) -Join ";"}} | Export-Csv -Path "c:\temp\users.csv" -NoTypeInformation -Encoding UTF8
My output :
"displayname","MemberOf"
"User01","Group01;Group02;Group03"
My desired output:
"displayname","MemberOf"
"User01","Group01;Contoso.com/OU1/OU2;Group02;Contoso.com/OU21/OU52;Group03;Contoso.com/OU1/OU21/OU22"
I agree with Mathias but this is how you can do it using the code you already have. Definitely recommend you to only call the properties that you need to query.
Get-ADUser -Filter {Enabled -eq $true} -Properties Displayname,MemberOf |
Select-Object Displayname,
#{
Name="MemberOf"
Expression={
# ($_.MemberOf | ForEach-Object{
# (Get-ADGroup $_ -Properties CanonicalName).CanonicalName
# }) -Join ";"
# You can pipe $_.MemberOf to Get-ADGroup, since it's an array of
# distinguishedNames it should work fine
($_.MemberOf | Get-ADGroup -Properties CanonicalName).CanonicalName -Join ";"
}
} | Export-Csv -Path "c:\temp\users.csv" -NoTypeInformation -Encoding UTF8
An alternative to that code, using a more classical approach:
$users = Get-ADUser -Filter {Enabled -eq $true} -Properties DisplayName
$result = foreach($user in $users)
{
$params = #{
LDAPFilter = "(member=$($user.DistinguishedName))"
Properties = "CanonicalName"
}
$membership = (Get-ADGroup #params).CanonicalName -join ";"
[pscustomobject]#{
DisplayName = $user.DisplayName
MemberOf = $membership
}
}
$result | Export-Csv -Path "c:\temp\users.csv" -NoTypeInformation -Encoding UTF8
First of all, you shouldn't be using Properties * when you only need two properties.
Then, the -Filter should be a string, not a scriptblock.
With just a small adaptation to your code, this should work:
Get-ADUser -Filter "Enabled -eq 'True'" -Properties DisplayName, MemberOf |
Select-Object DisplayName,
#{Name = "MemberOf"; Expression = {
($_.MemberOf | ForEach-Object {
($_ | Get-ADGroup -Properties CanonicalName).CanonicalName -Join ";" })
}
} |
Export-Csv -Path "c:\temp\users.csv" -NoTypeInformation -Encoding UTF8
Looking at your latest comment, I believe you want the group NAME joined with the canonicalname of the group as well.
You can do this like so:
Get-ADUser -Filter "Enabled -eq 'True'" -Properties DisplayName, MemberOf |
Select-Object DisplayName,
#{Name = "MemberOf"; Expression = {
$_.MemberOf | ForEach-Object {
$group = $_ | Get-ADGroup -Properties CanonicalName
'{0};{1}' -f $group.Name, ($group.CanonicalName -join ';')
}
}
} |
Export-Csv -Path "c:\temp\users.csv" -NoTypeInformation -Encoding UTF8
I am able to export to users that are not members of particular groups such as IT_Group like below. But, this script gives me all membership of users within memberof column in csv output. If they are members of any groups that matches "IT" they should be displayed within memberof column in csv output like below.
Also , If user is not member to any group that is beginning with IT_ then it will write "any IT group is not member" keyword within memberof column in csv output.
There are 3 security groups such as IT_Group,IT_Group1,IT_Group2
I have tried so far :
Get-ADUser -Filter {(emailaddress -like "*#contoso.com" -and Enabled -eq $false -and sAMAccountName -like "TEST*") -or (emailaddress -like "*#contoso.com" -and Enabled -eq $false -and sAMAccountName -like "PROD*")} -SearchBase "OU=USERS,DC=contoso,DC=com" -SearchScope Subtree -Properties * | Where { [string]$_.memberof -notmatch 'IT_Group'} | Select-Object name , samaccountname ,#{Name="MemberOf";Expression={($_.MemberOf | %{(Get-ADGroup $_).sAMAccountName}) -Join ";"}} |Export-CSV -Path "C:\tmp\output.csv" -NoTypeInformation -Encoding UTF8
My Desired output :
name,samaccountname,memberof
User01,TEST1,IT_Test
User02,PROD1,IT_Prod
User03,TEST4,any IT group is not member
The -Filter should not be written as script block ({..}), but as a normal string.
This should do what you are after:
$filter = "(Enabled -eq 'False' -and EmailAddress -like '*#contoso.com') -and (SamAccountName -like 'TEST*' -or SamAccountName -like 'PROD*')"
Get-ADUser -Filter $filter -SearchBase "OU=USERS,DC=contoso,DC=com" -SearchScope Subtree -Properties EmailAddress, MemberOf | ForEach-Object {
if ($_.MemberOf -match 'CN=IT_(Test|Prod)') {
# the user is a member of any IT_Group, get the names of all groups for this user
$groups = foreach ($grp in $_.MemberOf) { (Get-ADGroup -Identity $grp).Name }
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {$groups -join ', '}}
}
else {
# the user is not a member of any IT_Group
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {'Not a member of any IT_Group'}}
}
} | Export-CSV -Path "C:\tmp\output.csv" -NoTypeInformation -Encoding UTF8
Parsing the name of an object from the DistinghuishedName is tricky, because there can be special characters in there. That is why this code uses the Get-ADGroup cmdlet to get the group names.
If the SamAccountNames do not matter and you want to get ALL users in OU OU=USERS,DC=contoso,DC=com that are not Enabled AND have an EmailAddress ending in #contoso.com, than simply change the $filter variable to
$filter = "Enabled -eq 'False' -and EmailAddress -like '*#contoso.com'"
As per your latest comment, you would only want to list the groups IT_Test and/or IT_Prod for users that are member of any of these two groups, the code below should do that:
$filter = "(Enabled -eq 'False' -and EmailAddress -like '*#contoso.com') -and (SamAccountName -like 'TEST*' -or SamAccountName -like 'PROD*')"
Get-ADUser -Filter $filter -SearchBase "OU=USERS,DC=contoso,DC=com" -SearchScope Subtree -Properties EmailAddress, MemberOf | ForEach-Object {
$testgroups = $_.MemberOf | Where-Object { $_ -match 'CN=IT_(Test|Prod)'}
if ($testgroups) {
# the user is a member of group IT_Test and/or IT_Prod, get the names of these groups for this user
$groups = foreach ($grp in $testgroups) { (Get-ADGroup -Identity $grp).Name }
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {$groups -join ', '}}
}
else {
# the user is not a member of any IT_Group
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {'Not a member of any IT_Group'}}
}
} | Export-CSV -Path "C:\tmp\output.csv" -NoTypeInformation -Encoding UTF8
Hope that helps
This code get all users that have groups begining with "IT_" it's provided by $_.memberof -like 'CN=IT_*'.Then for each user getting his name,login and groups what beggins from"CN=IT_",format it with -replace and add it to csv file without rewrite.
$users=Get-ADUser -Filter {filter options} -Properties MemberOf| Where-Object { $_.memberof -like '*CN=IT_*'}
foreach ($user in $users){
$user|Select-Object name , samaccountname ,#{Name="MemberOf";Expression={((($_.MemberOf | Select-String -Pattern 'CN=IT_*')-replace "CN=")-replace ",.+$") -Join ";"}} |Export-CSV -Delimiter ';' -Path "D:\testdir\uss.csv" -NoTypeInformation -Encoding UTF8 -Append
}
I have a list with AD groups in a CSV file: Input_ADGroup.csv
Column A looks like this:
CN
ADgroup1
ADgroup2
I already have some code which list all the users of the groups in the output.csv file, however I am missing the ADgroup name. So it is unclear which users are member of which group.
$Manager = #{Name = "Manager"; Expression = {%{(Get-ADUser $_.Manager -Properties DisplayName).DisplayName}}}
$Manager_Location = #{Name = "Manager_Location"; Expression = {%{(Get-ADUser $_.Manager -Properties Office).Office}}}
$Fields = #(
'SamAccountName'
'CN'
'DisplayName'
'Office'
'mail'
'Department'
$Manager
$Manager_Location
)
Import-Csv -Path H:\Test\Input_ADGroup.csv |
ForEach-Object {
Get-ADGroup -Filter "CN -eq '$($_.CN)'" -Properties * -ErrorAction SilentlyContinue |
Get-ADGroupMember | Get-ADUser -properties * | Select $Fields
} | Export-Csv -Path H:\Test\Output_ADGroup.csv -NoTypeInformation
H:\Test\Output_ADGroup.csv
So is it possible to get a column which shows the "source-ADgroup"... or another format which breaks the list with the ADGroup name or something?
IMO my other suggested solution is more efficient applyig the same CN from the input:
$Data = ForEach($CN in (Import-Csv -Path H:\Test\Input_ADGroup.csv).CN) {
Get-ADGroup -Filter "CN -eq '$CN'" -Properties CN -ErrorAction SilentlyContinue |
Get-ADGroupMember | Get-ADUser -Properties * | Select-Object ($Fields+#{n="Group";e={$CN}})
}
$Data
$Data | Export-Csv -Path H:\Test\Output_ADGroup.csv -NoTypeInformation
As you already have AD group name in $_, you can add one more calculated property to your Select-Object by changing this:
Get-ADGroup -Filter "CN -eq '$($_.CN)'" -Properties * -ErrorAction SilentlyContinue |
Get-ADGroupMember | Get-ADUser -properties * | Select $Fields
to this (saving first group name to variable to not mix up with $_ used later in pipeline):
$GroupName = $_.CN
Get-ADGroup -Filter "CN -eq '$($_.CN)'" -Properties * -ErrorAction SilentlyContinue |
Get-ADGroupMember | Get-ADUser -properties * | Select ($Fields+#{n="Group";e={$GroupName}})
Credits to #LotPings and #Maikel for pointing out the issue with incorrect $_ usage in comments
NOTE: remember about brackets, otherwise you'd receive an error like:
Select-Object : A positional parameter cannot be found that accepts argument n="Group";e={$GroupName}
#Lotpings #robdy - Thanks for your input, I got it working so many thanks. See code below
Import-Csv -Path H:\Test\Input_ADGroup.csv |
ForEach-Object {
Get-ADGroup -Filter "CN -eq '$($_.CN)'" -Properties CN -PipelineVariable name -ErrorAction SilentlyContinue |
Get-ADGroupMember | Get-ADUser -properties * | Select ($Fields+#{n="Group";e={$name}})
} | Export-Csv -Path H:\Test\Output_ADGroup.csv -NoTypeInformation
H:\Test\Output_ADGroup.csv
One last note: The AD group gets displayed as CN=Groupname,OU=...OU=… etc
I couldn't get it to show just "Groupname" but this really is not an issue.
I found this example but I am not sure how I can properly save the output to a .csv.
Import-Module ActiveDirectory
$Groups = Get-ADGroup -Filter {GroupCategory -eq "Distribution"} -Properties Members
ForEach ($g in $Groups) {
Write-Host $g.name
Write-Host $g.members `n
}
I have tried something such as:
Import-Module ActiveDirectory
$Groups = Get-ADGroup -Filter {GroupCategory -eq "Distribution"} -Properties Members
ForEach ($g in $Groups) {
$g.name | Export-CSV C:\log.csv -notypeinformation -Append
$g.members | Export-CSV C:\log.csv -notypeinformation -Append
}
It only saves 1 column to the CSV which is called length.
This also makes me remove the 'n at the end of Write-Host $g.members `n
Is there a way that I can grab this data and save it to .csv properly?
UPDATE
With help from TheMadTechnician and this link https://blogs.technet.microsoft.com/heyscriptingguy/2013/07/22/export-user-names-and-proxy-addresses-to-csv-file/ I was able to get closer to what I want.
Import-Module ActiveDirectory
$Groups = Get-ADGroup -Filter {GroupCategory -eq "Distribution"} -Properties Members
ForEach ($g in $Groups) {
$g.name | Export-CSV C:\log.csv -notypeinformation -Append
$g.members | Export-CSV C:\log.csv -notypeinformation -Append
}
$Groups | Select Name,#{L='Members_1'; E={$_.members[0]}}, #{L='Members_2';E={$_.Members[1]}}, #{L='Members_3';E={$_.Members[2]}}, #{L='Members_4';E={$_.Members[3gq]}} | Export-Csv C:\log.csv -notype
This gives me an output of the below in my CSV:
Name Members_1 Members_2 ETC...
NameOfGroup CN=Stormy Daniels,OU=IT,DC=DomainName,DC=com CN=Joe Bob,OU=IT,DC=DomainName,DC=com
Now the list of users can be huge so I would have to continue creating Members_3, Members_4, etc...
I'm not sure if there is a way I can specify all users or loop
#{L='Members_1'; E={$_.members[0]}}
and increment the number until all users are displayed.
I also only need the CN with the name. I don't need the Ou= or Dc=.
Ah this proved harder than I expected - due to the member counting (you have to do a count which can be comparable to integer). I have added a possibility to limit result size as for large queries the active directory produces timeouts.
$limit_result_size = 10
$group_name = Get-ADGroup -Filter {GroupCategory -eq "Distribution"} -Properties Name, Members -ResultSetSize:$limit_result_size | Select-object name
ForEach ($name in $group_name.name) {
If ((![String]::IsNullOrEmpty("$name")) -And ("$name" -notlike 'index')) {
$count_members = Get-ADGroupMember -Identity "$name" | Measure-Object | Select-Object Count
Write-Output "The AD group $name has $($count_members.Count) members.`n"
For($counter = 0; $counter -lt $count_members.Count; $counter++) {
$person = Get-ADGroup -Filter {Name -eq $name} -Properties Name, Members | Select-Object Name, #{N='Members';E={$_.Members[$counter]}}
$person.Members = $person.Members | Select-String 'CN=[0-9a-zA-Z]+' -AllMatches | % { $_.Matches } | % { $_.Value }
$person | export-csv -NoTypeInformation -Append -Path '<your_path>\log.csv'
}
}
}
Short description:
(![String]::IsNullOrEmpty("$name")) -And ("$name" -notlike 'index')) conditions which the AD group should satisfy.
Select-String 'CN=[0-9a-zA-Z]+' -AllMatches | % { $_.Matches } | % { $_.Value } Selects only CN=string_with_numbers. You could replace it with CN=\w+ if you prefer.
The script produces a pair in CV AD group and the CN=user_name. If anything else is unclear please ask.
EDIT
If you have spaces in the names of the Common Names (CN) you have to adjust the regexp to CN=[0-9a-zA-Z\s]+.
EDIT 2 Adding user's email addresses.
Since your question has in the title request for emails I'll answer here without new question. Note that this solution uses lookbehind in regexp to exclude the CN= from the output so it can be used as source for the user query. It also uses a PSCustomObject which gathers all the information together. I have renamed some variables to make better sense in the context of user details.
$limit_result_size = 10
$group_name = Get-ADGroup -Filter {GroupCategory -eq "Distribution"} -Properties Name, Members -ResultSetSize:$limit_result_size | Select-object name
ForEach ($name in $group_name.name) {
If ((![String]::IsNullOrEmpty("$name")) -And ("$name" -notlike 'index')) {
$count_members = Get-ADGroupMember -Identity "$name" | Measure-Object | Select-Object Count
Write-Output "The AD group $name has $($count_members.Count) members.`n"
For($counter = 0; $counter -lt $count_members.Count; $counter++) {
$person = Get-ADGroup -Filter {Name -eq $name} -Properties Name, Members | Select-Object Name, #{N='Members';E={$_.Members[$counter]}}
$person.Members = $person.Members | Select-String '(?<=CN=)[0-9a-zA-Z\s]+' -AllMatches | % { $_.Matches } | % { $_.Value }
$person_details = Get-AdUser -filter {name -eq $member} -Properties mail | Select-Object mail
$person_additional_details = [PSCustomObject]#{ group_name = $group.Name
user_name = $group.Members
email = $person_details.mail
}
If ([String]::IsNullOrEmpty($($person_additional_details.email))) {
$person_additional_details.psobject.properties["email"].value = '<empty>'
}
# For user to see the written data
Write-Output "AD Group: $($person_additional_details.group_name) `
AD User: $($person_additional_details.user_name) `
Users`'s email: $($person_additional_details.email)`n"
# writing into the CSV file
$person_additional_details | export-csv -NoTypeInformation -Append -Path '<your_path>\log.csv'
}
}
}
I would like an active directory query to list all users who only belong to "Domain Users" and no other groups.
I already tried the following query, but it showed all users with all groups they belong to:
Import-Module Activedirectory
Get-ADUser -Filter * -Properties DisplayName,memberof | % {
New-Object PSObject -Property #{
UserName = $_.DisplayName
Groups = ($_.memberof | Get-ADGroup | Select -ExpandProperty Name) -join ","
}
} | Select UserName,Groups | Export-Csv C:\temp\report.csv -NTI
Search for an empty memberof-property while PrimaryGroup is "Domain Users". No need to list the groups if you expect nothing.
Get-ADUser -Filter "samaccountname -eq 'froflatest-sshf'" -Properties Memberof, PrimaryGroup, DisplayName, Description |
Where-Object { -not ($_.memberof) -and $_.PrimaryGroup -match 'Domain Users' } |
Select-Object SamAccountName, DisplayName, Description |
Export-CSV -Path "c:\report.csv" -NoTypeInformation
Import-Module Activedirectory
Get-ADUser -Filter "*" -Properties sAMAccountName,Description, Memberof, PrimaryGroup |
Where-Object { -not ($_.memberof) -and $_.PrimaryGroup -match 'Domain Users' } | Select sAMAccountName,Description | Export-Csv C:\temp\report.csv -NTI