PowerShell Array w/ Filter ~ ParameterBindingException - powershell

I am trying to make a list of users and compare their SamAccount Names to Active Directory and to filter which user AD accounts are disabled.
I receive the error message below when I execute the script.
I do the following:
$Names = #("Shannon.Hoffman","Kameron.Mack","Ashleigh.Reeves","Diego.Colon","Mayra Ortega","Mark.Dunn")
Get-ADUser -Filter {(Enabled -eq "False") -and (SAMAccountName -like $Names)}
I recieve this error message:
Get-ADUser : Cannot convert 'System.Object[]' to the type 'Microsoft.ActiveDirectory.Management.ADUser' required by parameter 'Identity'. Specified method is not supported.
I also get an error saying ParameterBindingException
I am relatively new to PowerShell. Can you please help me understand what I am doing wrong?
Many Thanks!

I would really suggest that you learn PowerShell before trying to do useful things. Things can go badly very quickly.
For one thing, you are filtering using the entire list instead of per user, so you would need to use a loop. Something like the below could do what you require:
$Names = #("username1","username2")
Foreach ($Name in $Names){
$User = Get-ADUser -Identity $Name
if ($User.Enabled){
#user is enabled, add to your list
}
}
Heres some extra reading:
Foreach
Pipeline
PS AD

Related

How to move multiple users to multiple OUs importing users from CSV and filtering by department

New to powershell and scripting in general. Trying to improve automation in our onboarding process, we have to move multiple user accounts to multiple OUs every couple of months.
Import-Module ActiveDirectory
$dept1 = "OU=Path1,DC=SOMEWHERE,DC=OUTTHERE"
$dept2 = "OU=Path2,DC=SOMEWHERE,DC=OUTTHERE"
Import-Csv "C:\Scripts\Incoming.csv" | ForEach-Object {
$samAccountName = $_."samAccountName"
Get-ADUser -Identity $samAccountName -Filter {Department -eq "Dept1"} | Move-ADObject -TargetPath $dept1
Get-ADUser -Identity $samAccountName -Filter {Department -eq "Dept2"} | Move-ADObject -TargetPath $dept2
}
This actually moves ALL users with the department marked into the path I have set.. but I only want it to look at those users in the csv and then filter their departments from AD - not the CSV. I feel like I'm missing a step but I've searched everywhere and tried the get-help. I feel like I need to get the identity, then search/filter against something else but I'm not quite sure how. Would appreciate any help.
edit
Okay, if I run the following:
Get-ADUser -Filter {Department -eq "Dept1"} -Properties Department
It returns everyone that fits that property but how do I compare those to the $samAccountName and ONLY try to move those accounts or run the commands against the accounts on the list? When I ran the second half of the command it tried to move them all and failed.
Move-ADObject $samAccountName -Target $dept1
I feel dumb.
It's ok to feel dumb. You're not and everyone feels that way at times when trying to learn a new thing. You're also here asking for help, so you're ahead of the game compared to a lot of others.
#Lee_Daily's comment is correct that Get-ADUser doesn't support using both -Identity and -Filter in the same command. They're part of different parameter sets. You can tell from the syntax output of Get-Help Get-ADUser or the online docs. Both show 3 different sets of parameters and Identity and Filter are not in the same one. What's odd is that your original script should have thrown an error because you tried to use both in the same command. No need to worry about that now though.
Here's a typical way one might approach this task. First, you query the user's details including the department you want to make a decision on. Then, you write your condition and perform the appropriate action. Doing it this way means you're only querying AD once for each user in your CSV rather than twice like your original script which is good for script performance and load on your AD. The inside of your ForEach-Object loop might look something like this. Note the addition of -Properties department in Get-ADUser. We need to ask for it explicitly because department isn't returned in the default result set.
# all of this goes inside your existing ForEach-Object loop
$u = Get-ADUser -Identity $_.samAccountName -Properties department
if ($u.Department -eq 'Dept1') {
$u | Move-ADObject -TargetPath $dept1
} elseif ($u.Department -eq 'Dept2') {
$u | Move-ADObject -TargetPath $dept2
}
Now let's talk about some alternative ways you might approach this.
The first way sort of flips things around so you end up only calling Get-ADUser once total, but end up doing a lot more filtering/processing on the client side. It's not my favorite, but it sets things up to understand my preferred solution. In particular, the Get-ADUser call uses the -LDAPFilter parameter. LDAP filter syntax is a little strange if you've never seen it before and this particular example could use the more common -Filter syntax just as easily. But in the next example it would be much more difficult and learning LDAP filter syntax enables you to query AD from anything rather than just PowerShell.
# instead of immediately looping on the CSV we imported, save it to a variable
$incoming = Import-Csv "C:\Scripts\Incoming.csv"
# then we make a single AD query for all users in either Dept1 or Dept2
$users = Get-ADUser -LDAPFilter '(|(department=Dept1)(department=Dept2))' -Properties department
# now we filter the set of users from AD by department and whether they're in the CSV and do the moves as appropriate
$users | Where-Object { $_.department -eq 'Dept1' -and
$_.samAccountName -in $incoming.samAccountName } | Move-ADObject -TargetPath $dept1
$users | Where-Object { $_.department -eq 'Dept2' -and
$_.samAccountName -in $incoming.samAccountName } | Move-ADObject -TargetPath $dept2
The benefit of this method is the single AD round trip for users rather than one for each in the CSV. But there are a lot more local loops checking the samAccountNames in the results with the samAccountNames from the CSV which can get expensive cpu-wise if your CSV and/or AD is huge.
The final example tweaks the previous example by expanding our LDAP filter and making AD do more of the work. AD is ridiculously good at returning LDAP query results. It's been fine-tuned over decades to do exactly that. So we should take advantange of it whenever possible.
Essentially what we're going to do is create a giant 'OR' filter out of the samAccountNames from the CSV so that when we get our results, the only check we have to do is the check for department. The way I verbalize this query in my head is that we're asking AD to "Return all users where SamAccountName is A or B or C or D, etc and Department is Dept1 or Dept2. The general form of the filter will look like this (spaces included for readability).
(& <SAM FILTER> <DEPT FILTER> )
# Where <DEPT FILTER> is copied from the previous example and
# <SAM FILTER> is similar but for each entry in the CSV like this
(|(samAccountName=a)(samAccountName=b)(samAccountName=c)...)
So let's see it in action.
# save our CSV to a variable like before
$incoming = Import-Csv "C:\Scripts\Incoming.csv"
# build the SAM FILTER
$samInner = $incoming.samAccountName -join ')(samAccountName='
$samFilter = "(|(samAccountName=$samInner))"
# build the DEPT FILTER
$deptFilter = '(|(department=Dept1)(department=Dept2))'
# combine the two with an LDAP "AND"
$ldapFilter = "(&$($samFilter)$($deptFilter))"
# now make our single AD query using the final filter
$users = Get-ADUser -LDAPFilter $ldapFilter -Properties department
# and finally filter and move the users based on department
$users | Where-Object { $_.department -eq 'Dept1' } | Move-ADObject -TargetPath $dept1
$users | Where-Object { $_.department -eq 'Dept2' } | Move-ADObject -TargetPath $dept2
There are more efficient ways to build the LDAP filter string, but I wanted to keep things simple for readability. It's also a lot easier to read with better PowerShell syntax highlighting than StackOverflow's. But hopefully you get the gist.
The only limitation with using this method is when your incoming CSV file is huge. There's a maximum size that your LDAP filter can be. Though I'm not sure what it is and I've never personally reached it with roughly ~4000 users in the filter. But even if you have to split up your incoming CSV file into batches of a few thousand users, it's still likely to be more efficient than the other examples.

