Pulling a specific proxyaddress from AD using powershell - powershell

I have a list of users in a csv file. This list contains users whose primary SMTP address is not internal to our organization. These are mail users who are having email forwarded elsewhere.
They have a proxyaddress listed in AD that is on their AD account that points to the organization and this is what I am trying to get to. The problem is that the proxyaddresses does not put the email in the same location so I need to somehow extrapolate the email(s). that match a certain criteria.
What I would really like to get at is the first.last#example.com or first_last.example.com without the {smtp: } formatting.
I have been able to produce a list of proxyaddresses but again it is just a list.
$users = import-csv $BadEmailList | % {Get-ADUser $_.LoginID -Properties proxyaddresses}
Foreach ($u in $users) {
$proxyAddress = [ordered]#{}
$proxyAddress.add(“User”,$u.name)
For ($i = 0; $i -le $u.proxyaddresses.count; $i++)
{
$proxyAddress.add(“ProxyAddress_$i”,$u.proxyaddresses[$i])
} #end for
[pscustomobject]$proxyAddress |
Export-Csv -Path $ProxyAddressList -NoTypeInformation –Append -Force
Remove-Variable -Name proxyAddress } #end foreach
What I am trying to get is the something similar to the following:
User ProxyAddress_0
---- -----
User1 first.last#example.com

If you just want to find the specific AD user with a given proxyaddress, as the header implies, you should be able to use a LDAP filter like this:
Get-ADUser -LDAPFilter "(&(objectCategory=person)(objectClass=user)(|(proxyAddresses=*:first.last#example.com)))"

Related

Why does -contains not seem to work with AD security permissions PSCustomObjects

I am trying to make a list of job titles and their security permissions. I would love to have two lists, a list of security permissions that are shared with more than one member with that title, and permissions that are outliers so that we can better make templates for new hires with certain job roles. I am using -contains to match security permissions with recurring security permissions but it always returns false. I am guessing that each security permission has some unique value to it per user, but even when I try to just match something like the name, it doesn't work
Here is my code.
#get all the users with a title and group them by title
$Titles = Get-ADUser -Filter * -Properties Title | Where-Object Title | Sort-Object Title | Group-Object Title
#loop through each group
foreach ($Title in $Titles){
#zero out outliers and shared permissions
$OutlierPermissions = #()
$SharedPermissions = #()
#loop through each user in each group
foreach ($User in $Title.Group){
$Permissions = #()
#get all the permissions of the user
$Permissions = Get-ADPrincipalGroupMembership $User | Sort-Object Name
#loop through each permission
foreach ($Permission in $Permissions){
#if this permission is shared by more than one user
if($OutlierPermissions -contains $Permission){
#and not already added
if($SharedPermissions -notcontains $Permission){
$SharedPermissions += $Permission
}
#else add to list of outliers
}else{$OutlierPermissions += $Permission}
}
}
}
I have also tried
-contains $Permission.Name
$Permissions = Get-ADPrincipalGroupMembership $User | Sort-Object Name | Select Name
anything to get some part of redundancy to the security permission
is there a way around this?
To put it simple $OutlierPermissions -contains $Permission will never work because $Permission is an instance of ADGroup and $OutlierPermissions is a collection of ADGroup instances and these objects are not comparable or equatable so -contains will always return $false. Instead what you want to do if pick one property of these objects that has such capabilities to have a proper comparison, in example, you can use the .ObjectGUID property.
If I'm understanding your code correctly, it could be simplified to this logic:
$map = #{}
# get all the users with the `Title` populated
foreach($user in Get-ADUser -LDAPFilter "(title=*)" -Properties Title) {
# if this `Title` has not yet been added to the hash
if(-not $map.ContainsKey($user.Title)) {
# use a `List<T>` for dynamic additions of new groups
# and a `HasShet<T>` to not duplicate additions
$map[$user.Title] = #{
ProcessedMembership = [System.Collections.Generic.HashSet[guid]]::new()
Membership = [System.Collections.Generic.List[object]]::new()
}
}
# for each group this user is a member of
foreach($group in Get-ADPrincipalGroupMembership $user) {
# if this group has not yet already been added
if(-not $map[$user.Title]['ProcessedMembership'].Add($group.ObjectGUID)) {
# add this group to the `Membership` List for this `Title`
$map[$user.Title]['Membership'].Add($group)
}
}
}
Using a Hashtable to gather all results where the Keys are the unique Titles and the Values is a nested Hashtable consisting of groups already processed ProcessedMembership (this keeps track of duplicates using a HashSet<T>) and a List<T> where you can keep a reference of all groups objects associated with each Title.

