How do I create a script to move certain users from our GPO Exempt OU to their regular OUs at the end of each day?

OK, I don't know much about scripting, but I was wondering if my task is possible, and if so, how would I do it?  Is writing a script for it the best way, or is there another way?  What I need to do is make sure that any users that were moved into the GPO Exempt OU during the course of the day (we move users into that OU when we're working on their computer or software issues and we want to make sure group policy settings don't get in the way - ideally, the users are moved back into their regular OUs when we're done with them, but not all admins at my organization remember to do so all the time) are moved back into their regular OUs at the end of each day (at a determined time), making them once again subject to GPOs applied to those OUs.  

Does anyone have any ideas how to do this?  Thanks in advance for your help!
m1knoxgAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Netman66Commented:
You can do it in a script, yes.

Use DSQUERY USER to query for any user in this OU, then send the output to a text file.
Then use DSMOVE and parse the text file.

0
m1knoxgAuthor Commented:
OK, like I said, scripting is something I don't know much about...

How do I DSQUERY USER for my GPO Exempt OU and then send its output to a text file, and the DSMOVE?  I don't really understand how all that works...
0
m1knoxgAuthor Commented:
I should also mention that not all of these users/computers would be going back into the same OU - they would have to be moved back to whichever OU each of them was in before the users/computers were moved into the GPO Exempt OU.
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Netman66Commented:
You won't be able to be selective on where the users came from since this variable will be unknown after the move.

You should post a link to this question here:

http://www.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/

Someone there may be able to help with a script to move the user into the GPO Exempt OU first then remember where it came from then move it back later.

You should also increase your points on this since what you are asking is not simple.

0
m1knoxgAuthor Commented:
Increasing point value because this doesn't appear to be an easy task...
0
Netman66Commented:
It's not impossible, it's going to be time consuming and will need to be (most likely) done in VBScript.

0
TheCleanerCommented:
Is the original OU the same for all users?

Basically like netman66 said, if you move someone manually into the exempt OU then there's not a way to tell which OU was their original OU.

Now, if you are stating you want a script that moves any user in "Exempt OU" to "Company Users OU"...that's not a problem, and can be easily scripted using vbscript or Netman's suggestion of DSQUERY and DSMOVE.  Then you just schedule it.

If that's what you want, let us know and we'll lay it out for you...
0
m1knoxgAuthor Commented:
No, the original OU may not be the same for all users.  Various users may be coming from different OUs into GPOExempt for the day for different issues.  The problem is, after we manually move those users into GPO Exempt so we can help them with a problem, some of our IT staff forget to put them back into their respective OUs from before.  Most users will be coming from the same Local Users OU, but underneath that one, there are 3 different OUs that users go into, based on which of the 3 facilities in which they are located.  So, that's what I mean about users coming from different places (also, sometimes each facility's OU has various OUs under it for users with different purposes and different settings required, which complicates putting the users back even more).  GPOExempt also has 3 OUs underneath it for each of our 3 facilities.  I don't know if that info helps in trying to achieve this very difficult task, but that's how our Active Directory structure works.  
0
TheCleanerCommented:
Well, in that case you're going to have one seriously long script.  It would have to key in on some attribute of each user, like their location field or similar, and then move them based on that field, and even then it's not going to be easy.

Your best bet is to basically just train IT on how to do things correctly.  If they move someone, they should document where they came from, and put them back when finished.

Easier said than done, I know, but really that's going to be the easiest way to go.
0
m1knoxgAuthor Commented:
Well, thanks to both of you for commenting on my question.  I'm sorry that it's not really possible, but I understand why it's not.  If everyone would just move the users back after they move them in the first place, that would be good, but some people are forgetful.  :)

What are some good resources for me to look at to get acquainted with scripting?  I am totally new to the subject.  
0
TheCleanerCommented:
www.microsoft.com/technet/scriptcenter

That's a great resource for learning windows scripting.


I'm not saying what you are asking for is impossible, just difficult.

The logic would require the script to query against something in the user account to know the original OU.  This would be an attribute of some kind that is entered into the account, just like the description field.

Then the script would say, ok, if attribute = St. Louis Accounting, then move the user to the STLACCT OU.

That's the basics of it, but you sound like it will introduce other criteria for sub-OUs, etc.

