diff --git a/lib/vagrant/util/platform.rb b/lib/vagrant/util/platform.rb index f57937428..b695546fe 100644 --- a/lib/vagrant/util/platform.rb +++ b/lib/vagrant/util/platform.rb @@ -79,24 +79,49 @@ module Vagrant return @_windows_admin end - # Checks if the user running Vagrant on Windows is a member of the - # "Hyper-V Administrators" group. + # Checks if Hyper-V is accessible to the local user. It will check + # if user is in the "Hyper-V Administrators" group, is a Domain + # administrator, and finally will run a manual interaction with + # Hyper-V to determine if Hyper-V is usable for the current user. # # From: https://support.microsoft.com/en-us/kb/243330 # SID: S-1-5-32-578 # Name: BUILTIN\Hyper-V Administrators + # SID: S-1-5-21DOMAIN-512 + # Name: Domain Admins # # @return [Boolean] def windows_hyperv_admin? return @_windows_hyperv_admin if defined?(@_windows_hyperv_admin) - @_windows_hyperv_admin = -> { - ps_cmd = "[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | ForEach-Object { if ($_.Value -eq 'S-1-5-32-578'){ Write-Host 'true'; break }}" - output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd) - return output == 'true' - }.call + if ENV["VAGRANT_IS_HYPERV_ADMIN"] + return @_windows_hyperv_admin = true + end - return @_windows_hyperv_admin + ps_cmd = "Write-Output ([System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | " \ + "Select-Object Value | ConvertTo-JSON)" + output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd) + if output + groups = begin + JSON.load(output) + rescue JSON::ParserError + [] + end + admin_group = groups.detect do |g| + g["Value"].to_s == "S-1-5-32-578" || + (g["Value"].start_with?("S-1-5-21") && g["Value"].to_s.end_with?("-512")) + end + + if admin_group + return @_windows_hyperv_admin = true + end + end + + ps_cmd = "$x = (Get-VMHost).Name; if($x -eq [System.Net.Dns]::GetHostName()){ Write-Output 'true'}" + output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd) + result = output == "true" + + return @_windows_hyperv_admin = result end # Checks if Hyper-V is enabled on the host system and returns true diff --git a/test/unit/vagrant/util/platform_test.rb b/test/unit/vagrant/util/platform_test.rb index 7aaa9dd85..82721b0e1 100644 --- a/test/unit/vagrant/util/platform_test.rb +++ b/test/unit/vagrant/util/platform_test.rb @@ -212,6 +212,44 @@ describe Vagrant::Util::Platform do end end + describe ".windows_hyperv_admin?" do + before { allow(Vagrant::Util::PowerShell).to receive(:execute_cmd).and_return(nil) } + + it "should return false when user is not in groups and cannot access Hyper-V" do + expect(Vagrant::Util::Platform.windows_hyperv_admin?).to be_falsey + end + + context "when VAGRANT_IS_HYPERV_ADMIN environment variable is set" do + before { allow(ENV).to receive(:[]).with("VAGRANT_IS_HYPERV_ADMIN").and_return("1") } + + it "should return true" do + expect(Vagrant::Util::Platform.windows_hyperv_admin?).to be_truthy + end + end + + context "when user is in the Hyper-V administators group" do + it "should return true" do + expect(Vagrant::Util::PowerShell).to receive(:execute_cmd).and_return(["Value" => "S-1-5-32-578"].to_json) + expect(Vagrant::Util::Platform.windows_hyperv_admin?).to be_truthy + end + end + + context "when user is in the Domain Admins group" do + it "should return true" do + expect(Vagrant::Util::PowerShell).to receive(:execute_cmd).and_return(["Value" => "S-1-5-21-000-000-000-512"].to_json) + expect(Vagrant::Util::Platform.windows_hyperv_admin?).to be_truthy + end + end + + context "when user has access to Hyper-V" do + it "should return true" do + expect(Vagrant::Util::PowerShell).to receive(:execute_cmd).with(/GetCurrent/).and_return(nil) + expect(Vagrant::Util::PowerShell).to receive(:execute_cmd).with(/Get-VMHost/).and_return("true") + expect(Vagrant::Util::Platform.windows_hyperv_admin?).to be_truthy + end + end + end + describe ".windows_hyperv_enabled?" do it "should return true if enabled" do allow(Vagrant::Util::PowerShell).to receive(:execute_cmd).and_return('Enabled') diff --git a/website/source/docs/other/environmental-variables.html.md b/website/source/docs/other/environmental-variables.html.md index 0ae2cc80b..6bca172bc 100644 --- a/website/source/docs/other/environmental-variables.html.md +++ b/website/source/docs/other/environmental-variables.html.md @@ -277,3 +277,10 @@ Vagrant will not display warning when `vagrant-winrm` plugin is installed. ## `VAGRANT_USER_AGENT_PROVISIONAL_STRING` Vagrant will append the contents of this variable to the default user agent header. + +## `VAGRANT_IS_HYPERV_ADMIN` + +Disable Vagrant's check for Hyper-V admin privileges and allow Vagrant to assume +the current user has full access to Hyper-V. This is useful if the internal +privilege check incorrectly determines the current user does not have access +to Hyper-V.