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 d5c05c16..d56b702e 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 @@ -852,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 } } @@ -869,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) { @@ -881,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 } ` @@ -909,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 } } @@ -925,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 } @@ -970,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("#.#"))%"} } @@ -1392,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 @@ -1421,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 = $_ @@ -1534,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." @@ -1556,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 } } ` diff --git a/builder/hyperv/common/powershell/powershell.go b/builder/hyperv/common/powershell/powershell.go index 241c8e4a..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 @@ -338,34 +334,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 -}