Powershell Get Users that are NOT in multiple Azure AD Group

I am trying to get a list of users that are NOT in multiple Azure AD Groups. I tried different scripts from the internet but then find out that the list is not complete. The code that i tried:
$users = Get-AzureADUser -All $true -Filter "accountEnabled eq true" | Where UserPrincipalName -like '*#company.com'
#list of groups by ObjectID that you want to check if users are NOT a member of
$groupids = #("662627b7-f1bd-4683-819d-36d299e19308", "9080a490-481b-4f7f-9d26-ecf7a186b00d", "3c3a6682-91bf-4afc-8634-7b54999e98b8")
#create hashtable that will contain users
$userht = #{}
Get-AzureADUser -Filter "accountEnabled eq true" | Where UserPrincipalName -like '*#irdeto.com' | ForEach-Object { $userht.Add($_.ObjectId, $_) } #add all AzureAD users to hashtable with ObjectID as unique key
ForEach ($id in $groupids) {
#if user is member of group, remove them from hashtable
Get-AzureADGroupMember -ObjectId $id | foreach-object { $userht.Remove($_.ObjectId) }
}
#return remaining users that are not in specified groups
$userht.Values
When I run this i found a few users that are non in the groups but i also still found a lot of users manually that are not in the group and was not in the outcome of the script.
Tried with your Powershell script getting all the user which have unique DIsplayName and Mail .
Note : Make Sure Every User should have unique DisplayName and Mail. If two user have same DisplayName or Mail it will count as one.
Example : I have total 44 users in AAD and 6 user added in 3 group (each having 2)
After running above script i am getting 36 count but expected is 38. But due to two user have same DisplayName and Mail it counted as one.

Get-ADUser account name whose email address matches any of the emails indicated in csv file

I have a comma-separated csv file as below (first row is the header):
category;email.1;email.2;email.3;email.4;email.5;email.6
category1;sample#gmail.com;;;;;
category2;;;sample2#gmail.com;;;
category3;;sample3#gmail.com;;sample44#hotmail.com;;sample55#gmail.com
and so on...
Now I import it:
$emails = Import-CSV -Encoding Default -Delimiter ";" "c:\temp\myFile.csv"
And finally, for each row in the csv I want to get the AD user account name whose email address matches any from email.1 to email.6
So I try this using a foreach loop but I have no idea what have to put within it to get what I want.
$emails | foreach {
$userAccountName = Get-ADUser -filter {something}
# do some stuff with $userAccountName
}
Note: I would like a generic solution taking into account that in future can be more than 6 emails by category. Also take into account that some emails can be empty for the category.
Once imported you can enumerate the headers matching a pattern
$emails = Import-CSV -Encoding Default -Delimiter ";" "c:\temp\myFile.csv"
$EmailHeaders = ($Emails[0].psobject.Properties|Where-Object Name -like 'email.*').Name
ATM this returns:
> $EmailHeaders
email.1
email.2
email.3
email.4
email.5
email.6
Nest foreachs's to iterate the emails per row which are populated.
Get-ADUser commented out for testing
foreach($Row in $Emails){
foreach($EmailHeader in $EmailHeaders){
if($Email=$Row.$EmailHeader){
[PSCustomObject]#{
Category = $Row.Category
Email_x = $EmailHeader
Email = $Email
SamAccountName= $Null #(Get-ADUser -Filter {EmailAddress -eq "$Email"} -Properties SamAccountName).SamAccountName
}
}
}
}
Category Email_x Email SamAccountName
-------- ------- ----- --------------
category1 email.1 sample#gmail.com
category2 email.3 sample2#gmail.com
category3 email.2 sample3#gmail.com
category3 email.4 sample44#hotmail.com
category3 email.6 sample55#gmail.com

Foreach in foreach (nested)

