Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support running PowerShell within Constrained Language Mode #12687

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions lib/vagrant/util/platform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ def windows?
# privileges.
#
# From: https://support.microsoft.com/en-us/kb/243330
# SID: S-1-5-19
# SID: S-1-5-32-544
# Name: Administrators
#
# @return [Boolean]
def windows_admin?
return @_windows_admin if defined?(@_windows_admin)

@_windows_admin = -> {
ps_cmd = '(new-object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)'
ps_cmd = '$x = (Get-LocalGroupMember -SID "S-1-5-32-544" | where Name -eq $(Get-WMIObject -class Win32_ComputerSystem | select username).username); if ($x){ Write-Output "True"}'
output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
return output == 'True'
}.call
Expand All @@ -105,6 +105,13 @@ def windows_hyperv_admin?
return @_windows_hyperv_admin = true
end

ps_cmd = "$x = (Get-LocalGroupMember -SID 'S-1-5-32-578' | where Name -eq $(Get-WMIObject -class Win32_ComputerSystem | select username).username); if ($x){ Write-Output 'true'}"
output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
return @_windows_hyperv_admin = true if output == "true"

# This won't work in constrained language mode, but there is no easy way to replicate.
# Leaving it as is because the most likley two cases (user is in administrators or hyperv administrators group)
# are already checked, so this script is unlikley to be required.
ps_cmd = "Write-Output ([System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | " \
"Select-Object Value | ConvertTo-JSON)"
output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
Expand All @@ -115,16 +122,15 @@ def windows_hyperv_admin?
[]
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"))
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'}"
ps_cmd = "if ((Get-VMHost).Name.StartsWith($env:computername)){ Write-Output 'true'}"
output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
result = output == "true"

Expand Down
24 changes: 3 additions & 21 deletions plugins/providers/hyperv/scripts/get_vm_status.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,14 @@ param(
[string]$VmId
)

# Make sure the exception type is loaded
try
{
# Microsoft.HyperV.PowerShell is present on all versions of Windows with HyperV
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.HyperV.PowerShell, Culture=neutral, PublicKeyToken=31bf3856ad364e35')
# Microsoft.HyperV.PowerShell.Objects is only present on Windows >= 10.0, so this will fail, and we ignore it since the needed exception
# type was loaded in Microsoft.HyperV.PowerShell
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.HyperV.PowerShell.Objects, Culture=neutral, PublicKeyToken=31bf3856ad364e35')
} catch {
# Empty catch ok, since if we didn't load the types, we will fail in the next block
}

$VmmsPath = if ([environment]::Is64BitProcess) { "$($env:SystemRoot)\System32\vmms.exe" } else { "$($env:SystemRoot)\Sysnative\vmms.exe" }
$HyperVVersion = [version](Get-Item $VmmsPath).VersionInfo.ProductVersion

if($HyperVVersion -lt ([version]'10.0')) {
$ExceptionType = [Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException]
} else {
$ExceptionType = [Microsoft.HyperV.PowerShell.VirtualizationException]
}
try {
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
$State = $VM.state
$Status = $VM.status
} catch [Exception] {
if($_.Exception.GetType() -eq $ExceptionType)
# "ObjectNotFound" when Hyper-V >= 10 (Microsoft.HyperV.PowerShell.VirtualizationException)
# "NotSpecified" when Hyper-V < 10 (Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException)
if(("ObjectNotFound", "NotSpecified") -Contains $_.Exception.ErrorCategory)
{
$State = "not_created"
$Status = $State
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Always stop when errors are encountered unless instructed not to
$ErrorActionPreference = "Stop"

# Vagrant VM creation functions

function New-VagrantVM {
Expand All @@ -18,7 +17,7 @@ function New-VagrantVM {
[parameter(Mandatory=$false)]
[string] $VMName
)
if([IO.Path]::GetExtension($VMConfigFile).ToLower() -eq ".xml") {
if($VMConfigFile.EndsWith(".xml", "CurrentCultureIgnoreCase")) {
return New-VagrantVMXML @PSBoundParameters
} else {
return New-VagrantVMVMCX @PSBoundParameters
Expand Down Expand Up @@ -85,6 +84,7 @@ function New-VagrantVMVMCX {
VhdDestinationPath = Join-Path $DataPath "Virtual Hard Disks";
VirtualMachinePath = $DataPath;
}

$VMConfig = (Hyper-V\Compare-VM -Copy -GenerateNewID @NewVMConfig -ErrorAction SilentlyContinue)

# If the config is empty it means the import failed. Attempt to provide
Expand Down Expand Up @@ -122,7 +122,7 @@ function New-VagrantVMVMCX {
}
foreach($Controller in $Controllers) {
foreach($Drive in $Controller.Drives) {
if([System.IO.Path]::GetFileName($Drive.Path) -eq [System.IO.Path]::GetFileName($SourcePath)) {
if((Split-Path -Leaf $Drive.Path) -eq (Split-Path -Leaf $SourcePath)) {
$Path = $Drive.Path
Hyper-V\Remove-VMHardDiskDrive $Drive
Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath -Differencing
Expand Down Expand Up @@ -729,8 +729,10 @@ function Check-VagrantHyperVAccess {
[string] $Path
)
$acl = Get-ACL -Path $Path
$systemAccount = [wmi]"Win32_SID.SID='S-1-5-18'"
$localisedAccount = $systemAccount.ReferencedDomainName + "\" + $systemAccount.AccountName
$systemACL = $acl.Access | where {
try { return $_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value -eq "S-1-5-18" } catch { return $false } -and
$_.IdentityReference.Value -eq $localisedAccount -and
$_.FileSystemRights -eq "FullControl" -and
$_.AccessControlType -eq "Allow" -and
$_.IsInherited -eq $true}
Expand Down
6 changes: 4 additions & 2 deletions test/unit/vagrant/util/platform_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,20 +230,22 @@

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::PowerShell).to receive(:execute_cmd).with(/S-1-5-32-578/).and_return("true")
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::PowerShell).to receive(:execute_cmd).with(/S-1-5-32-578/).and_return(nil)
expect(Vagrant::Util::PowerShell).to receive(:execute_cmd).with(/GetCurrent/).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(/S-1-5-32-578/).and_return(nil)
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
Expand Down