Link to home
Start Free TrialLog in
Avatar of missymadi
missymadi

asked on

How to run Powershell script on all Servers in domain?

Experts,

        I have an existing script that resets a users password. I would like to attach to all of the servers in our domain and run this script from the PDC. How would I accomplish this task? I have made a few attempts but the logic was incorrect.
I think I need to have something like $servers = Get-Content c:\servers.txt. Also the part that I do not know how\where to code the credentials to access each server. The passwords must be encrypted.  When I tested the script by adding a test $servers = Get-Content c:\servers.txt the password was changed on the PDC and not the server I wanted to be connected to.

Please advise, Missymadi
# Ask for a username

$Username = Read-Host "Enter UserName"

# Search for the user(s)

$Users = Get-QADUser -SamAccountName $Username | Select-Object Name, DN, 
  PasswordLastSet, PasswordAge,PasswordExpires, PasswordNeverExpires, 
  UserMustChangePassword, PasswordIsExpired, PasswordStatus

# Display the user(s)

$Users

If ($Users) {

  # Ask if they wish to proceed

  $Response = Read-Host "Do you want to reset the user's password?`n[1] Yes, [2] No"

  If ($Response -eq "1") {

    # Ask for password 

    $SecurePassword1 = Read-Host "Please enter a password to use" -AsSecureString
    $SecurePassword2 = Read-Host "Please re-enter the password to confirm" -AsSecureString

    $Password1 = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
      [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword1))
    $Password2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
      [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword2))

    If ($Password1 -ne $Password2) {

      Write-Host "Passwords do not match. Aborting script." -ForegroundColor Red

    } Else {

      # Perform work

      # For each user we found earlier, set the password. Log a few things and the name of the 
      # user running this script 

      $Users | ForEach-Object { 
        Set-QADUser $_.DN -UserPassword $Password1
        Write-Host "Password reset for $($_.Name)"
      } | Select-Object SamAccountName, PasswordLastSet, @{n='SetBy';e={ $Env:Username }} |
        Out-File c:\PwdChanged.txt -Append
    }
  }
} Else {

  Write-Host "No users found" -ForegroundColor Red

}

Open in new window

Avatar of KenMcF
KenMcF
Flag of United States of America image

Are you trying to reset the local user passwords on all your Servers?
Avatar of missymadi
missymadi

ASKER

Yes.

I will need to reset local Admin and local users on each server.

I did find a script that changed Admin's password on each server and the concept is what I'm looking for as far as connecting to each Server and changing the passwords BUT I want to use my script above that allows the users(maintainer) control over the script.
The script I found that changes only local admin password on domain servers is attached.  I found out on the net.
$servers = Get-Content c:\servers.txt
$old_credential = $host.ui.PromptForCredential("Please enter OLD credentials", "Please enter OLD user name/password e.g. local\netserv", "", " NetBiosUserName")
$new_credential = $host.ui.PromptForCredential("Please enter NEW credentials", "Please enter NEW user name/password e.g. local\netserv", "", " NetBiosUserName")
$new_password = $new_credential.GetNetworkCredential()
$npu = $new_password.username
$npp = $new_password.password

foreach($server in $servers) {
    Try {
        Get-WmiObject win32_BIOS -Computername $server -Credential $old_credential -ErrorAction stop | Out-Null
        "Recognized password for $($old_credential.username) in computer $server"
        "Changing password for $($new_credential.username) in computer $server"
        $admin=[adsi]("WinNT://$server/$npu, user")
        $admin.psbase.invoke("SetPassword", $npp)
    }
    Catch {
        "NOT changing password for $($old_credential.username) in computer $server"
    }
}

Open in new window

ok, if you are looking to change local user name you can not use the quest cmdlets.  The script will need to use the below syntax instead of using get-qaduser and set-qaduser, these are only used for domain accounts. I will look through your script and see what all needs updated.


$admin=[adsi]("WinNT://$Server/$User, user")
$admin.psbase.invoke("SetPassword", $Password1)
Thank you! You guys are great!
Is it only the local administrator account you need to reset on each computer?

