diff --git a/plugins/guests/windows/cap/change_host_name.rb b/plugins/guests/windows/cap/change_host_name.rb index 6b1af2b8a..9902c8565 100644 --- a/plugins/guests/windows/cap/change_host_name.rb +++ b/plugins/guests/windows/cap/change_host_name.rb @@ -2,11 +2,24 @@ module VagrantPlugins module GuestWindows module Cap module ChangeHostName + def self.change_host_name(machine, name) - # On windows, renaming a computer seems to require a reboot - machine.communicate.execute( - "wmic computersystem where name=\"%COMPUTERNAME%\" call rename name=\"#{name}\"", - shell: :cmd) + change_host_name_and_wait(machine, name, machine.config.vm.graceful_halt_timeout) + end + + def self.change_host_name_and_wait(machine, name, sleep_timeout) + # If the configured name matches the current name, then bail + return if machine.communicate.test("if ($env:ComputerName -eq '#{name}') { exit 0 } exit 1") + + # Rename and then reboot in one step + exit_code = machine.communicate.execute( + "netdom renamecomputer \"$Env:COMPUTERNAME\" /NewName:#{name} /Force /Reboot:0", + error_check: false) + + raise Errors::RenameComputerFailed if exit_code != 0 + + # Don't continue until the machine has shutdown and rebooted + sleep(sleep_timeout) end end end diff --git a/plugins/guests/windows/errors.rb b/plugins/guests/windows/errors.rb index ca1e3fb36..d5be14ce6 100644 --- a/plugins/guests/windows/errors.rb +++ b/plugins/guests/windows/errors.rb @@ -13,6 +13,10 @@ module VagrantPlugins class NetworkWinRMRequired < WindowsError error_key(:network_winrm_required) end + + class RenameComputerFailed < WindowsError + error_key(:rename_computer_failed) + end end end end diff --git a/templates/locales/guest_windows.yml b/templates/locales/guest_windows.yml index 4f247930d..a648f5a09 100644 --- a/templates/locales/guest_windows.yml +++ b/templates/locales/guest_windows.yml @@ -1,5 +1,5 @@ en: - vagrant_winrm: + vagrant_windows: errors: cant_read_mac_addresses: |- The provider being used to start Windows ('%{provider}') @@ -18,3 +18,10 @@ en: Note that the Windows guest must be configured to accept insecure WinRM connections, and the WinRM port must be forwarded properly from the guest machine. This is not always done by default. + rename_computer_failed: |- + Renaming the Windows guest failed. Most often this is because you've + specified a FQDN instead of just a host name. + + Ensure the new guest name is properly formatted. Standard names may + contain letters (a-z, A-Z), numbers (0-9), and hypens (-), but no + spaces or periods (.). The name may not consist entirely of digits. diff --git a/test/unit/plugins/guests/windows/cap/change_host_name_test.rb b/test/unit/plugins/guests/windows/cap/change_host_name_test.rb index bf17d7854..b90df3d3f 100644 --- a/test/unit/plugins/guests/windows/cap/change_host_name_test.rb +++ b/test/unit/plugins/guests/windows/cap/change_host_name_test.rb @@ -8,7 +8,7 @@ describe "VagrantPlugins::GuestWindows::Cap::ChangeHostName" do end let(:machine) { double("machine") } let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) } - let(:old_hostname) {'oldhostname.olddomain.tld' } + let(:old_hostname) { 'oldhostname' } before do allow(machine).to receive(:communicate).and_return(communicator) @@ -19,11 +19,19 @@ describe "VagrantPlugins::GuestWindows::Cap::ChangeHostName" do end describe ".change_host_name" do - it "changes the hostname" do - communicator.expect_command('wmic computersystem where name="%COMPUTERNAME%" call rename name="newhostname.newdomain.tld"') - described_class.change_host_name(machine, 'newhostname.newdomain.tld') + communicator.stub_command('if (!($env:ComputerName -eq \'newhostname\')) { exit 0 } exit 1', exit_code: 0) + communicator.stub_command('netdom renamecomputer "$Env:COMPUTERNAME" /NewName:newhostname /Force /Reboot:0', + exit_code: 0) + described_class.change_host_name_and_wait(machine, 'newhostname', 0) end + it "raises RenameComputerFailed when exit code is non-zero" do + communicator.stub_command('if (!($env:ComputerName -eq \'newhostname\')) { exit 0 } exit 1', exit_code: 0) + communicator.stub_command('netdom renamecomputer "$Env:COMPUTERNAME" /NewName:newhostname /Force /Reboot:0', + exit_code: 123) + expect { described_class.change_host_name_and_wait(machine, 'newhostname', 0) }. + to raise_error(VagrantPlugins::GuestWindows::Errors::RenameComputerFailed) + end end end