I need some way to report which users in our AD are having duplicated ProxyAddresses or aliases.
Get-ADUser -filter * -properties proxyaddresses |
Select-Object Name,
#{ L = "proxyAddresses"; E = { ($_.ProxyAddresses -like 'smtp:*') -join ";" } } |
export-csv -Path C:\proxyaddresses.csv -NoTypeInformation
I need only the duplicated AD user, not the whole lot, how can I get that report to . CSV file?
You need to wait before concatening your proxy addresses until you are done working with them.
You can get the duplicates by comparing the count of proxy addresses with the count of unique proxy addresses (Select-Object -Unique). If the count mismatch, then you have some dupe in there. If it is the same, then no duplicates.
Here is an example:
$Users = Get-ADUser -filter * -properties proxyaddresses |
Select-Object Name,
#{ L = "proxyAddresses"; E = { $_.ProxyAddresses -like 'smtp:*' } }
$Dupes = $Users | Where-Object -FilterScript { $_.proxyaddresses.Count -ne ($_.ProxyAddresses | Select-Object -Unique).Count }
$Dupes | Select Name, #{'Name' = 'ProxyAddresses' ; 'Expression' = { $_.proxyAddresses -join ';' } } | export-csv -Path C:\proxyaddresses.csv -NoTypeInformation
Reference dataset used
$Users = #(
[PSCustomObject]#{Name = 'Value'; proxyaddresses = #('SMTP:a#a.com', 'SMTP:a#a.com' ) }
[PSCustomObject]#{Name = 'Bob Value'; proxyaddresses = #('SMTP:a#a.com', 'b#a.com') }
)
Not sure if you want:
Users that have a duplicated address in their proxy list (see answer #SagePourpre), or
All users that have the same proxy addresses in their list as another user (this answer)
Create an index (hashtable) where each proxy address refers to a list of users that own that specific proxy address:
$ADUserByProxy = #{}
Get-ADUser -filter * -properties proxyaddresses |
ForEach-Object {
ForEach ($Proxy in $_.ProxyAddresses) {
if (!$ADUserByProxy.Contains($Proxy)) {
$ADUserByProxy[$Proxy] = [Collections.Generic.List[Object]]::new()
}
$ADUserByProxy[$Proxy].Add($_)
}
}
Than list all the values that contain more then 1 user:
$ADUserByProxy.GetEnumerator() |
Where-Object { $_.Value.Count -gt 1 } |
ForEach-Object { $_.Value } |
Export-csv -Path C:\proxyaddresses.csv -NoTypeInformation
Perhaps not the fastest method, but here's an alternative:
Get-ADUser -Filter * -Properties proxyaddresses | Foreach-Object {
$unique = $_.ProxyAddresses | Select-Object -Unique
$dupes = Compare-object -ReferenceObject $unique -DifferenceObject $_.ProxyAddresses -PassThru
if (#($dupes).Count) {
$_ | Select-Object Name, #{Name = 'DuplicateAddresses'; Expression = {$dupes -join ';'}}
}
} | Export-Csv -Path 'C:\proxyaddresses.csv' -NoTypeInformation
Related
Is it possible to change the PS script below in two ways:
The group members are now exported horizontally but I want all the users in 1 cell in the column beside the group name. We have a lot of groups and it is not readable this way.
The path to the folders in the description field of the AD groups are not exported. I would like to have the content of the description field also exported in the column beside the group.
I would like to see this result, see the photo below please:
cls
$Groups = "Group1", "Group2", "Group3"
$results = foreach ($Group in $Groups) {
Get-ADGroupMember -Server contoso.com $group |
select SamAccountName, #{n='GroupName';e={$group}}, #{n='Description';e={(Get-ADGroup $group -Properties description).description}}
}
$results
$results | Export-csv C:\TEMP\GroupMemberShip.CSV -NoTypeInformation
With some minor changes to your original code, you could first gather the wanted info per group and before exporting to CSV, use Group-Object to merge the details.
Something like:
$Groups = "Group1", "Group2", "Group3"
$results = foreach ($Group in $Groups) {
$adGroup = Get-ADGroup $group -Properties Description -ErrorAction SilentlyContinue
if ($adGroup) {
$adGroup | Get-ADGroupMember -Server 'contoso.com' |
Select-Object SamAccountName,
#{Name = 'GroupName'; Expression = {$adGroup.Name}},
#{Name = 'Description'; Expression = {$adGroup.Description}}
}
else {
Write-Warning "Group '$group' could not be found.."
}
}
# now group the results on the GroupName property and
# return objects with joined SamAccountNames and Descriptions
$results | Group-Object GroupName | ForEach-Object {
[PsCustomObject]#{
SamAccountName = ($_.Group.SamAccountName | Sort-Object -Unique) -join ', '
GroupName = $_.Name
Description = ($_.Group.Description | Sort-Object -Unique) -join ', '
}
} | Export-Csv -Path 'C:\TEMP\GroupMemberShip.CSV' -NoTypeInformation
Although I don't understand why you would like to have duplicate items in your output, you can do this like below
$Groups = "Group1", "Group2", "Group3", "Group2", "Group3"
$results = foreach ($Group in $Groups) {
$adGroup = Get-ADGroup $group -Properties Description -ErrorAction SilentlyContinue
if ($adGroup) {
$adGroup | Get-ADGroupMember -Server 'contoso.com' |
Select-Object #{Name = 'SamAccountName'; Expression = {($_.SamAccountName | Sort-Object -Unique) -join ', '}},
#{Name = 'GroupName'; Expression = {$adGroup.Name}},
#{Name = 'Description'; Expression = {$adGroup.Description}} -ExcludeProperty SamAccountName
}
else {
Write-Warning "Group '$group' could not be found.."
}
}
$results | Sort-Object GroupName | Export-Csv -Path 'C:\TEMP\GroupMemberShip.CSV' -NoTypeInformation
I have to check the lastlogon for different users.
My script queries my domain controllers to output my report, however I have an issue.
My report does not come out in descending order. I added sort-object lastlogon -descending, but the dates don't come out correctly in my file. Can you help me?
$data = #()
$DCs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty name
$users =
#'
samaccountname;
user1
user2
'# | ConvertFrom-Csv -Delimiter ';'
foreach ($DC in $DCs) {
foreach($user in $users)
{$data += Get-ADUser $User.samaccountname.Trim() -Properties displayname, userprincipalname, samaccountname, lastlogon -server $DC | Select-Object DisplayName, UserPrincipalName, SamAccountName, Enabled, #{name='LastLogon';expression={[datetime]::fromFileTime($_.lastLogon).ToString('yyyy-MM-dd')}} }
}
$data | Group-Object Lastlogon | Foreach-Object {$_.Group | Sort-Object lastLogon -Descending | Select-Object -Last 10 | Export-Excel "C:\temp\lastlogon ($(Get-Date -Format "yyyy-MM-dd")).xlsx"}
write-host Done! -ForegroundColor Green
It's unclear what you want to accomplish with your script but basically, if you .ToString(..) a DateTime object then Sort-Object will not know how to sort it correctly. Here is how you can approach your code:
$DCs = (Get-ADDomainController -Filter *).Name
$users = #'
samaccountname;
user1
user2
'# | ConvertFrom-Csv -Delimiter ';'
& {
foreach ($DC in $DCs) {
foreach($user in $users) {
$params = #{
Properties = 'displayname', 'lastlogon'
Server = $DC
Identity = $User.samaccountname.Trim()
}
Get-ADUser #params | Select-Object #(
'DisplayName'
'UserPrincipalName'
'SamAccountName'
'Enabled'
#{
Name = 'LastLogon'
Expression = {
[datetime]::fromFileTime($_.LastLogon)
}
}
)
}
}
} | Group-Object { $_.Lastlogon.ToString('yyyy-MM-dd') } | Foreach-Object {
$_.Group | Sort-Object LastLogon -Descending | Select-Object -Last 10 |
Export-Excel "C:\temp\lastlogon ($(Get-Date -Format "yyyy-MM-dd")).xlsx"
}
You also want to avoid adding elements (+=) to a fixed collection (#()).
I have an AD group from which I need to pull all smtp addresses from ProxyAddresses for each user into a single column. I have the script below which is only pulling the first addresses from ProxyAddresses. Some users will have two or more addresses. What can I add to my script to pull all smtp addresses from ProxyAddresses. I'm new with Powershell have have struggled to get this to work. I've spent a good part of the day googling and just can't get there. Any help would be greatly appreciated. Thanks!
<pre><Get-ADGroupMember -Identity "EDL_ProEquities Smarsh" -Recursive |
Get-ADUser -Properties Proxyaddresses |
Select-Object #{ L = "ProxyAddresses"; E = {($_.ProxyAddresses | Where-Object
{$_ -like "*smtp:*"} | ForEach-Object {$_ -replace 'smtp:'}) -join
"`r`n'`;"}} |
Export-CSV -Path "c:\temp\EDL.csv" -NoTypeInformation</pre>
You're almost there. ;-) I think you have at least two options to approach this task. Either you join all desired smtp addresses in one cell in your csv file like this:
Get-ADGroupMember -Identity 'EDL_ProEquities Smarsh' -Recursive |
Get-ADUser -Properties ProxyAddresses |
ForEach-Object {
[PSCustomObject]#{
sAMAccountName = $_.sAMAccountName
ProxyAddresses = ($_.ProxyAddresses | Where-Object { $_ -match '^smtp:' } | ForEach-Object { $_ -replace 'smtp:' }) -join ','
}
} |
Export-CSV -Path 'c:\temp\EDL.csv' -NoTypeInformation
... or you output each individual smtp address on an individual line like this:
Get-ADGroupMember -Identity 'EDL_ProEquities Smarsh' -Recursive |
Get-ADUser -Properties ProxyAddresses |
ForEach-Object {
$User = $_
$SMTPAddressList = $_.ProxyAddresses | Where-Object { $_ -match '^smtp:' } | ForEach-Object { $_ -replace 'smtp:' }
foreach ($SMTPAddress in $SMTPAddressList) {
[PSCustomObject]#{
sAMAccountName = $User.sAMAccountName
SMTPAddress = $SMTPAddress
}
}
} |
Export-CSV -Path 'c:\temp\EDL.csv' -NoTypeInformation
I'm trying to export the username and the user's group membership (of specifc groups) to a CSV file using Export-Csv. However, I couldn't accomplish this using several approaches.
My current script works fine but the output is shown on the PowerShell console alone:
$accounts = Get-Content "C:\Scripts\getUserGroups\users.txt"
foreach ($account in $accounts) {
"$account member of:"
Get-ADPrincipalGroupMembership -Identity $account |
select Name |
Where-Object { $_.name -like 'Browsing_Group*' } |
Sort Name
}
I want to export it to a file in an ordered manner:
UserName1
group membership
UserName2
group membership
etc...
I've tried to add to a variable but probably didn't do that correctly:
$ArrList = [System.Collections.ArrayList]#()
$accounts = Get-Content "C:\Scripts\getUserGroups\users.txt"
foreach ($account in $accounts) {
$ArrList.Add($account)
$groups = Get-ADPrincipalGroupMembership -Identity $account |
select Name |
Where-Object {$_.name -like 'Browsing_group*' } |
Sort Name
$ArrList.Add($grops)
}
Might be a different approach.
You need to build custom objects in order to export the data to a CSV via Export-Csv. The 2 main ways of doing that are:
using calculated properties:
$accounts |
Select-Object #{n='Username';e={$_}}, #{n='Groups';e={
(Get-ADPrincipalGroupMembership -Identity $_ |
Select-Object -Expand Name |
Where-Object {$_ -like 'Browsing_group*' } |
Sort-Object) -join ';'
}} |
Export-Csv 'C:\path\to\output.csv' -NoType
building custom objects directly:
$accounts | ForEach-Object {
$groups = Get-ADPrincipalGroupMembership -Identity $_ |
Select-Object -Expand Name |
Where-Object {$_ -like 'Browsing_group*' } |
Sort-Object
New-Object -Type PSObject -Property #{
'Username' = $_
'Groups' = $groups -join ';'
}
} | Export-Csv 'C:\path\to\output.csv' -NoType
With PowerShell version 3 or newer you can replace New-Object with the [PSCustomObject] type accelerator:
[PSCustomObject]#{
'Username' = $_
'Groups' = $groups -join ';'
}
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'
}
}
}