If it is then I do not understand why you need an input of the username. If it is not the lcoal administrator account then why do you need to use so many local user accounts on your servers and not domain accounts?
Local administrator and local user accounts.
Our setup is as follows:
no central user database, all users are maintained on each machine.
Are these all stand-alone server or are they in a AD domain? I would assume a domain since you said you want to run from a DC
AD domain. The user accounts are maintained by the AD.
ok, now I am really confused. Are these local account to each server or are they user account in AD that the password needs changed? If these are local accounts to each server then we will have to use what I posted before. If these are domain accounts we can use the Quest cmdlets and do not have to loop through a list of servers to change.
Sorry - our setup is quite different than most. But you actually helped me ..... I will need two scripts.
One using the cmdlets and one using the one you posted above. We have two separate LAN's one that has no central db so accounts are maintained on each machine. The other LAN is maintained by AD. One the one that has AD is very time sensitive and any discrepancies between Server/client will result in a user not being able to log in.

ok, let me look through the scripts and see what needs changed. For the servers that have local accounts, are these servers on the domain or are they stand alone?
They are stand alone.
resetting those may be a little difficult becuase you will need to specify a username and password to connect. So you will need to either prompt for a username and password or hard code one in the script. So you may want to have an account on each server for this so they are all the same username and password.
Could we prompt the user(maintainer) for the server connecion credentials? And could this be encrypted?
The script must be ONE script that resides on the PDC and can reset passwords on a domain and stand alone machines.
Our network is as follows:
One LAN consists of all users maintained on each machine (no central db) the OS is Linux, Linux thin client and monta vista. The other LAN consists of AD and VM's all Windows, VMware(esx) There is one firewall and switches.

Is it possible to create one script and access each machine from PDC? I imagine the script calling other scripts to create a connection to open sockets.

Please advise.
Missymadi
That makes it even more complicated. I assumed since you started out with using powershell and the quest cmdlets these were windows based computers. I am not very familiar with linux so I do not know how much help I can be. Can you give me an example of how you reset the passwords now on those computers? Do you do it remotly now for a single computer?
I can definitely use the Powershell script for the Windows machines and it's doing exactly what the requirements call for. So I will keep this one and use for the Windows machines.  

Right now we log into each machine separately. It is a strange mix of machines and we are looking for one script to reach all the servers and reset the password by prompting the user for server credentials then running the script to change username and password.
I posted this before and now I'm understanding this a little more, it will contact the machine from a list of hosts and make a connection through appropriate protocol to a waiting open socket then run the script that resides on that machine to reset the password. Does that make sense? Can you help me get there?  Here is an example I found below. This is just an example but I think this is what I need?

Thanks! Missymadi

#! /usr/bin/ksh
# Change_Password --- change the user's password on a list of hosts
#
#  You will need to adjust HOSTLIST.  You may need to adjust DELAY
#  and all of section 2.
#


#
#  Section 0 --- Set stuff up

HOSTLIST="test1 test2"
DELAY=3
stty -echo
print -n Enter Old Password-
read OLDPASS
print 
print -n Enter New Password-
read NEWPASS
print
stty echo
USER=$(whoami)
exec 4>&1


#
#  Section 1 --- Prove that we can talk with the hosts in HOSTLIST
#     Part 1 --- telnet to each and touch a file

for HOST in $HOSTLIST ; do
	telnet $HOST >&4 2>&4 |&
	sleep $DELAY
	print -p $USER
	sleep $DELAY
	print -p $OLDPASS
	sleep $DELAY
	print -p touch changepassdatafile.$HOST
	sleep $DELAY
	print -p exit
	wait
done

#
#  Section 1 --- Prove that we can talk with the hosts in HOSTLIST
#     Part 2 --- Retrieve the files via ftp

ftp -nv >&4 2>&4 |&
for HOST in $HOSTLIST ; do
	print -p open $HOST
	print -p user $USER $OLDPASS
	print -p get changepassdatafile.${HOST}
	print -p close
