Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.
I use dsSetPassword to successfully change my domain password.
I am trying to use wntChgPswd("","",oldpass,newpass) to change the locally cached password. However I get Extender Error 562 Invalid Username when this runs. What command should I use to change the locally cached password.
My ultimate goal of this script is to allow the user to change thier domain password over dial-up and keep the cached password synchronized with the domain password.
Here is the contents of my wwwbatch.ini file created in the windows folder:
[WWWNT34I] LastError=2221 (NetUserChangePassword)Any help would be appreciated.
I'm very concerned about how the NT and ADSI extenders are being mixed here with regard to the password changes that are being performed.
Here is my understanding of the problem domain properlyl; please correct me if I'm wrong:
Is this correct?
Once I know for certain that I'm understanding the problem domain I'll go into further discussion about what might be going wrong.
I am using Connection Manager Access Kit(CMAK) to create a custom dial-up entry to launch my winbatch script after a connection is made.
If the password is < threshold the user will be prompted to change their password.
The user's password is changed directly in AD, then the locally cached credentials in the user's access-token are now stale
The function wntChgPswd() is being used in an attempt at getting the locally cached password to be updated to match the one stored in AD. The function wntChgPswd() is failing with a 562 error when it is used in a script with empty string [default] parameter values for the server & username parameters.
The part that really bothers me is making the password change directly in AD such that is bypasses the local workstation. If you used wntChgPswd() to make the change while connected to the network then the updated password would be in both the local cache and back in AD. However, once you change AD and thus invalidate the locally cached credentials, I'm not sure if there is any way to fix things short of logging out locally, and then logging back on such that you use dial-up networking and authenticate via a domain controller so that your domain account credentials get refreshed as part of performing the logon to the local workstation.
What I need to research is whether or not there is any way to get the cached credentials updated w/o the logoff & logon.
And, of course, there's the matter of the 562 error. Given your special situation, there may be an issue with the LSA [Local Security Authority] on the workstation not being able to resolve a SID back to a name or a name to a SID. Underneath it all, the wntChgPswd() function uses 2 different Win32 API functions to perform password reset & change tasks. If it is a reset with a "*UNKNOWN*" password, then NetUserSetInfo() is called and a new password is forcibly set. If you do know the old password [e.g. changing your own password], then NetUserChangePassword() is called. In either case, the server name & username values are not processed at all by the NT extender; they are simply passed directly in to the Win32 API functions "as is". The error 562 is simply how the NT extender translates a Win32 API error code into something more friendly. Given these facts, it makes me think that something in your configuration falls outside of the boundary conditions under which wntChgPswd() was developed, tested & documented.
But, AFAIK, the underlying NetUserChangePassword() function requires you to be connected to the network to change your password when you are logged on locally using a domain account. It really doesn't care if you're on a LAN or a dial-up connections, the important part is that you're able to communicate with a domain controller when the change is made.
Here's one MS KB article that I ran across that is of some interest. I don't know that it directly applies to this problem, but it does relate to cached credentials & domain resource access problems after establishing a dial-up connection.
According to Microsoft, the proper sequence to go through to get the cached credentials updated to match the domain credentials is to logon to the local workstation while connected to the domain so that a domain controller may be contacted. Doing this results in the domain controller being used to authenticate the user's credentials rather than using cached credentials, and it results in the local credential cache being updated with fresh information. This is the recommended solution for when the locally cached credentials get out of sync with the user's credentials stored in the domain [e.g. within AD].
Changing the password directly in AD bypasses the mechanisms that are used during a locally initiated password change that would have resulted in updating the locally cached credentials. In that situation, the above mentioned procedure is the only way to re-sync the credentials.
Microsoft states that the function NetUserChangePassword() will update the locally cached credentials when it changes the password in the domain. However, a domain controller must be reachable when this function is called or else it will fail. When you call wntChgPswd() and specify the old username as a value other than "*UNKNOWN*", then NetUserChangePassword() is the Win32 API function that gets called to perform the password change.
There is a caveat with NetUserChangePassword(), though, with regard to the usernames that it can accept. If you omit the server name and/or username when calling NetUserChangePassword(), the function is documented in the Win32 Platform SDK as defaulting to using the current logon domain & logon username. Even if it uses these defaults, the username must meet some naming requirements that may be exceeded in an AD environment. From the Win32 Platform SDK docs, the following requirements are stated:
User account names are limited to 20 characters and group names are limited to 256 characters. In addition, account names cannot be terminated by a period and they cannot include commas or any of the following printable characters: ", /, \, [, ], :, |, <, >, +, =, ;, ?, *. Names also cannot include nonprintable characters in the ranges 1-7, 10-17, 20-27, and 30-37.
Since you're getting an error 562 when calling wntChgPswd(), which indicates that the user was not found, I suspect that perhaps you are logging on with your username specified in the more modern AD-style UPN notation rather than in the NT-style NTLM simple username notation. If your username doesn't meet these naming requirements then NetUserChangePassword() is going to fail and return an error code that the NT extender translates into error 562.
Please confirm whether or not your usernames comply with these account naming requirements. If in doubt, please provide samples here that can be reviewed.
Lacking any further factual information about this problem, I have a strong inclination to think that the NT extender is working properly and that your configuration & usage of password changing methods is creating a problem condition for which Microsoft has clearly described both the cause of the problem and the recommended solution to the problem. If that is in fact the case, then you are going to need to alter your password changing procedures so that they no longer create this problem condition.
addextender("wwads34i.dll") addextender("wwwnt34i.dll") domain1 = "" domain2 = "" ;Admin account to perform AD functions adminln = "" adminps = "" ;Number of days before passwords expire passexpire = 45 ;Number of days left before password expires to prompt for change threshold = 10 ;Current User logged in username = environment("username") verify = @false ;Set AD Credentials dsSetCredent(adminln, adminps) ;Check for AD existence ADPath = "LDAP://%domain1%/DC=%domain1%,DC=%domain2%" if !(dsIsObject(ADPath)) goto goodbye endif ;Get path of Users AD account in AD errormode(@off) lDAPPath= dsFindPath(ADPath, "sAMAccountName=%username%") errormode(@cancel) lasterr = lasterror() if (lasterr != 0) message("Error","Error #%lasterr% occured while finding the username in AD") goto goodbye endif ;Is User account < X days from expiration errormode(@off) lastset = dsGetProperty(LDAPPath, "pwdLastSet") errormode(@cancel) lasterr = lasterror() if (lasterr != 0) message("Error","Error #%lasterr% occured while requesting the password expiration date from AD") goto goodbye endif currenttime = TimeYmdHms() lastset = strfixchars(lastset,"",10) currenttime = strfixchars(currenttime,"",10) timedif = TimeDiffDays(currenttime,lastset) expire = (passexpire - timedif) if (expire > threshold) exit endif ;Prompt User to change password :ChangePass Gosub LoadDialog Dialogtxt = "Your Password will expire in %expire% day(s) and should be changed immediately. Please enter the information below and choose SET PASSWORD to avoid this notification." ButtonPushed=Dialog("GetPassword") while((strlen(newpass) < 6) || (newpass != newpassconfirm) || (currentpass == newpass) || (strlen(currentpass) < 6)) if (currentpass == newpass) message("ERROR","New Password must be different from Current Password") else if (newpass != newpassconfirm) message("ERROR","Your New Passwords do not match!") else if (strlen(newpass) < 6) message("ERROR","New Password must be at least 6 characters") else if (strlen(currentpass) < 6) message("ERROR","Current Password must be at least 6 characters") endif endif endif endif ButtonPushed=Dialog("GetPassword") endwhile ;Change password verify = @true result = wntChgPswd(domain1, username, currentpass, newpass) while (result != 1) askline = ("Invalid Current Password", 'Please enter the password you used to login to your machine after you were prompted to "Press Ctrl+Alt+Del":') result = wntChgPswd(domain1, username, currentpass, newpass) endwhile message("Success","Your Password has been Successfully Changed and is now Valid for %passexpire% Days." goto goodbye :Cancel if verify == @true message("Last Step",'To complete this process please immediately logout of windows and choose "LOGIN USING DIAL-UP CONNECTION" option to synchronize your local and domain password') goto goodbye endif quit = AskYesNo("Confirm Exit","Your PASSWORD will expire in %expire% day(s). Are you sure you want to exit?") select quit case 0 goto ChangePass break case 1 goto goodbye break :goodbye exit :LoadDialog GetPasswordFormat=`WWWDLGED,6.1` GetPasswordCaption=`Password Expiration Notice` GetPasswordX=202 GetPasswordY=100 GetPasswordWidth=140 GetPasswordHeight=152 GetPasswordNumControls=009 GetPasswordProcedure=`DEFAULT` GetPasswordFont=`DEFAULT` GetPasswordTextColor=`DEFAULT` GetPasswordBackground=`DEFAULT,DEFAULT` GetPasswordConfig=0 GetPassword001=`015,123,044,012,PUSHBUTTON,DEFAULT,"Set Password",1,4,32,DEFAULT,DEFAULT,DEFAULT` GetPassword002=`077,123,044,012,PUSHBUTTON,DEFAULT,"Cancel",0,5,DEFAULT,DEFAULT,DEFAULT,DEFAULT` GetPassword003=`065,049,056,012,EDITBOX,CurrentPass,DEFAULT,DEFAULT,1,16,DEFAULT,DEFAULT,DEFAULT` GetPassword004=`065,079,056,012,EDITBOX,NewPass,DEFAULT,DEFAULT,2,16,DEFAULT,DEFAULT,DEFAULT` GetPassword005=`005,007,131,032,VARYTEXT,Dialogtxt,DEFAULT,DEFAULT,6,0,"Microsoft Sans Serif|6144|40|34","0|0|0",DEFAULT` GetPassword006=`065,097,056,012,EDITBOX,NewPassConfirm,DEFAULT,DEFAULT,3,16,DEFAULT,DEFAULT,DEFAULT` GetPassword007=`015,049,046,012,STATICTEXT,DEFAULT,"Current Password:",DEFAULT,7,1024,DEFAULT,DEFAULT,DEFAULT` GetPassword008=`015,079,046,012,STATICTEXT,DEFAULT,"New Password:",DEFAULT,8,1024,DEFAULT,DEFAULT,DEFAULT` GetPassword009=`015,097,046,012,STATICTEXT,DEFAULT,"Confirm Password:",DEFAULT,9,1024,DEFAULT,DEFAULT,DEFAULT` return
Article ID: W16325
File Created: 2005:02:18:12:19:48
Last Updated: 2005:02:18:12:19:48