Windows Vista Forums
Vista Forums Home Join Vista Forums Windows 7 Forum Vista Tutorials Tags
Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks.

Go Back   Vista Forums > Misc Newsgroups > PowerShell

Vista - Read "userAccountControl" property to determine if account isdisabled?

Reply
 
Old 12-21-2007   #1 (permalink)
psmith2112


 
 

Read "userAccountControl" property to determine if account isdisabled?

I have a PS script that retrieves an object's LastLogonTimeStamp and
it's working fine (thanks to some VBS code from the MS ScriptCenter
and a post by Shay in a previous thread on calling the VBS code from
inside a PS function).

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()
}


My System SpecsSystem Spec
Old 12-21-2007   #2 (permalink)
Bob Butler


 
 

Re: Read "userAccountControl" property to determine if account is disabled?

<psmith2112@xxxxxx> wrote in message
news:05c46ff3-6535-42d3-8c9b-738b4b0d8276@xxxxxx
Quote:

>I have a PS script that retrieves an object's LastLogonTimeStamp and
> it's working fine (thanks to some VBS code from the MS ScriptCenter
> and a post by Shay in a previous thread on calling the VBS code from
> inside a PS function).
>
> 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.
if (flag -band 2) {
disabled
}
else {
enabled
}

My System SpecsSystem Spec
Old 12-21-2007   #3 (permalink)
Brandon Shell [MVP]


 
 

Re: Read "userAccountControl" property to determine if account is disabled?

A couple of things...

* 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
Quote:

> I have a PS script that retrieves an object's LastLogonTimeStamp and
> it's working fine (thanks to some VBS code from the MS ScriptCenter
> and a post by Shay in a previous thread on calling the VBS code from
> inside a PS function).
>
> 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()
> }

My System SpecsSystem Spec
Old 12-21-2007   #4 (permalink)
psmith2112


 
 

Re: Read "userAccountControl" property to determine if account isdisabled?

On Dec 21, 11:29*am, Brandon Shell [MVP] <a_bshell.m...@xxxxxx>
wrote:
Quote:

> A couple of things...
>
> * 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
My System SpecsSystem Spec
Old 12-21-2007   #5 (permalink)
Brandon Shell [MVP]


 
 

Re: Read "userAccountControl" property to determine if account is disabled?

I don't know of an authorative list of these "hidden" methods\properties.
I just know them from past experience.

Brandon Shell
---------------
Blog: http://www.bsonposh.com/
PSH Scripts Project: www.codeplex.com/psobject
Quote:

> On Dec 21, 11:29 am, Brandon Shell [MVP] <a_bshell.m...@xxxxxx>
> wrote:
>
Quote:

>> A couple of things...
>>
>> * 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

My System SpecsSystem Spec
Old 12-21-2007   #6 (permalink)
Bob Butler


 
 

Re: Read "userAccountControl" property to determine if account is disabled?

<psmith2112@xxxxxx> wrote in message
news:1782989f-6e27-4efe-aa12-cd79b76ba9e4@xxxxxx
On Dec 21, 11:29 am, Brandon Shell [MVP] <a_bshell.m...@xxxxxx>
wrote:
Quote:

>PS C:\> $object.useraccountcontrol -band 2
> Cannot convert "System.DirectoryServices.PropertyValueCollection" to
>"System.Int32".

$object.userAccountControl.Value -band 2

My System SpecsSystem Spec
Reply

Thread Tools


Similar Threads
Thread Forum
programmingly determine if "Show common tasks in folders" is selec VB Script
How to: Dual use USB drive ---> Read/Write from Computer and Read from "Stand Alone DVD Player" Vista General
How to determine "activations" left? (Vista Ultimate) Vista General
How do you remove "Find a message" & "Add a newsgroup account" from the view? Live Mail
"Setup cannot determine if this computer supprts installation." Vista installation & setup


Vista Forums is an independent web site and has not been authorized,
sponsored, or otherwise approved by Microsoft Corporation.
"Windows Vista", the Start Orb, and related materials are trademarks of Microsoft Corp.
© Designer Media Ltd

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46