I'm trying to loop all disabled users through an array of groups to check if the users have membership in any of the listed groups. My thought is that for every user in the list loop them through and check if they are present in one of the listed groups. That would require nesting foreach loops, right? The output I get is like this:
...
user1
user2
user3
is not a member of group1
Here is the source code:
$dUsers = Get-ADUser -Filter {enabled -eq $false} |
FT samAccountName |
Out-String
$groups = 'Group1', 'Group2'
foreach ($dUser in $dUsers) {
foreach ($group in $groups) {
$members = Get-ADGroupMember -Identity $group -Recursive |
Select -ExpandProperty SamAccountName
if ($members -contains $dUsers) {
Write-Host "[+] $dUser is a member of $group"
} else {
Write-Host "[-] $dUser is not a member of $group"
}
}
}
I'm pulling my hair because I feel like there is a simple solution, but I'm lost.
Update:
I wanted to put all disabled users in variable $dUsers.
It actually works if I manually put users in the variable like this:
$dUsers = 'user1','user2','user3'
Which gives me the following output:
user1 is not a member of group1
user1 is not a member of group2
user2 is not a member of group1
user2 is not a member of group2
...
This makes me question how it gets "foreached" when the variable is:
$dUsers = Get-ADUser -Filter {enabled -eq $false} |
FT samAccountName |
Out-String
Anyone got a clarification on that?
Update:
This is the final code. It takes a long time to run, even with only two groups.
$dUsers = Get-ADUser -Filter {enabled -eq $false} | Select-Object -Expand SamAccountName
$groups = 'Group1', 'Group2'
Write-host '[+] Checking if any disabled user is member of any SSL groups'
Write-host '[+] This might take a while. Get a coffee!'
write-host '[+] Running...'`n
foreach ($dUser in $dUsers) {
foreach ($group in $groups) {
$members = Get-ADGroupMember -Identity $group -Recursive | Select -ExpandProperty SamAccountName
if($members -contains $dUser) {
Write-Host "$dUser is a member of $group"
} Else {
# Remove or comment out the line below to get a clutterfree list.
# Write-Host "$dUser is not a member of $group"
}
}
}
You have two issues in your code:
You're creating a single string from the Get-ADUser output. Piping the output of that cmdlet through Format-Table (alias ft) and then Out-String creates one string with a tabular display of all matching account names including the table header.
If you output $dUsers in a way that makes beginning and end of a string visible you'd see something like this (the leading and trailing == marking the beginning and end):
PS> $dUsers | ForEach-Object { "==$_==" }
==samAccountName
--------------
user1
user2
user3==
Since there is no account with a username matching this string no match can be found in any group and you're getting the output you observed.
This misuse of Format-* cmdlets is a common beginner's mistake. People get a nicely formatted string output and then try to work with that. ONLY use Format-* cmdlets when you're presenting data directly to a user, NEVER when further processing of the data is required or intended.
What you actually want is not a string with a tabular display of usernames, but an array of username strings. You get that by expanding the SamAccountName property of the user objects you get from Get-ADUser.
$dUsers = Get-ADUser ... | Select-Object -Expand SamAccountName
The second issue is probably just a typo. Your condition $members -contains $dUsers won't work, since both $members and $dUsers are arrays (after fixing the first issue, that is). The -contains operator expects an array as the first operand and a single value as the second operand.
Change
$members -contains $dUsers
to
$members -contains $dUser
Depending on what PowerShell version you are on, there is a cmdlet for this use case and others.
As for
I'm Trying to loop all disabled users
Just do...
Search-ADAccount -AccountDisabled |
Select-Object -Property Name, Enabled,
#{Name = 'GroupName';Expression = {$_.DistinguishedName.Split(',')[1] -replace 'CN='}}
# Results
Name Enabled GroupName
---- ------- ---------
...
testuser2 NewTest False Users
Guest False Users
Or different cmdlet…
# Get disabled users and their group membership, display user and group name
ForEach ($TargetUser in (Get-ADUser -Filter {Enabled -eq $false}))
{
"`n" + "-"*12 + " Showing group membership for " + $TargetUser.SamAccountName
Get-ADPrincipalGroupMembership -Identity $TargetUser.SamAccountName | Select Name
}
# Results
...
------------ Showing group membership for testuser1
Domain Users
Users
------------ Showing group membership for testuser2
Domain Users
As for ...
an array of Groups
Just select or filter the DN for the group name you want using the normal comparison operators.
As for...
Unfortunately I'm not well versed in powershell.
… be sure to spend the necessary time to get ramped up on it, to limit the amount of misconceptions, confusions, errors, etc. that you are going to encounter. There are plenty of no cost / free video and text-based training / presentations all over the web.
Example:
Videos
Use tools that will write the code for you that you can later tweak as needed.
Step-By-Step: Utilizing PowerShell History Viewer in Windows Server 2012 R2
Learning PowerShell with Active Directory Administrative Center (PowerShell History Viewer)
As well as plenty of sample scripts and modules via the MS PowerShell Script / Module Gallery.
There are two commands for the AD Groups.
First I see that you want the membership of the disabled users that is easy.
#Get the dissabled users from your AD with all their attributes (properties and select)
$dUsers = Get-ADUser -Filter {Enabled -eq $false} -Properties * | Select *
#Run a loop for each user to get the group membership
Foreach ($User in $dUsers) {
$User = $User.SamAccountName
Get-ADUser $User -Properties * | Select Name, SamAccountName, MemberOf | Format-Table -Wrap # > "D:\test\$user.txt" -HideTableHeaders
}
This one can work but I don't like the output that we get.
I prefer to run the groupmembership command and check the users.
$GroupMembers = Get-ADGroupMember "groupname"| Select Name, SamAccountName
ForEach ($User in $GroupMembers)
{
$UserProperties = Get-ADUser $User.SamAccountName -Properties * | select *
If ($UserProperties.Enabled -eq $False) {
Write-Host $UserProperties.SamAccountName
}
}
Edit:
Let me know if those fits you.
Kind regards.
The first thing you should try to check is whenever you are only interested in direct memberships or indirect ones as well. Depending on the answer the options you got availabel change a bit. You probably will encounter Distinguished Names while working on this so check out what they are if you don't know (mostly a path for an object).
If it's only direct memberships using memberOf with Get-ADUser should be sufficient. The memberOf attribute contains every direct group membership of the user with the full Distinguished Name of the group.
Get-ADUser test -Properties MemberOf | Select-Object -ExpandProperty memberOf
You can match the groups you're looking for in various ways. You could get the whole Distinguished Name of those groups or you could do a partial match. It's up to you to decide how to proceed.
If you need the indirect memberships as well you might want to split up your code to make it easier for yourself. For instance you could first find the users and save them. Afterwards find all group members of those groups (You already got that with Get-ADGroupMember) and finally compare the two.
Currently for every user you build the whole list of group members again. This approach would save a few resources as you wouldn't be doing the same queries over and over again.
Finally you could also use the MemberOf approach but get the list of every direct and indirect membership of a user using an LDAP query.
$dn = (Get-ADUser example).DistinguishedName
$userGroups = Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn)
This approach uses a LDAP search query. It can be quite complex, you could also only check for one one of the groups by modifying it a bit.
In the end even your current approach should work. The problem is that you're comparing the AD object against the list of SAM Accountnames. You would need to check for the SAM Accountnames as well.
if($members -contains $dUsers.SamAccountName)
if($members -contains $dUsers | Select-Object -ExpandProperty SamAccountName)
One of these should work if you change your $dUsers as well. As it currently is you end up with a giant string. You probably can check that by checking $dUsers.length. Just drop the Format-Table and Out-String.

