Solved

How can i disable inactive user accounts and move them to specified OU?

Posted on 2009-07-06
19
1,484 Views
Last Modified: 2012-05-07
Hello,

I need a vbscript that can disable inactive AD user accounts that hasn't logged on for more than 90 days and move them to a specified OU after disabling them.

Appreciate your fast response.

Yassein
0
Comment
Question by:amyassein
  • 8
  • 8
  • 3
19 Comments
 
LVL 57

Expert Comment

by:Mike Kline
ID: 24791914
Yassein,
Does this have to be done using vbscript?   The reason I ask is because there is a great tool called old computer by MVP Joe Richards.
...don't worry it also works on users
http://www.joeware.net/freetools/tools/oldcmp/index.htm
To look at a quick report run
oldcmp -report -users -llts
that -llts is for lastlogontimestamp which is available in a w2k3 domain which it looks like you are.
It can disable and move too
Thanks
Mike
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24792432

Because it's sometimes useful to know how... VbScript version below :)

Chris
' Inactivity period
 

Const PERIOD_TO_REMOVE = 90
 

' Create a connection to the OU which holds disabled accounts
 

Set objOU = GetObject("LDAP://OU=Disabled Users,DC=yourdomain,DC=com")
 

' Create a value to represent the date
 

Dim dblInt8 : dblInt8 = CDbl(DateDiff("s", CDate("01/01/1601 00:00:00"), Now - PERIOD_TO_REMOVE))
 

' Create a filter to return all user accounts which have been inactive for PERIOD_TO_REMOVE and

' and are still enabled.
 

Dim strLdapFilter

strLdapFilter = "(&(objectClass=user)(objectCategory=person)(lastLogonTimeStamp<=" & _

  CStr(dblInt8) & "0000000)(!userAccountControl:1.2.840.113556.1.4.803:=2))"
 

' Search the current AD domain
 

Dim objConnection : Set objConnection = CreateObject("ADODB.Connection")

objConnection.Provider = "ADsDSOObject"

objConnection.Open "Active Directory Provider"
 

Dim objCommand : Set objCommand = Createobject("ADODB.Command")

objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000
 

Dim objRootDSE : Set objRootDSE = GetObject("LDAP://RootDSE")
 

objCommand.CommandText = "<LDAP://" & objRootDSE.Get("defaultNamingContext") & ">;" & _

  strLdapFilter & ";distinguishedName,userAccountControl;subtree"
 

Dim objRecordSet : Set objRecordSet = objCommand.Execute
 

Do Until objRecordSet.EOF

  Set objUser = GetObject("LDAP://" & objRecordSet.Fields("distinguishedName").Value)
 

  ' Debugging / Testing

  WScript.Echo "Disable: " & objRecordSet.Fields("distinguishedName").Value
 

  ' Disable this account - Note: these are commented out to allow testing prior to activation

  ' objUser.AccountDisabled = True

  ' objUser.SetInfo
 

  Set objUser = Nothing
 

  ' Debugging / Testing

  WScript.Echo "Moving: " & objRecrodSet.Fields("distinguishedName").Value  
 

  ' Move the account to a new OU - Note: this is commented out to allow testing prior to activation
 

  ' objOU.MoveHere "LDAP://" & objRecordSet.Fields("distinguishedName").Value, VbNullString
 

  objRecordSet.MoveNext

Loop

Open in new window

0
 
LVL 1

Author Comment

by:amyassein
ID: 24793023
Chris,Mkline

Thanks for the quick response and i appreciate it.

Chris,

I have a question, Which date shall i insert in this function ? CDate("01/01/1601 00:00:00" ..... Sorry but i don't do scripting too much.

Thank You again.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24793042

The lastLogonTimeStamp attribute is the number of 100-nanosecond intervals since 01/01/1601 00:00:00. That means it has to be calculated to fit into the script.

The script does that by taking the value you set for "PERIOD_TO_REMOVE" and figuring out the difference between the date above (01/01/1601) and todays date (Now) minus the specified number of days.

In short, you only need to set a value for "PERIOD_TO_REMOVE", it's 90 days at the moment.

Chris
0
 
LVL 1

Author Comment

by:amyassein
ID: 24793091
Chris,

I am very sorry that i didn't mention this from the beginning but instead of searching the whole AD domain , i need only to look for inactive accounts in "People" OU since all user accounts are placed inside one OU.

My bad :)

