In PowerShell I use the following LDAP query to retrieve the active directory properties of a host name:
$Filter = "(&(ObjectCategory=Computer)(ObjectClass=Computer)(CN=$ComputerName))"
if ($Found = ([ADSISEARCHER]$Filter).FindOne()) {
$Details = $Found.GetDirectoryEntry()
}
Once I have these properties I would like to check if the computer account is disabled. The following LDAP query is allowing me to do that:
$Filter = "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=2)(CN=$ComputerName))"
([ADSISEARCHER]$Filter).FindOne()
What I would like to know is, how can I avoid using the second LDAP query and use the variable $Details from the first LDAP query to obtain $True or $False if the computer account is disabled?
I found some extra information but I can't seem to put the pieces together.
Thank you for your help.
The information you're looking for is encoded in the userAccountControl of the directory entry object. However, the property contains an array with a numeric value, so you need to check if the "disabled" flag (numeric value 2) in the first array element is set:
$disabled = [bool]($Details.userAccountControl[0] -band 2)
Related
I've built a filter to look for a number of AD fields and properties that works well until I try to add a section looking for 'enabled -eq $true.'
Here is the filter that works successfully:
$filter = "(&(msExchMailboxguid=*)"+"(facilityID=12345)"+"(|(jobCodeID=0001)"+"(jobCodeID=0002)"+"(jobCodeID=0003)(jobCodeID=0004)"+"(jobCodeID=0005)"+"(jobCodeID=0006)))"
Get-ADUser -SearchBase "dc=acme,dc=corp" -LDAPFilter $filter
This works, and produces the correct AD user objects (four total).
But if I try looking for enabled accounts only, like so:
$filter = "(&(msExchMailboxguid=*)"+"(facilityID=12345)"+"(enabled=$true)"+"(|(jobCodeID=0001)"+"(jobCodeID=0002)"+"(jobCodeID=0003)(jobCodeID=0004)"+"(jobCodeID=0005)"+"(jobCodeID=0006)))"
It either fails with "the search filter can not be recognized," or it returns nothing at all depending on whether there are 3 or 4 closed parentheses. I've tried a bunch of variations like (enabled=true), (enabled -eq true) but none of them work.
The issue is that you are using an LDAP filter which is different than a native PowerShell filter and so has a different syntax. Even though most LDAP fields match pretty closely to their normal names, the Enabled field is not stored as a "normal" property (e.g. boolean true/false). Instead, it is held in a part of a bitmasked property userAccountControl. That means you have to use the "intuitive" filter:
(!(userAccountControl:1.2.840.113556.1.4.803:=2))
To filter out only the enabled accounts.
So that makes your filter for your example to become:
$filter = "(&(msExchMailboxguid=*)"+"(facilityID=12345)"+"(!(userAccountControl:1.2.840.113556.1.4.803:=2))"+"(|(jobCodeID=0001)"+"(jobCodeID=0002)"+"(jobCodeID=0003)(jobCodeID=0004)"+"(jobCodeID=0005)"+"(jobCodeID=0006)))"
Because we don't have the active directory module available on all our systems we're using ADSI instead. The following code retrieves a user object from AD by using the AdsiSearcher:
$ADUser = ([AdsiSearcher]"(samaccountname=$SamAccountName)").FindOne()
This results in finding the property primarygroupid which represents the domain primary group for user, usually number 513. When we have this number we would like to find the distinguishedName of the group. However, the code below does that just fine I was wondering if there is a better filter that can be used instead of filtering after the FindAll() method?
$searcher = [adsisearcher]'objectclass=group'
$searcher.PropertiesToLoad.Add('primarygrouptoken')
$searcher.PropertiesToLoad.Add('distinguishedName')
$searcher.FindAll() |
Where-Object { $_.Properties.primarygrouptoken -eq 513}
Something like this would be great but it's not possible:
([adsisearcher]”(&(objectCategory=group)(primaryGroupid=513))”).FindOne()
The primaryGroupToken is a constructed attribute, meaning that it's not actually materialized in the database, and can't be filtered using LDAP.
In order to build an equivalent filter we'll need to look at how it is constructed - and the primary group token in Active Directory is always the same as the group's RID part (the relative identifier) of the objectSid attribute.
So, if we want to search by it, we can simply filter by objectSid instead:
# Obtain domain SID
$dncDN = ([adsi]"LDAP://RootDSE").defaultNamingContext
$dnc = [adsi]"LDAP://$dncDN"
$domainSID = [System.Security.Principal.SecurityIdentifier]::new($dnc.objectSid.Value, 0)
# Set the group ID we're looking for
$RID = 513
# Search for group by objectSid value:
([adsisearcher]"(&(objectCategory=group)(objectSid=${domainSID}-${RID}))").FindOne()
Background:
I'm trying to make a script that will see if a new users email ($email) is the same as one already existing (which would cause an error). I have a very remedial understanding of objects so this is what I have so far (yes it is ugly):
$email = "smithj#company.com"
$mailcheck = Get-ADUser -filter * -Properties * | ForEach-Object {$_.mail}
$mailcheck | ForEach-Object {if ($email -eq $_.mail){"$email = $($_.mail) - Matching email"}else{"$email = $($_.mail) - No duplicate email"}}
Problem 1:
The script doesn't match emails. When I have a matching email in AD it doesn't recognize it.
Problem 2: When executing just the 2nd line, indexing doesn't work properly. While it looks like a consecutive list of emails, if a user doesn't have an email at all (blank) really it could be something like this:
smithj#company.com
johnsonj#company.com
robertsr#company.com
doej#company.com
So $mailcheck[0] returns smithj#company.com while $mailcheck[1] returns blank despite the list actually looking like this:
smithj#company.com
johnsonj#company.com
robertsr#company.com
doej#company.com
Conclusion: I really just need problem 1 solved but problem 2 peaked my curiosity. Thanks.
The way you are doing it above is really inefficient. -Properties * will return every property on the user, some properties are expensive in terms of processing power to return. Only use the properties you need. The properties returned by default without specifying that parameters do not need to be specified with -Properties, only additional nondefault properties. -Filter * will also match on literally any value for any field, effectively returning every ADUser, further increasing the resources required for your script to execute as you will now have to process every user to find any accounts matching that email.
Now that that's out of the way, here is a more efficient method to implement what you're asking:
# Set the email address to search for
$emailAddress = 'box#domain.tld'
# Get all users where the email address matches what is set above
# Force it as an array so you can treat it like one even if only
# one or zero users are returned
$adUsers = #( Get-ADUser -Filter "EmailAddress -eq '${emailAddress}'" )
# Make sure no accounts were returned
# If there are, throw an error with the number of users and who they are
if( $adUsers ) {
throw "Found $($adUsers.Count) users matching EmailAddress ${emailAddress}: $($adUsers.SamAccountName -join ', ')"
}
By using the filter to only match the specific email address, Powershell does not need to collect every single AD user in the system, or iterate over all of them to find a specific email address. This will take a long time to check, especially in larger environments, whereas filtering the returned objects based on email address (or on any other property) results in a faster operation and less data to sift through.
You can then check whether $adUsers contains anything (an array count of anything but 0 evaluates to $True, you could also use if( $adUsers.Count -gt 0 ) as the condition), and if so, throw an error with more information as I do above.
Update for comment question:
To answer your other question in the comment, "I didn't know what object to compare $email to", EmailAddress and Mail both look to be valid properties, but I don't know the difference between them. In my environment, both Mail and EmailAddress are populated with my email address, but have always used EmailAddress and haven't run into issues using that. Maybe one is deprecated and the other is new or something, but I'm not really sure.
There is also yet another property called proxyAddresses as well, which preliminary research shows that both EmailAddress and Mail are related to it, but I don't know much about it. It's not populated on my ADUser objects, so I can't poke around with it.
I've tried to search but could not find anything whcih is not a surprise as I don't think what we're trying to do is so common.
I have a script that gathers a AD users according to filter together with custom attributes properties, we use a custom extended schema, and their values.
I do have an attribute called smtpHistory where an history of SMTP assigned to user are stored, I need to add what's in the $_.email attribute as the primary SMTP address (with SMTP in uppercase) while convertting any existing entry in lower case.
What I am doing right now is similar to
$mailHistory = $_.smtpHistory
$lowerMailHistory = $mailHistory.tolower()
# Insert all existing addresses in lowercase to the history attribute
Set-ADUser $_.SamAccountName -add #{ smtpHistory= $lowerMailHistory }
$newMail = $_.mail
# Append new default email address to smtpHistory
#Set-ADUser $_.SamAccountNAme -Add #{ smtpHistory= "SMTP:$newMail" }
Technically speaking the above works but when I check the smtpHistory attribute what I get is multiple values on a single line like
smtp:test7#gmail.com smtp:test6#gmail.com
Instead of one value per line like
smtp:test7#gmail.com
smtp:test6#gmail.com
The way I'm cycling through the users is via
$usersProxyAddress | ForEach-Object { ...
As using a foreach ($a in $usersProxyAddress ) is yielding the DN of each user and I cannot access the single properties (probably my fault).
Probably this is something silly that I'm overlooking but I cannot find a solution to the issue and any pointer/help would be highly appreciated.
Thanks in advance, Dan.
try something like this
$mailHistory = $_.smtpHistory -join ';'
$mHistory = $mailHistory -spilt ";"
foreach($mH in $mHisotry)
{
#yourcode
}
"Need to be tested as i dont have domain controller available with me now."
All I am trying to accomplish is to return if an LDAP group has any members in it. So, I have a list of groups, and I want to query each one for a list of members to ensure there is at least 1 member in every group.
I am using powershell and this is NOT Active Directory.
This is currently what I am trying
$user = "username"
$pwd = "password"
$de = "LDAP://[SERVERNAME]/cn=user,ou=people,o=company"
$deObject = New-Object -TypeName System.DirectoryServices.DirectoryEntry($de,$user,$pwd,'FastBind')
This returns a DirectoryEntry object (at least as far as I can tell). I can't really see any attributes or anything except for if I do the following:
$deObject.Name
This returns the cn of "user" and that's it. Any suggestions?
I've tried:
$deObject.Properties
$deObject.Properties['member']
$deObject.Properties.Values['member']
Thanks in advance!
This will show you all the properties there are:
$deObject | Format-List * -force
And this will return you the number of members in a group:
$deObject.member.Count