move AD group by file

I'm new with PS and doing my first steps..
I have a file named "C:\temp\used_groups.csv".
The file has email address of AD Groups populated by Powershell script to check which distributions group are being used in 365.
Now I want to be able to move them to different OU.
the file has some AD group's email address as follow:
"RecipientAddress"
"test#test.com"
"test1#test.com"
"test2#test.com"
is it possible to move the AD group only by their email address attribute?
how can I resolve the group's sAMAccountName attribute by their email address attribute?
this is what I tried with no success:
$Groups=import-csv "C:\temp\used_groups.csv"
ForEach ($Group in $Groups){
Get-ADGroup -Filter "mail -like $Group "
# rest of script.. not done yet.
}
I would do something like this:
# put the DistinghuishedName of the destination OU here
$destinationOU = "OU=Test,DC=Fabrikam,DC=COM"
# read the CSV and grab the 'RecipientAddress' fields in an array
$emailAddresses = (Import-Csv "C:\temp\used_groups.csv").RecipientAddress
foreach ($email in $emailAddresses){
$GroupToMove = Get-ADGroup -Filter "mail -like '$email'"
if ($GroupToMove) {
# Move-ADObject takes the 'DistinghuishedName' or the 'objectGUID' as Identity parameter
# but it also works when piping the group object itself to it.
$GroupToMove | Move-ADObject -TargetPath $destinationOU
Write-Host "Moved group '$($GroupToMove.Name)'."
}
else {
Write-Warning "Could not find group with email address '$email'"
}
}
When using a CSV you have to specify the fieldname. Another problem in your script is the absence of quotes in the AD filter.
Try this:
$Groups=import-csv "C:\temp\used_groups.csv"
ForEach ($Group in $Groups){
(Get-ADGroup -Filter "mail -like '$($Group.RecipientAddress)'").samaccountname
# rest of script.. not done yet.
}
Cheers,
Gert Jan