Please can you help in this?

Thanks
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24793594

Sure :)

Fill in the value for SEARCH_ROOT here.

Chris
' Inactivity period

 

Const PERIOD_TO_REMOVE = 90
 

' Search base - The AD path you wish to find users in (and beneath)
 

Const SEARCH_ROOT = "OU=People,DC=yourdomain,DC=com"

 

' Create a connection to the OU which holds disabled accounts

 

Set objOU = GetObject("LDAP://OU=Disabled Users,DC=yourdomain,DC=com")

 

' Create a value to represent the date

 

Dim dblInt8 : dblInt8 = CDbl(DateDiff("s", CDate("01/01/1601 00:00:00"), Now - PERIOD_TO_REMOVE))

 

' Create a filter to return all user accounts which have been inactive for PERIOD_TO_REMOVE and

' and are still enabled.

 

Dim strLdapFilter

strLdapFilter = "(&(objectClass=user)(objectCategory=person)(lastLogonTimeStamp<=" & _

  CStr(dblInt8) & "0000000)(!userAccountControl:1.2.840.113556.1.4.803:=2))"

 

' Search the current AD domain

 

Dim objConnection : Set objConnection = CreateObject("ADODB.Connection")

objConnection.Provider = "ADsDSOObject"

objConnection.Open "Active Directory Provider"

 

Dim objCommand : Set objCommand = Createobject("ADODB.Command")

objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000

 

objCommand.CommandText = "<LDAP://" & SEARCH_ROOT & ">;" & _

  strLdapFilter & ";distinguishedName,userAccountControl;subtree"

 

Dim objRecordSet : Set objRecordSet = objCommand.Execute

 

Do Until objRecordSet.EOF

  Set objUser = GetObject("LDAP://" & objRecordSet.Fields("distinguishedName").Value)

 

  ' Debugging / Testing

  WScript.Echo "Disable: " & objRecordSet.Fields("distinguishedName").Value

 

  ' Disable this account - Note: these are commented out to allow testing prior to activation

  ' objUser.AccountDisabled = True

  ' objUser.SetInfo

 

  Set objUser = Nothing

 

  ' Debugging / Testing

  WScript.Echo "Moving: " & objRecrodSet.Fields("distinguishedName").Value  

 

  ' Move the account to a new OU - Note: this is commented out to allow testing prior to activation

 

  ' objOU.MoveHere "LDAP://" & objRecordSet.Fields("distinguishedName").Value, VbNullString

 

  objRecordSet.MoveNext

Loop

Open in new window

0
 
LVL 57

Expert Comment

by:Mike Kline
ID: 24795018
Just to follow up with oldcmp, you can also change the base where it searches
...for that you use the -b switch then your OU
so
oldcmp -b "DN of your OU here" -report -users -llts
That report gives you 90 days but you can change the age by using the -age switch.  If you want to check for 120 days for example
oldcmp -b "DN of your OU here" -report -age 120 -users -llts  
Thanks
Mike
0
 
LVL 1

Author Comment

by:amyassein
ID: 24795458
Chris,

Thank you so much for the valuable information. Tomorrow i will test it and will update you.

Mkline,

Fantastic follow up !!! i promise i will give it a try later. The reason why i love scripting because it's flexible, less CPU consuming and give you results in terms of visible outputs such as MsgBox.

Thanks again all.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24795464

We should have had a bit of PowerShell as well, just to round things off nicely :)

Chris
0
 
LVL 57

Expert Comment

by:Mike Kline
ID: 24795495
One thing that I also like about oldcmp is that you can send those html reports to the managers.  Can make you look good.
...even managers can understand them :)
0
 
LVL 1

Author Comment

by:amyassein
ID: 24800847
Chris,

I tried your final code but it generated a run time error "Object required "objRecordSet".

Any Suggestions?
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24801661

That confused me for a while, but there's a typo, it complains about "objRecrodSet" being required instead :)

Fixed here.

Chris
' Inactivity period

 

Const PERIOD_TO_REMOVE = 90

 

' Search base - The AD path you wish to find users in (and beneath)

 

Const SEARCH_ROOT = "OU=People,DC=yourdomain,DC=com"

 

' Create a connection to the OU which holds disabled accounts

 

