April 13, 2010

How to get or set the AccountExpires attribute

This not as easy as one might think. the active Directory is not storing dates as a normal [datetime],it use a special a 64bit interger call an IADsLargeInterger.

This mean that you can’t simply use a $user.accountExpires property to get or set the value, this will return a System.__ComObject

To get the AccountExpires property the easiest way (I think), is to use the DirectorySearcher [ADSISearcher] . This will not return a normal DirectoryEntry but a SearchResult data type. The difference is that the accountExpires property is return as an int64 instead of a IADsLargeInterger (don’t ask me why). An int64 is much easier to handle, here’s how to do it :

$search = [ADSISearcher] "" 
$search.Filter = "(cn=testUser)" 
$user = $search.FindOne()  
[datetime]::fromfiletime($user.properties.accountexpires[0])

Of course you can’t set the  AccoutExpires with a SearchResult data type. But you can use a special invokeSet on a DirectoryEntry that seems to convert a [datetime] to the correct format :

$user=[adsi]"LDAP://cn=testUser,dc=mycompany,dc=com"
$newAccountExpires=(Get-Date).addMonths(1)
$User.InvokeSet("AccountExpirationDate",$newAccountExpires)

You can also try to use an InvokeGet("AccountExpirationDate") method on a DirectoryEntry but it will throw an error if the AccountExpires attribute is not set (E_FAIL).

Update october 28th, 2013

With Powershell 2.0 and greater you can use the ConvertLargeIntegerToInt64 method :

$user=[adsi]"LDAP://cn=testUser,dc=mycompany,dc=com"
[datetime]::fromfiletime($user.ConvertLargeIntegerToInt64($user.properties.lastlogon[0]))

6 comments:

B_inside said...

Hi there,

I tried to use your Script for setting the AccountExpirationDate, but it doesn't work for me. I got: Exception calling "InvokeSet" with "2" arguments: "Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))"
At C:\Script.ps1:149 char19
+ $User.Invoke( <<<< "AccountExpirationDate",$newAccountExpires)
while trying it. Which requirements do you need for this Script? Do you use any modules? May this work on "Windows Server 2008"?

ParadisJ said...

Are you by any chance running this code in PowerShell 1.0 ?

It runs well with PowerShell 2.0 on my Windows 7 computer. I've tried it on a Windows 2008 with Powershell 1.0 and got the DISP_E_UNKNOWNNAME error.

I'm also getting strange behavior in PowerGUI Script Editor (don't know why yet).

B_inside said...

This may be categorized as Epic Fail -.-
You're totally right. I wasn't thinking of this, cause every little XP-SP3 Workstation has Powershell v2 on it. I am a bit shocked. Thank you for your help.

Stef said...

You can use the DirectoryEntry's method ConvertLargeIntegerToInt64 to convert Large integer to Int64

[DateTime]::FromFileTime($user.ConvertLargeIntegerToInt64($user.pwdLastSet.Value))

++
Stef

ParadisJ said...

Thanks Stef, didn't know about this one (ConvertLargeintegertoInt64).

Anonymous said...

I spent several hours tearing my hair out and this is the simplest solution. Thank you.

Post a Comment