Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Wanet Telecoms Ltd on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Changing more than one password - Access Denied??

Status
Not open for further replies.

keybrdcowboy

IS-IT--Management
Aug 31, 2004
96
US
Hoping someone can help me out here. I am writing a script that will input a list of usernames into an array, and then for each user in the array, reset the password to a specified value. If I edit my input text file to have only 1 username in it, it works fine. But if I put two usernames in it, it errors out with an Access Denied error. And it doesn't even change the password first. Anyone seen or heard of this before? Thanks for any help.
 
How about some code to look at?

[red]"... isn't sanity really just a one trick pony anyway?! I mean, all you get is one trick, rational thinking, but when you are good and crazy, oooh, oooh, oooh, the sky is the limit!" - The Tick[/red]
 
Here ya go.....

Code:
'  This script will enable the user to specify if they want to enable accounts, disable accounts,
'  or change the password on selected accounts.  The script is setup to use text files already 
'  created which contain the usernames that need to be modified.
'

Option Explicit

Dim oFSO, readFile, outFile, iUpperBound, strUserName, oRootDSE, oConnection, oCommand, oRecordSet, strConnect, UserObj
Dim strGoodCount, strLogPath, oShell, strEmailLen, strSid, strTotalCount, strOKCount, strEmail, strQuery, strErrorControl
Dim strConfirm, strAction1, strLoopControl, strAction2, strActionSelected, strFileOpen, strAccountStatus, strConfirmPW
Dim strNewPassword

Public strUser

Const ForAppending = 8
Const ADS_UF_ACCOUNTDISABLE = 2

Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oShell = CreateObject("WScript.Shell")
strLogPath = oShell.ExpandEnvironmentStrings("%USERPROFILE%")

'  Confirmation box asking user to make sure they want to run this script
strConfirm = MsgBox ("Please confirm that you want to run the ResetAccountsSA script.  This script will allow you to enable, " & _
                    " disable, or change the password for selected accounts.  The script will prompt you for what action you want to " & _
                    "take and then ask you to select the usernames that you want to perform that action on." & vbCrLf & vbCrLf & _
                    "Press OK to continue or CANCEL to quit.",1,"PLEASE CONFIRM")
                    
If strConfirm = 2 Then
  WScript.Quit
End If

strLoopControl = 0

Do While strLoopControl = 0
  strAction1 = InputBox ("Please type in the action that you want to perform on the selected user accounts." & vbCrLf & vbCrLf & "Enable - " & _
                        "Enable the selected accounts" & vbCrLf & "Disable - Disable the selected accounts" & vbCrLf & "Reset - Reset the " & _
                        "passwords on the selected " & vbCrLf & "            accounts." & vbCrLf & vbCrLf & "Please click cancel to exit " & _
                        "the script without making any changes.", "SELECT ACTION")
                      
  strAction1 = Trim(strAction1)
  strAction1 = Left(strAction1, 1)
  If LCase(strAction1) = "r" Then
    strActionSelected = "ResetPasswords"
    strLoopControl = 1
  ElseIf LCase(strAction1) = "e" Then
    strActionSelected = "EnableAccounts"
    strLoopControl = 1
  ElseIf LCase(strAction1) = "d" Then
    strActionSelected = "DisableAccounts"
    strLoopControl = 1
  Else
    WScript.Echo "Invalid entry.  Please try again." 
  End If
Loop

Do While strLoopControl = 1
  strAction2 = InputBox ("Please type in the number of the group of usernames you would like to make the change to:" & vbCrLf & vbCrLf & _
  				         "1.  group1" & vbCrLf & "2.  group2" & vbCrLf & "3.  group3" & vbCrLf & "4.  group4" & vbCrLf & "5. All Users" & _
  				         vbCrLf & vbCrLf & "Please click cancel to exit the script without making any changes.","SELECT USERS")
  				       
  strAction2 = Trim(strAction2)
  If strAction2 = "1" Then
    strFileOpen = "testSAscript.txt"
    strLoopControl = 0 
  ElseIf strAction2 = "2" Then
    strFileOpen = "345c112xx.txt"
    strLoopControl = 0
  ElseIf strAction2 = "3" Then
    strFileOpen = "345c117xx.txt"
    strLoopControl1 = 0
  ElseIf strAction2 = "4" Then
    strLoopControl = 0
  ElseIf strAction2 = "5" Then
    strLoopControl = 0
  Else
    WScript.Echo "Invalid entry.  Please try again."
  End If