Set objOU = GetObject("LDAP://OU=Disabled Users,DC=yourdomain,DC=com")

 

' Create a value to represent the date

 

Dim dblInt8 : dblInt8 = CDbl(DateDiff("s", CDate("01/01/1601 00:00:00"), Now - PERIOD_TO_REMOVE))

 

' Create a filter to return all user accounts which have been inactive for PERIOD_TO_REMOVE and

' and are still enabled.

 

Dim strLdapFilter

strLdapFilter = "(&(objectClass=user)(objectCategory=person)(lastLogonTimeStamp<=" & _

  CStr(dblInt8) & "0000000)(!userAccountControl:1.2.840.113556.1.4.803:=2))"

 

' Search the current AD domain

 

Dim objConnection : Set objConnection = CreateObject("ADODB.Connection")

objConnection.Provider = "ADsDSOObject"

objConnection.Open "Active Directory Provider"

 

Dim objCommand : Set objCommand = Createobject("ADODB.Command")

objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000

 

objCommand.CommandText = "<LDAP://" & SEARCH_ROOT & ">;" & _

  strLdapFilter & ";distinguishedName,userAccountControl;subtree"

 

Dim objRecordSet : Set objRecordSet = objCommand.Execute

 

Do Until objRecordSet.EOF

  Set objUser = GetObject("LDAP://" & objRecordSet.Fields("distinguishedName").Value)

 

  ' Debugging / Testing

  WScript.Echo "Disable: " & objRecordSet.Fields("distinguishedName").Value

 

  ' Disable this account - Note: these are commented out to allow testing prior to activation

  ' objUser.AccountDisabled = True

  ' objUser.SetInfo

 

  Set objUser = Nothing

 

  ' Debugging / Testing

  WScript.Echo "Moving: " & objRecordSet.Fields("distinguishedName").Value  

 

  ' Move the account to a new OU - Note: this is commented out to allow testing prior to activation

 

  ' objOU.MoveHere "LDAP://" & objRecordSet.Fields("distinguishedName").Value, VbNullString

 

  objRecordSet.MoveNext

Loop

Open in new window

0
 
LVL 1

Author Comment

by:amyassein
ID: 24810969
Chris,

Thank you so much for fixing that error. Well, when i run the script, it works fine by showing pop up messages for disabling and moving the intended accounts but the thing is, when i checked the accounts, i noticed that they still not disabled and not moved to the specified OU. I am sure that i mentioned the name of the destination OU correctly (where all disabled accounts will be placed). Actually, i got many DCs in my environment so i waited for 30 minutes which is the DC replication interval because i doubted the script ran against a specified DC not all DCs.

Anyways, how can i tell the script to run against all the DCs in my environment?

Thank you again man.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24811506

Hey :)

It's because the lines that make the changes are commented out. I wanted to give you a chance to test it before it starting actually making changes.

You should see two sections for this:

  ' Disable this account - Note: these are commented out to allow testing prior to activation
  ' objUser.AccountDisabled = True
  ' objUser.SetInfo

And:

  ' Move the account to a new OU - Note: this is commented out to allow testing prior to activation

  ' objOU.MoveHere "LDAP://" & objRecordSet.Fields("distinguishedName").Value, VbNullString

Removing the ' will activate them (don't remove it from the actual comment though :)).

Chris
0
 
LVL 1

Author Comment

by:amyassein
ID: 24812692
Chris,

Yeah Yeah, now it's working man after removing these things  :)

But, there is still minor issue. Moving to the new OU is not performed.

It's moving to the same OU where i perform the search. For example, I perform the search in People OU and my destination folder is Decommissioned OU. After i configure these OUs in the script, the accoun is disabled properly but not moving to the destination OU. It also says "The server is unwilling to process the request"

Any ideas my friend?
0
 
LVL 1

Author Comment

by:amyassein
ID: 24834865
Chris,

Ok let me clarify things more.

After running the script, it says:

"Disable: CN=Smith,OU=People,DC=Domain,DC=com"

I click "Ok", then the second message appears:

"Moving: CN=Smith,OU=People,DC=Domain,DC=com"

Well, it should say:

"Moving: CN=Smith,OU=Decommissioned,DC=Domain,DC=com"

The this runtime error appears:

"The server is unwilling to process the request"