powershell script add-adgroupmember

I'm writing a script which is supposed to show me security groups by matching an input e.g. 'marketing'.
Afterwards I want to add a user to this security group. Since the exchange-powershell can search for user via -anr it's much easier to find the right person.
Here is the part of my script:
$grparray = get-adgroup -filter * | where { $_.name -match "marketing" -and $_.GroupCategory -eq 'Security' }
$potentarray = get-mailbox -anr Julia | select SamAccoutName
$grparray[1] | add-adgroupmember -members $potentarray[1]
But I get the error:
CannotConvertArgumentNoMessage,Microsoft.AcitveDirectory.Management.Commands.AddAdGroupMember
Seems like the ad-modules can't handle the Exchange input.
Does anyone know how I can solve this issue, or got another idea how to?
Ambiguous Name Resolution is available with Get-ADUser, this is preferable over Get-Mailbox as it returns an AD Object which can be used as an input for Add-ADGroupmember.
Try $potentarray = Get-ADUser -LDAPFilter "(anr=Julia)" instead of Get-Mailbox.

How to pass a variable to -Filter

I have come across a very strange situation in PS.
In a script I have, there is a cmdlet (Get-Mailbox) which pulls back a few mailboxes and stores them in $mailboxes.
I then loop through this as follows to find a matching AD account.
foreach ($user in $mailboxes) {
Get-ADUser -Filter {UserPrincipalName -eq $user.UserPrincipalName}
}
When I run this it errors saying that it can't find the property UserPrincipalName on $user.
I have debugged the script and tested it thoroughly. At the point where it errors if I type $user.UserPrincipalName it outputs a list of UPNs and their date type is string so the property is there and has data.
I came to the conclusion that for some reason -Filter can't see the $user variable - as if it is isolated inside the {} brackets which I have heard can be the case with functions. However if I modify the code like so it works.
foreach ($user in $mailboxes) {
$name = $user.UserPrincipalName
Get-ADUser -Filter {UserPrincipalName -eq $name}
}
Although this fixes my problem I'd like to learn why the first example doesn't work. Can anyone explain?
Something worth noting is the get-mailbox actually connects to Exchange Online first and returns a data type of:
Deserialized.Microsoft.Exchange.Data.Directory.Management.Mailbox
but when the Get-ADUser command errors it says the the object is of type PSCustomobject. I think this maybe part of the problem.
Get-ADUser -Filter "userprincipalname -eq '$($user.userprincipalname)'"
I don't know why, but there's some more discussion here about which syntaxes do and don't work with Get-ADUser, and how the scriptblock syntax you are using works with a full user object but not with a PSCustomObject, here:
http://www.powershellish.com/blog/2015-11-17-ad-filter