Loop

Set readFile = oFSO.OpenTextFile("c:\inputfiles\" & strFileOpen)

' Opens a textfile containing the usernames you want to pull and puts them in an array
iUpperBound = 0
While Not readFile.AtEndOfStream
  ReDim Preserve arrUserNames(iUpperBound)
  arrUserNames(UBound(arrUserNames)) = readFile.ReadLine
  iUpperBound = iUpperBound + 1
Wend
readFile.Close

If strActionSelected = "DisableAccounts" Then
  fncDisableAccounts
ElseIf strActionSelected = "EnableAccounts" Then
  fncEnableAccounts
ElseIf strActionSelected = "ResetPasswords" Then
  fncResetPasswords
End If

WScript.Echo "Finished with Script"

WScript.Quit 

Function fncEnableAccounts
  For Each strUser In arrUserNames
    strConnect = fncConnectAD(strUser)
    strConnect = Replace(strConnect,"/","\/")
    
    Set UserObj = GetObject("LDAP://" & strConnect)
    
    strAccountStatus = UserObj.Get("userAccountControl")
    
    UserObj.Put "userAccountControl", strAccountStatus Xor ADS_UF_ACCOUNTDISABLE
    UserObj.SetInfo
  Next
End Function

Function fncDisableAccounts
  For Each strUser In arrUserNames
    strConnect = fncConnectAD(strUser)
    strConnect = Replace(strConnect,"/","\/")
        
    Set UserObj = GetObject("LDAP://" & strConnect)
    
    strAccountStatus = UserObj.Get("userAccountControl")
    
    UserObj.Put "userAccountControl", strAccountStatus Or ADS_UF_ACCOUNTDISABLE
    UserObj.SetInfo
  Next
End Function

Function fncResetPasswords
  Do While strLoopControl = 0
    strNewPassword = InputBox("Please type in the new password." & vbCrLf & vbCrLf & vbCrLf & vbCrlf & "Please click Cancel to exit the script without making any changes.","SEL" & _
                              "ECT NEW PASSWORD")
                             
    If strNewPassword = "" Then
      WScript.Quit 
    End If
    
    strConfirmPW = MsgBox("The password you entered is: " & strNewPassword & vbCrLf & "Is this correct?" & vbCrLf & vbCrLf & _
                          "Press OK to continue with resetting the passwords, or press Cancel to retype the new password" & _
                          ".",1,"CONFIRM NEW PASSWORD")
                      
    If strConfirmPW = 1 Then
      strLoopControl = 1
    End If
  Loop
  
  For Each strUser In arrUserNames
    strConnect = fncConnectAD(strUser)
    strConnect = Replace(strConnect,"/","\/")
    
    Set UserObj = GetObject("LDAP://" & strConnect)
    
    strUser = Trim(strUser)
    
    WScript.Echo strUser
    WScript.Echo strNewPassword
    
    UserObj.SetPassword strNewPassword
  Next
End Function


' This funtion will take a username and return the complete Distinguished Name
Public Function fncConnectAD(strUserName)
  'On Error Resume Next
  Set oRootDSE = GetObject("LDAP://rootDSE")
  Set oConnection = CreateObject("ADODB.Connection")
  oConnection.Open "Provider=ADsDSOObject;"
  Set oCommand = CreateObject("ADODB.Command")
  oCommand.ActiveConnection = oConnection
  oCommand.CommandText = "<LDAP://" & oRootDSE.get("defaultNamingContext") & ">;(&(objectCategory=User)(sAMAccountName=" & _
                         strUserName & "));distinguishedName;subtree"
  Set oRecordSet = oCommand.Execute
  fncConnectAD = oRecordSet("distinguishedName")
  'If fncConnectAD = null Then 
  '  outFile.WriteLine strUserName & ",Null DN returned.," & Date & "," & Time
  '  outFile.WriteLine "Null DN returned.     " & Date & "     " & Time
  'ElseIf Err <> 0 Then
  '  outFile.WriteLine strUserName & ",Error getting DN.," & Date & "," & Time
  'End If
  'On Error Goto 0
End Function
 
which line gives the error?
at a guess i would say that your array has blank strings??

on a more general note you using functions which dont return anything, subs would be better

you dont pass you subroutines anything, you let them use objects which are created globally...makes for you code to be harder to read/follow/debug and sort of negates one of the reasons for subs/functions.

the variables that you use in your functions are not declared in them, they are declared globally,,,again the same style concerns apply as my above point

there is little in the way of error checking...i.e.

For Each strUser In arrUserNames
strConnect = fncConnectAD(strUser)
strConnect = Replace(strConnect,"/","\/")

Set UserObj = GetObject("LDAP://" & strConnect)

strAccountStatus = UserObj.Get("userAccountControl")

UserObj.Put "userAccountControl", strAccountStatus Or ADS_UF_ACCOUNTDISABLE
UserObj.SetInfo
Next

might be nicer to start with
For Each strUser In arrUserNames
If strUser <> "" Then '''
 
Let's see, I will try and reply to each of your comments here.

The array did not have blank strings; I had an Echo statement showing me what it was pulling. Turns out it was trying to reset the passwords too quickly. Why that gives me an access denied error, I dunno. But I put a sleep statement right before the Next statement, and it works fine now.

I always wondered what the difference between functions and subroutines was; guess I should be using them in this particualr case.

So your saying that I should declare variables in my functions, instead of just using the same variables from above?

Error checking is not built in yet. I am not finished with this script, and for some reason I always just add that at the end.

Thanks for everyone's help...

 
I tested your script and it appears to work fine. I imagine that when you are testing this script you are modifying your own account, plus a test account? If you don't have Domain Admin rights on your account, you will only be able to change the password on your own account.

Honestly, I typically use the "dsmod" command when I need to reset large numbers of passwords. I just dump a user list from AD, then use the "For" command at a CMD prompt on the server...
Code:
For /f %a in (userlist.txt) do dsmod user "CN=%a,OU=myOU,DC=mydomain,DC=tld" /pwd Password1

PSC

Governments and corporations need people like you and me. We are samurai. The keyboard cowboys. And all those other people out there who have no idea what's going on are the cattle. Mooo! --Mr. The Plague, from the movie "Hackers
 
Hi KBKB,
with regards to the variables in functions.
i try and work like this

1. setup functions and subs when performing repetitive tasks
2. pass the functions or subs the objects that they require to perform their intended task
3. create variables in the functions or subs when the function or sub requires them to perform there intended task.

a few of the advantages:

+ the function or sub becomes portable/re-useable. it means you can simply copy and paste it from one vbscript to another and it will work off the bat, or it means you can include the vbscripts/func/subs in other scripts by calling them remotely (see the FAQ on subject) this i would suggest is a good place to start on your way to OO working

+ each time one creates a variable it takes up memory. if you use and destroy the variables once they are no longer needed then it should limit the resources you are stealing (in theory)
 
to avoid problems with On Error Resume Next you should change this section

For Each strUser In arrUserNames
strConnect = fncConnectAD(strUser)
strConnect = Replace(strConnect,"/","\/")

Set UserObj = GetObject("LDAP://" & strConnect)

strUser = Trim(strUser)

WScript.Echo strUser
WScript.Echo strNewPassword

UserObj.SetPassword strNewPassword
'to include ######
UserObj = Nothing
'before the next iteration
Next

Next

 
Thanks for everyone's comments. I will make sure to check that FAQ out mrmovie. PScottC, I can't use the dsmod in this particular case because this script is intended for certain users to run on their own. This is so they can modify their own student accounts they have without having to call me to do it all the time....
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top