Just difficult and dynamic to your organization, which would require a consultant to come in and program it....that's all.
0
dlwyatt82Commented:
The quick solution I would recommend is to have TWO scripts.

One that your employees use to move a user into this "Exempt" OU.  Part of what this script would do is append the user's original OU to a field in the account (such as Description).

The second script would be a scheduled task to enumerate all users in the Exempt OU, read their Description (or whichever attribute you choose to have the first script use) to determine their proper OU, and move them back.  This script should write a log with records of failures, so you have a reference when a user's original OU can't be determined (or doesn't exist, etc).

Here is a quick example of what these scripts will probably look like.

*** NOTE *** I ran out of time typing this at the office, so I'm just posting what's done so far.  If no one else completes this for you, I will pick it up again when I have time.

'**************************************
' Script #1 - Move User to Exempt OU
'
' Argument:  /u:LoginName
'
' Attempts to move the user account with sAMAccountName <LoginName>
' to the Exempt OU.  Stores the user's original OU in the user's
' Description attribute for later use.
'
' This sample attempts to run in the same domain the administrator
' is currently logged on to (using rootDSE)
'
'**************************************

Option Explicit

Const cExemptOU = "OU=Exempt"

Dim objRootDSE, objAdoCon, objAdoCmd, objAdoRS, objUser, objExemptOU
Dim strDomainDN, strExemptOU, strLogin, strADsPath, strDesc

If (Not WScript.Arguments.Named.Exists("u")) Then
  WScript.Echo "Usage:  cscript " & WScript.ScriptName & " /u:<LoginName>"
  WScript.Quit 1
End If

strLogin = WScript.Arguments.Named.Item("u")

On Error Resume Next
Set objRootDSE = GetObject("LDAP://rootDSE")
strDomainDN = objRootDSE.Get("defaultNamingContext")

If (Err.Number) Then
  WScript.Echo "Error determining the current user's domain: " & _
               Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

strExemptOU = cExemptOU & ", " & strDomainDN

Set objExemptOU = GetObject("LDAP://" & strExemptOU)

If (Err.Number) Then
  WScript.Echo "Error binding to Exempt OU: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

' We've determined the current domain and that the Exempt OU exists.  Now, try to find the user
' object in Active Directory.

Set objAdoCon = CreateObject("ADODB.Connection")
Set objAdoCmd = CreateObject("ADODB.Command")

objAdoCon.Open "Provider=ADsDSOObject;"
Set objAdoCmd.ActiveConnection = objAdoCon

objAdoCmd.CommandText = "SELECT ADsPath FROM 'LDAP://" & strDomainDN & "' WHERE " & _
                        "objectCategory='person' AND objectClass='user' AND " & _
                        "sAMAccountName='" & strLogin & "'"

Set objAdoRS = objAdoCmd.Execute

If (Err.Number) Then
  WScript.Echo "Error searching Active Directory: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

strADsPath = ""
Do While (Not objAdoRS.EOF)
  strADsPath = objAdoRS.Fields("ADsPath").Value
  objAdoRS.MoveNext
Loop

If (strADsPath = "") Then
  WScript.Echo "User '" & strLogin & "' was not found in Active Directory."
  WScript.Quit 1
End If

Set objUser = GetObject(strADsPath)

If (Err.Number) Then
  WScript.Echo "Error binding to user account: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

If (objUser.Parent = objExemptOU.Get("ADsPath")) Then
  WScript.Echo "User '" & strLogin & "' is already in the Exempt OU."
  WScript.Quit 1
End If

objUser.Description = objUser.Description & "<|>" & objUser.Parent & "<|>"
objUser.SetInfo

If (Err.Number) Then
  WScript.Echo "Error setting user description: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

0
m1knoxgAuthor Commented:
Thanks to Netman66 and TheCleaner for your help so far.  Thanks to dlwyatt82 for the example you typed out for me.  I will have to better educate myself on scripting to see what all of that means before I try it on any users.  
0
dlwyatt82Commented:
OK, here are the two completed scripts.  Let me say up front that these have not been tested, as I do not have an Active Directory domain suitable for this test at present.  There is plenty of error trapping in each script (in the form of Echo statements in script #1, and a log file in script #2), and I am happy to help you debug them if unexpected errors occur.

'**************************************
' Script #1 - Move User to Exempt OU
'
' Argument:  /u:LoginName
'
' Attempts to move the user account with sAMAccountName <LoginName>
' to the Exempt OU.  Stores the user's original OU in the user's
' Description attribute for later use.
'
' This sample attempts to run in the same domain the administrator
' is currently logged on to (using rootDSE)
'
'**************************************

Option Explicit

Const cExemptOU = "OU=Exempt"

Dim objRootDSE, objAdoCon, objAdoCmd, objAdoRS, objUser, objExemptOU
Dim strDomainDN, strExemptOU, strLogin, strADsPath, strDescPre, strDescPost
Dim objRegExp, colMatches, objMatch

If (Not WScript.Arguments.Named.Exists("u")) Then
  WScript.Echo "Usage:  cscript " & WScript.ScriptName & " /u:<LoginName>"
  WScript.Quit 1
End If

strLogin = WScript.Arguments.Named.Item("u")

On Error Resume Next
Set objRootDSE = GetObject("LDAP://rootDSE")
strDomainDN = objRootDSE.Get("defaultNamingContext")

If (Err.Number) Then
  WScript.Echo "Error determining the current user's domain: " & _
               Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

strExemptOU = cExemptOU & ", " & strDomainDN

Set objExemptOU = GetObject("LDAP://" & strExemptOU)

If (Err.Number) Then
  WScript.Echo "Error binding to Exempt OU: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

' We've determined the current domain and that the Exempt OU exists.  Now, try to find the user
' object in Active Directory.

Set objAdoCon = CreateObject("ADODB.Connection")
Set objAdoCmd = CreateObject("ADODB.Command")

objAdoCon.Open "Provider=ADsDSOObject;"
Set objAdoCmd.ActiveConnection = objAdoCon

objAdoCmd.CommandText = "SELECT ADsPath FROM 'LDAP://" & strDomainDN & "' WHERE " & _
                        "objectCategory='person' AND objectClass='user' AND " & _
                        "sAMAccountName='" & strLogin & "'"

Set objAdoRS = objAdoCmd.Execute

If (Err.Number) Then
  WScript.Echo "Error searching Active Directory: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

strADsPath = ""
Do While (Not objAdoRS.EOF)
  strADsPath = objAdoRS.Fields("ADsPath").Value
  objAdoRS.MoveNext
Loop

If (strADsPath = "") Then
  WScript.Echo "User '" & strLogin & "' was not found in Active Directory."
  WScript.Quit 1
End If

Set objUser = GetObject(strADsPath)

If (Err.Number) Then
  WScript.Echo "Error binding to user account: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

If (objUser.Parent = objExemptOU.Get("ADsPath")) Then
  WScript.Echo "User '" & strLogin & "' is already in the Exempt OU."
  WScript.Quit 1
End If

' Process user's description attribute.  Make sure an ADsPath hasn't already been stored
' but not removed.  If so, just replace what's there.

Set objRegExp = New RegExp
objRegExp.Global = False
objRegExp.Pattern = "^(.*)<\|>[^<]+<\|>(.*)$"

If (objRegExp.Test(objUser.Description)) Then
  Set colMatches = objRegExp.Execute(objUser.Description)
  For Each objMatch In colMatches
    strDescPre = objMatch.SubMatches(0)
    strDescPost = objMatch.SubMatches(1)
  Next
Else
  strDescPre = objUser.Description
  strDescPost = ""
End If

objUser.Description = strDescPre & "<|>" & objUser.Parent & "<|>" & strDescPost
objUser.SetInfo

If (Err.Number) Then
  WScript.Echo "Error setting user description: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

Set objUser = Nothing
objExemptOU.MoveHere strADsPath, vbNullString

If (Err.Number) Then
  WScript.Echo "Error moving the user object: " & Hex(Err.Number) & ", " & Err.Description
  Err.Clear
 
  ' Attepmt to revert user's description
  Set objUser = GetObject(strADsPath)
  If (Not Err.Number) Then
    objUser.Description = strDescPre & strDescPost
    objUser.SetInfo
  End If
  Set objUser = Nothing
 
  WScript.Quit 1
End If

WScript.Echo "User '" & strLogin & "' was successfully moved to the Exempt OU."

' **************************
' End of Script #1
' **************************

'**************************************
' Script #2 - Move users in Exempt OU back to
'             their original locations.
'
' Enumerates the user objects in the Exempt OU, and attempts
' to move them back to their original locations based on
' the contents of their Description attribute.
'
' This sample attempts to run in the same domain as the account
' used to run the script.
'
'**************************************

Option Explicit

Const cExemptOU = "OU=Exempt"
Const cLogFile = "ExemptMoves.txt"

Const ForAppending = 8

Dim objRootDSE, objUser, objExemptOU, objUserOU
Dim strDomainDN, strExemptOU, strDescPre, strDescPost, strParent
Dim objRegExp, colMatches, objMatch
Dim objFSO, objLogFile

On Error Resume Next

' Open log file.
Set objFSO = CreateObject("Scripting.FileSystemObject")
If (objFSO.FileExists(cLogFile)) Then
  Set objLogFile = objFSO.OpenTextFile(cLogFile, ForAppending)
Else
  Set objLogFile = objFSO.CreateTextFile(cLogFile)
End If

If (TypeName(objLogFile) <> "TextStream") Then
  ' If log file can't be opened, exit with error code 2
  WScript.Quit 2
End If

objLogFile.WriteLine vbCrLf & CStr(Now) & " - Script starting."

Set objRootDSE = GetObject("LDAP://rootDSE")
strDomainDN = objRootDSE.Get("defaultNamingContext")

If (Err.Number) Then
  objLogFile.WriteLine "Error determining the current user's domain: " & _
                       Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

strExemptOU = cExemptOU & ", " & strDomainDN

Set objExemptOU = GetObject("LDAP://" & strExemptOU)

If (Err.Number) Then
  objLogFile.WriteLine "Error binding to Exempt OU: " & Hex(Err.Number) & ", " & Err.Description
  WScript.Quit 1
End If

' We've determined the current domain and that the Exempt OU exists.  Enumerate the user objects

objExemptOU.Filter = "user"
  For Each objUser In objExemptOU
 
  ' Process user's description attribute.  Make sure an ADsPath hasn't already been stored
  ' but not removed.  If so, just replace what's there.
 
  Set objRegExp = New RegExp
  objRegExp.Global = False
  objRegExp.Pattern = "^(.*)<\|>([^<]+)<\|>(.*)$"
 
  If (objRegExp.Test(objUser.Description)) Then
    Set colMatches = objRegExp.Execute(objUser.Description)
    For Each objMatch In colMatches
      strDescPre = objMatch.SubMatches(0)
      strParent = objMatch.SubMatches(1)
      strDescPost = objMatch.SubMatches(2)
    Next
   
    ' Attempt to bind to target OU
    Set objUserOU = GetObject(strParent)
    If (Err.Number) Then
      objLogFile.WriteLine "User: " & objUser.Get("sAMAccountName") & " Could not bind to user's parent OU '" & _
        strParent & "': " & Hex(Err.Number) & ", " & Err.Description
      Err.Clear
    Else    
      ' Attempt to revert user's description
      objUser.Description = strDescPre & strDescPost
      objUser.SetInfo
     
      If (Err.Number) Then
        objLogFile.WriteLine "User: " & objUser.Get("sAMAccountName") & " Description attribute could " & _
          "not be modified: " & Hex(Err.Number) & ", " & Err.Description
        Err.Clear
      End If
     
      ' Attempt to move the user back.
      objUserOU.MoveHere objUser.Get("ADsPath"), vbNullString
     
      If (Err.Number) Then
        objLogFile.WriteLine "User: " & objUser.Get("sAMAccountName") & " User could not be moved to " & _
          "OU '" & strParent & "': " & Hex(Err.Number) & ", " & Err.Description
        Err.Clear
      End If
    End If
  Else
    objLogFile.WriteLine "User: " & objUser.Get("sAMAccountName") & " Description attribute could " & _
                         "not be parsed."
  End If
   
  Set objUserOU = Nothing
Next

objLogFile.Close

' *************************
' End of Script #2
' *************************
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
m1knoxgAuthor Commented:
Thanks, dlwyatt82.  I will take a look at your scripts after I finish educating myself on what all that stuff means, which may take a while, given my lack of experience in this area.  :)  You've been very helpful so far.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Windows Server 2003

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.