Search code examples
expectchange-password

Expect script to change default password


I'm trying to build a simple Expect script to change the default password. Our admin forces us to change passwords immediately after deploying a new system in our cloud infrastructure. I want to build an Expect script because I have to do this across a few dozen systems.

The prompts look like this:

❯ ssh [email protected]
[email protected]'s password:
You are required to change your password immediately (administrator enforced)
Last login: Tue Aug 23 12:14:58 2022 from 10.123.45.67
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user root.
New password: 
Retype new password:
passwd: all authentication tokens updated successfully.
Connection to mysystem.company.com closed.

My expect script looks like this:

#! /usr/local/bin/expect -f

set timeout 60

set user [lindex $argv 0]
set host [lindex $argv 1]
set old [lindex $argv 2]
set new [lindex $argv 3]

spawn -noecho ssh -q -o StrictHostKeychecking=no "$user\@$host"

expect "password:"
send "$old\r"
expect "New password"
send "$new\r"
expect "Retype new password:"
send "$new\r"

That 1st expect statement is working, but I cannot figure out why the 2nd expect statement isn't working:

❯ expect spawn root mysystem.company.com oldPassword newPassword
[email protected]'s password: 
You are required to change your password immediately (administrator enforced)
Last login: Tue Aug 23 13:14:12 2022 from 10.123.45.67
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user root.
New password: %   

It immediately exits from the script once it reaches New password:. I've tried various things but not figuring this out.

Please help!


It was suggested to re-run with -d (debug) enabled. The output appears to show its working as expected (no pun intended), but the password wasn't actually changed. When I attempt to login, I'm prompted through the same steps. Maybe someone else can help interpret this output:

❯ expect -d spawn root mysystem.company.com lgmPjgY2xTJH 73a40HpVCgRey9fP
expect version 5.45
argv[0] = expect  argv[1] = -d  argv[2] = spawn  argv[3] = root  argv[4] = mysystem.company.com  argv[5] = lgmPjgY2xTJH  argv[6] = 73a40HpVCgRey9fP
set argc 4
set argv0 "spawn"
set argv "root mysystem.company.com lgmPjgY2xTJH 73a40HpVCgRey9fP"
executing commands from command file spawn
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {10930}

expect: does "" (spawn_id exp6) match glob pattern "password:"? no

expect: does "\r" (spawn_id exp6) match glob pattern "password:"? no
[email protected]'s password:
expect: does "\[email protected]'s password: " (spawn_id exp6) match glob pattern "password:"? yes
expect: set expect_out(0,string) "password:"
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\[email protected]'s password:"
send: sending "lgmPjgY2xTJH\r" to { exp6 }

expect: does " " (spawn_id exp6) match glob pattern "New password"? no


expect: does " \r\n" (spawn_id exp6) match glob pattern "New password"? no
You are required to change your password immediately (administrator enforced)
Last login: Wed Aug 24 20:01:38 2022 from 10.123.45.678
WARNING: Your password has expired.
You must change your password now and login again!

expect: does " \r\nYou are required to change your password immediately (administrator enforced)\r\nLast login: Wed Aug 24 20:01:38 2022 from 10.123.45.678\r\r\nWARNING: Your password has expired.\r\nYou must change your password now and login again!\r\n" (spawn_id exp6) match glob pattern "New password"? no
Changing password for user root.

expect: does " \r\nYou are required to change your password immediately (administrator enforced)\r\nLast login: Wed Aug 24 20:01:38 2022 from 10.123.45.678\r\r\nWARNING: Your password has expired.\r\nYou must change your password now and login again!\r\nChanging password for user root.\r\n" (spawn_id exp6) match glob pattern "New password"? no
New password:
expect: does " \r\nYou are required to change your password immediately (administrator enforced)\r\nLast login: Wed Aug 24 20:01:38 2022 from 10.123.45.678\r\r\nWARNING: Your password has expired.\r\nYou must change your password now and login again!\r\nChanging password for user root.\r\nNew password: " (spawn_id exp6) match glob pattern "New password"? yes
expect: set expect_out(0,string) "New password"
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) " \r\nYou are required to change your password immediately (administrator enforced)\r\nLast login: Wed Aug 24 20:01:38 2022 from 10.123.45.678\r\r\nWARNING: Your password has expired.\r\nYou must change your password now and login again!\r\nChanging password for user root.\r\nNew password"
send: sending "73a40HpVCgRey9fP\r" to { exp6 }

expect: does ": " (spawn_id exp6) match glob pattern "Retype new password:"? no


expect: does ": \r\n" (spawn_id exp6) match glob pattern "Retype new password:"? no
Retype new password:
expect: does ": \r\nRetype new password: " (spawn_id exp6) match glob pattern "Retype new password:"? yes
expect: set expect_out(0,string) "Retype new password:"
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) ": \r\nRetype new password:"
send: sending "73a40HpVCgRey9fP\r" to { exp6 }
❯ echo $?
0

Solution

  • According to the expect -d output, the script stopped after sending the password for the Retype new password: prompt.

    So just add expect eof at the end of the script.

    This is the most common mistake when using Expect. You must wait for the spawned program to finish.

    (credit goes to @sexpect)