Active Directory PowerShell Filter

I'm having issues with a script in powershell using AD Module.
I know the general rule of thumb as to how AD commands like to receive its queries so I've wrote this script to (what I thought) would fall inline with those guidelines.
$CSV=Import-Csv "c:\temp\deleteduserlist.csv"
foreach ($entry in $CSV)
{
$filter = "{SamAccountName -like ""$($entry.username)""}"
Get-ADObject -filter $filter
}
I basically need to be able to query and restore any of the users that have been deleted however it fails with:
Error Message: 'syntax error' at position: '1'
At first I was sending through the filter with single quotations like so:
{SamAccountName -like 'xxx'"}
However I have fixed this now.
One thing that puzzles me is that I can literally show the results of $filter, copy them to Get-ADObject -Filter (paste) manually and it works. Therefore I cannot understand why Powershell does not like it..
Whole Error:
Get-ADObject : Error parsing query: '{SamAccountName -like "xxxx"}'
Error M essage: 'syntax error' at position: '1'. At
C:\temp\GetDeleted.ps1:5 char:14
+ Get-ADObject <<<< -filter $filter
+ CategoryInfo : ParserError: (:) [Get-ADObject], ADFilterParsing Exception
+ FullyQualifiedErrorId : Error parsing query: '{SamAccountName -like "xxx "}' Error Message: 'syntax error' at position: '1'.,Microsoft.ActiveD irectory.Management.Commands.GetADObject
One way to do it is this
$CSV=Import-Csv "c:\temp\deleteduserlist.csv"
foreach ($entry in $CSV) {
## Set username to entry from csv file
$directory_username = $entry.username
## Build search filter before using it, interested in username and deleted objects
$directory_filter = {(SamAccountName -like $directory_username) -and (Deleted -eq $true)}
## Search for ADObject based on filter and deleted objects explicitely included in the search
$directory_found_object = Get-ADObject -Filter $directory_filter -IncludeDeletedObjects -Properties sAMAccountName, Deleted
foreach ($directory_object in $directory_found_object) {
### Execute required action on each found $directory_object
### Perhaps pipe $directory_object | Restore-ADObject with appropriate attribute values for restore
}
}
$directory_filter can be of course modified to fit your needs better. However one challenge you will be facing still is to decide which of the found objects for given sAMAccountName should be restored. This is because any given objects can be in deleted state multiple times. Perhaps one way to solve for that is to restore object with latest WhenCreated attribute value.
Also I'm not sure what motivation you have to build filter beforehand. It might be useful in case you built in on the fly for different attribute values but it seems not to be the case in your example. So for simplicity it can be also removed and included directly in Get-ADObject call like this
$directory_found_object = Get-ADObject -Filter {(SamAccountName -like $directory_username) -and (Deleted -eq $true)} -IncludeDeletedObjects -Properties sAMAccountName, Deleted

Updating users with different descriptions in AD

I have a .csv file with a couple of users and each user has a different description. I'm trying to create a script to update the users' description with what is in the .csv file. I have searched but have been unable to find a script that does what I need it to do. Can someone take a look at my script please? I am erroring at:
Unexpected token 'in' in expression or statement. At line:6 char:35
Unexpected token 'in' in expression or statement. At line:6 char:38
ipmo ac*
$file = c:\user_file.csv
$user = $_.samaccountname
$desc = $_.description
Import-csv $file | Foreach ($user in $file) {
#(Set-aduser -identity $($file.user) -description $($file.desc))
}
Any help would be appreciated since I have been trying to do this for a week now and I'm sure it's something easy?
I would instead do something like this.
ipmo ac*
$file = "c:\user_file.csv"
Import-csv $file | ForEach-Object{
Set-aduser -identity $_.samaccountname -description $_.description
}
This is assuming you have your CSV with columns called samaccountname and description.
Not sure what you were trying to do with $user and $desc so those are just omitted. Guessing they would have actually been null since $_ is meant to be used inside a pipeline.
The ForEach you were using is not meant to have pipeline input. The way you have it usually stands on its own. So we switched it to the ForEach-Object version that allows pipeline input.