Therefore, the result is that the account is disabled successfully but remains in the source OU. I checked my permissions in the destination OU and i can move to and from this OU.

Hope this was clear.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 24838037

Hey sorry dude, bit distracted.

> Well, it should say:

No, it shouldn't. It's telling you which object is being moved, not what the object will be after the move. That's only there for debugging.

> "The server is unwilling to process the request"

There aren't any other accounts in the target OU with the same name are there?

Chris
0
 
LVL 1

Author Comment

by:amyassein
ID: 24846467
Chris,

You know what! you are right! .... your script now is working like charm. I was access denied on the target OU when some administrator was doing maintenance for the OU permissions.

I know i ask too many questions but i have one last request which i beleive it's very easy to you.
I need the script to silently do this operation without poping up messages to me because it's headache to keep clicking "OK" after each message prompt. I think you need to remove those "Echo" lines. i don't want to do it as i am afraid i ruin something.

Many Thanks.
0
 
LVL 70

Accepted Solution

by:
Chris Dent earned 125 total points
ID: 24847123

No worries, all we need to do is comment out or remove the lines beginning WScript.Echo. As in the version below.

Chris
' Inactivity period

 

Const PERIOD_TO_REMOVE = 90

 

' Search base - The AD path you wish to find users in (and beneath)

 

Const SEARCH_ROOT = "OU=People,DC=yourdomain,DC=com"

 

' Create a connection to the OU which holds disabled accounts

 

Set objOU = GetObject("LDAP://OU=Disabled Users,DC=yourdomain,DC=com")

 

' Create a value to represent the date

 

Dim dblInt8 : dblInt8 = CDbl(DateDiff("s", CDate("01/01/1601 00:00:00"), Now - PERIOD_TO_REMOVE))

 

' Create a filter to return all user accounts which have been inactive for PERIOD_TO_REMOVE and

' and are still enabled.

 

Dim strLdapFilter

strLdapFilter = "(&(objectClass=user)(objectCategory=person)(lastLogonTimeStamp<=" & _

  CStr(dblInt8) & "0000000)(!userAccountControl:1.2.840.113556.1.4.803:=2))"

 

' Search the current AD domain

 

Dim objConnection : Set objConnection = CreateObject("ADODB.Connection")

objConnection.Provider = "ADsDSOObject"

objConnection.Open "Active Directory Provider"

 

Dim objCommand : Set objCommand = Createobject("ADODB.Command")

objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000

 

objCommand.CommandText = "<LDAP://" & SEARCH_ROOT & ">;" & _

  strLdapFilter & ";distinguishedName,userAccountControl;subtree"

 

Dim objRecordSet : Set objRecordSet = objCommand.Execute

 

Do Until objRecordSet.EOF

  Set objUser = GetObject("LDAP://" & objRecordSet.Fields("distinguishedName").Value)

 

  ' Debugging / Testing

  ' WScript.Echo "Disable: " & objRecordSet.Fields("distinguishedName").Value

 

  ' Disable this account - Note: these are commented out to allow testing prior to activation

  objUser.AccountDisabled = True

  objUser.SetInfo

 

  Set objUser = Nothing

 

  ' Debugging / Testing

  ' WScript.Echo "Moving: " & objRecordSet.Fields("distinguishedName").Value  

 

  ' Move the account to a new OU - Note: this is commented out to allow testing prior to activation

 

  objOU.MoveHere "LDAP://" & objRecordSet.Fields("distinguishedName").Value, VbNullString

 

  objRecordSet.MoveNext

Loop

Open in new window

0

Join & Write a Comment

Introduction You may have a need to setup a group of users to allow local administrative access on workstations.  In a domain environment this can easily be achieved with Restricted Groups and Group Policies. This article will demonstrate how to…
Is your Office 365 signature not working the way you want it to? Are signature updates taking up too much of your time? Let's run through the most common problems that an IT administrator can encounter when dealing with Office 365 email signatures.
This tutorial will walk an individual through the steps necessary to join and promote the first Windows Server 2012 domain controller into an Active Directory environment running on Windows Server 2008. Determine the location of the FSMO roles by lo…
This tutorial will walk an individual through the process of transferring the five major, necessary Active Directory Roles, commonly referred to as the FSMO roles from a Windows Server 2008 domain controller to a Windows Server 2012 domain controlle…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now