I'd like to also check the status of the account and add some
indicator in the output if the account is disabled. From some basic
Google-fu, I've found that the disabled flag is stored in the second
bit of the userAccountControl property. I've found plenty of examples
how to add a binary "and" to the LDAP query string to return a list of
enabled/disabled accounts, but I can't find anything on how to
programmatically read the second bit directly once a user object has
been obtained.
My script takes a list of names, loops through them and uses the
DirectorySearcher to retrieve the object with this query:
(&(objectCategory=User)(sAMAccountName=$name))
I then use the FindOne() method of the DirectorySearcher to get the
specific object. Once I have the object is there a way to just read
the second bit of the userAccountControl property or do I need to
execute another search and add that filter to the query? Something
like this:
(&(objectCategory=User)(sAMAccountName=$name)(userAccountControl:
1.2.840.113556.1.4.803:=2))
If that query returns a result then the account is disabled, but it
seems like a second AD query is a waste of time if that attribute can
be read directly.
The script is below, if it helps to see it in context. I removed the
"DisplayUsage" function from the listing to save space so ignore the
call to it.
Thanks,
Paul
param (
[string[]] $names,
[string] $inputFile
)
function Get-LastLogonTimeStamp($ldapPath) {
$vbsCode = @"
On Error Resume Next
Set objUser = getObject(`"$ldapPath`")
Set objLastLogon = objUser.Get("lastLogonTimeStamp")
intLastLogonTime = objLastLogon.HighPart * (2^32) +
objLastLogon.LowPart
intLastLogonTime = intLastLogonTime / (60 * 10000000)
intLastLogonTime = intLastLogonTime / 1440
result = intLastLogonTime + `#1/1/1601`#
"@
$vbs = new-object -com MSScriptControl.ScriptControl
$vbs.language = 'vbscript'
$vbs.ExecuteStatement($vbsCode)
$lastLogonTimeStamp = $vbs.Eval("result")
if ($lastLogonTimeStamp -eq "1/1/1601 12:00:00 AM") {
"Never"
}
else {
$lastLogonTimeStamp
}
}
if ($args -or (!$names -and !$inputFile)) {
DisplayUsage
exit
}
if ($inputFile) {
$names += get-content $inputFile
}
if ($names) {
$results = @{}
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
foreach ($name in $names) {
$blnUser = $true
$strFilter = "(&(objectCategory=User)(sAMAccountName=$name))"
$objSearcher.Filter = $strFilter
$objSearchResult = $objSearcher.FindOne()
if (!$objSearchResult) {
$blnUser = $false
$strFilter = "(&(objectCategory=Computer)(Name=$name))"
$objSearcher.Filter = $strFilter
$objSearchResult = $objSearcher.FindOne()
if (!$objSearchResult) {
$displayName = $name.ToUpper()
if (!$results.ContainsKey($displayName)) {
$results += @{$displayName = "Object Not Found"}
}
}
}
if ($objSearchResult) {
$object = $objSearchResult.GetDirectoryEntry()
if ($blnUser) {
$displayName = ([string]$object.sAMAccountName).ToUpper()
}
else {
$displayName = ([string]$object.Name).ToUpper()
}
$lastLogon = Get-LastLogonTimeStamp($objSearchResult.Path)
if (!$results.ContainsKey($displayName)) {
$results += @{$displayName = $lastlogon}
}
}
}
}
if ($results) {
$results.GetEnumerator()
}
if (flag -band 2) {
disabled
}
else {
enabled
}
* This would be WAY eaiser using the FREE CMDlets from Quest
http://www.quest.com/activeroles-server/arms.aspx
* I would use DirectorySearcher for the LastLogonTimeStamp look here for
more info
http://bsonposh.com/modules/wordpress/?p=30
* There is a hidden GetEx() method you can use to get 'AccountDisabled'.
Returns $true or $false
Example: $user.psbase.invokeget('AccountDisabled')
Brandon Shell
---------------
Blog: http://www.bsonposh.com/
PSH Scripts Project: www.codeplex.com/psobject
Yes, I know the Quest tools would simplify this. The script started
as an exercise to get to know the DirectoryServices class a little
better, before it morphed into something I thought would actually be
useful. Then it became one of those "I know I can do this"
things. :)
The hidden GetEx() method works like a charm. Obviously I don't see
it in the get-member list for a DirectoryEntry object. How would I go
about finding hidden methods?
Also, thanks to Bob for his -band solution. It looks like that also
works, although I got a type convesion error when trying to use the
userAccountControl attribute directly:
PS C:\> $object.useraccountcontrol -band 2
Cannot convert "System.DirectoryServices.PropertyValueCollection" to
"System.Int32".
At line:1 char:33
+ $object.useraccountcontrol -band <<<< 2
I noticed if I converted it to a string first, the type conversion
would work:
PS C:\> $object.useraccountcontrol.tostring() -band 2
0
Thanks for both solutions. Binary arithmetic is still a bit over my
head. :)
Thanks,
Paul
$object.userAccountControl.Value -band 2