I need to change the Passwords of an Active Directory account in windows 10 in VB.NET.
The program, I wrote, runs as local administrator,
My working code with a valid user account is (Domain_xps and UserName_xps are Strings and pwdPtr System.Runtime.InteropServices.Marshal.SecureStringToBSTR of a SecureString):
dEntry = New DirectoryServices.DirectoryEntry("LDAP://" & Domain_xps, UserName_xps
, System.Runtime.InteropServices.Marshal.PtrToStringBSTR(pwdPtr)
, System.DirectoryServices.AuthenticationTypes.Secure
+ System.DirectoryServices.AuthenticationTypes.Sealing
+ System.DirectoryServices.AuthenticationTypes.ServerBind) ',pwd)
nativeObject = dEntry.NativeObject
Dim searcher_Fullname_xpo As System.DirectoryServices.DirectorySearcher
= New System.DirectoryServices.DirectorySearcher(dEntry)
With searcher_Fullname_xpo
.Filter = "(&(objectClass=User) (sAMAccountName=" & UserName_xps & "))"
End With
result_xpo = searcher_Fullname_xpo.FindOne
Dim user As DirectoryServices.DirectoryEntry 'open directory
user = result_xpo.GetDirectoryEntry() 'get directory results
user.Username = UserName_xps
user.Password = PWD_xps
user.Path = result_xpo.GetDirectoryEntry().Path
user.AuthenticationType = System.DirectoryServices.AuthenticationTypes.Secure
+ System.DirectoryServices.AuthenticationTypes.Sealing
+ System.DirectoryServices.AuthenticationTypes.ServerBind
user.Options.PasswordPort = 389
user.Options.PasswordEncoding = 1
user.Invoke("ChangePassword", New Object() {PWD_xps, PWDNeu_xps})
user.CommitChanges() 'commit changes
user.Close() 'close directory
But if a account has expired through holidays or if a new user with a one time password is generated and tries to change his password, i get an error.
The user or password are wrong.
while debugging i noticed, that following lines produce the same error.
nativeObject = dEntry.NativeObject
Dim searcher_Fullname_xpo As System.DirectoryServices.DirectorySearcher = New System.DirectoryServices.DirectorySearcher(dEntry)
With searcher_Fullname_xpo
.Filter = "(&(objectClass=User) (sAMAccountName=" & UserName_xps & "))"
End With
result_xpo = searcher_Fullname_xpo.FindOne
And also
user.Options.PasswordPort = 389
user.Options.PasswordEncoding = 1
user.Invoke("ChangePassword", New Object() {PWD_xps, PWDNeu_xps})
each of these produce the error and doesn't change the password correctly, after encapsulating every line in a try catch expression.
Active Directory shows a change, but the user account is not valid any more.
I tried basically the same methods, in hope that i could set the options.
Dim ADS_OPTION_PASSWORD_PORTNUMBER As Long = 6
Dim ADS_OPTION_PASSWORD_METHOD As Long = 7
Dim ADS_PASSWORD_ENCODE_REQUIRE_SSL As Integer = 0
Dim ADS_PASSWORD_ENCODE_CLEAR As Integer = 1
Try
user.Invoke("SetOption", New Object() {ADS_OPTION_PASSWORD_PORTNUMBER, 389})
Catch ex3 As Exception
End Try
Try
user.Invoke("SetOption", New Object() {ADS_OPTION_PASSWORD_METHOD, ADS_PASSWORD_ENCODE_CLEAR})
Catch ex3 As Exception
End Try
And i tried also
user.Invoke("SetPassword", New Object() {PWDNeu_xps})
the error message stays the same
To set the password seems the right way, but as i can't set the password port or enable the password method, it produces the same error.
i also found this old thread How to change password in active directory when password expired
but that is not longer possible under windows 10.
How can i change the password, of an expired account with the needed options in VB Net or can i configure the account, so that it is possible to achieve it.
I also tried as workaround a powershell command as described in Microsoft or here for that matter.
And the same thing happens, the password change isn't possible,
Set-ADAccountPassword : The server has rejected the client credentials.
With a valid user the comand works as does it in DotNet
After long time struggling and long discussion with microsoft, it became clear that settings a passowrd without having an user account that has right privileges, would ot be possible with Dot Net.
So i experimented further and found a practicable solution with a posershell comand.
you need to install the Active directory package for powershell see https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps
you need an Active directory user that can set password(ideally nothing more). as the password has to be saved on the computer where app is run from, it must comply with the password rules and should be changed according to SOPs regularly. The computer where the app runs must be secured, so that only personal with clearance can access it and run the program.
The rest is a powershell command to change the password of a active directory user( AD), as i couldn't find any useful solution, you can find the command below.
Dim execProcess As New System.Diagnostics.Process
Dim psScriptTextArg = "-command " & Chr(34) & "$Credential = New-Object System.Management.Automation.PSCredential ('" & Domain_xps & "\" & superuserName_xps _
& "' , (ConvertTo-SecureString -AsPlainText '" & SuperuserPWD_xps & "' -Force));" _
& "Set-ADAccountPassword -Server '" & Domain_xps &
"' -Credential $Credential -Identity '" & UserName_xps & "' -OldPassword (ConvertTo-SecureString -AsPlainText '" & PWD_xps &
"' -Force) -NewPassword (ConvertTo-SecureString -AsPlainText '" & PWDNeu_xps & "' -Force)" & Chr(34)
powershell_xps = psScriptTextArg
execProcess.StartInfo.FileName = "powershell.exe"
execProcess.StartInfo.Arguments = psScriptTextArg
execProcess.StartInfo.UseShellExecute = True
execProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
execProcess.Start()
if the computer has restricted access, the risk is acceptable and the evry user can set his own password even if his password was expired, without calling the it support.