diff --git a/plugins/communicators/winrm/shell.rb b/plugins/communicators/winrm/shell.rb index 949908a79..e21399d2b 100644 --- a/plugins/communicators/winrm/shell.rb +++ b/plugins/communicators/winrm/shell.rb @@ -71,7 +71,13 @@ module VagrantPlugins def elevated(command, opts = {}, &block) connection.shell(:elevated) do |shell| shell.interactive_logon = opts[:interactive] || false - execute_with_rescue(shell, command, &block) + uname = shell.username + begin + shell.username = elevated_username + execute_with_rescue(shell, command, &block) + ensure + shell.username = uname + end end end @@ -216,6 +222,24 @@ module VagrantPlugins retry_delay: @config.retry_delay, retry_limit: @config.max_tries } end + + def elevated_username + if @elevated_username + return @elevated_username + end + if username.include?("\\") + return @elevated_username = username + end + computername = "" + powershell("Write-Output $env:computername") do |type, data| + computername << data if type == :stdout + end + computername.strip! + if computername.empty? + return @elevated_username = username + end + @elevated_username = "#{computername}\\#{username}" + end end #WinShell class end end diff --git a/test/unit/plugins/communicators/winrm/shell_test.rb b/test/unit/plugins/communicators/winrm/shell_test.rb index daffd48e0..9a32a5df8 100644 --- a/test/unit/plugins/communicators/winrm/shell_test.rb +++ b/test/unit/plugins/communicators/winrm/shell_test.rb @@ -75,6 +75,14 @@ describe VagrantPlugins::CommunicatorWinRM::WinRMShell do end describe ".elevated" do + let(:username) { double("username") } + + before do + allow(subject).to receive(:elevated_username).and_return(username) + allow(shell).to receive(:username).and_return(username) + allow(shell).to receive(:username=) + end + it "should call winrm elevated" do expect(shell).to receive(:run).with("dir").and_return(output) expect(shell).to receive(:interactive_logon=).with(false) @@ -93,6 +101,13 @@ describe VagrantPlugins::CommunicatorWinRM::WinRMShell do expect { subject.powershell("dir") }.to raise_error( VagrantPlugins::CommunicatorWinRM::Errors::ExecutionError) end + + it "should use elevated username" do + expect(subject).to receive(:elevated_username).and_return(username) + expect(shell).to receive(:run).with("dir").and_return(output) + expect(shell).to receive(:interactive_logon=).with(false) + expect(subject.elevated("dir").exitcode).to eq(0) + end end describe ".cmd" do @@ -178,4 +193,41 @@ describe VagrantPlugins::CommunicatorWinRM::WinRMShell do end end + describe "#elevated_username" do + let(:username) { "username" } + + before do + allow(subject).to receive(:username).and_return(username) + allow(subject).to receive(:powershell) + end + + it "should return username" do + expect(subject.send(:elevated_username)).to eq(username) + end + + it "should attempt to get computer name" do + expect(subject).to receive(:powershell).with(/computername/) + subject.send(:elevated_username) + end + + it "should prepend computer name when available" do + expect(subject).to receive(:powershell).with(/computername/).and_yield(:stdout, "COMPUTERNAME") + expect(subject.send(:elevated_username)).to eq("COMPUTERNAME\\#{username}") + end + + it "should only compute elevated username once" do + expect(subject).to receive(:powershell).once.with(/computername/).and_yield(:stdout, "COMPUTERNAME") + expect(subject.send(:elevated_username)).to eq("COMPUTERNAME\\#{username}") + expect(subject.send(:elevated_username)).to eq("COMPUTERNAME\\#{username}") + end + + context "when username includes computer/domain name" do + let(:username) { "machine\\username" } + + it "should not attempt to get computer name" do + expect(subject).not_to receive(:powershell) + expect(subject.send(:elevated_username)).to eq(username) + end + end + end end