Use "Set-ADAccountPassword" to change own password - powershell

I'm writing a PS script to change an AD account's password by:
grabbing current user password from a Key Vault
Create a PSCredential $credential using the user's username and password obtained from KV
Generate new password in plain text and convert to secure string $newpass
Running Set-ADAccountPassword:
Set-ADAccountPassword -Identity "testuser" -Reset -NewPassword $newpass -Credential $credential
This fails with "Set-ADAccountPassword: Access is denied". The $credential object contains the current user's credentials which are valid (I'm testing this in advance).
As I understand it users have SELF as able to change their own password, as they can just CTRL+ALT+DEL to reset it. In this case, this account is not allowed interactive logins (so I can't test in a PS terminal using RUNAS), and powershell would be an easy wait to change the password periodically.
Why am I getting access denied, and is there a way around this?

There are two types of password update operations natively supported by AD:
Password Reset
In this operation, permission to update the account password is granted to an administrative user who can then set it without having to know the existing password
Password Change
In this operation, the calling user supplies the existing password as an argument, this authenticating the change - this is what you want!
When you specific the -Reset switch parameter, Set-ADAccountPassword takes it to mean you want to perform a password reset.
To perform a password change instead:
Remove the -Reset switch
Pass the existing password value as an argument to the -OldPassword parameter

Related

PowerShell script Scheduled Task change local user password value based on set password

I am working on a PowerShell script that would run in a Task Scheduler.
The way I want it to work is:
Default value is set to force user to change password at next logon:
net user su /logonpasswordchg:yes
Now the code would be something like:
$password = Azerty123!
if $password is different from $password
switch password from "user must change password at next logon" to "Password never expires"
else leave value to change password at next logon
After multiple tests I figured that the 2 following values would need to be switched based on the current password
Set-LocalUser -Name "su" -PasswordNeverExpires:$true
Set-LocalUser -Name "su" -PasswordNeverExpires:$false
net user su /logonpasswordchg:yes
net user su /logonpasswordchg:no
Basically the script is deployed with Intune, creates a Task Scheduler, it would check the password value every day one per day, if the password has been changed, the password value is changed to never expire, as long as the password as never been changed, leave it as change password at next logon.
Can anyone help me on this ? sorry for my clumsy explanations
Alternative approach could be to change the password expiry setting globally on Windows system.
This will apply to all users and can be done prior specific user changed their password. It can be accomplished by running following command:
net accounts /maxpwage:0
Note: check comments section to the answer for in depth discussion of other approaches

ChangePasswordAtLogon for LocalUser

I found this post helpful. PowerShell - User Must Change Password at Next Logon
Is it possible to force a user to set a password on next sign in by using something like this?
Set-LocalUser -ChangePasswordAtLogon:$true
I get a NamedParameter error when trying the script above.
What's the best way to force a local user account to reset a password upon login?
The Set-LocalUser cmdlet does not have a parameter ChangePasswordAtLogon
Try
Set-LocalUser -Name "TheUser" -PasswordNeverExpires $false
or use
$user = [ADSI]"WinNT://$env:ComputerName/TheUserName,user"
$user.PasswordExpired = 1
$user.SetInfo()
From how it looks, the Set-LocalUser doesn't have a force password change, the post you referenced is for ActiveDirectory users. Looking at this SuperUser post, there is a workaround using net user and wmic that you could code in PowerShell to emulate it:
Here's what I found worked for me on Windows 10 Home.
wmic UserAccount where name='John Doe' set Passwordexpires=true
Followed by
net user "John Doe" /logonpasswordchg:yes

Can I change my own password in Active Directory using Powershell

I am trying to change password for my own account in AD using powershell. My account is just a regular account (no domain admin rights)
I tried net user, dsquery and powershell cmdlets, but all of them errors out "Access is denied". I think all of those requires admin rights.
Is there a way to change my own password using powershell or cmd ?
Why I am doing that?
We have 8 different AD domains and I have an account in each. With different password expiration policies it is very difficult to remember all the passwords. So I want to do a script that connects to each domain with my user account in that domain and changes the password. I'll repeat that for all the domains.
If you have the Active Directory PowerShell Module installed, this is a pretty easy task using Set-ADAccountPassword.
You can use the -Server parameter to supply a different Domain Controller name from each Domain to set the password on that Domain.
$DomainControllers = "Domain1DC","Domain2DC","Domain3DC"
$MyName = "MyUserName"
ForEach ($DomainController In $DomainControllers) {
Set-AdAccountPassword -Identity $MyName -Server $DomainController
}
Set-ADUserAccountPassword used this way will prompt you for the old password then the new password for each domain controller.

How can I use powershell's read-host function to accept a password for an external service?

I have a script I'm writing that makes a connection to a SOAP service. After the connection is made, I need to pass in a the username/pass with every command I send. The problem I have is that when I use read-host to do this, my password is shown in cleartext and remains in the shell:
PS C:\Users\Egr> Read-Host "Enter Pass"
Enter Pass: MyPassword
MyPassword
If I hide it with -AsSecureString, the value can no longer be passed to the service because it is now a System.Security.SecureString object:
PS C:\Users\gross> Read-Host "Enter Pass" -AsSecureString
Enter Pass: **********
System.Security.SecureString
When I pass this, it does not work. I don't care about the passwords being passed to the service in cleartext, I just don't want them sticking around on a user's shell after they enter their password. Is it possible to hide the Read-Host input, but still have the password stored as cleartext? If not, is there a way I can pass the System.Security.SecureString object as cleartext?
Thanks
$Password is a Securestring, and this will return the plain text password.
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
You can save the password(input) as a variable and pass it to your service. If the code is run in a script or as a function, the variable containing the password will be deleted after it's done(they are stored in a temp. local scope). If you run the commands in the console(or dot-source the script like . .\myscript.ps1), the password variable will stay in the session scope, and they will be stored until you delete it or close the session. If you want to be sure the variable is removed after your script is run, you can delete it yourself. Like this:
#Get password in cleartext and store in $password variable
$password = Read-Host "Enter Pass"
#run code that needs password stored in $password
#Delete password
Remove-Variable password
To read more about how variables are stored in scopes, check out about_Scopes
There is a way to do this in PowerShell versions 6.x+:
$password = read-host -maskinput "Enter password"
, thanks to jborean93 for pointing this out to me.

Get current user's credentials object in Powershell without prompting

I have a Powershell script that is going to be run through an automation tool against multiple servers.
It works fine on Windows machines, as the remote calls use the tool's service account without any need for prompting or exposing any credentials in code.
This script also runs against Linux machines via SSH using the SharpSSH package. SharpSSH does not automatically use the Powershell user's credentials but requires either a username and password, an RSA key file, or a PSCredential object.
I can't prompt for credentials using Get-Credential, because it's being run through the automation tool. I don't want to expose the username and password in code or have an RSA key sitting out there. I would like to construct a PSCredential object from the current Powershell user (the service account).
Trying [System.Net.CredentialCache]::DefaultNetworkCredentials shows a blank, and [System.Security.Principal.WindowsIdentity]::GetCurrent() doesn't provide the object or information I need.
Does anyone have a method for creating a PSCredential object from the current user? Or maybe a completely different alternative for this problem?
Many thanks!
The Windows API will not expose the information you need, which is why Powershell can't get to them. Its an intentional feature of the security subsystem. The only way for this to work is for the Linux machines to trust the calling machine, such as joining them to an Active Directory (or any kerberos setup really).
Aside from that, you'd need to store and pass this information somehow.
You could store the RSA key in the user's keystore and extract it at runtime (using the .NET Crypto/Keystore libs), so you aren't storing the key around with the code. That way the key itself would be protected by the OS and available only when the calling user was authenticated. You'd have one more thing to install, but may be the only way to achieve what you are aiming for.
"Trying [System.Net.CredentialCache]::DefaultNetworkCredentials shows a blank, and [System.Security.Principal.WindowsIdentity]::GetCurrent() doesn't provide the object or information I need."
You already have your answer. I use this to pass the currently logged in user's credentials along in several scripts:
$Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$Username = $Credentials.UserName
$Password = $Credentials.Password
If you try to dump them to any kind of readable output, those values are empty when you dump them (for obvious security reasons), however they do work where you need a PSCredential object.
How about encrypting the password using the service account's encryption key?
A quick example:
Run PowerShell as the service account, run the following and save the output to a text file (or embed it in the scheduled task call):
$String = '<PASSWORD>'
ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String $String -AsPlainText -Force)
Use the following in your scheduled task in order to decrypt and utilize the password:
$EncryptedString = '<ENCRYPTED PASSWORD FROM ABOVE>'
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((ConvertTo-SecureString -String $EncryptedString)))
That should do the trick. You cannot reuse the encrypted password on a different computer, though, or if you for whatever reason destroy you local key store :)
Since you can get the password in plaintext from a credential object, I doubt you can get this without prompting.