I have a need to query AD based on a field that is not one of the fields that is not indexed. We have a field called EmployeeID. When I try to filter on that I get a invalid argument. I can query for any indexed field but I just don't have those.
Import-Module ActiveDirectory
$users = ForEach ($user in $(Get-Content "C:\Users\leaker.AUTH\Documents\MADO - General\Tools\ED Dump tool\ED Dump tool\badgem.txt"))
{
Get-AdUser $user -filter "EmployeeID -eq '$_.employeeID)'" -Properties SamAccountNAme,displayName,employeeID,mail
}
$users |
Select-Object SamAccountNAme,displayName,employeeID,mail |
Export-CSV -Path "C:\Users\leaker.AUTH\Documents\MADO - General\Tools\ED Dump tool\ED Dump tool\output.csv" -NoTypeInformation
Any Help would be appreciated.
$user will be bound to the Identity parameter - Filter and Identity does not exist in the same parameter set.
Remove -filter "EmployeeID -eq '$_.employeeID)'"
I assume that your CSV has a field named "employeeID"? If so, that will be a property of the $name variable that is created in the ForEach loop.
You don't need the $user argument for Get-ADUser and it looks like your filter syntax has strange brackets and quotes in it. Try the following:
...
Get-ADUser -Filter {EmployeeID -eq $name.employeeId} -Properties samAccountNAme,displayName,employeeID,mail
...
Related
I have a list of names taken from Oracle that Im trying to find the SamAccountName for. The file is a CSV and some names are "last, first" or "last, first middle initial" and some have three or four names like "alpha bravo charlie delta". The names in the list are likely not the same as listed in AD. Trying to figure out how to sort through this to find AD accounts. The code I currently have is not producing any results.
Import-Module ActiveDirectory
Import-Csv "\\server\users\folder\Oracle_HR.csv"
ForEach-Object{
Get-ADUser -Filter { Name -like "'$($_.name)'"} -Properties Name |
Select-Object Name,SamAccountName |
Export-CSV "\\server\users\folder\Oracle_ADs.csv" -NoTypeInformation
}
The answers by Gabriel Luci and Mathias R. Jessen give good advice on "fuzzy" filtering of AD users.[1]
However, your primary problem is that your ForEach-Object call is not receiving pipeline input, because you haven't connected it to output from the Import-Csv call.
Simply join the two commands with |:
Import-Csv "\\server\users\folder\Oracle_HR.csv" | ForEach-Object { # ...
Secondarily, your -Filter argument { Name -like "'$($_.name)'"} mistakenly applies two layers of quoting and is missing wildcard characters, given that -like compares against the entire field, yet you want substring matching.
Since it's better to avoid the use of script blocks ({ ... }) as -Filter arguments, use a string:
"Name -like `"*$($_.name)*`"" # Note the enclosing '*' to match substrings
Note that I've used embedded " quoting (escaped as `") rather than ' quoting, so as not to break the filter with names that contain ', such as O'Malley.
That said, if, as your question suggests, the names in your CSV data aren't direct substrings of the AD users' .Name property values, the above filter will not be enough, and even the ANR (Ambiguous Name Resolution) technique shown in the linked answers may not be enough.
Thirdly, your Export-Csv call is misplaced: because it is inside the ForEach-Object script block, the same output file gets overwritten in every iteration.
Restructure your command as follows:
Import-Csv ... | ForEach-Object { ... } | Export-Csv ...
Optional reading: ForEach-Object behavior when not providing pipeline input:
The associated script block is executed once.
$_, the automatic variable that contains the current input object, is $null.
[1] Note that the search term in the LDAP filter may need escaping ; per this article, the characters * ( ) \ NUL require escaping and must be escaped as \<hh>, where <hh> is the two-digit hex representation of the char's ASCII code (e.g., * must be escaped as \2A):
$escapedName = -join $(foreach ($c in [char[]] $_.name) { if ('*', '\', '(', ')', "`0" -contains $c) { '\' + ([int] $c).ToString('X2') } else { $c } })
Get-ADUser -LDAPFilter "(anr=$escapedName)"
With $_.name containing string "James* (Jimmy) Smith\Smyth`0", $escapedName would evaluate to literal James\2A \28Jimmy\29 Smith\5CSmyth\00
Keep in mind that the property names in PowerShell are not named the same as the attributes in AD. The Name property corresponds to both the name and cn attributes in AD (both attributes are always the same).
There is also DisplayName (displayName in AD), GivenName (givenName), and Surname (sn). You could try matching against the DisplayName:
Get-ADUser -Filter "DisplayName -eq '$($_.name)'"
If none of those properties match your data exactly, you will have some trouble. No one thing you do will probably work for every account. Hopefully this is just a one-time job and you can work through them in pieces (try one thing, take out the ones that work, and try something different on the rest).
One thing you can try is using AD's Ambiguous Name Resolution (ANR), which will match a search string against several different attributes and even match a first and last name against givenName and sn. That might work with some in your list. You would use it like this:
Get-ADUser -LDAPFilter "(anr=$($_.name))"
If none of that works, you'll have to split the names (for example, by spaces: $_.name.Split(" ")) and try to match pieces of it to different attributes. You'll have to look at your data and see what works.
One approach is to use the Ambiguous Name Resolution feature in Active Directory.
It'll do fuzzy matching against multiple attributes, like the displayName, Name and mail attributes (among others), so it's pretty good for this exact kind of scenario where you don't necessarily know the order or the names or the full name up front:
Get-ADUser -LDAPFilter "(&(anr=$($_.name)))"
I recommend using LDAPFilter and Ambiguous Name Resolution (anr) with Get-ADUser. The algorithm looks up several name fields in different orders to find matches:
Get-ADUser -LDAPFilter "(anr=John Doe)"
Or modifying your code:
Get-ADUser -LDAPFilter "(anr=$($_.name))"
You could try something like the following:
Import-Module ActiveDirectory
$allUsers = Get-Content "\\server\users\folder\Oracle_HR.csv"
$users = #()
ForEach($obj in $allUsers){
$user = Get-ADUser -Filter { GivenName -like $obj} -Properties Name, samAccountName
if(!$user){
$user = Get-ADUser -Filter { SurName -like $obj} -Properties Name, samAccountName
}
if(!$user){
$user = Get-ADUser -Filter { Name -like $obj} -Properties Name, samAccountName
}
if(!$user){
Write-Host "User $obj could not be found" -ForegroundColor Red
}else{
$users += $user
}
}
$users | Select-Object Name,SamAccountName | Export-CSV "\\server\users\folder\Oracle_ADs.csv" -NoTypeInformation
You might need to split the values also like:
Import-Module ActiveDirectory
$allUsers = Get-Content "\\server\users\folder\Oracle_HR.csv"
$users = #()
ForEach($obj in $allUsers){
$objSplit = $obj.Split(",")
foreach($split in $objSplit){
$user = Get-ADUser -Filter { GivenName -like $split} -Properties Name, samAccountName
if(!$user){
$user = Get-ADUser -Filter { SurName -like $split} -Properties Name, samAccountName
}
if(!$user){
$user = Get-ADUser -Filter { Name -like $split} -Properties Name, samAccountName
}
if(!$user){
Write-Host "User $split could not be found" -ForegroundColor Red
}else{
if($users.samAccountName -notcontains $user.SamAccountName){
$users += $user
}
}
}
}
$users | Select-Object Name,SamAccountName | Export-CSV "\\server\users\folder\Oracle_ADs.csv" -NoTypeInformation
when i want to get some information from an user i use this:
Get-ADUser -Filter {EmailAddress -eq 'jperez#dominio.com'}
but when i wanna check the information from a bulk of users i try this:
$batch| foreach {Get-ADUser -Filter {emailaddress -eq $_.email}}
email is the name of the variable in the CSV file
but i am getting this error:
"Get-ADUser : Property: 'email' not found in object of type: 'System.Management.Automation.PSCustomObject'"
i can not use the identity because te emailaddess is not supported for this one
It doesn't look like you are setting up properties for the search result to return. Ie:
Import-csv -Path \\tsclient\c\temp\test.csv -delimiter ";" | ForEach {
Get-ADUser -Filter "EmailAddress -eq '$($_.email)'" -Properties EmailAddress
}
What kind of format are you getting this information in?
Personally, I like to make a temporary file then query using a variable in the for loop. For instance, if I had a file that was a list of email addresses at C:\Users\MyUser\Documents\emailList.txt I would do the following:
$my_list = Get-Content C:\Users\MyUser\Documents\emailList.txt
foreach ($x in $my_list){
$x = $x replace '\s',''
Get-ADUser -Filter {EmailAddress -eq $x}
}
This will pull a Get-ADuser for the entire list by email address. It will also remove white space, which has caused me issues in this situation in the past. Let me know if you have further questions or if you have trouble getting the above commands to work.
Or you can do it per invoke-expression.
$content = Get-Content c:\folder\file.txt
foreach ($emails in $content)
{
$command = "get-aduser -Filter {emailaddress -eq ""$emails""} | select -ExpandProperty SamAccountName"
Invoke-Expression $command
}
Works too :)
Another quick solution is to only pass the property that you want to filter on to the filter expression (this works well when working with CSV imports). Using your example it would change to:
$batch.email| foreach {Get-ADUser -Filter {emailaddress -eq $_}}
I am trying to create a script that will check a list of user names and show the user full name and some attribute settings from AD. Basically I have been sent a list of usernames which are just numbers and management want to know the users full name for each username. they also want to know want division they work for.
Below is the script I have created which doesn't work.
$csv = Import-Csv "C:\temp\users.csv"
foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter {EmployeeID -eq $name} -Properties * |
Get-ADUser -Division $user.Programme
} | Export-Csv "C:\Temp\Results.csv"
So I'm working under the assumption that there is a column named myid in your csv file that contains the id you need to be looking up. Assuming that is the case you'll need to make a few changes here. You'll need to remove the second get-aduser as it is not really doing anything for you, and there is no -division switch available to the get-aduser cmdlet, if you need to restrict your results to just a few settings you can do that using the -properties switch and piping to select as shown below. Keep in mind that none of this will matter if the users do not have the "employeeid" and "division" properties set on their AD accounts, which is fairly rare in my experience but if your company does as a matter of policy when creating accounts should be fine. If you replace the get-aduser line in your script with this it should get the account of any user with an EmployeeID property that matches the one in your spreadsheet and then output that person's full name, division, and employeeid to your CSV file.
Get-ADUser -Filter {EmployeeID -eq $name} -Properties "displayname","division","employeeid" | Select-Object "employeeid","displayname","division"
When in doubt, read the documentation. Get-ADUser doesn't have a parameter -Division. You need to select the properties you want in the output file. Also, foreach loops don't pass output into the pipeline. You need a ForEach-Object loop if you want to pass the output directly into Export-Csv:
Import-Csv 'C:\temp\users.csv' |
ForEach-Object {
$name = $_.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
} |
Select-Object SamAccountName, DisplayName, Division |
Export-Csv 'C:\Temp\Results.csv' -NoType
Otherwise you need to collect the output in a variable:
$users = foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
}
$users | Export-Csv 'C:\Temp\Results.csv' -NoType
or run the loop in a subexpression:
$(foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
}) | Export-Csv 'C:\Temp\Results.csv' -NoType
This is a generic code structure that can be adapted for data collection / enumeration and production of CSV files, tailored to your scenario. We use similar at my workplace. It contains some error handling - the last thing you'd want is inaccurate results in your CSV file.
# Create an array from a data source:
$dataArray = import-csv "C:\temp\users.csv"
# Create an array to store results of foreach loop:
$arrayOfHashtables = #()
# Loop the data array, doing additional work to create our custom data for the CSV file:
foreach($item in $dataArray)
{
try
{
$ADObject = Get-ADUser -Filter { EmployeeID -eq $item.MyID } -Properties DisplayName,Division -ErrorAction Stop
}
catch
{
Write-Output "$($item.MyID): Error looking up this ID. Error was $($Error[0].Exception.Message)"
}
if($ADObject)
{
# Create a hashtable to store information about a single item:
$hashTable = [ordered]#{
EmployeeID=$item.myID
DisplayName=$ADObject.DisplayName
}
# Add the hashtable into the results array:
$arrayOfHashtables += (New-Object -TypeName PSObject -Property $hashTable)
}
else
{
Write-Output "$($item.MyID): No result found for this ID."
}
}
# If the results array was populated, export it:
if($arrayOfHashtables.Count -gt 0)
{
$arrayOfHashtables | Export-CSV -Path "C:\Temp\Results.csv" -Confirm:$false -NoTypeInformation
}
As mentioned elsewhere, division isn't a property on an AD object so you might need to lookup this data elsewhere. If you can do that with another line of PowerShell inside your foreach loop, you could add this to your hashtable object like so:
$hashTable = [ordered]#{
EmployeeID=$item.myID
DisplayName=$ADObject.DisplayName
Division=$DivisionFromOtherSource
}
We have a lot of disabled users, I want to write a script to delete the memberof property and keep the default (domain user). The .csv file I'm importing has a list of 5 samaccountname for testing purpose. when I execute this script I get this error message.
I do not get this message when I run the script for individual users but when I import the .csv file with the list of users I receive this error. Thanks for the help in advance.
c:\user\..\Desktop> .\powerAD.ps1
Get-ADPrincipalGroupMembership : Cannot validate argument on parameter 'Identity'. The
argument is null or empty. Provide an argument that is not null or empty, and then try
the command again.
This is the script I wrote:
This there something wrong with my syntax??
Import-Module ActiveDirectory
ForEach ($user in (import-csv -path "C:\users\j\desktop\ADUSER1.csv"))
{
Get-ADPrincipalGroupMembership -Identity $user.samaccountname |
% {Remove-ADPrincipalGroupMembership -Identity $user.samaccountname -MemberOf -confirm:$false $_}
}
.csv file is in this format.
jbry
pbarb
dvan
Screenshot from excel
The issue is your csv file. You are calling for the samaccountname property from it, but no column has that as the column header. Either read it in as a text file with Get-Content or give it a header.
ForEach ($user in (Get-Content "C:\users\j\desktop\ADUSER1.csv")) {
Get-ADPrincipalGroupMembership -Identity $user |
? {$_.Name -ne "Domain Users"} |
% {Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_}
}
Based on comments above and your linked image from Excel, BenH is probably correct. What you need to do now is convert your names, which are strings in PowerShell, into ADUser objects to pass as the -Identity parameter to Get-ADPrincipalGroupMembership and Remove-ADPrincipalGroupMembership:
foreach ($user in (Import-CSV -Path "C:\users\j\desktop\ADUSER1.csv"))
{
$u = Get-ADUser -Filter 'sAMAccountName -eq $user'
$u | Get-ADPrincipalGroupMembership |
Where-Object {$_.name -ne "Domain Users"} |
ForEach-Object {Remove-ADPrincipalGroupMembership -Identity $u -MemberOf $_}
}
I'm currently working on some PowerShell to update Active Directory User Attributes. The script will read the updated attributes from a CSV.
What I would like to achieve is to iterate through users and compare each user attribute against the value stored in the CSV. If the CSV attribute value doesn’t match the user's Active Directory attribute I would like to update the value in Active Directory
At present I can select a user and display the all the properties using the following:
Get-ADUser -Filter "UserPrincipalName -eq '$($upn)'" -Properties * -SearchBase 'DC=core,DC=com'
What I'm struggling on is the ability to loop through all the properties for each user and compare them against the CSV values for that user.
Here is the snippet I'm working from:
# Import CSV into variable $users
$users = Import-Csv -Path 'C:\PowerShell\AD\UserUpdates.csv'
# Loop through each user
foreach ($user in $users) {
#Search in specified OU and Update existing attributes
$userproperties = Get-ADUser -Filter "UserPrincipalName -eq '$($user.UserPrincpalName)'" -Properties * -SearchBase 'DC=core,DC=com'
}
Does anyone know a way of looping through all the user profile attributes for a user?
Any help or guidance would be greatly appreciated?
UPDATE
Ok working on this a bit further, I have made progress but I don't think it's the cleanest way of accomplishing this.
$userproperties = Get-ADUser -Filter "UserPrincipalName -eq '$($upn)'" -Properties * -SearchBase 'DC=core,DC=com' | Select-Object Name,Created, LastLogon,GivenName,SurName,DisplayName,DistinguishedName,UserPrincipleName
This allows me to select items such as the following:
$userproperties.DisplayName
But with this approach I need to list out every attribute I wish to work with. I would prefer to be able to loop across all properties. Maybe I can put all the properties I wish to utulise into an array and loop through that?
this is a way to cycle into the properties of an object (an AD user in this case):
$user = Get-ADUser -Filter "UserPrincipalName -eq '$($user.UserPrincpalName)'" -Properties * -SearchBase 'DC=core,DC=com'
$user | gm | ? membertype -eq property | select -expa name | % { $user.$_ }
in the foreach-object (%) you can add the logic you need to update some proeprty
It's not too hard to loop through all the properties of one entry in the CSV file. The trick is to transform the hashtable you get from looping through the imported
csv data into a PS object, as follows:
# Import CSV into variable $users
$users = Import-Csv -Path 'C:\PowerShell\AD\UserUpdates.csv'
# Loop through each user
foreach ($user in $users) {
#Obtain attributes from corresponding ADuser.
$userproperties = Get-ADUser -Filter '
"UserPrincipalName -eq '$($user.UserPrincpalName)'" `
-Properties * -SearchBase 'DC=core,DC=com'
#Search in specified OU and Update existing attributes
foreach ($prop in $user.psobject.properties) {
Set-variable -name $prop.name -value $prop.value
# Instead of doing a set-variable, you could set the corresponding attribute
# in the appropriate AD.
}
}
Set-ADUser has a -Replace parameter that accepts a hash table of properties and values that you can use to update multiple properties at once. Rather than looping through each property for each user, you can just build that hash table and then do a single update operation. You can make it a little more efficient by just returning the AD User properties you're checking from your CSV. That list of properties can be had by simply getting a property list from the first object in the collection created from your imported CSV file.
# Import CSV into variable $users
$CSVusers = Import-Csv -Path 'C:\PowerShell\AD\UserUpdates.csv'
#Get the list of properties to check
$Properties = $CSVusers[0].psobject.properties.name
# Loop through each user
foreach ($CSVuser in $CSVusers) {
$UpdateProperties = #{}
#Search in specified OU and Update existing attributes
$ADUser = Get-ADUser -Filter "UserPrincipalName -eq '$($CSVuser.UserPrincpalName)'" -Properties $Properties -SearchBase 'DC=core,DC=com'
#Create a hash table of properties that need updated
Foreach ($Property in $Properties)
{
if ($CSVUser.$Property -ne $ADUser.$Property)
{ $UpdateProperties[$Property] = $CSVuser.$Property }
}
#Update user
if ( $UpdateProperties.Count -gt 0 )
{ Set-ADUser $ADUser.DistinguishedName -Replace $UpdateProperties }
}