done
print -p bye
wait

#
#  Section 1 --- Prove that we can talk with the hosts in HOSTLIST
#     Part 3 --- Inspect the retrieved files

errors=0
for HOST in $HOSTLIST ; do
	if [[ -f changepassdatafile.${HOST} ]] ; then
		echo $HOST was ok
		rm changepassdatafile.${HOST}
	else
		echo $HOST has a problem
		((errors=errors+1))
	fi
done
((errors)) && exit 1

#
#  Section 2 --- Change the passwords

for HOST in $HOSTLIST ; do
    telnet $HOST >&4 2>&4 |&
    sleep $DELAY
    print -p $USER
    sleep $DELAY
    print -p $OLDPASS
    sleep $DELAY
    print -p passwd
    sleep $DELAY
    print -p $OLDPASS
    sleep $DELAY
    print -p $NEWPASS
    sleep $DELAY
    print -p $NEWPASS
    sleep $DELAY
    print -p exit
    wait
done

#
#  Section 3 --- Verify that the passwords were changed
#     Part 1 --- Retrieve those files via ftp again

ftp -nv >&4 2>&4 |&
for HOST in $HOSTLIST ; do
    print -p open $HOST
    print -p user $USER $NEWPASS
    print -p get changepassdatafile.${HOST}
    print -p delete changepassdatafile.${HOST}
    print -p close
done
print -p bye
wait

#
#  Section 3 --- Verify that the passwords were changed
#     Part 2 --- Inspect the retrieved files

errors=0
for HOST in $HOSTLIST ; do
    if [[ -f changepassdatafile.${HOST} ]] ; then
        rm changepassdatafile.${HOST}
    else
        echo $HOST has a problem!
        ((errors=errors+1))
    fi
done
((errors)) && exit 1


exit 0

Open in new window

But the hostlist script would run from windows not linux(in example)
That is a Linux shell script, I do not know enough about Linux and do not have anyway to test. You may need something like cygwin installed on your windows computer to run this. You will probably be better off to close this question and post a new one in a Linux Zone, they would be able to help you better than I can and a lot faster.

http://www.cygwin.com/
Could you still help me with the original question? I would need the two scripts - one for stand alone and one for AD to change the passwords. I will use these locally.

I do need the host list of servers script  , to be in Windows format because it needs to run on our Win2K3 (PDC) server. I'll post another question for this one.

Thanks for your help!
Missymadi
Yes I can help with that. These are the servers that are all in the domain correct? If that is the case we do not need to run against a list of servers, we can just change the password on the DC.
Yes they are in the domain. If it's not too much could  you provide the one that goes through a list of servers? Just curious to see how I would connect to a server not on a domain and run a script against it.

Thanks so much!
Yes, I will test this out tonight and post back.
missymadi

The script you posted will change a domain users password. Here is one that will loop through a list a servers and change a local users password.


# Ask for a username  
  
$Username = Read-Host "Enter UserName"  
$Servers = get-content C:\Servers.txt



$Servers | %{



    # Ask for password   
  
    $SecurePassword1 = Read-Host "Please enter a password to use" -AsSecureString  
    $SecurePassword2 = Read-Host "Please re-enter the password to confirm" -AsSecureString  
  
    $Password1 = [Runtime.InteropServices.Marshal]::PtrToStringAuto(  
      [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword1))  
    $Password2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto(  
      [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword2))  
  
    If ($Password1 -ne $Password2) {  
  
      Write-Host "Passwords do not match. Aborting script." -ForegroundColor Red  
  
    } Else {  

$admin = [adsi]("WinNT://$($_)/$($UserName), user")
Try{
$admin.SetPassword($Password1)
"The password for $($Username) was changed on $($_)"}
Catch{
"Failed to change password for $($Username) on $($_)"}  
}

Open in new window

Thanks for the response. Exactly what I needed except could we change instead of having a servers.txt, could we prompt the user for a computer?

Thanks! Missymadi
ASKER CERTIFIED SOLUTION
Avatar of KenMcF
KenMcF
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial