From bf7094158696b62a135c6d18f4884f4e16431908 Mon Sep 17 00:00:00 2001 From: Cameron Jack Date: Wed, 16 Feb 2022 20:52:07 +1100 Subject: [PATCH 1/4] Remove unreferenced code --- .../hyperv/common/powershell/powershell.go | 31 -------- builder/hyperv/common/step_configure_ip.go | 77 ------------------- 2 files changed, 108 deletions(-) delete mode 100644 builder/hyperv/common/step_configure_ip.go diff --git a/builder/hyperv/common/powershell/powershell.go b/builder/hyperv/common/powershell/powershell.go index 241c8e4a..dd083da2 100644 --- a/builder/hyperv/common/powershell/powershell.go +++ b/builder/hyperv/common/powershell/powershell.go @@ -338,34 +338,3 @@ return $generation return generation, err } - -func SetUnattendedProductKey(path string, productKey string) error { - - var script = ` -param([string]$path,[string]$productKey) - -$unattend = [xml](Get-Content -Path $path) -$ns = @{ un = 'urn:schemas-microsoft-com:unattend' } - -$setupNode = $unattend | - Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | - Select-Object -ExpandProperty Node - -$productKeyNode = $setupNode | - Select-Xml -XPath '//un:ProductKey' -Namespace $ns | - Select-Object -ExpandProperty Node - -if ($productKeyNode -eq $null) { - $productKeyNode = $unattend.CreateElement('ProductKey', $ns.un) - [Void]$setupNode.AppendChild($productKeyNode) -} - -$productKeyNode.InnerText = $productKey - -$unattend.Save($path) -` - - var ps PowerShellCmd - err := ps.Run(script, path, productKey) - return err -} diff --git a/builder/hyperv/common/step_configure_ip.go b/builder/hyperv/common/step_configure_ip.go deleted file mode 100644 index 7126e144..00000000 --- a/builder/hyperv/common/step_configure_ip.go +++ /dev/null @@ -1,77 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepConfigureIp struct { -} - -func (s *StepConfigureIp) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error configuring ip address: %s" - vmName := state.Get("vmName").(string) - - ui.Say("Configuring ip address...") - - count := 60 - var duration time.Duration = 1 - sleepTime := time.Minute * duration - var ip string - - for count != 0 { - cmdOut, err := driver.GetVirtualMachineNetworkAdapterAddress(vmName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ip = strings.TrimSpace(cmdOut) - - if ip != "False" { - break - } - - log.Println(fmt.Sprintf("Waiting for another %v minutes...", uint(duration))) - time.Sleep(sleepTime) - count-- - } - - if count == 0 { - err := fmt.Errorf(errorMsg, "IP address assigned to the adapter is empty") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("ip address is " + ip) - - hostName, err := driver.GetHostName(ip) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("hostname is " + hostName) - - state.Put("ip", ip) - state.Put("hostname", hostName) - - return multistep.ActionContinue -} - -func (s *StepConfigureIp) Cleanup(state multistep.StateBag) { - // do nothing -} From 626b244033b3cc4b4c0a75174b7d436214f4d94f Mon Sep 17 00:00:00 2001 From: Cameron Jack Date: Wed, 16 Feb 2022 21:04:18 +1100 Subject: [PATCH 2/4] Remove code that rewrites VMCX to XML. This would need modifications to work in constrained language mode but also seems fragile. Is this conversion still required since VMCX has been the default since Server 2016? --- .../hyperv/common/powershell/hyperv/hyperv.go | 94 ------------------- 1 file changed, 94 deletions(-) diff --git a/builder/hyperv/common/powershell/hyperv/hyperv.go b/builder/hyperv/common/powershell/hyperv/hyperv.go index d5c05c16..9ead35dd 100644 --- a/builder/hyperv/common/powershell/hyperv/hyperv.go +++ b/builder/hyperv/common/powershell/hyperv/hyperv.go @@ -742,100 +742,6 @@ func ExportVirtualMachine(vmName string, path string) error { var script = ` param([string]$vmName, [string]$path) Hyper-V\Export-VM -Name $vmName -Path $path - -if (Test-Path -Path ([IO.Path]::Combine($path, $vmName, 'Virtual Machines', '*.VMCX'))) -{ - $vm = Hyper-V\Get-VM -Name $vmName - $vm_adapter = Hyper-V\Get-VMNetworkAdapter -VM $vm | Select -First 1 - - $config = [xml]@" - - - - $($vm.Generation - 1) - $($vm.Name) - - - - $($vm.ProcessorCount) - - - - $($vm.DynamicMemoryEnabled) - $($vm.MemoryMaximum / 1MB) - $($vm.MemoryMinimum / 1MB) - $($vm.MemoryStartup / 1MB) - - - - $($vm_adapter.SwitchName) - - Optical - - False - MicrosoftWindows - $($vm.Notes) - - -"@ - - if ($vm.Generation -eq 1) - { - $vm_controllers = Hyper-V\Get-VMIdeController -VM $vm - $controller_type = $config.SelectSingleNode('/configuration/vm-controllers') - # IDE controllers are not stored in a special XML container - } - else - { - $vm_controllers = Hyper-V\Get-VMScsiController -VM $vm - $controller_type = $config.CreateElement('scsi') - $controller_type.SetAttribute('ChannelInstanceGuid', 'x') - # SCSI controllers are stored in the scsi XML container - if ((Hyper-V\Get-VMFirmware -VM $vm).SecureBoot -eq [Microsoft.HyperV.PowerShell.OnOffState]::On) - { - $config.configuration.secure_boot_enabled.'#text' = 'True' - $config.configuration.secure_boot_template.'#text' = (Hyper-V\Get-VMFirmware -VM $vm).SecureBootTemplate - } - else - { - $config.configuration.secure_boot_enabled.'#text' = 'False' - } - } - - $vm_controllers | ForEach { - $controller = $config.CreateElement('controller' + $_.ControllerNumber) - $_.Drives | ForEach { - $drive = $config.CreateElement('drive' + ($_.DiskNumber + 0)) - $drive_path = $config.CreateElement('pathname') - $drive_path.SetAttribute('type', 'string') - $drive_path.AppendChild($config.CreateTextNode($_.Path)) - $drive_type = $config.CreateElement('type') - $drive_type.SetAttribute('type', 'string') - if ($_ -is [Microsoft.HyperV.PowerShell.HardDiskDrive]) - { - $drive_type.AppendChild($config.CreateTextNode('VHD')) - } - elseif ($_ -is [Microsoft.HyperV.PowerShell.DvdDrive]) - { - $drive_type.AppendChild($config.CreateTextNode('ISO')) - } - else - { - $drive_type.AppendChild($config.CreateTextNode('NONE')) - } - $drive.AppendChild($drive_path) - $drive.AppendChild($drive_type) - $controller.AppendChild($drive) - } - $controller_type.AppendChild($controller) - } - if ($controller_type.Name -ne 'vm-controllers') - { - $config.SelectSingleNode('/configuration/vm-controllers').AppendChild($controller_type) - } - - $config.Save([IO.Path]::Combine($path, $vm.Name, 'Virtual Machines', 'box.xml')) -} ` var ps powershell.PowerShellCmd From b924dab6d84327254b3fa9129bad53a701f1a6ad Mon Sep 17 00:00:00 2001 From: Cameron Jack Date: Wed, 16 Feb 2022 21:06:23 +1100 Subject: [PATCH 3/4] Changing TypeScanCodes to work in constrained language mode, removing much of what was not used --- .../hyperv/common/powershell/hyperv/hyperv.go | 112 +----------------- 1 file changed, 6 insertions(+), 106 deletions(-) diff --git a/builder/hyperv/common/powershell/hyperv/hyperv.go b/builder/hyperv/common/powershell/hyperv/hyperv.go index 9ead35dd..986e95dc 100644 --- a/builder/hyperv/common/powershell/hyperv/hyperv.go +++ b/builder/hyperv/common/powershell/hyperv/hyperv.go @@ -1298,9 +1298,9 @@ func TypeScanCodes(vmName string, scanCodes string) error { param([string]$vmName, [string]$scanCodes) #Requires -Version 3 - function Hyper-V\Get-VMConsole + function Hyper-V\Get-VMKeyboard { - [CmdletBinding()] + [OutputType([CimInstance])] param ( [Parameter(Mandatory)] [string] $VMName @@ -1327,106 +1327,10 @@ param([string]$vmName, [string]$scanCodes) Write-Error ("VirtualMachine({0}) keyboard class is not found!" -f $VMName) } - #TODO: It may be better using New-Module -AsCustomObject to return console object? - - #Console object to return - $console = [pscustomobject] @{ - Msvm_ComputerSystem = $vm - Msvm_Keyboard = $vmKeyboard - } - - #Need to import assembly to use System.Windows.Input.Key - Add-Type -AssemblyName WindowsBase - - #region Add Console Members - $console | Add-Member -MemberType ScriptMethod -Name TypeText -Value { - [OutputType([bool])] - param ( - [ValidateNotNullOrEmpty()] - [Parameter(Mandatory)] - [string] $AsciiText - ) - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeText" -Arguments @{ asciiText = $AsciiText } - return (0 -eq $result.ReturnValue) - } - - #Define method:TypeCtrlAltDel - $console | Add-Member -MemberType ScriptMethod -Name TypeCtrlAltDel -Value { - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeCtrlAltDel" - return (0 -eq $result.ReturnValue) - } - - #Define method:TypeKey - $console | Add-Member -MemberType ScriptMethod -Name TypeKey -Value { - [OutputType([bool])] - param ( - [Parameter(Mandatory)] - [Windows.Input.Key] $Key, - [Windows.Input.ModifierKeys] $ModifierKey = [Windows.Input.ModifierKeys]::None - ) - - $keyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey($Key) - - switch ($ModifierKey) - { - ([Windows.Input.ModifierKeys]::Control){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftCtrl)} - ([Windows.Input.ModifierKeys]::Alt){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftAlt)} - ([Windows.Input.ModifierKeys]::Shift){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftShift)} - ([Windows.Input.ModifierKeys]::Windows){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LWin)} - } - - if ($ModifierKey -eq [Windows.Input.ModifierKeys]::None) - { - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } - } - else - { - $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "PressKey" -Arguments @{ keyCode = $modifierKeyCode } - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } - $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "ReleaseKey" -Arguments @{ keyCode = $modifierKeyCode } - } - $result = return (0 -eq $result.ReturnValue) - } - - #Define method:Scancodes - $console | Add-Member -MemberType ScriptMethod -Name TypeScancodes -Value { - [OutputType([bool])] - param ( - [Parameter(Mandatory)] - [byte[]] $ScanCodes - ) - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $ScanCodes } - return (0 -eq $result.ReturnValue) - } - - #Define method:ExecCommand - $console | Add-Member -MemberType ScriptMethod -Name ExecCommand -Value { - param ( - [Parameter(Mandatory)] - [string] $Command - ) - if ([String]::IsNullOrEmpty($Command)){ - return - } - - $console.TypeText($Command) > $null - $console.TypeKey([Windows.Input.Key]::Enter) > $null - #sleep -Milliseconds 100 - } - - #Define method:Dispose - $console | Add-Member -MemberType ScriptMethod -Name Dispose -Value { - $this.Msvm_ComputerSystem.Dispose() - $this.Msvm_Keyboard.Dispose() - } - - - #endregion - - return $console + return $vmKeyboard } - $vmConsole = Hyper-V\Get-VMConsole -VMName $vmName + $vmKeyboard = Hyper-V\Get-VMKeyboard -VMName $vmName $scanCodesToSend = '' $scanCodes.Split(' ') | %{ $scanCode = $_ @@ -1440,9 +1344,7 @@ param([string]$vmName, [string]$scanCodes) if ($scanCodesToSend){ $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) - $scanCodesToSendByteArray | %{ - $vmConsole.TypeScancodes($_) - } + $vmKeyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $scanCodesToSendByteArray } } write-host "Special code found, will sleep $timeToWait second(s) at this point." @@ -1462,9 +1364,7 @@ param([string]$vmName, [string]$scanCodes) if ($scanCodesToSend){ $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) - $scanCodesToSendByteArray | %{ - $vmConsole.TypeScancodes($_) - } + $vmKeyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $scanCodesToSendByteArray } } ` From e4fe68bd66f23f5a6453ac4bd0b5aa6836f3f3ef Mon Sep 17 00:00:00 2001 From: Cameron Jack Date: Wed, 16 Feb 2022 21:08:43 +1100 Subject: [PATCH 4/4] Modifying PowerShell to work in Constrained Language Mode --- builder/hyperv/common/driver_ps_4.go | 6 +----- .../hyperv/common/powershell/hyperv/hyperv.go | 18 +++++++++--------- builder/hyperv/common/powershell/powershell.go | 6 +----- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/builder/hyperv/common/driver_ps_4.go b/builder/hyperv/common/driver_ps_4.go index 2316eace..64893031 100644 --- a/builder/hyperv/common/driver_ps_4.go +++ b/builder/hyperv/common/driver_ps_4.go @@ -345,11 +345,7 @@ func (d *HypervPS4Driver) isCurrentUserAHyperVAdministrator() (bool, error) { //SID:S-1-5-32-578 = 'BUILTIN\Hyper-V Administrators' //https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems - var script = ` -$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() -$principal = new-object System.Security.Principal.WindowsPrincipal($identity) -$hypervrole = [System.Security.Principal.SecurityIdentifier]"S-1-5-32-578" -return $principal.IsInRole($hypervrole) + var script = `$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"} ` var ps powershell.PowerShellCmd diff --git a/builder/hyperv/common/powershell/hyperv/hyperv.go b/builder/hyperv/common/powershell/hyperv/hyperv.go index 986e95dc..d56b702e 100644 --- a/builder/hyperv/common/powershell/hyperv/hyperv.go +++ b/builder/hyperv/common/powershell/hyperv/hyperv.go @@ -758,11 +758,11 @@ param([string]$srcPath, [string]$dstPath) $srcPath, $dstPath | % { if ($_) { if (! (Test-Path $_)) { - [System.Console]::Error.WriteLine("Path $_ does not exist") + Write-Error -Message "Path $_ does not exist." -Category ObjectNotFound exit } } else { - [System.Console]::Error.WriteLine("A supplied path is empty") + Write-Error -Message "A supplied path is empty" -Category ObjectNotFound exit } } @@ -775,7 +775,7 @@ Move-Item -Path (Join-Path (Get-Item $srcPath).FullName "*.*") -Destination (Get $dirObj = Get-ChildItem $srcPath -Directory | % { New-Object PSObject -Property @{ FullName=$_.FullName; - HasContent=$(if ($_.GetFileSystemInfos().Count -gt 0) {$true} else {$false}) + HasContent=$(if (Get-ChildItem $_.FullName | measure | %{$_.Count -gt 0}) {$true} else {$false}) } } foreach ($directory in $dirObj) { @@ -787,14 +787,14 @@ foreach ($directory in $dirObj) { } # Only remove the source directory if it is now empty -if ( $((Get-Item $srcPath).GetFileSystemInfos().Count) -eq 0 ) { +if (Get-ChildItem $srcPath | measure | %{$_.Count -eq 0}) { Remove-Item -Path $srcPath } else { # 'Return' an error message to PowerShellCmd as the directory should # always be empty at the end of the script. The check is here to stop # the Remove-Item command from doing any damage if some unforeseen # error has occured - [System.Console]::Error.WriteLine("Refusing to remove $srcPath as it is not empty") + Write-Error -Message "Refusing to remove $srcPath as it is not empty." -Category ResourceExists exit } ` @@ -815,11 +815,11 @@ param([string]$srcPath, [string]$dstPath) $srcPath, $dstPath | % { if ($_) { if (! (Test-Path $_)) { - [System.Console]::Error.WriteLine("Path $_ does not exist") + Write-Error -Message "Path $_ does not exist." -Category ObjectNotFound exit } } else { - [System.Console]::Error.WriteLine("A supplied path is empty") + Write-Error -Message "A supplied path is empty." -Category ObjectNotFound exit } } @@ -831,7 +831,7 @@ $dstPathAbs = (Get-Item($dstPath)).FullName # Get the full path to all disks under the directory or exit if none are found $disks = Get-ChildItem -Path $srcPathAbs -Recurse -Filter *.vhd* -ErrorAction SilentlyContinue | % { $_.FullName } if ($disks.Length -eq 0) { - [System.Console]::Error.WriteLine("No disks found under $srcPathAbs") + Write-Error -Message "No disks found under $srcPathAbs." -Category ObjectNotFound exit } @@ -876,7 +876,7 @@ foreach ($disk in $disks) { if ($sizeAfter -gt 0) { # Protect against division by zero $percentChange = ( ( $sizeAfter / $sizeBefore ) * 100 ) - 100 switch($percentChange) { - {$_ -lt 0} {Write-Output "Disk size reduced by: $(([math]::Abs($_)).ToString("#.#"))%"} + {$_ -lt 0} {Write-Output "Disk size reduced by: $((-$_).ToString("#.#"))%"} {$_ -eq 0} {Write-Output "Disk size is unchanged"} {$_ -gt 0} {Write-Output "WARNING: Disk size increased by: $($_.ToString("#.#"))%"} } diff --git a/builder/hyperv/common/powershell/powershell.go b/builder/hyperv/common/powershell/powershell.go index dd083da2..349e0efc 100644 --- a/builder/hyperv/common/powershell/powershell.go +++ b/builder/hyperv/common/powershell/powershell.go @@ -201,11 +201,7 @@ try { } func IsCurrentUserAnAdministrator() (bool, error) { - var script = ` -$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() -$principal = new-object System.Security.Principal.WindowsPrincipal($identity) -$administratorRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator -return $principal.IsInRole($administratorRole) + var script = `$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"} ` var ps PowerShellCmd