Active Directory PowerShell Filter - powershell

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

Related

PowerShell Array w/ Filter ~ ParameterBindingException

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

Get-ADUser Filter parameter matching second time around

I'm going to have to explain this step by step. First, here's some code that I'm trying to get working:
$Users = Get-Content c:\textfile.txt
foreach ($user in $users) {Get-ADuser -Filter {UserPrincipalName -like "$user*"}}
So when I run this, it returns nothing, which I know is wrong. So I used break points to look a little closer. I found that the variable $user is indeed populating with the correct values. As a test, I replaced $user in the filter with one value (so that it looks like code below) from the text file and stepped through it.
$Users = Get-Content c:\textfile.txt
foreach ($user in $users) {Get-ADuser -Filter {UserPrincipalName -like "1234567890*"}}
This is where it gets interesting. I put the break point on the foreach line and as I let it run through the first time, nothing wrote to the screen except a blank line. When I stepped through it the second time, output as if the command had run twice came out, i.e. the user object with the user principal name like 1234567890* wrote to the screen twice.
As another clue, I tried the following line:
Get-Content c:\textfile.txt | Get-ADuser -Filter {UserPrincipalName -like "$_*" }
And it pops out an error saying that the Filter parameter doesn't take pipeline input. I don't know if that means anything, but I suspect it doesn't since I'm not really using the pipeline in my original code. It's probably something super basic with the Get-ADUser cmdlet that I'm not tracking, even though I've been using Powershell for a while now.
Using the filter is a little finicky within AD. It is actually -filter <string>
Get-ADUser -Filter "UserPrincipalName -like '$($user)*'"
where-object is the other type of filter syntax you were attempting to use. E.G. where-object {UserPrincipalName -like "$user*"}

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

PowerShell Pipeline Script Block inside Hashtable

Hopefully a PowerShell noob question, but how do I access the current pipeline object inside a script block which is also within a hashtable?
Here is what I'm trying to do in its entirety:
Get-ADGroupMember "Group Name" |
Where {$_.objectClass -eq "user"} |
Get-ADUser -properties extensionAttribute1 |
Where {$_.extensionAttribute1 -ne ($_.UserPrincipalName -replace "#ADdomain.com", "#GAdomain.com")} |
Set-ADUser -replace #{extensionAttribute1=&{$_.UserPrincipalName -replace "#ADdomain.com", "#GAdomain.com"}}
I have everything working except for that last line, where the new extensionAttribute1 should be generated from the current users UserPrincipalName, replacing the domain. Running this code results in an error:
+ Set-ADUser <<<< -replace #{ExtensionAttribute1=&{$_.UserPrincipalName -replace "#ADdomain.com", "#GAdomain.com"}}
+ CategoryInfo : InvalidOperation: (CN=Bar\, Fo...ADdomain,DC=com:ADUser) [Set-ADUser], ADInvalidOperationException
+ FullyQualifiedErrorId : replace,Microsoft.ActiveDirectory.Management.Commands.SetADUser
Replacing the code inside the script block with a string works ok (below), so it seems like some sort of access issue to the current pipeline object. Does $_ not work in this case?
Set-ADUser -replace #{extensionAttribute1=&{"foobar"}}
The short answer seems to be using a foreach in your pipeline, as such:
Get-ADGroupMember "Group Name" |
Where {$_.objectClass -eq "user"} |
Get-ADUser -properties extensionAttribute1 |
Where {$_.extensionAttribute1 -ne ($_.UserPrincipalName -replace "#ADdomain.com", "#GAdomain.com")} |
foreach-objct {Set-ADUser $_ -replace #{extensionAttribute1=&{$_.UserPrincipalName -replace "#ADdomain.com", "#GAdomain.com"}}}
As for why, I'm pretty sure it's because Set-ADUser only accepts one object, whether it's one ADUser or one collection of ADUsers. Since $_ represents this, the way you had it was causing Set-ADUser to see $_ as the one object you were providing in the pipeline - the group of users (instead of each individual user).
Note: The following is speculation! If I'm wrong please correct me!
Regarding Set-ADUser taking one or more objects... here's my guess. If you look at the Input Types of Set-ADUser, it gives the types of None or Microsoft.ActiveDirectory.Management.ADUser. But as you have seen, you can also pass along a collection of ADUser objects and Set-ADUser will accept that as well. From my understanding of that cmdlet, when you call it you can run the same Set command on all objects in that collection. For instance, you could do as you mentioned (assuming $users contains everything in the pipeline up until then):
$users | Set-ADUser -replace #{extensionAttribute1=&{"foobar"}}
My guess is that under the hood, Set-ADUser is accepting $users as the single parameter value (by setting the ValueFromPipeline attribute to true in the code) and applying the parameters you provided to each object therein. Since the iteration of the collection is happening within the cmdlet's code (which is no longer in PowerShell, it's the compiled .Net code), the $_ would have no use here in terms of representing each object.
I'm not sure the mechanics of why the pipeline lets you run Get-ADUser in a pseudo-foreach fashion since they have the same input types (you called that in a similar manner without using foreach) but based on the evidence, I have to assume it's under the hood. If anyone has further insights, I'm definitely curious to know. I may be totally off base!