Repository: crc-org/crc

Issue:
Implement 9P server support for libhvee
This is a follow-up to #3229, but will provide 9P support through the changes introduced by @mheon; via PR https://github.com/containers/gvisor-tap-vsock/pull/280. They will be moved to another repo which allows us to re-use it via libhvee and CRC

Discussion:
@gbraad: Not a spike anymore as changes has been introduced to Podman's codebase@cfergeau: The relevant code in podman is:
https://github.com/containers/podman/blob/main/cmd/podman/machine/client9p.go
https://github.com/containers/podman/blob/main/cmd/podman/machine/server9p.go
https://github.com/containers/podman/tree/main/pkg/fileserver@vyasgun: @cfergeau Just had a chat with @gbraad and I will also be looking into this.@cfergeau: 9p server code from podman is easy to reuse in crc, even more so with these changes https://github.com/cfergeau/podman/tree/9p
Then with https://github.com/cfergeau/crc/blob/f698247126d89819638f6db4975c2e6397a5853d/cmd/crc/cmd/daemon.go#L203-L212 a 9p share is started at daemon startup time, and is reachable from the guest on `192.168.127.1` on port `564`.

However the guest part is more problematic, while podman can use `mount -t 9p ...` to mount the share because it's using fedora, this is not working in our microshift/openshift images because they are RHEL-based, and don't provide support for 9p out of the box. As 9p support is getting more complicated than expected, imo we should be moving forward with https://github.com/crc-org/crc/pull/3824 without 9p support, and work on it as a follow-up.@gbraad: > we should be moving forward with https://github.com/crc-org/crc/pull/3824 without 9p support, and work on it as a follow-up.

Agree. I would even want to create a new issue for the 9P guest support.@redbeam: Results of 9P integration and server support are described in #4858.

Solution patch:
diff --git a/go.mod b/go.mod
index 570a910a0..06752f15f 100644
--- a/go.mod
+++ b/go.mod
@@ -11,8 +11,10 @@ require (
 	github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
 	github.com/cavaliergopher/grab/v3 v3.0.1
 	github.com/cheggaaa/pb/v3 v3.1.5
+	github.com/containers/common v0.59.1
 	github.com/containers/gvisor-tap-vsock v0.7.5
 	github.com/containers/image/v5 v5.32.2
+	github.com/containers/libhvee v0.7.1
 	github.com/coreos/go-systemd/v22 v22.5.0
 	github.com/crc-org/admin-helper v0.5.4
 	github.com/crc-org/machine v0.0.0-20240715101719-0c1bc9eb95f8
@@ -96,7 +98,7 @@ require (
 	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/go-jose/go-jose/v4 v4.0.2 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
-	github.com/go-ole/go-ole v1.2.6 // indirect
+	github.com/go-ole/go-ole v1.3.0 // indirect
 	github.com/go-openapi/analysis v0.23.0 // indirect
 	github.com/go-openapi/errors v0.22.0 // indirect
 	github.com/go-openapi/jsonpointer v0.21.0 // indirect
diff --git a/go.sum b/go.sum
index 29081bfb8..793c4bdc8 100644
--- a/go.sum
+++ b/go.sum
@@ -43,10 +43,14 @@ github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vc
 github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
 github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
 github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/containers/common v0.59.1 h1:7VkmJN3YvD0jLFwaUjLHSRJ98JLffydiyOJjYr0dUTo=
+github.com/containers/common v0.59.1/go.mod h1:53VicJCZ2AD0O+Br7VVoyrS7viXF4YmwlTIocWUT8XE=
 github.com/containers/gvisor-tap-vsock v0.7.5 h1:bTy4u3DOmmUPwurL6me2rsgfypAFDhyeJleUcQmBR/E=
 github.com/containers/gvisor-tap-vsock v0.7.5/go.mod h1:GW9jOqAEEGdaS20XwTYdm6KCYDHIulOE/yEEOabkoE4=
 github.com/containers/image/v5 v5.32.2 h1:SzNE2Y6sf9b1GJoC8qjCuMBXwQrACFp4p0RK15+4gmQ=
 github.com/containers/image/v5 v5.32.2/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk=
+github.com/containers/libhvee v0.7.1 h1:dWGF5GLq9DZvXo3P8aDp3cNieL5eCaSell4UmeA/jY4=
+github.com/containers/libhvee v0.7.1/go.mod h1:fRKB3AyIqHMvq6xaeYhTpckM2cdoq0oecolyoiuLP7M=
 github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
 github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
 github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM=
@@ -118,8 +122,9 @@ github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0
 github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
 github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
 github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
 github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
 github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
 github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
diff --git a/pkg/crc/machine/driver_windows.go b/pkg/crc/machine/driver_windows.go
index bff781695..0a9a6b516 100644
--- a/pkg/crc/machine/driver_windows.go
+++ b/pkg/crc/machine/driver_windows.go
@@ -5,28 +5,28 @@ import (
 	"errors"
 
 	"github.com/crc-org/crc/v2/pkg/crc/machine/config"
-	"github.com/crc-org/crc/v2/pkg/crc/machine/hyperv"
-	machineHyperv "github.com/crc-org/crc/v2/pkg/drivers/hyperv"
+	"github.com/crc-org/crc/v2/pkg/crc/machine/libhvee"
+	machineLibhvee "github.com/crc-org/crc/v2/pkg/drivers/libhvee"
 	"github.com/crc-org/crc/v2/pkg/libmachine"
 	"github.com/crc-org/crc/v2/pkg/libmachine/host"
 )
 
 func newHost(api libmachine.API, machineConfig config.MachineConfig) (*host.Host, error) {
-	json, err := json.Marshal(hyperv.CreateHost(machineConfig))
+	json, err := json.Marshal(libhvee.CreateHost(machineConfig))
 	if err != nil {
 		return nil, errors.New("Failed to marshal driver options")
 	}
 	return api.NewHost("hyperv", "", json)
 }
 
-func loadDriverConfig(host *host.Host) (*machineHyperv.Driver, error) {
-	var hypervDriver machineHyperv.Driver
-	err := json.Unmarshal(host.RawDriver, &hypervDriver)
+func loadDriverConfig(host *host.Host) (*machineLibhvee.Driver, error) {
+	var libhveeDriver machineLibhvee.Driver
+	err := json.Unmarshal(host.RawDriver, &libhveeDriver)
 
-	return &hypervDriver, err
+	return &libhveeDriver, err
 }
 
-func updateDriverConfig(host *host.Host, driver *machineHyperv.Driver) error {
+func updateDriverConfig(host *host.Host, driver *machineLibhvee.Driver) error {
 	driverData, err := json.Marshal(driver)
 	if err != nil {
 		return err
@@ -34,7 +34,7 @@ func updateDriverConfig(host *host.Host, driver *machineHyperv.Driver) error {
 	return host.UpdateConfig(driverData)
 }
 
-func updateDriverStruct(host *host.Host, driver *machineHyperv.Driver) error {
+func updateDriverStruct(host *host.Host, driver *machineLibhvee.Driver) error {
 	host.Driver = driver
 	return nil
 }
diff --git a/pkg/crc/machine/hyperv/constants_windows.go b/pkg/crc/machine/hyperv/constants_windows.go
deleted file mode 100644
index ec04f1b6a..000000000
--- a/pkg/crc/machine/hyperv/constants_windows.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package hyperv
-
-const (
-	// Alternative
-	AlternativeNetwork = "crc"
-)
diff --git a/pkg/crc/machine/hyperv/driver_windows.go b/pkg/crc/machine/libhvee/driver_windows.go
similarity index 61%
rename from pkg/crc/machine/hyperv/driver_windows.go
rename to pkg/crc/machine/libhvee/driver_windows.go
index 252dfe3b4..9464b7ac6 100644
--- a/pkg/crc/machine/hyperv/driver_windows.go
+++ b/pkg/crc/machine/libhvee/driver_windows.go
@@ -1,4 +1,4 @@
-package hyperv
+package libhvee
 
 import (
 	"path/filepath"
@@ -6,29 +6,17 @@ import (
 
 	"github.com/crc-org/crc/v2/pkg/crc/constants"
 	"github.com/crc-org/crc/v2/pkg/crc/machine/config"
-	"github.com/crc-org/crc/v2/pkg/crc/network"
-	"github.com/crc-org/crc/v2/pkg/drivers/hyperv"
-	winnet "github.com/crc-org/crc/v2/pkg/os/windows/network"
+	"github.com/crc-org/crc/v2/pkg/drivers/libhvee"
 	"github.com/crc-org/machine/libmachine/drivers"
 )
 
-func CreateHost(machineConfig config.MachineConfig) *hyperv.Driver {
-	hypervDriver := hyperv.NewDriver(machineConfig.Name, constants.MachineBaseDir)
+func CreateHost(machineConfig config.MachineConfig) *libhvee.Driver {
+	libhveeDriver := libhvee.NewDriver(machineConfig.Name, constants.MachineBaseDir)
 
-	config.InitVMDriverFromMachineConfig(machineConfig, hypervDriver.VMDriver)
+	config.InitVMDriverFromMachineConfig(machineConfig, libhveeDriver.VMDriver)
 
-	hypervDriver.DisableDynamicMemory = true
-
-	if machineConfig.NetworkMode == network.UserNetworkingMode {
-		hypervDriver.VirtualSwitch = ""
-	} else {
-		// Determine the Virtual Switch to be used
-		_, switchName := winnet.SelectSwitchByNameOrDefault(AlternativeNetwork)
-		hypervDriver.VirtualSwitch = switchName
-	}
-
-	hypervDriver.SharedDirs = configureShareDirs(machineConfig)
-	return hypervDriver
+	libhveeDriver.SharedDirs = configureShareDirs(machineConfig)
+	return libhveeDriver
 }
 
 // converts a path like c:\users\crc to /mnt/c/users/crc
diff --git a/pkg/crc/preflight/preflight_checks_windows.go b/pkg/crc/preflight/preflight_checks_windows.go
index 18fae462f..3f61aeccc 100644
--- a/pkg/crc/preflight/preflight_checks_windows.go
+++ b/pkg/crc/preflight/preflight_checks_windows.go
@@ -8,11 +8,9 @@ import (
 	"github.com/crc-org/crc/v2/pkg/crc/logging"
 
 	"github.com/crc-org/crc/v2/pkg/crc/adminhelper"
-	winnet "github.com/crc-org/crc/v2/pkg/os/windows/network"
 	"github.com/crc-org/crc/v2/pkg/os/windows/powershell"
 
 	"github.com/crc-org/crc/v2/pkg/crc/constants"
-	"github.com/crc-org/crc/v2/pkg/crc/machine/hyperv"
 )
 
 const (
@@ -166,19 +164,6 @@ func fixUserPartOfCrcUsersAndHypervAdminsGroup() error {
 	return errReboot
 }
 
-func checkIfHyperVVirtualSwitchExists() error {
-	switchName := hyperv.AlternativeNetwork
-
-	// use winnet instead
-	exists, foundName := winnet.SelectSwitchByNameOrDefault(switchName)
-	if exists {
-		logging.Info("Found Virtual Switch to use: ", foundName)
-		return nil
-	}
-
-	return fmt.Errorf("Virtual Switch not found")
-}
-
 func checkIfRunningAsNormalUser() error {
 	if !powershell.IsAdmin() {
 		return nil
@@ -187,17 +172,6 @@ func checkIfRunningAsNormalUser() error {
 	return fmt.Errorf("crc should be run in a shell without administrator rights")
 }
 
-func removeDNSServerAddress() error {
-	resetDNSCommand := `Set-DnsClientServerAddress -InterfaceAlias ("vEthernet (crc)") -ResetServerAddresses`
-	if exist, defaultSwitch := winnet.GetDefaultSwitchName(); exist {
-		resetDNSCommand = fmt.Sprintf(`Set-DnsClientServerAddress -InterfaceAlias ("vEthernet (%s)","vEthernet (crc)") -ResetServerAddresses`, defaultSwitch)
-	}
-	if _, _, err := powershell.ExecuteAsAdmin("Remove dns entry for default switch", resetDNSCommand); err != nil {
-		return err
-	}
-	return nil
-}
-
 func removeCrcVM() (err error) {
 	if _, _, err := powershell.Execute("Get-VM -Name crc"); err != nil {
 		// This means that there is no crc VM exist
diff --git a/pkg/crc/preflight/preflight_windows.go b/pkg/crc/preflight/preflight_windows.go
index 2d8ea876b..03e488a0d 100644
--- a/pkg/crc/preflight/preflight_windows.go
+++ b/pkg/crc/preflight/preflight_windows.go
@@ -60,21 +60,6 @@ var hypervPreflightChecks = []Check{
 
 		labels: labels{Os: Windows},
 	},
-	{
-		configKeySuffix:  "check-hyperv-switch",
-		checkDescription: "Checking if the Hyper-V virtual switch exists",
-		check:            checkIfHyperVVirtualSwitchExists,
-		flags:            StartUpOnly,
-
-		labels: labels{Os: Windows, NetworkMode: System},
-	},
-	{
-		cleanupDescription: "Removing dns server from interface",
-		cleanup:            removeDNSServerAddress,
-		flags:              CleanUpOnly,
-
-		labels: labels{Os: Windows, NetworkMode: System},
-	},
 }
 
 var cleanupCheckRemoveCrcVM = Check{
diff --git a/pkg/crc/services/dns/dns_windows.go b/pkg/crc/services/dns/dns_windows.go
index 908ad511c..e7cdfd779 100644
--- a/pkg/crc/services/dns/dns_windows.go
+++ b/pkg/crc/services/dns/dns_windows.go
@@ -2,50 +2,14 @@ package dns
 
 import (
 	"fmt"
-	"time"
 
 	"github.com/crc-org/crc/v2/pkg/crc/network"
 	"github.com/crc-org/crc/v2/pkg/crc/services"
-	winnet "github.com/crc-org/crc/v2/pkg/os/windows/network"
-	"github.com/crc-org/crc/v2/pkg/os/windows/powershell"
-	"github.com/crc-org/crc/v2/pkg/os/windows/win32"
-	crcstrings "github.com/crc-org/crc/v2/pkg/strings"
-)
-
-const (
-	// Alternative
-	AlternativeNetwork = "crc"
 )
 
 func runPostStartForOS(serviceConfig services.ServicePostStartConfig) error {
-	if serviceConfig.NetworkMode == network.UserNetworkingMode {
-		return addOpenShiftHosts(serviceConfig)
-	}
-
-	_, switchName := winnet.SelectSwitchByNameOrDefault(AlternativeNetwork)
-	networkInterface := fmt.Sprintf("vEthernet (%s)", switchName)
-
-	setInterfaceNameserverValue(networkInterface, serviceConfig.IP)
-
-	time.Sleep(2 * time.Second)
-
-	if !crcstrings.Contains(getInterfaceNameserverValues(networkInterface), serviceConfig.IP) {
-		return fmt.Errorf("Nameserver %s not successfully set on interface %s. Perhaps you can try this new network mode: https://github.com/crc-org/crc/wiki/VPN-support--with-an--userland-network-stack", serviceConfig.IP, networkInterface)
+	if serviceConfig.NetworkMode != network.UserNetworkingMode {
+		return fmt.Errorf("only user-mode networking is supported on Windows")
 	}
-	return nil
-}
-
-func getInterfaceNameserverValues(iface string) []string {
-	getDNSServerCommand := fmt.Sprintf(`(Get-DnsClientServerAddress "%s")[0].ServerAddresses`, iface)
-	stdOut, _, _ := powershell.Execute(getDNSServerCommand)
-
-	return crcstrings.SplitLines(stdOut)
-}
-
-func setInterfaceNameserverValue(iface string, address string) {
-	exe := "netsh"
-	args := fmt.Sprintf(`interface ip set dns "%s" static %s primary`, iface, address)
-
-	// ignore the error as this is useless (prefer not to use nolint here)
-	_ = win32.ShellExecuteAsAdmin(fmt.Sprintf("add dns server address to interface %s", iface), win32.HwndDesktop, exe, args, "", 0)
+	return addOpenShiftHosts(serviceConfig)
 }
diff --git a/pkg/drivers/hyperv/hyperv_windows.go b/pkg/drivers/hyperv/hyperv_windows.go
deleted file mode 100644
index 40705bf69..000000000
--- a/pkg/drivers/hyperv/hyperv_windows.go
+++ /dev/null
@@ -1,416 +0,0 @@
-package hyperv
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"os/exec"
-	"strconv"
-	"strings"
-	"time"
-
-	log "github.com/crc-org/crc/v2/pkg/crc/logging"
-	crcos "github.com/crc-org/crc/v2/pkg/os"
-	"github.com/crc-org/crc/v2/pkg/os/windows/powershell"
-	crcstrings "github.com/crc-org/crc/v2/pkg/strings"
-	"github.com/crc-org/machine/libmachine/drivers"
-	"github.com/crc-org/machine/libmachine/state"
-)
-
-type Driver struct {
-	*drivers.VMDriver
-	VirtualSwitch        string
-	MacAddress           string
-	DisableDynamicMemory bool
-}
-
-const (
-	defaultMemory               = 8192
-	defaultCPU                  = 4
-	defaultDisableDynamicMemory = false
-)
-
-// NewDriver creates a new Hyper-v driver with default settings.
-func NewDriver(hostName, storePath string) *Driver {
-	return &Driver{
-		DisableDynamicMemory: defaultDisableDynamicMemory,
-		VMDriver: &drivers.VMDriver{
-			BaseDriver: &drivers.BaseDriver{
-				MachineName: hostName,
-				StorePath:   storePath,
-			},
-			Memory: defaultMemory,
-			CPU:    defaultCPU,
-		},
-	}
-}
-
-func (d *Driver) UpdateConfigRaw(rawConfig []byte) error {
-	var newDriver Driver
-
-	err := json.Unmarshal(rawConfig, &newDriver)
-	if err != nil {
-		return err
-	}
-	if newDriver.Memory != d.Memory {
-		log.Debugf("Updating memory from %d MB to %d MB", d.Memory, newDriver.Memory)
-		err := cmd("Hyper-V\\Set-VMMemory",
-			"-VMName", d.MachineName,
-			"-StartupBytes", toMb(newDriver.Memory))
-		if err != nil {
-			log.Warnf("Failed to update memory to %d MB: %v", newDriver.Memory, err)
-			return err
-		}
-	}
-
-	if newDriver.CPU != d.CPU {
-		log.Debugf("Updating CPU count from %d to %d", d.CPU, newDriver.CPU)
-		err := cmd("Hyper-V\\Set-VMProcessor",
-			d.MachineName,
-			"-Count", fmt.Sprintf("%d", newDriver.CPU))
-		if err != nil {
-			log.Warnf("Failed to set CPU count to %d", newDriver.CPU)
-			return err
-		}
-	}
-	if newDriver.DiskCapacity != d.DiskCapacity {
-		if err := d.resizeDisk(int64(newDriver.DiskCapacity)); err != nil {
-			log.Warnf("Failed to set disk size to %d", newDriver.DiskCapacity)
-			return err
-		}
-	}
-	*d = newDriver
-	return nil
-}
-
-// DriverName returns the name of the driver
-func (d *Driver) DriverName() string {
-	return "hyperv"
-}
-
-func (d *Driver) GetState() (state.State, error) {
-	stdout, stderr, err := powershell.Execute("Hyper-V\\Get-VM", d.MachineName, "|", "Select-Object", "-ExpandProperty", "State")
-	if err != nil {
-		return state.Error, fmt.Errorf("Failed to find the VM status: %v - %s", err, stderr)
-	}
-
-	resp := crcstrings.FirstLine(stdout)
-	if resp == "" {
-		return state.Error, fmt.Errorf("unexpected Hyper-V state %s", stdout)
-	}
-
-	switch resp {
-	case "Starting", "Running", "Stopping":
-		return state.Running, nil
-	case "Off":
-		return state.Stopped, nil
-	default:
-		return state.Error, fmt.Errorf("unexpected Hyper-V state %s", resp)
-	}
-}
-
-// PreCreateCheck checks that the machine creation process can be started safely.
-func (d *Driver) PreCreateCheck() error {
-	// Check that powershell was found
-	if _, err := exec.LookPath("powershell.exe"); err != nil {
-		return ErrPowerShellNotFound
-	}
-
-	// Check that hyperv is installed
-	if err := hypervAvailable(); err != nil {
-		return err
-	}
-
-	// Check that the user is an Administrator
-	isAdmin, err := isAdministrator()
-	if err != nil {
-		return err
-	}
-	if !isAdmin {
-		return ErrNotAdministrator
-	}
-
-	if d.VirtualSwitch == "" {
-		return nil
-	}
-
-	// Check that there is a virtual switch already configured
-	if _, err := d.chooseVirtualSwitch(); err != nil {
-		return err
-	}
-
-	return err
-}
-
-func (d *Driver) getDiskPath() string {
-	return d.ResolveStorePath(fmt.Sprintf("%s.%s", d.MachineName, d.ImageFormat))
-}
-
-func (d *Driver) resizeDisk(newSize int64) error {
-	diskPath := d.getDiskPath()
-	out, err := cmdOut(fmt.Sprintf("@(Get-VHD -Path %s).Size", quote(diskPath)))
-	if err != nil {
-		return fmt.Errorf("unable to get current size of crc.vhdx: %w", err)
-	}
-	currentSize, err := strconv.ParseInt(strings.TrimSpace(out), 10, 64)
-	if err != nil {
-		return fmt.Errorf("unable to convert disk size to int: %w", err)
-	}
-	if newSize == currentSize {
-		log.Debugf("%s is already %d bytes", diskPath, newSize)
-		return nil
-	}
-	if newSize < currentSize {
-		return fmt.Errorf("current disk image capacity is bigger than the requested size (%d > %d)", currentSize, newSize)
-	}
-
-	log.Debugf("Resizing disk from %d bytes to %d bytes", currentSize, newSize)
-	return cmd("Hyper-V\\Resize-VHD",
-		"-Path",
-		quote(diskPath),
-		"-SizeBytes",
-		fmt.Sprintf("%d", newSize))
-}
-
-func (d *Driver) Create() error {
-	if err := crcos.CopyFile(d.ImageSourcePath, d.getDiskPath()); err != nil {
-		return err
-	}
-
-	args := []string{
-		"Hyper-V\\New-VM",
-		d.MachineName,
-		"-Path", fmt.Sprintf("'%s'", d.ResolveStorePath(".")),
-		"-MemoryStartupBytes", toMb(d.Memory),
-	}
-	if d.VirtualSwitch != "" {
-		virtualSwitch, err := d.chooseVirtualSwitch()
-		if err != nil {
-			return err
-		}
-		log.Debugf("Using switch %q", virtualSwitch)
-		args = append(args, "-SwitchName", quote(virtualSwitch))
-	}
-
-	log.Debugf("Creating VM...")
-	if err := cmd(args...); err != nil {
-		return err
-	}
-
-	if d.VirtualSwitch == "" {
-		if err := cmd("Hyper-V\\Remove-VMNetworkAdapter", "-VMName", d.MachineName); err != nil {
-			return err
-		}
-	}
-
-	if d.DisableDynamicMemory {
-		if err := cmd("Hyper-V\\Set-VMMemory",
-			"-VMName", d.MachineName,
-			"-DynamicMemoryEnabled", "$false"); err != nil {
-			return err
-		}
-	}
-
-	if d.CPU > 1 {
-		if err := cmd("Hyper-V\\Set-VMProcessor",
-			d.MachineName,
-			"-Count", fmt.Sprintf("%d", d.CPU)); err != nil {
-			return err
-		}
-	}
-
-	if d.VirtualSwitch != "" && d.MacAddress != "" {
-		if err := cmd("Hyper-V\\Set-VMNetworkAdapter",
-			"-VMName", d.MachineName,
-			"-StaticMacAddress", fmt.Sprintf("\"%s\"", d.MacAddress)); err != nil {
-			return err
-		}
-	}
-
-	// Disables creating checkpoints and Automatic Start
-	// Shuts down the VM when host shuts down
-	if err := cmd("Hyper-V\\Set-VM",
-		"-VMName", d.MachineName,
-		"-AutomaticStartAction", "Nothing",
-		"-AutomaticStopAction", "ShutDown",
-		"-CheckpointType", "Disabled"); err != nil {
-		return err
-	}
-
-	if err := cmd("Hyper-V\\Add-VMHardDiskDrive",
-		"-VMName", d.MachineName,
-		"-Path", quote(d.getDiskPath())); err != nil {
-		return err
-	}
-
-	return d.resizeDisk(int64(d.DiskCapacity))
-
-}
-
-func (d *Driver) chooseVirtualSwitch() (string, error) {
-	if d.VirtualSwitch == "" {
-		return "", errors.New("no virtual switch given")
-	}
-
-	stdout, err := cmdOut("[Console]::OutputEncoding = [Text.Encoding]::UTF8; (Hyper-V\\Get-VMSwitch).Name")
-	if err != nil {
-		return "", err
-	}
-
-	switches := crcstrings.SplitLines(stdout)
-
-	found := false
-	for _, name := range switches {
-		if name == d.VirtualSwitch {
-			found = true
-			break
-		}
-	}
-
-	if !found {
-		return "", fmt.Errorf("virtual switch %q not found", d.VirtualSwitch)
-	}
-
-	return d.VirtualSwitch, nil
-}
-
-// waitForIP waits until the host has a valid IP
-func (d *Driver) waitForIP() (string, error) {
-	if d.VirtualSwitch == "" {
-		return "", errors.New("no virtual switch given")
-	}
-
-	log.Debugf("Waiting for host to start...")
-
-	for {
-		ip, _ := d.GetIP()
-		if ip != "" {
-			return ip, nil
-		}
-
-		time.Sleep(1 * time.Second)
-	}
-}
-
-// waitStopped waits until the host is stopped
-func (d *Driver) waitStopped() error {
-	log.Debugf("Waiting for host to stop...")
-
-	for {
-		s, err := d.GetState()
-		if err != nil {
-			return err
-		}
-
-		if s != state.Running {
-			return nil
-		}
-
-		time.Sleep(1 * time.Second)
-	}
-}
-
-// Start starts an host
-func (d *Driver) Start() error {
-	if err := cmd("Hyper-V\\Start-VM", d.MachineName); err != nil {
-		return err
-	}
-
-	if d.VirtualSwitch == "" {
-		return nil
-	}
-
-	ip, err := d.waitForIP()
-	if err != nil {
-		return err
-	}
-
-	d.IPAddress = ip
-
-	return nil
-}
-
-// Stop stops an host
-func (d *Driver) Stop() error {
-	if err := cmd("Hyper-V\\Stop-VM", d.MachineName); err != nil {
-		return err
-	}
-
-	if err := d.waitStopped(); err != nil {
-		return err
-	}
-
-	d.IPAddress = ""
-
-	return nil
-}
-
-// Remove removes an host
-func (d *Driver) Remove() error {
-	if _, _, err := powershell.Execute(`Hyper-V\Get-VM`, d.MachineName, "-ErrorAction", "SilentlyContinue", "-ErrorVariable", "getVmErrors"); err != nil {
-		return nil
-	}
-
-	s, err := d.GetState()
-	if err != nil {
-		return err
-	}
-
-	if s == state.Running {
-		if err := d.Kill(); err != nil {
-			return err
-		}
-	}
-
-	return cmd("Hyper-V\\Remove-VM", d.MachineName, "-Force")
-}
-
-// Kill force stops an host
-func (d *Driver) Kill() error {
-	if err := cmd("Hyper-V\\Stop-VM", d.MachineName, "-TurnOff"); err != nil {
-		return err
-	}
-
-	if err := d.waitStopped(); err != nil {
-		return err
-	}
-
-	d.IPAddress = ""
-
-	return nil
-}
-
-func (d *Driver) GetIP() (string, error) {
-	if d.VirtualSwitch == "" {
-		return "", errors.New("no virtual switch given")
-	}
-
-	s, err := d.GetState()
-	if err != nil {
-		return "", err
-	}
-	if s != state.Running {
-		return "", drivers.ErrHostIsNotRunning
-	}
-
-	stdout, err := cmdOut("((", "Hyper-V\\Get-VM", d.MachineName, ").networkadapters[0]).ipaddresses[0]")
-	if err != nil {
-		return "", err
-	}
-
-	resp := crcstrings.FirstLine(stdout)
-	if resp == "" {
-		return "", fmt.Errorf("IP not found")
-	}
-
-	return resp, nil
-}
-
-func (d *Driver) GetSharedDirs() ([]drivers.SharedDir, error) {
-	for _, dir := range d.SharedDirs {
-		if !smbShareExists(dir.Tag) {
-			return []drivers.SharedDir{}, nil
-		}
-	}
-	return d.SharedDirs, nil
-}
diff --git a/pkg/drivers/libhvee/libhvee_windows.go b/pkg/drivers/libhvee/libhvee_windows.go
new file mode 100644
index 000000000..7028c819a
--- /dev/null
+++ b/pkg/drivers/libhvee/libhvee_windows.go
@@ -0,0 +1,305 @@
+package libhvee
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"os/exec"
+
+	log "github.com/crc-org/crc/v2/pkg/crc/logging"
+	crcos "github.com/crc-org/crc/v2/pkg/os"
+	"github.com/crc-org/machine/libmachine/drivers"
+	"github.com/crc-org/machine/libmachine/state"
+
+	"github.com/containers/common/pkg/strongunits"
+	"github.com/containers/libhvee/pkg/hypervctl"
+)
+
+type Driver struct {
+	*drivers.VMDriver
+	DynamicMemory bool
+}
+
+const (
+	defaultMemory        = 8192
+	defaultCPU           = 4
+	defaultDynamicMemory = false
+	systemGeneration     = "Microsoft:Hyper-V:SubType:2"
+)
+
+// NewDriver creates a new Hyper-v driver with default settings.
+func NewDriver(hostName, storePath string) *Driver {
+	return &Driver{
+		VMDriver: &drivers.VMDriver{
+			BaseDriver: &drivers.BaseDriver{
+				MachineName: hostName,
+				StorePath:   storePath,
+			},
+			Memory: defaultMemory,
+			CPU:    defaultCPU,
+		},
+		DynamicMemory: defaultDynamicMemory,
+	}
+}
+
+func (d *Driver) UpdateConfigRaw(rawConfig []byte) error {
+	var update Driver
+
+	err := json.Unmarshal(rawConfig, &update)
+	if err != nil {
+		return err
+	}
+
+	if update.Memory != d.Memory {
+		log.Debugf("Machine: libhvee -> Updating memory from %d MB to %d MB", d.Memory, update.Memory)
+
+		vm, err := d.getMachine()
+		if err != nil {
+			return err
+		}
+
+		err = vm.UpdateProcessorMemSettings(
+			func(_ *hypervctl.ProcessorSettings) {},
+			func(ms *hypervctl.MemorySettings) {
+				ms.VirtualQuantity = uint64(update.Memory)
+				ms.Limit = uint64(update.Memory)
+			})
+
+		if err != nil {
+			return err
+		}
+	}
+
+	if update.CPU != d.CPU {
+		log.Debugf("Machine: libhvee -> Updating CPU count from %d to %d", d.CPU, update.CPU)
+
+		vm, err := d.getMachine()
+		if err != nil {
+			return err
+		}
+
+		err = vm.UpdateProcessorMemSettings(
+			func(ps *hypervctl.ProcessorSettings) {
+				ps.VirtualQuantity = uint64(update.CPU)
+			},
+			func(_ *hypervctl.MemorySettings) {})
+
+		if err != nil {
+			return err
+		}
+	}
+	if update.DiskCapacity != d.DiskCapacity {
+		if err := d.resizeDisk(int64(update.DiskCapacity)); err != nil {
+			log.Warnf("Machine: libhvee -> Failed to set disk size to %d", update.DiskCapacity)
+			return err
+		}
+	}
+	*d = update
+	return nil
+}
+
+// DriverName returns the name of the driver
+func (d *Driver) DriverName() string {
+	return "libhvee"
+}
+
+func (d *Driver) GetState() (state.State, error) {
+	log.Debugf("Machine: libhvee -> state")
+	vm, err := d.getMachine()
+	if err != nil {
+		return state.Error, err
+	}
+
+	log.Debugf("Machine: libhvee -> state: get")
+	vmState := vm.State()
+	switch vmState {
+	case hypervctl.Enabled:
+		log.Debugf("Machine: libhvee -> state: running")
+		return state.Running, nil
+	case hypervctl.Disabled:
+		log.Debugf("Machine: libhvee -> state: stopped")
+		return state.Stopped, nil
+	}
+
+	log.Debugf("Machine: libhvee -> state: unknown")
+	return state.Error, fmt.Errorf("unknown state")
+}
+
+// PreCreateCheck checks that the machine creation process can be started safely.
+func (d *Driver) PreCreateCheck() error {
+	// Check that powershell was found
+	if _, err := exec.LookPath("powershell.exe"); err != nil {
+		return ErrPowerShellNotFound
+	}
+
+	// Check that hyperv is installed
+	if err := hypervAvailable(); err != nil {
+		return err
+	}
+
+	// Check that the user is an Administrator
+	isAdmin, err := isAdministrator()
+	if err != nil {
+		return err
+	}
+	if !isAdmin {
+		return ErrNotAdministrator
+	}
+
+	return nil
+}
+
+func (d *Driver) Create() error {
+	log.Debugf("Machine: libhvee -> creating: system settings")
+	systemSettings, err := hypervctl.NewSystemSettingsBuilder().
+		PrepareSystemSettings(d.MachineName, nil).
+		PrepareMemorySettings(
+			func(ms *hypervctl.MemorySettings) {
+				ms.DynamicMemoryEnabled = d.DynamicMemory
+				ms.VirtualQuantity = uint64(d.Memory)
+				ms.Reservation = 1024
+				ms.Limit = uint64(d.Memory)
+			}).
+		PrepareProcessorSettings(
+			func(ps *hypervctl.ProcessorSettings) {
+				ps.VirtualQuantity = uint64(d.CPU)
+			}).
+		Build()
+
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> creating: copy disk image")
+	diskPath := d.getDiskPath()
+	if err := crcos.CopyFile(d.ImageSourcePath, diskPath); err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> creating: hardware setup")
+	err = hypervctl.NewDriveSettingsBuilder(systemSettings).
+		AddScsiController().
+		AddSyntheticDiskDrive(0).
+		DefineVirtualHardDisk(diskPath,
+			func(_ *hypervctl.VirtualHardDiskStorageSettings) {}).
+		Finish().
+		Finish().
+		Finish().
+		Complete()
+
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> creating: done")
+
+	return d.resizeDisk(int64(d.DiskCapacity))
+
+}
+
+func (d *Driver) getMachine() (*hypervctl.VirtualMachine, error) {
+	vmm := hypervctl.NewVirtualMachineManager()
+
+	log.Debugf("Machine: libhvee -> get machine")
+	return vmm.GetMachine(d.MachineName)
+}
+
+// Start starts an host
+func (d *Driver) Start() error {
+	vm, err := d.getMachine()
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> start")
+	return vm.Start()
+}
+
+// Stop stops an host
+func (d *Driver) Stop() error {
+	vm, err := d.getMachine()
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> stop")
+	return vm.Stop()
+}
+
+// Remove removes an host
+func (d *Driver) Remove() error {
+	s, err := d.GetState()
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> remove running")
+	if s == state.Running {
+		if err := d.Kill(); err != nil {
+			return err
+		}
+	}
+
+	vm, err := d.getMachine()
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> remove vm")
+	err = vm.Remove("")
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> remove disk file")
+	return os.Remove(d.getDiskPath())
+}
+
+// Kill force stops an host
+func (d *Driver) Kill() error {
+	vm, err := d.getMachine()
+	if err != nil {
+		return err
+	}
+
+	log.Debugf("Machine: libhvee -> stop with force")
+	return vm.StopWithForce()
+}
+
+func (d *Driver) GetIP() (string, error) {
+	return "", drivers.ErrNotSupported
+}
+
+func (d *Driver) GetSharedDirs() ([]drivers.SharedDir, error) {
+	for _, dir := range d.SharedDirs {
+		if !smbShareExists(dir.Tag) {
+			return []drivers.SharedDir{}, nil
+		}
+	}
+	return d.SharedDirs, nil
+}
+
+func (d *Driver) getDiskPath() string {
+	return d.ResolveStorePath(fmt.Sprintf("%s.%s", d.MachineName, d.ImageFormat))
+}
+
+func (d *Driver) resizeDisk(newSizeBytes int64) error {
+
+	newSize := strongunits.B(newSizeBytes)
+
+	diskPath := d.getDiskPath()
+	currentSize, err := hypervctl.GetDiskSize(diskPath)
+	if err != nil {
+		return fmt.Errorf("unable to get current size of crc.vhdx: %w", err)
+	}
+	if newSize == currentSize.ToBytes() {
+		log.Debugf("%s is already %d bytes", diskPath, newSize)
+		return nil
+	}
+	if newSize < currentSize.ToBytes() {
+		return fmt.Errorf("current disk image capacity is bigger than the requested size (%d > %d)", currentSize.ToBytes(), newSize)
+	}
+
+	log.Debugf("Resizing disk from %d bytes to %d bytes", currentSize.ToBytes(), newSize.ToBytes())
+	return hypervctl.ResizeDisk(diskPath, strongunits.ToGiB(newSize))
+}
diff --git a/pkg/drivers/hyperv/powershell_windows.go b/pkg/drivers/libhvee/powershell_windows.go
similarity index 92%
rename from pkg/drivers/hyperv/powershell_windows.go
rename to pkg/drivers/libhvee/powershell_windows.go
index 7bc117802..6c8f5c7ab 100644
--- a/pkg/drivers/hyperv/powershell_windows.go
+++ b/pkg/drivers/libhvee/powershell_windows.go
@@ -1,4 +1,4 @@
-package hyperv
+package libhvee
 
 import (
 	"errors"
@@ -76,14 +76,6 @@ func isWindowsAdministrator() (bool, error) {
 	return resp == "True", nil
 }
 
-func quote(text string) string {
-	return fmt.Sprintf("'%s'", text)
-}
-
-func toMb(value int) string {
-	return fmt.Sprintf("%dMB", value)
-}
-
 func smbShareExists(name string) bool {
 	if err := cmd(fmt.Sprintf("Get-SmbShare -Name %s", name)); err != nil {
 		return false
diff --git a/pkg/libmachine/load_windows.go b/pkg/libmachine/load_windows.go
index 12e26fa40..062379e5d 100644
--- a/pkg/libmachine/load_windows.go
+++ b/pkg/libmachine/load_windows.go
@@ -3,12 +3,12 @@ package libmachine
 import (
 	"encoding/json"
 
-	"github.com/crc-org/crc/v2/pkg/drivers/hyperv"
+	"github.com/crc-org/crc/v2/pkg/drivers/libhvee"
 	"github.com/crc-org/crc/v2/pkg/libmachine/host"
 )
 
 func (api *Client) NewHost(_ string, driverPath string, rawDriver []byte) (*host.Host, error) {
-	driver := hyperv.NewDriver("", "")
+	driver := libhvee.NewDriver("", "")
 	if err := json.Unmarshal(rawDriver, &driver); err != nil {
 		return nil, err
 	}
@@ -29,7 +29,7 @@ func (api *Client) Load(name string) (*host.Host, error) {
 		return nil, err
 	}
 
-	driver := hyperv.NewDriver("", "")
+	driver := libhvee.NewDriver("", "")
 	if err := json.Unmarshal(h.RawDriver, &driver); err != nil {
 		return nil, err
 	}
diff --git a/pkg/os/windows/network/vswitch_windows.go b/pkg/os/windows/network/vswitch_windows.go
deleted file mode 100644
index bf5cf5786..000000000
--- a/pkg/os/windows/network/vswitch_windows.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package network
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/crc-org/crc/v2/pkg/os/windows/powershell"
-)
-
-const hypervDefaultVirtualSwitchID = "c08cb7b8-9b3c-408e-8e30-5e16a3aeb444"
-
-func SelectSwitchByNameOrDefault(name string) (bool, string) {
-	// if named exists
-	if ExistsSwitchByName(name) {
-		return true, name
-	}
-
-	// else use Default
-	return GetDefaultSwitchName()
-}
-
-func ExistsSwitchByName(name string) bool {
-	getSwitchByNameCmd := fmt.Sprintf("Get-VMSwitch %s | ForEach-Object { $_.Name }", name)
-	stdOut, stdErr, _ := powershell.Execute(getSwitchByNameCmd)
-
-	// If stdErr contains the command then execution failed
-	if strings.Contains(stdErr, "Get-VMSwitch") {
-		return false
-	}
-
-	if strings.Contains(stdOut, name) {
-		return true
-	}
-	return false
-}
-
-func GetDefaultSwitchName() (bool, string) {
-	getDefaultSwitchNameCmd := fmt.Sprintf("[Console]::OutputEncoding = [Text.Encoding]::UTF8; Get-VMSwitch -Id %s | ForEach-Object { $_.Name }", hypervDefaultVirtualSwitchID)
-	stdOut, stdErr, _ := powershell.Execute(getDefaultSwitchNameCmd)
-
-	// If stdErr contains the command then execution failed
-	if strings.Contains(stdErr, "Get-VMSwitch") {
-		return false, ""
-	}
-
-	return true, strings.TrimSpace(stdOut)
-}
diff --git a/vendor/github.com/containers/common/LICENSE b/vendor/github.com/containers/common/LICENSE
new file mode 100644
index 000000000..8dada3eda
--- /dev/null
+++ b/vendor/github.com/containers/common/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/github.com/containers/common/pkg/strongunits/config.go b/vendor/github.com/containers/common/pkg/strongunits/config.go
new file mode 100644
index 000000000..35a6b0c3d
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/strongunits/config.go
@@ -0,0 +1,65 @@
+package strongunits
+
+// supported units
+
+// B represents bytes
+type B uint64
+
+// KiB represents KiB
+type KiB uint64
+
+// MiB represents MiB
+type MiB uint64
+
+// GiB represents GiB
+type GiB uint64
+
+const (
+	// kibToB is the math convert from bytes to KiB
+	kibToB = 1 << 10
+	// mibToB is the math to convert from bytes to MiB
+	mibToB = 1 << 20
+	// gibToB s the math to convert from bytes to GiB
+	gibToB = 1 << 30
+)
+
+// StorageUnits is an interface for converting disk/memory storage
+// units amongst each other.
+type StorageUnits interface {
+	ToBytes() B
+}
+
+// ToBytes is a pass-through function for bytes
+func (b B) ToBytes() B {
+	return b
+}
+
+// ToBytes converts KiB to bytes
+func (k KiB) ToBytes() B {
+	return B(k * kibToB)
+}
+
+// ToBytes converts MiB to bytes
+func (m MiB) ToBytes() B {
+	return B(m * mibToB)
+}
+
+// ToBytes converts GiB to bytes
+func (g GiB) ToBytes() B {
+	return B(g * gibToB)
+}
+
+// ToKiB converts any StorageUnit type to KiB
+func ToKiB(b StorageUnits) KiB {
+	return KiB(b.ToBytes() >> 10)
+}
+
+// ToMib converts any StorageUnit type to MiB
+func ToMib(b StorageUnits) MiB {
+	return MiB(b.ToBytes() >> 20)
+}
+
+// ToGiB converts any StorageUnit type to GiB
+func ToGiB(b StorageUnits) GiB {
+	return GiB(b.ToBytes() >> 30)
+}
diff --git a/vendor/github.com/containers/libhvee/LICENSE b/vendor/github.com/containers/libhvee/LICENSE
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/diskdrive_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/diskdrive_settings.go
new file mode 100644
index 000000000..5e669302d
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/diskdrive_settings.go
@@ -0,0 +1,72 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+const SyntheticDiskDriveType = "Microsoft:Hyper-V:Synthetic Disk Drive"
+
+type SyntheticDiskDriveSettings struct {
+	ResourceSettings
+	systemSettings     *SystemSettings
+	controllerSettings *ScsiControllerSettings
+}
+
+type diskAssociation interface {
+	setParent(parent string)
+	setHostResource(resource []string)
+	Path() string
+}
+
+func (d *SyntheticDiskDriveSettings) DefineVirtualHardDisk(vhdxFile string, beforeAdd func(*VirtualHardDiskStorageSettings)) (*VirtualHardDiskStorageSettings, error) {
+	vhd := &VirtualHardDiskStorageSettings{}
+
+	var cb func()
+	if beforeAdd != nil {
+		cb = func() {
+			beforeAdd(vhd)
+		}
+	}
+
+	if err := createDiskResourceInternal(d.systemSettings.Path(), d.Path(), vhdxFile, vhd, VirtualHardDiskType, cb); err != nil {
+		return nil, err
+	}
+
+	vhd.driveSettings = d
+	vhd.systemSettings = d.systemSettings
+	return vhd, nil
+}
+
+func createDiskResourceInternal(systemPath string, drivePath string, file string, settings diskAssociation, resourceType string, cb func()) error {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	if err = populateDefaults(resourceType, settings); err != nil {
+		return err
+	}
+
+	settings.setHostResource([]string{file})
+	settings.setParent(drivePath)
+	if cb != nil {
+		cb()
+	}
+
+	diskResource, err := createResourceSettingGeneric(settings, resourceType)
+	if err != nil {
+		return err
+	}
+
+	path, err := addResource(service, systemPath, diskResource)
+	if err != nil {
+		return err
+	}
+
+	return service.GetObjectAsObject(path, settings)
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/drive_settings_builder.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/drive_settings_builder.go
new file mode 100644
index 000000000..21d67478c
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/drive_settings_builder.go
@@ -0,0 +1,186 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+type DriveSettingsBuilder struct {
+	systemSettings *SystemSettings
+	err            error
+}
+
+type ControllerSettingsBuilder struct {
+	driveSettingsBuilder DriveSettingsBuilder
+	controllerSettings   *ScsiControllerSettings
+	err                  error
+}
+
+type SyntheticDiskDriveSettingsBuilder struct {
+	controllerBuilder *ControllerSettingsBuilder
+	driveSettings     *SyntheticDiskDriveSettings
+	err               error
+}
+
+type SyntheticDvdDriveSettingsBuilder struct {
+	controllerBuilder *ControllerSettingsBuilder
+	driveSettings     *SyntheticDvdDriveSettings
+	err               error
+}
+
+type VirtualHardDiskStorageSettingsBuilder struct {
+	driveBuilder *SyntheticDiskDriveSettingsBuilder
+	diskSettings *VirtualHardDiskStorageSettings
+	err          error
+}
+
+type VirtualDvdDiskStorageSettingsBuilder struct {
+	driveBuilder *SyntheticDvdDriveSettingsBuilder
+	diskSettings *VirtualDvdDiskStorageSettings
+	err          error
+}
+
+func NewDriveSettingsBuilder(systemSettings *SystemSettings) *DriveSettingsBuilder {
+	return &DriveSettingsBuilder{systemSettings: systemSettings}
+}
+
+func (builder *DriveSettingsBuilder) AddScsiController() *ControllerSettingsBuilder {
+	if builder.err != nil {
+		return &ControllerSettingsBuilder{driveSettingsBuilder: *builder, err: builder.err}
+	}
+
+	controllerSettings, err := builder.systemSettings.AddScsiController()
+	builder.setErr(err)
+
+	return &ControllerSettingsBuilder{
+		driveSettingsBuilder: *builder,
+		controllerSettings:   controllerSettings,
+		err:                  err,
+	}
+}
+
+func (builder *ControllerSettingsBuilder) AddSyntheticDiskDrive(slot uint) *SyntheticDiskDriveSettingsBuilder {
+	if builder.err != nil {
+		return &SyntheticDiskDriveSettingsBuilder{controllerBuilder: builder, err: builder.err}
+	}
+
+	driveSettings, err := builder.controllerSettings.AddSyntheticDiskDrive(slot)
+	builder.setErr(err)
+
+	return &SyntheticDiskDriveSettingsBuilder{
+		controllerBuilder: builder,
+		driveSettings:     driveSettings,
+		err:               err,
+	}
+}
+
+func (builder *ControllerSettingsBuilder) AddSyntheticDvdDrive(slot uint) *SyntheticDvdDriveSettingsBuilder {
+	if builder.err != nil {
+		return &SyntheticDvdDriveSettingsBuilder{controllerBuilder: builder, err: builder.err}
+	}
+
+	driveSettings, err := builder.controllerSettings.AddSyntheticDvdDrive(slot)
+	builder.setErr(err)
+
+	return &SyntheticDvdDriveSettingsBuilder{
+		controllerBuilder: builder,
+		driveSettings:     driveSettings,
+		err:               err,
+	}
+}
+
+func (builder *SyntheticDiskDriveSettingsBuilder) DefineVirtualHardDisk(vhdxFile string, beforeAdd func(*VirtualHardDiskStorageSettings)) *VirtualHardDiskStorageSettingsBuilder {
+	if builder.err != nil {
+		return &VirtualHardDiskStorageSettingsBuilder{driveBuilder: builder, err: builder.err}
+	}
+
+	diskSettings, err := builder.driveSettings.DefineVirtualHardDisk(vhdxFile, beforeAdd)
+	builder.setErr(err)
+
+	return &VirtualHardDiskStorageSettingsBuilder{
+		driveBuilder: builder,
+		diskSettings: diskSettings,
+		err:          err,
+	}
+}
+
+func (builder *SyntheticDvdDriveSettingsBuilder) DefineVirtualDvdDisk(imageFile string) *VirtualDvdDiskStorageSettingsBuilder {
+	if builder.err != nil {
+		return &VirtualDvdDiskStorageSettingsBuilder{driveBuilder: builder, err: builder.err}
+	}
+
+	diskSettings, err := builder.driveSettings.DefineVirtualDvdDisk(imageFile)
+	builder.setErr(err)
+
+	return &VirtualDvdDiskStorageSettingsBuilder{
+		driveBuilder: builder,
+		diskSettings: diskSettings,
+		err:          err,
+	}
+}
+
+func (builder *SyntheticDvdDriveSettingsBuilder) setErr(err error) {
+	builder.err = err
+	builder.controllerBuilder.setErr(err)
+}
+
+func (builder *SyntheticDiskDriveSettingsBuilder) setErr(err error) {
+	builder.err = err
+	builder.controllerBuilder.setErr(err)
+}
+
+func (builder *ControllerSettingsBuilder) setErr(err error) {
+	builder.err = err
+	builder.driveSettingsBuilder.setErr(err)
+}
+
+func (builder *DriveSettingsBuilder) setErr(err error) {
+	builder.err = err
+}
+
+func (builder *ControllerSettingsBuilder) Finish() *DriveSettingsBuilder {
+	return &builder.driveSettingsBuilder
+}
+
+func (builder *VirtualHardDiskStorageSettingsBuilder) Finish() *SyntheticDiskDriveSettingsBuilder {
+	return builder.driveBuilder
+}
+
+func (builder *VirtualDvdDiskStorageSettingsBuilder) Finish() *SyntheticDvdDriveSettingsBuilder {
+	return builder.driveBuilder
+}
+
+func (builder *SyntheticDiskDriveSettingsBuilder) Finish() *ControllerSettingsBuilder {
+	return builder.controllerBuilder
+}
+
+func (builder *SyntheticDvdDriveSettingsBuilder) Finish() *ControllerSettingsBuilder {
+	return builder.controllerBuilder
+}
+
+func (builder *VirtualHardDiskStorageSettingsBuilder) Get(s **VirtualHardDiskStorageSettings) *VirtualHardDiskStorageSettingsBuilder {
+	*s = builder.diskSettings
+	return builder
+}
+
+func (builder *VirtualDvdDiskStorageSettingsBuilder) Get(s **VirtualDvdDiskStorageSettings) *VirtualDvdDiskStorageSettingsBuilder {
+	*s = builder.diskSettings
+	return builder
+}
+
+func (builder *SyntheticDiskDriveSettingsBuilder) Get(s **SyntheticDiskDriveSettings) *SyntheticDiskDriveSettingsBuilder {
+	*s = builder.driveSettings
+	return builder
+}
+
+func (builder *SyntheticDvdDriveSettingsBuilder) Get(s **SyntheticDvdDriveSettings) *SyntheticDvdDriveSettingsBuilder {
+	*s = builder.driveSettings
+	return builder
+}
+
+func (builder *ControllerSettingsBuilder) Get(s **ScsiControllerSettings) *ControllerSettingsBuilder {
+	*s = builder.controllerSettings
+	return builder
+}
+
+func (builder *DriveSettingsBuilder) Complete() error {
+	return builder.err
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/dvddrive_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/dvddrive_settings.go
new file mode 100644
index 000000000..2f66163a2
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/dvddrive_settings.go
@@ -0,0 +1,24 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+const SyntheticDvdDriveType = "Microsoft:Hyper-V:Synthetic DVD Drive"
+
+type SyntheticDvdDriveSettings struct {
+	ResourceSettings
+	systemSettings     *SystemSettings
+	controllerSettings *ScsiControllerSettings
+}
+
+func (d *SyntheticDvdDriveSettings) DefineVirtualDvdDisk(imageFile string) (*VirtualDvdDiskStorageSettings, error) {
+	vdvd := &VirtualDvdDiskStorageSettings{}
+
+	if err := createDiskResourceInternal(d.systemSettings.Path(), d.Path(), imageFile, vdvd, VirtualDvdDiskType, nil); err != nil {
+		return nil, err
+	}
+
+	vdvd.driveSettings = d
+	vdvd.systemSettings = d.systemSettings
+	return vdvd, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go
new file mode 100644
index 000000000..2f169712a
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go
@@ -0,0 +1,174 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+// VM State errors
+var (
+	ErrMachineAlreadyRunning = errors.New("machine already running")
+	ErrMachineNotRunning     = errors.New("machine not running")
+	ErrMachineStateInvalid   = errors.New("machine in invalid state for action")
+	ErrMachineStarting       = errors.New("machine is currently starting")
+)
+
+// VM Creation errors
+var (
+	ErrMachineAlreadyExists = errors.New("machine already exists")
+)
+
+type DestroySystemResult int32
+
+// VM Destroy Exit Codes
+const (
+	VMDestroyCompletedwithNoError DestroySystemResult = 0
+	VMDestroyNotSupported         DestroySystemResult = 1
+	VMDestroyFailed               DestroySystemResult = 2
+	VMDestroyTimeout              DestroySystemResult = 3
+	VMDestroyInvalidParameter     DestroySystemResult = 4
+	VMDestroyInvalidState         DestroySystemResult = 5
+)
+
+func (e DestroySystemResult) Reason() string {
+	switch e {
+	case VMDestroyNotSupported:
+		return "not supported"
+	case VMDestroyFailed:
+		return "failed"
+	case VMDestroyTimeout:
+		return "timeout"
+	case VMDestroyInvalidParameter:
+		return "invalid parameter"
+	case VMDestroyInvalidState:
+		return "invalid state"
+	}
+	return "Unknown"
+}
+
+// Shutdown operation error codes
+const (
+	ErrShutdownFailed           = 32768
+	ErrShutdownAccessDenied     = 32769
+	ErrShutdownNotSupported     = 32770
+	ErrShutdownStatusUnkown     = 32771
+	ErrShutdownTimeout          = 32772
+	ErrShutdownInvalidParameter = 32773
+	ErrShutdownSystemInUse      = 32774
+	ErrShutdownInvalidState     = 32775
+	ErrShutdownIncorrectData    = 32776
+	ErrShutdownNotAvailable     = 32777
+	ErrShutdownOutOfMemory      = 32778
+	ErrShutdownFileNotFound     = 32779
+	ErrShutdownNotReady         = 32780
+	ErrShutdownMachineLocked    = 32781
+	ErrShutdownInProgress       = 32782
+)
+
+type shutdownCompError struct {
+	errorCode int
+	message   string
+}
+
+func (s *shutdownCompError) Error() string {
+	return fmt.Sprintf("%s (%d)", s.message, s.errorCode)
+}
+
+func translateShutdownError(code int) error {
+	var message string
+	switch code {
+	case ErrShutdownFailed:
+		message = "shutdown failed"
+	case ErrShutdownAccessDenied:
+		message = "access was denied"
+	case ErrShutdownNotSupported:
+		message = "shutdown not supported by virtual machine"
+	case ErrShutdownStatusUnkown:
+		message = "virtual machine status is unknown"
+	case ErrShutdownTimeout:
+		message = "timeout starting shutdown"
+	case ErrShutdownInvalidParameter:
+		message = "invalid parameter"
+	case ErrShutdownSystemInUse:
+		message = "system in use"
+	case ErrShutdownInvalidState:
+		message = "virtual machine is in an invalid state for shutdown"
+	case ErrShutdownIncorrectData:
+		message = "incorrect data type"
+	case ErrShutdownNotAvailable:
+		message = "system is not available"
+	case ErrShutdownOutOfMemory:
+		message = "out of memory"
+	case ErrShutdownFileNotFound:
+		message = "file not found"
+	case ErrShutdownMachineLocked:
+		message = "machine is locked and cannot be shut down without the force option"
+	case ErrShutdownInProgress:
+		message = "shutdown is already in progress"
+	default:
+		message = "unknown error"
+	}
+
+	return &shutdownCompError{code, message}
+}
+
+// Modify resource errors
+const (
+	ErrModifyResourceNotSupported     = 1
+	ErrModifyResourceFailed           = 2
+	ErrModifyResourceTimeout          = 3
+	ErrModifyResourceInvalidParameter = 4
+	ErrModifyResourceInvalidState     = 5
+	ErrModifyResourceIncompatParam    = 6
+)
+
+type modifyResourceError struct {
+	errorCode int
+	message   string
+}
+
+func (m *modifyResourceError) Error() string {
+	return fmt.Sprintf("%s (%d)", m.message, m.errorCode)
+}
+
+func translateModifyError(code int) error {
+	var message string
+	switch code {
+	case ErrModifyResourceNotSupported:
+		message = "virtual machine does not support modification operations"
+	case ErrModifyResourceFailed:
+		message = "resource modification failed"
+	case ErrModifyResourceTimeout:
+		message = "timeout modifying resource"
+	case ErrModifyResourceInvalidParameter:
+		message = "a modify resource operation was passed an invalid parameter"
+	case ErrModifyResourceInvalidState:
+		message = "the requested modification could not be applied due to an invalid state"
+	case ErrModifyResourceIncompatParam:
+		message = "an incompatible parameter was passed to a modify resource operation"
+	default:
+		message = "unknown error"
+	}
+
+	return &modifyResourceError{code, message}
+}
+
+var (
+	ErrHyperVNamespaceMissing = errors.New("HyperV namespace not found, is HyperV enabled?")
+)
+
+func translateCommonHyperVWmiError(wmiError error) error {
+	if werr, ok := wmiError.(*wmiext.WmiError); ok {
+		switch werr.Code() {
+		case wmiext.WBEM_E_INVALID_NAMESPACE:
+			return ErrHyperVNamespaceMissing
+		}
+	}
+
+	return wmiError
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/ethernet_alloc_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/ethernet_alloc_settings.go
new file mode 100644
index 000000000..9cdb64495
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/ethernet_alloc_settings.go
@@ -0,0 +1,50 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+const EthernetPortAllocationResourceType = "Microsoft:Hyper-V:Ethernet Connection"
+
+type EthernetPortAllocationSettings struct {
+	InstanceID              string // = "Microsoft:GUID\DeviceSpecificData"
+	Caption                 string // = "Ethernet Switch Port Settings"
+	Description             string // = "Ethernet Switch Port Settings"
+	ElementName             string
+	ResourceType            uint16 // = 33
+	OtherResourceType       string
+	ResourceSubType         string
+	PoolID                  string
+	ConsumerVisibility      uint16 // = 3
+	HostResource            []string
+	AllocationUnits         string
+	VirtualQuantity         uint64
+	Reservation             uint64
+	Limit                   uint64
+	Weight                  uint32 // = 0
+	AutomaticAllocation     bool
+	AutomaticDeallocation   bool
+	Parent                  string
+	Connection              []string
+	Address                 string
+	MappingBehavior         uint16
+	AddressOnParent         string
+	VirtualQuantityUnits    string // = "count"
+	DesiredVLANEndpointMode uint16
+	OtherEndpointMode       string
+	EnabledState            uint16
+	LastKnownSwitchName     string
+	RequiredFeatures        []string
+	RequiredFeatureHints    []string
+	TestReplicaPoolID       string
+	TestReplicaSwitchName   string
+	CompartmentGuid         string
+}
+
+func fetchEthernetPortAllocationSettings() (*EthernetPortAllocationSettings, error) {
+	settings := &EthernetPortAllocationSettings{}
+	return settings, populateDefaults(EthernetPortAllocationResourceType, settings)
+}
+
+func creatEthernetPortAllocationSettings(settings *EthernetPortAllocationSettings) (string, error) {
+	return createResourceSettingGeneric(settings, EthernetPortAllocationResourceType)
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/ethernet_port_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/ethernet_port_settings.go
new file mode 100644
index 000000000..294d87e5e
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/ethernet_port_settings.go
@@ -0,0 +1,109 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"fmt"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+const SyntheticEthernetPortResourceType = "Microsoft:Hyper-V:Synthetic Ethernet Port"
+const DefaultSwitchId = "C08CB7B8-9B3C-408E-8E30-5E16A3AEB444"
+
+type SyntheticEthernetPortSettings struct {
+	S__PATH                  string
+	InstanceID               string
+	Caption                  string // = "Virtual Ethernet Port Default Settings"
+	Description              string // = "Describes the default settings for the virtual Ethernet port resources."
+	ElementName              string
+	ResourceType             uint16 // = 10
+	OtherResourceType        string
+	ResourceSubType          string // = "Microsoft:Hyper-V:Synthetic Ethernet Port"
+	PoolID                   string
+	ConsumerVisibility       uint16 // = 3
+	HostResource             []string
+	AllocationUnits          string // = "count"
+	VirtualQuantity          uint64 // = 1
+	Reservation              uint64 // = 1
+	Limit                    uint64 // = 1
+	Weight                   uint32 // = 0
+	AutomaticAllocation      bool   // = True
+	AutomaticDeallocation    bool   // = True
+	Parent                   string
+	Connection               []string
+	Address                  string
+	MappingBehavior          uint16
+	AddressOnParent          string
+	VirtualQuantityUnits     string // = "count"
+	DesiredVLANEndpointMode  uint16
+	OtherEndpointMode        string
+	VirtualSystemIdentifiers []string
+	DeviceNamingEnabled      bool // = FALSE
+	AllowPacketDirect        bool // = FALSE
+	StaticMacAddress         bool // = False
+	ClusterMonitored         bool // = TRUE
+
+	systemSettings *SystemSettings
+}
+
+func (p *SyntheticEthernetPortSettings) Path() string {
+	return p.S__PATH
+}
+
+func (p *SyntheticEthernetPortSettings) DefineEthernetPortConnection(switchName string) (*EthernetPortAllocationSettings, error) {
+	const wqlFormat = "select * from Msvm_VirtualEthernetSwitch where %s = '%s'"
+
+	var wqlProperty, wqlValue string
+	if len(switchName) > 0 {
+		wqlProperty = "ElementName"
+		wqlValue = switchName
+	} else {
+		wqlProperty = "Name"
+		wqlValue = DefaultSwitchId
+	}
+
+	wql := fmt.Sprintf(wqlFormat, wqlProperty, wqlValue)
+
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return nil, err
+	}
+	defer service.Close()
+
+	switchInst, err := service.FindFirstInstance(wql)
+	if err != nil {
+		return nil, err
+	}
+	defer switchInst.Close()
+	switchPath, err := switchInst.Path()
+	if err != nil {
+		return nil, err
+	}
+
+	connectSettings, err := fetchEthernetPortAllocationSettings()
+	if err != nil {
+		return nil, err
+	}
+
+	connectSettings.Parent = p.Path()
+	connectSettings.HostResource = append(connectSettings.HostResource, switchPath)
+
+	resource, err := creatEthernetPortAllocationSettings(connectSettings)
+	if err != nil {
+		return nil, err
+	}
+
+	path, err := addResource(service, p.systemSettings.Path(), resource)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := service.GetObjectAsObject(path, connectSettings); err != nil {
+		return nil, err
+	}
+
+	return connectSettings, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/kvp.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/kvp.go
new file mode 100644
index 000000000..04bed3429
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/kvp.go
@@ -0,0 +1,138 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"encoding/xml"
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+const (
+	KvpOperationFailed    = 32768
+	KvpAccessDenied       = 32769
+	KvpNotSupported       = 32770
+	KvpStatusUnknown      = 32771
+	KvpTimeoutOccurred    = 32772
+	KvpIllegalArgument    = 32773
+	KvpSystemInUse        = 32774
+	KvpInvalidState       = 32775
+	KvpIncorrectDataType  = 32776
+	KvpSystemNotAvailable = 32777
+	KvpOutOfMemory        = 32778
+	KvpNotFound           = 32779
+
+	KvpExchangeDataItemName = "Msvm_KvpExchangeDataItem"
+	MemorySettingDataName   = "Msvm_MemorySettingData"
+)
+
+type CimKvpItems struct {
+	Instances []CimKvpItem `xml:"INSTANCE"`
+}
+
+type CimKvpItem struct {
+	Properties []CimKvpItemProperty `xml:"PROPERTY"`
+}
+
+type CimKvpItemProperty struct {
+	Name  string `xml:"NAME,attr"`
+	Value string `xml:"VALUE"`
+}
+
+type KvpError struct {
+	ErrorCode int
+	message   string
+}
+
+func (k *KvpError) Error() string {
+	return fmt.Sprintf("%s (%d)", k.message, k.ErrorCode)
+}
+
+func createKvpItem(service *wmiext.Service, key string, value string) (string, error) {
+	item, err := service.SpawnInstance(KvpExchangeDataItemName)
+	if err != nil {
+		return "", err
+	}
+	defer item.Close()
+
+	_ = item.Put("Name", key)
+	_ = item.Put("Data", value)
+	_ = item.Put("Source", 0)
+	itemStr := item.GetCimText()
+	return itemStr, nil
+}
+
+func parseKvpMapXml(kvpXml string) (map[string]string, error) {
+	// Workaround XML decoder's inability to handle multiple root elements
+	r := io.MultiReader(
+		strings.NewReader("<root>"),
+		strings.NewReader(kvpXml),
+		strings.NewReader("</root>"),
+	)
+
+	var items CimKvpItems
+	if err := xml.NewDecoder(r).Decode(&items); err != nil {
+		return nil, err
+	}
+
+	ret := make(map[string]string)
+	for _, item := range items.Instances {
+		var key, value string
+		for _, prop := range item.Properties {
+			if strings.EqualFold(prop.Name, "Name") {
+				key = prop.Value
+			} else if strings.EqualFold(prop.Name, "Data") {
+				value = prop.Value
+			}
+		}
+		if len(key) > 0 {
+			ret[key] = value
+		}
+	}
+
+	return ret, nil
+}
+
+func translateKvpError(source error, illegalSuggestion string) error {
+	j, ok := source.(*wmiext.JobError)
+
+	if !ok {
+		return source
+	}
+
+	var message string
+	switch j.ErrorCode {
+	case KvpOperationFailed:
+		message = "Operation failed"
+	case KvpAccessDenied:
+		message = "Access denied"
+	case KvpNotSupported:
+		message = "Not supported"
+	case KvpStatusUnknown:
+		message = "Status is unknown"
+	case KvpTimeoutOccurred:
+		message = "Timeout occurred"
+	case KvpIllegalArgument:
+		message = "Illegal argument (" + illegalSuggestion + ")"
+	case KvpSystemInUse:
+		message = "System is in use"
+	case KvpInvalidState:
+		message = "Invalid state for this operation"
+	case KvpIncorrectDataType:
+		message = "Incorrect data type"
+	case KvpSystemNotAvailable:
+		message = "System is not available"
+	case KvpOutOfMemory:
+		message = "Out of memory"
+	case KvpNotFound:
+		message = "Not found"
+	default:
+		return source
+	}
+
+	return &KvpError{j.ErrorCode, message}
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go
new file mode 100644
index 000000000..960694eb7
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go
@@ -0,0 +1,56 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import "fmt"
+
+const MemoryResourceType = "Microsoft:Hyper-V:Memory"
+
+type MemorySettings struct {
+	S__PATH                    string
+	InstanceID                 string
+	Caption                    string // = "Memory Default Settings"
+	Description                string // = "Describes the default settings for the memory resources."
+	ElementName                string
+	ResourceType               uint16 // = 4
+	OtherResourceType          string
+	ResourceSubType            string // = "Microsoft:Hyper-V:Memory"
+	PoolID                     string
+	ConsumerVisibility         uint16
+	HostResource               []string
+	HugePagesEnabled           bool
+	AllocationUnits            string // = "byte * 2^20"
+	VirtualQuantity            uint64
+	Reservation                uint64
+	Limit                      uint64
+	Weight                     uint32
+	AutomaticAllocation        bool // = True
+	AutomaticDeallocation      bool // = True
+	Parent                     string
+	Connection                 []string
+	Address                    string
+	MappingBehavior            uint16
+	AddressOnParent            string
+	VirtualQuantityUnits       string // = "byte * 2^20"
+	DynamicMemoryEnabled       bool
+	TargetMemoryBuffer         uint32
+	IsVirtualized              bool // = True
+	SwapFilesInUse             bool
+	MaxMemoryBlocksPerNumaNode uint64
+	SgxSize                    uint64
+	SgxEnabled                 bool
+}
+
+func createMemorySettings(settings *MemorySettings) (string, error) {
+	str, err := createResourceSettingGeneric(settings, MemoryResourceType)
+	if err != nil {
+		err = fmt.Errorf("could not create memory settings: %w", err)
+	}
+	return str, err
+}
+
+func fetchDefaultMemorySettings() (*MemorySettings, error) {
+	settings := &MemorySettings{}
+	return settings, populateDefaults(MemoryResourceType, settings)
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/network_settings_builder.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/network_settings_builder.go
new file mode 100644
index 000000000..ed5abd637
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/network_settings_builder.go
@@ -0,0 +1,86 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+type NetworkSettingsBuilder struct {
+	systemSettings *SystemSettings
+	err            error
+}
+
+type SyntheticEthernetPortSettingsBuilder struct {
+	networkSettingsBuilder *NetworkSettingsBuilder
+	portSettings           *SyntheticEthernetPortSettings
+	err                    error
+}
+
+type EthernetPortAllocationSettingsBuilder struct {
+	portSettingsBuilder *SyntheticEthernetPortSettingsBuilder
+	allocSettings       *EthernetPortAllocationSettings
+	err                 error
+}
+
+func NewNetworkSettingsBuilder(systemSettings *SystemSettings) *NetworkSettingsBuilder {
+	return &NetworkSettingsBuilder{systemSettings: systemSettings}
+}
+
+func (builder *NetworkSettingsBuilder) AddSyntheticEthernetPort(beforeAdd func(*SyntheticEthernetPortSettings)) *SyntheticEthernetPortSettingsBuilder {
+	if builder.err != nil {
+		return &SyntheticEthernetPortSettingsBuilder{networkSettingsBuilder: builder, err: builder.err}
+	}
+
+	portSettings, err := builder.systemSettings.AddSyntheticEthernetPort(beforeAdd)
+	builder.setErr(err)
+
+	return &SyntheticEthernetPortSettingsBuilder{
+		networkSettingsBuilder: builder,
+		portSettings:           portSettings,
+		err:                    err,
+	}
+}
+
+func (builder *SyntheticEthernetPortSettingsBuilder) AddEthernetPortAllocation(switchName string) *EthernetPortAllocationSettingsBuilder {
+	if builder.err != nil {
+		return &EthernetPortAllocationSettingsBuilder{portSettingsBuilder: builder, err: builder.err}
+	}
+
+	allocSettings, err := builder.portSettings.DefineEthernetPortConnection(switchName)
+	builder.setErr(err)
+
+	return &EthernetPortAllocationSettingsBuilder{
+		portSettingsBuilder: builder,
+		allocSettings:       allocSettings,
+		err:                 err,
+	}
+}
+
+func (builder *SyntheticEthernetPortSettingsBuilder) Finish() *NetworkSettingsBuilder {
+	return builder.networkSettingsBuilder
+}
+
+func (builder *EthernetPortAllocationSettingsBuilder) Finish() *SyntheticEthernetPortSettingsBuilder {
+	return builder.portSettingsBuilder
+}
+
+func (builder *NetworkSettingsBuilder) setErr(err error) {
+	builder.err = err
+}
+
+func (builder *SyntheticEthernetPortSettingsBuilder) setErr(err error) {
+	builder.err = err
+	builder.networkSettingsBuilder.setErr(err)
+}
+
+func (builder *EthernetPortAllocationSettingsBuilder) Get(s **EthernetPortAllocationSettings) *EthernetPortAllocationSettingsBuilder {
+	*s = builder.allocSettings
+	return builder
+}
+
+func (builder *SyntheticEthernetPortSettingsBuilder) Get(s **SyntheticEthernetPortSettings) *SyntheticEthernetPortSettingsBuilder {
+	*s = builder.portSettings
+	return builder
+}
+
+func (builder *NetworkSettingsBuilder) Complete() error {
+	return builder.err
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go
new file mode 100644
index 000000000..9c0d6d95e
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go
@@ -0,0 +1,98 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import "fmt"
+
+const ProcessorResourceType = "Microsoft:Hyper-V:Processor"
+
+/*
+AllocationUnits                : percent / 1000
+AllowACountMCount              : True
+AutomaticAllocation            : True
+AutomaticDeallocation          : True
+Caption                        : Processor
+Connection                     :
+ConsumerVisibility             : 3
+CpuGroupId                     : 00000000-0000-0000-0000-000000000000
+Description                    : Settings for Microsoft Virtual Processor.
+DisableSpeculationControls     : False
+ElementName                    : Processor
+EnableHostResourceProtection   : False
+EnableLegacyApicMode           : False
+EnablePageShattering           : 0
+EnablePerfmonIpt               : False
+EnablePerfmonLbr               : False
+EnablePerfmonPebs              : False
+EnablePerfmonPmu               : False
+ExposeVirtualizationExtensions : False
+HideHypervisorPresent          : False
+HostResource                   :
+HwThreadsPerCore               : 0
+InstanceID                     : Microsoft:B5314955-3924-42BA-ABF9-793993D340A0\b637f346-6a0e-4dec-af52-bd70cb80a21d\0
+Limit                          : 100000
+LimitCPUID                     : False
+LimitProcessorFeatures         : False
+MappingBehavior                :
+MaxNumaNodesPerSocket          : 1
+MaxProcessorsPerNumaNode       : 4
+OtherResourceType              :
+Parent                         :
+PoolID                         :
+Reservation                    : 0
+ResourceSubType                : Microsoft:Hyper-V:Processor
+ResourceType                   : 3
+VirtualQuantity                : 2
+VirtualQuantityUnits           : count
+Weight                         : 100
+*/
+
+type ProcessorSettings struct {
+	S__PATH                        string
+	InstanceID                     string
+	Caption                        string // = "Processor"
+	Description                    string // = "A logical processor of the hypervisor running on the host computer system."
+	ElementName                    string
+	ResourceType                   uint16 // = 3
+	OtherResourceType              string
+	ResourceSubType                string // = "Microsoft:Hyper-V:Processor"
+	PoolID                         string
+	ConsumerVisibility             uint16
+	HostResource                   []string
+	AllocationUnits                string // = "percent / 1000"
+	VirtualQuantity                uint64 // = "count"
+	Reservation                    uint64 // = 0
+	Limit                          uint64 // = 100000
+	Weight                         uint32 // = 100
+	AutomaticAllocation            bool   // = True
+	AutomaticDeallocation          bool   // = True
+	Parent                         string
+	Connection                     []string
+	Address                        string
+	MappingBehavior                uint16
+	AddressOnParent                string
+	VirtualQuantityUnits           string // = "count"
+	LimitCPUID                     bool
+	HwThreadsPerCore               uint64
+	LimitProcessorFeatures         bool
+	MaxProcessorsPerNumaNode       uint64
+	MaxNumaNodesPerSocket          uint64
+	EnableHostResourceProtection   bool
+	CpuGroupId                     string
+	HideHypervisorPresent          bool
+	ExposeVirtualizationExtensions bool
+}
+
+func fetchDefaultProcessorSettings() (*ProcessorSettings, error) {
+	settings := &ProcessorSettings{}
+	return settings, populateDefaults(ProcessorResourceType, settings)
+}
+
+func createProcessorSettings(settings *ProcessorSettings) (string, error) {
+	str, err := createResourceSettingGeneric(settings, ProcessorResourceType)
+	if err != nil {
+		err = fmt.Errorf("could not create processor settings: %w", err)
+	}
+	return str, err
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/resources_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/resources_settings.go
new file mode 100644
index 000000000..eda4b2523
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/resources_settings.go
@@ -0,0 +1,135 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+type ResourceSettings struct {
+	S__PATH                  string
+	InstanceID               string // = "Microsoft:GUID\DeviceSpecificData"
+	Caption                  string
+	Description              string
+	ElementName              string
+	ResourceType             uint16
+	OtherResourceType        string
+	ResourceSubType          string
+	PoolID                   string
+	ConsumerVisibility       uint16
+	HostResource             []string
+	AllocationUnits          string
+	VirtualQuantity          uint64
+	Reservation              uint64
+	Limit                    uint64
+	Weight                   uint32
+	AutomaticAllocation      bool
+	AutomaticDeallocation    bool
+	Parent                   string
+	Connection               []string
+	Address                  string
+	MappingBehavior          uint16
+	AddressOnParent          string
+	VirtualQuantityUnits     string   // = "count"
+	VirtualSystemIdentifiers []string // = { "GUID" }
+}
+
+func (s *ResourceSettings) setParent(parent string) {
+	s.Parent = parent
+}
+
+func (s *ResourceSettings) setAddressOnParent(address string) {
+	s.AddressOnParent = address
+}
+
+func (s *ResourceSettings) Path() string {
+	return s.S__PATH
+}
+
+func createResourceSettingGeneric(settings interface{}, resourceType string) (string, error) {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return "", err
+	}
+
+	ref, err := findResourceDefaults(service, resourceType)
+	if err != nil {
+		return "", err
+	}
+
+	resource, err := service.GetObject(ref)
+	if err != nil {
+		return "", err
+	}
+
+	defer resource.Close()
+	resource, err = resource.CloneInstance()
+	if err != nil {
+		return "", err
+	}
+	defer resource.Close()
+
+	if err = resource.PutAll(settings); err != nil {
+		return "", err
+	}
+
+	return resource.GetCimText(), nil
+}
+
+func populateDefaults(subType string, settings interface{}) error {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	ref, err := findResourceDefaults(service, subType)
+	if err != nil {
+		return err
+	}
+
+	return service.GetObjectAsObject(ref, settings)
+}
+
+func findResourceDefaults(service *wmiext.Service, subType string) (string, error) {
+	wql := fmt.Sprintf("SELECT * FROM Msvm_AllocationCapabilities WHERE ResourceSubType = '%s'", subType)
+	instance, err := service.FindFirstInstance(wql)
+	if err != nil {
+		return "", err
+	}
+	defer instance.Close()
+
+	path, err := instance.Path()
+	if err != nil {
+		return "", err
+	}
+
+	enum, err := service.ExecQuery(fmt.Sprintf("references of {%s} where ResultClass = Msvm_SettingsDefineCapabilities", path))
+	if err != nil {
+		return "", err
+	}
+	defer enum.Close()
+
+	for {
+		entry, err := enum.Next()
+		if err != nil {
+			return "", err
+		}
+		if entry == nil {
+			return "", errors.New("could not find settings definition for resource")
+		}
+
+		value, vErr := entry.GetAsUint("ValueRole")
+		ref, pErr := entry.GetAsString("PartComponent")
+		entry.Close()
+		if vErr == nil && pErr == nil && value == 0 {
+			return ref, nil
+		}
+	}
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/scsi_controller.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/scsi_controller.go
new file mode 100644
index 000000000..d38bfacb6
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/scsi_controller.go
@@ -0,0 +1,69 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"fmt"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+type ScsiControllerSettings struct {
+	ResourceSettings
+	systemSettings *SystemSettings
+}
+
+type driveAssociation interface {
+	setParent(parent string)
+	setAddressOnParent(address string)
+}
+
+func (c *ScsiControllerSettings) AddSyntheticDiskDrive(slot uint) (*SyntheticDiskDriveSettings, error) {
+	drive := &SyntheticDiskDriveSettings{}
+	if err := c.createSyntheticDriveInternal(slot, drive, SyntheticDiskDriveType); err != nil {
+		return nil, err
+	}
+	drive.systemSettings = c.systemSettings
+	drive.controllerSettings = c
+	return drive, nil
+}
+
+func (c *ScsiControllerSettings) AddSyntheticDvdDrive(slot uint) (*SyntheticDvdDriveSettings, error) {
+	drive := &SyntheticDvdDriveSettings{}
+	if err := c.createSyntheticDriveInternal(slot, drive, SyntheticDvdDriveType); err != nil {
+		return nil, err
+	}
+	drive.systemSettings = c.systemSettings
+	drive.controllerSettings = c
+	return drive, nil
+}
+
+func (c *ScsiControllerSettings) createSyntheticDriveInternal(slot uint, settings driveAssociation, resourceType string) error {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	if err = populateDefaults(resourceType, settings); err != nil {
+		return err
+	}
+
+	settings.setParent(c.Path())
+	settings.setAddressOnParent(fmt.Sprintf("%d", slot))
+
+	driveResource, err := createResourceSettingGeneric(settings, resourceType)
+	if err != nil {
+		return err
+	}
+
+	path, err := addResource(service, c.systemSettings.Path(), driveResource)
+	if err != nil {
+		return err
+	}
+
+	err = service.GetObjectAsObject(path, settings)
+	return err
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/storage_alloc_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/storage_alloc_settings.go
new file mode 100644
index 000000000..e6baa5430
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/storage_alloc_settings.go
@@ -0,0 +1,61 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+type StorageAllocationSettings struct {
+	S__PATH                         string
+	InstanceID                      string
+	Caption                         string // = "Hard Disk Image Default Settings"
+	Description                     string // = "Describes the default settings for the hard disk image resources"
+	ElementName                     string
+	ResourceType                    uint16
+	OtherResourceType               string
+	ResourceSubType                 string
+	PoolID                          string
+	ConsumerVisibility              uint16
+	HostResource                    []string
+	AllocationUnits                 string
+	VirtualQuantity                 uint64
+	Limit                           uint64 // = 1
+	Weight                          uint32
+	StorageQoSPolicyID              string
+	AutomaticAllocation             bool
+	AutomaticDeallocation           bool
+	Parent                          string
+	Connection                      []string
+	Address                         string
+	MappingBehavior                 uint16
+	AddressOnParent                 string
+	VirtualResourceBlockSize        uint64
+	VirtualQuantityUnits            string // = "count(fixed size block)"
+	Access                          uint16
+	HostResourceBlockSize           uint64
+	Reservation                     uint64
+	HostExtentStartingAddress       uint64
+	HostExtentName                  string
+	HostExtentNameFormat            uint16
+	OtherHostExtentNameFormat       string
+	HostExtentNameNamespace         uint16
+	OtherHostExtentNameNamespace    string
+	IOPSLimit                       uint64
+	IOPSReservation                 uint64
+	IOPSAllocationUnits             string
+	PersistentReservationsSupported bool
+	CachingMode                     uint16
+	SnapshotId                      string // = ""
+	IgnoreFlushes                   bool
+	WriteHardeningMethod            uint16
+}
+
+func (s *StorageAllocationSettings) setParent(parent string) {
+	s.Parent = parent
+}
+
+func (s *StorageAllocationSettings) setHostResource(resource []string) {
+	s.HostResource = resource
+}
+
+func (s *StorageAllocationSettings) Path() string {
+	return s.S__PATH
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go
new file mode 100644
index 000000000..c8abcef1b
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go
@@ -0,0 +1,202 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import "time"
+
+const (
+	SummaryRequestName                             = 0
+	SummaryRequestElementName                      = 1
+	SummaryRequestCreationTime                     = 2
+	SummaryRequestNotes                            = 3
+	SummaryRequestProcessors                       = 4
+	SummaryRequestSmallThumbnail                   = 5
+	SummaryRequestMediumThumbnail                  = 6
+	SummaryRequestLargeThumbnail                   = 7
+	SummaryRequestAllocatedGPU                     = 8
+	SummaryRequestVirtualSwitchNames               = 9
+	SummaryRequestVersion                          = 10
+	SummaryRequestShielded                         = 11
+	SummaryRequestEnabledState                     = 100
+	SummaryRequestProcessorLoad                    = 101
+	SummaryRequestProcessorLoadHistory             = 102
+	SummaryRequestMemoryUsage                      = 103
+	SummaryRequestHeartbeat                        = 104
+	SummaryRequestUptime                           = 105
+	SummaryRequestGuestOperatingSystem             = 106
+	SummaryRequestSnapshots                        = 107
+	SummaryRequestAsynchronousTasks                = 108
+	SummaryRequestHealthState                      = 109
+	SummaryRequestOperationalStatus                = 110
+	SummaryRequestStatusDescriptions               = 111
+	SummaryRequestMemoryAvailable                  = 112
+	SummaryRequestMemoryBuffer                     = 113
+	SummaryRequestReplicationMode                  = 114
+	SummaryRequestReplicationState                 = 115
+	SummaryRequestReplicationHealth                = 116
+	SummaryRequestApplicationHealth                = 117
+	SummaryRequestReplicationStateEx               = 118
+	SummaryRequestReplicationHealthEx              = 119
+	SummaryRequestSwapFilesInUse                   = 120
+	SummaryRequestIntegrationServicesVersionState  = 121
+	SummaryRequestReplicationProvider              = 122
+	SummaryRequestMemorySpansPhysicalNumaNodes     = 123
+	SummaryRequestIntegrationServicesVersionState2 = 132
+	SummaryRequestOtherEnabledState                = 132
+)
+
+type SummaryRequestSet []uint
+
+var (
+
+	// SummaryRequestCommon includes a smaller subset of commonly used fields
+	SummaryRequestCommon = SummaryRequestSet{
+		SummaryRequestName,
+		SummaryRequestElementName,
+		SummaryRequestCreationTime,
+		SummaryRequestNotes,
+		SummaryRequestProcessors,
+		SummaryRequestEnabledState,
+		SummaryRequestProcessorLoad,
+		SummaryRequestMemoryUsage,
+		SummaryRequestHeartbeat,
+		SummaryRequestUptime,
+		SummaryRequestGuestOperatingSystem,
+		SummaryRequestHealthState,
+		SummaryRequestOperationalStatus,
+		SummaryRequestStatusDescriptions,
+		SummaryRequestMemoryAvailable,
+		SummaryRequestMemoryBuffer,
+		SummaryRequestSwapFilesInUse,
+	}
+
+	// SummaryRequestNearAll includes everything but load history and thumbnails
+	SummaryRequestNearAll = SummaryRequestSet{
+		SummaryRequestName,
+		SummaryRequestElementName,
+		SummaryRequestCreationTime,
+		SummaryRequestNotes,
+		SummaryRequestProcessors,
+		SummaryRequestAllocatedGPU,
+		SummaryRequestVirtualSwitchNames,
+		SummaryRequestVersion,
+		SummaryRequestShielded,
+		SummaryRequestEnabledState,
+		SummaryRequestProcessorLoad,
+		SummaryRequestMemoryUsage,
+		SummaryRequestHeartbeat,
+		SummaryRequestUptime,
+		SummaryRequestGuestOperatingSystem,
+		SummaryRequestSnapshots,
+		SummaryRequestAsynchronousTasks,
+		SummaryRequestHealthState,
+		SummaryRequestOperationalStatus,
+		SummaryRequestStatusDescriptions,
+		SummaryRequestMemoryAvailable,
+		SummaryRequestMemoryBuffer,
+		SummaryRequestReplicationMode,
+		SummaryRequestReplicationState,
+		SummaryRequestReplicationHealth,
+		SummaryRequestApplicationHealth,
+		SummaryRequestReplicationStateEx,
+		SummaryRequestReplicationHealthEx,
+		SummaryRequestSwapFilesInUse,
+		SummaryRequestIntegrationServicesVersionState,
+		SummaryRequestReplicationProvider,
+		SummaryRequestMemorySpansPhysicalNumaNodes,
+		SummaryRequestIntegrationServicesVersionState2,
+		SummaryRequestOtherEnabledState,
+	}
+)
+
+// SummaryInformation https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/msvm-summaryinformation
+type SummaryInformation struct {
+	InstanceID                      string
+	AllocatedGPU                    string
+	Shielded                        bool
+	AsynchronousTasks               []ConcreteJob
+	CreationTime                    time.Time
+	ElementName                     string
+	EnabledState                    uint16
+	OtherEnabledState               string
+	GuestOperatingSystem            string
+	HealthState                     uint16
+	Heartbeat                       uint16
+	MemoryUsage                     uint64
+	MemoryAvailable                 int32
+	AvailableMemoryBuffer           int32
+	SwapFilesInUse                  bool
+	Name                            string
+	Notes                           string
+	Version                         string
+	NumberOfProcessors              uint16
+	OperationalStatus               []uint16
+	ProcessorLoad                   uint16
+	ProcessorLoadHistory            []uint16
+	Snapshots                       []SystemSettings
+	StatusDescriptions              []string
+	ThumbnailImage                  []uint8
+	ThumbnailImageHeight            uint16
+	ThumbnailImageWidth             uint16
+	UpTime                          uint64
+	ReplicationState                uint16
+	ReplicationStateEx              []uint16
+	ReplicationHealth               uint16
+	ReplicationHealthEx             []uint16
+	ReplicationMode                 uint16
+	TestReplicaSystem               string // REF to CIM_ComputerSystem
+	ApplicationHealth               uint16
+	IntegrationServicesVersionState uint16
+	MemorySpansPhysicalNumaNodes    bool
+	ReplicationProviderId           []string
+	EnhancedSessionModeState        uint16
+	VirtualSwitchNames              []string
+	VirtualSystemSubType            string
+	HostComputerSystemName          string
+}
+
+// CIM_ConcreteJob https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/msvm-concretejob
+type ConcreteJob struct {
+	InstanceID              string
+	Caption                 string
+	Description             string
+	ElementName             string
+	InstallDate             time.Time
+	Name                    string
+	OperationalStatus       []uint16 // = { 2 }
+	StatusDescriptions      []string // = { "OK" }
+	Status                  string
+	HealthState             uint16 // = 5
+	CommunicationStatus     uint16
+	DetailedStatus          uint16
+	OperatingStatus         uint16
+	PrimaryStatus           uint16
+	JobStatus               string
+	TimeSubmitted           time.Time
+	ScheduledStartTime      time.Time
+	StartTime               time.Time
+	ElapsedTime             time.Duration
+	JobRunTimes             uint32
+	RunMonth                uint8
+	RunDay                  int8
+	RunDayOfWeek            int8
+	RunStartInterval        time.Time
+	LocalOrUtcTime          uint16
+	UntilTime               time.Time
+	Notify                  string
+	Owner                   string
+	Priority                uint32
+	PercentComplete         uint16
+	DeleteOnCompletion      bool
+	ErrorCode               uint16
+	ErrorDescription        string
+	ErrorSummaryDescription string
+	RecoveryAction          uint16
+	OtherRecoveryAction     string
+	JobState                uint16
+	TimeOfLastStateChange   time.Time
+	TimeBeforeRemoval       time.Duration // =
+	Cancellable             bool
+	JobType                 uint16
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go
new file mode 100644
index 000000000..cfb4207dc
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go
@@ -0,0 +1,207 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+type SystemSettings struct {
+	S__PATH                              string
+	InstanceID                           string
+	Caption                              string // = "Virtual Machine Settings"
+	Description                          string
+	ElementName                          string
+	VirtualSystemIdentifier              string
+	VirtualSystemType                    string
+	Notes                                []string
+	CreationTime                         time.Time
+	ConfigurationID                      string
+	ConfigurationDataRoot                string
+	ConfigurationFile                    string
+	SnapshotDataRoot                     string
+	SuspendDataRoot                      string
+	SwapFileDataRoot                     string
+	LogDataRoot                          string
+	AutomaticStartupAction               uint16 // non-zero
+	AutomaticStartupActionDelay          time.Duration
+	AutomaticStartupActionSequenceNumber uint16
+	AutomaticShutdownAction              uint16 // non-zero
+	AutomaticRecoveryAction              uint16 // non-zero
+	RecoveryFile                         string
+	BIOSGUID                             string
+	BIOSSerialNumber                     string
+	BaseBoardSerialNumber                string
+	ChassisSerialNumber                  string
+	Architecture                         string
+	ChassisAssetTag                      string
+	BIOSNumLock                          bool
+	BootOrder                            []uint16
+	Parent                               string
+	UserSnapshotType                     uint16 // non-zero
+	IsSaved                              bool
+	AdditionalRecoveryInformation        string
+	AllowFullSCSICommandSet              bool
+	DebugChannelId                       uint32
+	DebugPortEnabled                     uint16
+	DebugPort                            uint32
+	Version                              string
+	IncrementalBackupEnabled             bool
+	VirtualNumaEnabled                   bool
+	AllowReducedFcRedundancy             bool // = False
+	VirtualSystemSubType                 string
+	BootSourceOrder                      []string
+	PauseAfterBootFailure                bool
+	NetworkBootPreferredProtocol         uint16 // non-zero
+	GuestControlledCacheTypes            bool
+	AutomaticSnapshotsEnabled            bool
+	IsAutomaticSnapshot                  bool
+	GuestStateFile                       string
+	GuestStateDataRoot                   string
+	LockOnDisconnect                     bool
+	ParentPackage                        string
+	AutomaticCriticalErrorActionTimeout  time.Duration
+	AutomaticCriticalErrorAction         uint16
+	ConsoleMode                          uint16
+	SecureBootEnabled                    bool
+	SecureBootTemplateId                 string
+	LowMmioGapSize                       uint64
+	HighMmioGapSize                      uint64
+	EnhancedSessionTransportType         uint16
+}
+
+func DefaultSystemSettings() *SystemSettings {
+	return &SystemSettings{
+		// setup all non-zero settings
+		AutomaticStartupAction:       2,    // no auto-start
+		AutomaticShutdownAction:      4,    // shutdown
+		AutomaticRecoveryAction:      3,    // restart
+		UserSnapshotType:             2,    // no snapshotting
+		NetworkBootPreferredProtocol: 4096, // ipv4 for pxe
+		VirtualSystemSubType:         "Microsoft:Hyper-V:SubType:2",
+	}
+
+}
+
+func (s *SystemSettings) Path() string {
+	return s.S__PATH
+}
+
+func (s *SystemSettings) AddScsiController() (*ScsiControllerSettings, error) {
+	const scsiControllerType = "Microsoft:Hyper-V:Synthetic SCSI Controller"
+	controller := &ScsiControllerSettings{}
+
+	if err := s.createSystemResourceInternal(controller, scsiControllerType, nil); err != nil {
+		return nil, err
+	}
+
+	controller.systemSettings = s
+	return controller, nil
+}
+
+func (s *SystemSettings) createSystemResourceInternal(settings interface{}, resourceType string, cb func()) error {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	if err = populateDefaults(resourceType, settings); err != nil {
+		return err
+	}
+
+	if cb != nil {
+		cb()
+	}
+
+	resourceStr, err := createResourceSettingGeneric(settings, resourceType)
+	if err != nil {
+		return err
+	}
+
+	path, err := addResource(service, s.Path(), resourceStr)
+	if err != nil {
+		return err
+	}
+
+	err = service.GetObjectAsObject(path, settings)
+	return err
+}
+
+func (s *SystemSettings) AddSyntheticEthernetPort(beforeAdd func(*SyntheticEthernetPortSettings)) (*SyntheticEthernetPortSettings, error) {
+	const networkAdapterType = SyntheticEthernetPortResourceType
+	port := &SyntheticEthernetPortSettings{}
+
+	var cb func()
+	if beforeAdd != nil {
+		cb = func() {
+			beforeAdd(port)
+		}
+	}
+
+	if err := s.createSystemResourceInternal(port, networkAdapterType, cb); err != nil {
+		return nil, err
+	}
+
+	port.systemSettings = s
+	return port, nil
+}
+
+func addResource(service *wmiext.Service, systemSettingPath string, resourceSettings string) (string, error) {
+	vsms, err := service.GetSingletonInstance(VirtualSystemManagementService)
+	if err != nil {
+		return "", err
+	}
+	defer vsms.Close()
+
+	var res int32
+	var resultingSettings []string
+	var job *wmiext.Instance
+	err = vsms.BeginInvoke("AddResourceSettings").
+		In("AffectedConfiguration", systemSettingPath).
+		In("ResourceSettings", []string{resourceSettings}).
+		Execute().
+		Out("Job", &job).
+		Out("ResultingResourceSettings", &resultingSettings).
+		Out("ReturnValue", &res).End()
+
+	if err != nil {
+		return "", fmt.Errorf("AddResourceSettings failed: %w", err)
+	}
+
+	err = waitVMResult(res, service, job, "failed to add resource", nil)
+
+	if len(resultingSettings) > 0 {
+		return resultingSettings[0], err
+	}
+
+	return "", err
+}
+
+func (s *SystemSettings) GetVM() (*VirtualMachine, error) {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return nil, err
+	}
+	defer service.Close()
+
+	inst, err := service.FindFirstRelatedInstance(s.Path(), "Msvm_ComputerSystem")
+	if err != nil {
+		return nil, err
+	}
+	defer inst.Close()
+
+	vm := &VirtualMachine{}
+
+	if err = inst.GetAll(vm); err != nil {
+		return nil, err
+	}
+
+	return vm, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go
new file mode 100644
index 000000000..76b599536
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go
@@ -0,0 +1,161 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"fmt"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+type SystemSettingsBuilder struct {
+	systemSettings    *SystemSettings
+	processorSettings *ProcessorSettings
+	memorySettings    *MemorySettings
+	err               error
+}
+
+func NewSystemSettingsBuilder() *SystemSettingsBuilder {
+	return &SystemSettingsBuilder{}
+}
+
+func (builder *SystemSettingsBuilder) PrepareSystemSettings(name string, beforeAdd func(*SystemSettings)) *SystemSettingsBuilder {
+	if builder.err != nil {
+		return builder
+	}
+
+	if builder.systemSettings == nil {
+		settings := DefaultSystemSettings()
+		settings.ElementName = name
+		builder.systemSettings = settings
+	}
+
+	if beforeAdd != nil {
+		beforeAdd(builder.systemSettings)
+	}
+
+	return builder
+}
+
+func (builder *SystemSettingsBuilder) PrepareProcessorSettings(beforeAdd func(*ProcessorSettings)) *SystemSettingsBuilder {
+	if builder.err != nil {
+		return builder
+	}
+
+	if builder.processorSettings == nil {
+		settings, err := fetchDefaultProcessorSettings()
+		if err != nil {
+			builder.err = err
+			return builder
+		}
+		builder.processorSettings = settings
+	}
+
+	if beforeAdd != nil {
+		beforeAdd(builder.processorSettings)
+	}
+
+	return builder
+}
+
+func (builder *SystemSettingsBuilder) PrepareMemorySettings(beforeAdd func(*MemorySettings)) *SystemSettingsBuilder {
+	if builder.err != nil {
+		return builder
+	}
+
+	if builder.memorySettings == nil {
+		settings, err := fetchDefaultMemorySettings()
+		if err != nil {
+			builder.err = err
+			return builder
+		}
+		builder.memorySettings = settings
+	}
+
+	if beforeAdd != nil {
+		beforeAdd(builder.memorySettings)
+	}
+
+	return builder
+}
+
+func (builder *SystemSettingsBuilder) Build() (*SystemSettings, error) {
+	var service *wmiext.Service
+	var err error
+
+	if builder.PrepareSystemSettings("unnamed-vm", nil).
+		PrepareProcessorSettings(nil).
+		PrepareMemorySettings(nil).err != nil {
+		return nil, err
+	}
+
+	if service, err = NewLocalHyperVService(); err != nil {
+		return nil, err
+	}
+	defer service.Close()
+
+	systemSettingsInst, err := service.SpawnInstance("Msvm_VirtualSystemSettingData")
+	if err != nil {
+		return nil, err
+	}
+	defer systemSettingsInst.Close()
+
+	err = systemSettingsInst.PutAll(builder.systemSettings)
+	if err != nil {
+		return nil, err
+	}
+
+	memoryStr, err := createMemorySettings(builder.memorySettings)
+	if err != nil {
+		return nil, err
+	}
+
+	processorStr, err := createProcessorSettings(builder.processorSettings)
+	if err != nil {
+		return nil, err
+	}
+
+	vsms, err := service.GetSingletonInstance(VirtualSystemManagementService)
+	if err != nil {
+		return nil, err
+	}
+	defer vsms.Close()
+
+	systemStr := systemSettingsInst.GetCimText()
+
+	var job *wmiext.Instance
+	var res int32
+	var resultingSystem string
+	err = vsms.BeginInvoke("DefineSystem").
+		In("SystemSettings", systemStr).
+		In("ResourceSettings", []string{memoryStr, processorStr}).
+		Execute().
+		Out("Job", &job).
+		Out("ResultingSystem", &resultingSystem).
+		Out("ReturnValue", &res).End()
+
+	if err != nil {
+		return nil, fmt.Errorf("failed to define system: %w", err)
+	}
+
+	err = waitVMResult(res, service, job, "failed to define system", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	newSettings, err := service.FindFirstRelatedInstance(resultingSystem, "Msvm_VirtualSystemSettingData")
+	if err != nil {
+		return nil, err
+	}
+	path, err := newSettings.Path()
+	if err != nil {
+		return nil, err
+	}
+
+	if err = service.GetObjectAsObject(path, builder.systemSettings); err != nil {
+		return nil, err
+	}
+
+	return builder.systemSettings, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vdvd_storage_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vdvd_storage_settings.go
new file mode 100644
index 000000000..ad5eceabe
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vdvd_storage_settings.go
@@ -0,0 +1,13 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+const VirtualDvdDiskType = "Microsoft:Hyper-V:Virtual CD/DVD Disk"
+
+type VirtualDvdDiskStorageSettings struct {
+	StorageAllocationSettings
+
+	systemSettings *SystemSettings
+	driveSettings  *SyntheticDvdDriveSettings
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd.go
new file mode 100644
index 000000000..c7310be95
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd.go
@@ -0,0 +1,108 @@
+package hypervctl
+
+import (
+	"encoding/xml"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/containers/common/pkg/strongunits"
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+// ResizeDisk takes a diskPath and strongly typed new size and uses powershell
+// to change its size.  There is no error protection for trying to size a disk
+// smaller than the current size.
+func ResizeDisk(diskPath string, newSize strongunits.GiB) error {
+	var (
+		service *wmiext.Service
+		err     error
+		job     *wmiext.Instance
+		ret     int32
+	)
+
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	imms, err := service.GetSingletonInstance("Msvm_ImageManagementService")
+	if err != nil {
+		return err
+	}
+	defer imms.Close()
+
+	err = imms.BeginInvoke("ResizeVirtualHardDisk").
+		In("Path", diskPath).
+		In("MaxInternalSize", int64(newSize.ToBytes())).
+		Execute().
+		Out("Job", &job).
+		Out("ReturnValue", &ret).
+		End()
+
+	if err != nil {
+		return fmt.Errorf("failed to resize disk: %w", err)
+	}
+	return waitVMResult(ret, service, job, "failed to resize disk", nil)
+}
+
+func GetDiskSize(diskPath string) (strongunits.B, error) {
+	var (
+		service *wmiext.Service
+		err     error
+		job     *wmiext.Instance
+		ret     int32
+		results string
+	)
+
+	if service, err = NewLocalHyperVService(); err != nil {
+		return 0, err
+	}
+	defer service.Close()
+	imms, err := service.GetSingletonInstance("Msvm_ImageManagementService")
+	if err != nil {
+		return 0, err
+	}
+	defer imms.Close()
+
+	inv := imms.BeginInvoke("GetVirtualHardDiskSettingData").
+		In("Path", diskPath).
+		Execute().
+		Out("Job", &job).
+		Out("ReturnValue", &ret)
+
+	if err := inv.Error(); err != nil {
+		return 0, fmt.Errorf("failed to get setting data for disk %s: %q", diskPath, err)
+	}
+
+	if err := waitVMResult(ret, service, job, "failure waiting on result from disk settings", nil); err != nil {
+		return 0, err
+	}
+
+	err = inv.Out("SettingData", &results).End()
+	if err != nil {
+		return 0, fmt.Errorf("failed to retrieve setting object payload for disk: %q", err)
+	}
+
+	type CimSingleInstance struct {
+		XMLName    xml.Name             `xml:"INSTANCE"`
+		Properties []CimKvpItemProperty `xml:"PROPERTY"`
+	}
+
+	diskSettings := CimSingleInstance{}
+	if err := xml.Unmarshal([]byte(results), &diskSettings); err != nil {
+		return 0, fmt.Errorf("unable to parse disk settings xml: %q", err)
+	}
+
+	for _, prop := range diskSettings.Properties {
+		if strings.EqualFold(prop.Name, "MaxInternalSize") {
+			size, err := strconv.ParseUint(prop.Value, 10, 64)
+			if err != nil {
+				return 0, fmt.Errorf("unable to parse size in disk settings")
+			}
+			return strongunits.B(size), nil
+		}
+	}
+
+	return 0, fmt.Errorf("disk settings was missing a size value")
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd_settings.go
new file mode 100644
index 000000000..e6bd8b4bf
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd_settings.go
@@ -0,0 +1,28 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import "time"
+
+type VirtualHardDiskSettings struct {
+	S__PATH                    string
+	InstanceID                 string
+	Caption                    string // = "Virtual Hard Disk Setting Data"
+	Description                string // = "Setting Data for a Virtual Hard Disk"
+	ElementName                string
+	Type                       uint16
+	Format                     uint16
+	Path                       string
+	ParentPath                 string
+	ParentTimestamp            time.Time
+	ParentIdentifier           string
+	MaxInternalSize            uint64
+	BlockSize                  uint32
+	LogicalSectorSize          uint32
+	PhysicalSectorSize         uint32
+	VirtualDiskId              string
+	DataAlignment              uint64
+	PmemAddressAbstractionType uint16
+	IsPmemCompatible           bool
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd_storage_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd_storage_settings.go
new file mode 100644
index 000000000..0384408ce
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vhd_storage_settings.go
@@ -0,0 +1,13 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+const VirtualHardDiskType = "Microsoft:Hyper-V:Virtual Hard Disk"
+
+type VirtualHardDiskStorageSettings struct {
+	StorageAllocationSettings
+
+	systemSettings *SystemSettings
+	driveSettings  *SyntheticDiskDriveSettings
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go
new file mode 100644
index 000000000..7fcae23af
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go
@@ -0,0 +1,629 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/containers/libhvee/pkg/kvp/ginsu"
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+// delete this when close to being done
+var (
+	ErrNotImplemented = errors.New("function not implemented")
+)
+
+type VirtualMachine struct {
+	S__PATH                                  string `json:"-"`
+	S__CLASS                                 string `json:"-"`
+	InstanceID                               string
+	Caption                                  string
+	Description                              string
+	ElementName                              string
+	InstallDate                              time.Time
+	OperationalStatus                        []uint16
+	StatusDescriptions                       []string
+	Status                                   string
+	HealthState                              uint16
+	CommunicationStatus                      uint16
+	DetailedStatus                           uint16
+	OperatingStatus                          uint16
+	PrimaryStatus                            uint16
+	EnabledState                             uint16
+	OtherEnabledState                        string
+	RequestedState                           uint16
+	EnabledDefault                           uint16
+	TimeOfLastStateChange                    string
+	AvailableRequestedStates                 []uint16
+	TransitioningToState                     uint16
+	CreationClassName                        string
+	Name                                     string
+	PrimaryOwnerName                         string
+	PrimaryOwnerContact                      string
+	Roles                                    []string
+	NameFormat                               string
+	OtherIdentifyingInfo                     []string
+	IdentifyingDescriptions                  []string
+	Dedicated                                []uint16
+	OtherDedicatedDescriptions               []string
+	ResetCapability                          uint16
+	PowerManagementCapabilities              []uint16
+	OnTimeInMilliseconds                     uint64
+	ProcessID                                uint32
+	TimeOfLastConfigurationChange            string
+	NumberOfNumaNodes                        uint16
+	ReplicationState                         uint16
+	ReplicationHealth                        uint16
+	ReplicationMode                          uint16
+	FailedOverReplicationType                uint16
+	LastReplicationType                      uint16
+	LastApplicationConsistentReplicationTime string
+	LastReplicationTime                      time.Time
+	LastSuccessfulBackupTime                 string
+	EnhancedSessionModeState                 uint16
+	vmm                                      *VirtualMachineManager
+}
+
+func (vm *VirtualMachine) Path() string {
+	return vm.S__PATH
+}
+func (vm *VirtualMachine) SplitAndAddIgnition(keyPrefix string, ignRdr *bytes.Reader) error {
+	parts, err := ginsu.Dice(ignRdr)
+	if err != nil {
+		return err
+	}
+	for idx, val := range parts {
+		key := fmt.Sprintf("%s%d", keyPrefix, idx)
+		if err := vm.AddKeyValuePair(key, val); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (vm *VirtualMachine) AddKeyValuePair(key string, value string) error {
+	return vm.kvpOperation("AddKvpItems", key, value, false, "key already exists?")
+}
+
+func (vm *VirtualMachine) ModifyKeyValuePair(key string, value string) error {
+	return vm.kvpOperation("ModifyKvpItems", key, value, false, "key invalid?")
+}
+
+func (vm *VirtualMachine) PutKeyValuePair(key string, value string) error {
+	err := vm.AddKeyValuePair(key, value)
+	kvpError, ok := err.(*KvpError)
+	if !ok || kvpError.ErrorCode != KvpIllegalArgument {
+		return err
+	}
+
+	return vm.ModifyKeyValuePair(key, value)
+}
+
+func (vm *VirtualMachine) RemoveKeyValuePair(key string) error {
+	return vm.kvpOperation("RemoveKvpItems", key, "", false, "key invalid?")
+}
+
+func (vm *VirtualMachine) RemoveKeyValuePairNoWait(key string) error {
+	return vm.kvpOperation("RemoveKvpItems", key, "", true, "key invalid?")
+}
+
+func (vm *VirtualMachine) GetKeyValuePairs() (map[string]string, error) {
+	var service *wmiext.Service
+	var err error
+
+	if service, err = NewLocalHyperVService(); err != nil {
+		return nil, err
+	}
+
+	defer service.Close()
+
+	i, err := service.FindFirstRelatedInstance(vm.Path(), "Msvm_KvpExchangeComponent")
+	if err != nil {
+		return nil, err
+	}
+
+	defer i.Close()
+
+	var path string
+	path, err = i.GetAsString("__PATH")
+	if err != nil {
+		return nil, err
+
+	}
+
+	i, err = service.FindFirstRelatedInstance(path, "Msvm_KvpExchangeComponentSettingData")
+	if err != nil {
+		return nil, err
+	}
+	defer i.Close()
+
+	s, err := i.GetAsString("HostExchangeItems")
+	if err != nil {
+		return nil, err
+	}
+
+	return parseKvpMapXml(s)
+}
+
+func (vm *VirtualMachine) kvpOperation(op string, key string, value string, nowait bool, illegalSuggestion string) error {
+	var service *wmiext.Service
+	var vsms, job *wmiext.Instance
+	var ret int32
+	var err error
+
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	vsms, err = service.GetSingletonInstance(VirtualSystemManagementService)
+	if err != nil {
+		return err
+	}
+	defer vsms.Close()
+
+	itemStr, err := createKvpItem(service, key, value)
+	if err != nil {
+		return err
+	}
+
+	execution := vsms.BeginInvoke(op).
+		In("TargetSystem", vm.Path()).
+		In("DataItems", []string{itemStr}).
+		Execute().
+		Out("ReturnValue", &ret).
+		Out("Job", &job)
+
+	if err := execution.End(); err != nil {
+		return fmt.Errorf("%s execution failed: %w", op, err)
+	}
+
+	defer job.Close()
+	if ret == 0 || (nowait && ret == 4096) {
+		return nil
+	}
+
+	if ret == 4096 {
+		err = wmiext.WaitJob(service, job)
+	} else {
+		err = &wmiext.JobError{ErrorCode: int(ret)}
+	}
+
+	return translateKvpError(err, illegalSuggestion)
+}
+
+func waitVMResult(res int32, service *wmiext.Service, job *wmiext.Instance, errorMsg string, translate func(int) error) error {
+	var err error
+
+	switch res {
+	case 0:
+		return nil
+	case 4096:
+		err = wmiext.WaitJob(service, job)
+		defer job.Close()
+	default:
+		if translate != nil {
+			return translate(int(res))
+		}
+
+		return fmt.Errorf("%s (result code %d)", errorMsg, res)
+	}
+
+	if err != nil {
+		desc, _ := job.GetAsString("ErrorDescription")
+		desc = strings.Replace(desc, "\n", " ", -1)
+		return fmt.Errorf("%s: %w (%s)", errorMsg, err, desc)
+	}
+
+	return err
+}
+
+func (vm *VirtualMachine) StopWithForce() error {
+	return vm.stop(true)
+}
+
+func (vm *VirtualMachine) Stop() error {
+	return vm.stop(false)
+}
+
+func (vm *VirtualMachine) stop(force bool) error {
+	if !Enabled.equal(vm.EnabledState) {
+		return ErrMachineNotRunning
+	}
+	var (
+		err error
+		res int32
+		srv *wmiext.Service
+	)
+	if srv, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	wmiInst, err := srv.FindFirstRelatedInstance(vm.Path(), "Msvm_ShutdownComponent")
+	if err != nil {
+		return err
+	}
+	// https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/msvm-shutdowncomponent-initiateshutdown
+	err = wmiInst.BeginInvoke("InitiateShutdown").
+		In("Reason", "User requested").
+		In("Force", force).
+		Execute().
+		Out("ReturnValue", &res).End()
+	if err != nil {
+		return err
+	}
+
+	if res != 0 {
+		return translateShutdownError(int(res))
+	}
+
+	// Wait for vm to actually *be* down
+	for i := 0; i < 200; i++ {
+		refreshVM, err := vm.vmm.GetMachine(vm.ElementName)
+		if err != nil {
+			return err
+		}
+		if refreshVM.State() == Disabled {
+			break
+		}
+		time.Sleep(50 * time.Millisecond)
+	}
+	return nil
+}
+
+func (vm *VirtualMachine) Start() error {
+	var (
+		srv *wmiext.Service
+		err error
+		job *wmiext.Instance
+		res int32
+	)
+
+	if s := vm.EnabledState; !Disabled.equal(s) {
+		if Enabled.equal(s) {
+			return ErrMachineAlreadyRunning
+		} else if Starting.equal(s) {
+			return ErrMachineAlreadyRunning
+		}
+		return errors.New("machine not in a state to start")
+	}
+
+	if srv, err = getService(srv); err != nil {
+		return err
+	}
+	defer srv.Close()
+
+	instance, err := srv.GetObject(vm.Path())
+	if err != nil {
+		return err
+	}
+	defer instance.Close()
+
+	// https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/cim-concretejob-requeststatechange
+	if err := instance.BeginInvoke("RequestStateChange").
+		In("RequestedState", uint16(start)).
+		In("TimeoutPeriod", &time.Time{}).
+		Execute().
+		Out("Job", &job).
+		Out("ReturnValue", &res).End(); err != nil {
+		return err
+	}
+	return waitVMResult(res, srv, job, "failed to start vm", nil)
+}
+
+func getService(_ *wmiext.Service) (*wmiext.Service, error) {
+	// any reason why when we instantiate a vm, we should NOT just embed a service?
+	return NewLocalHyperVService()
+}
+
+func (vm *VirtualMachine) GetConfig(diskPath string) (*HyperVConfig, error) {
+	var (
+		diskSize uint64
+	)
+	summary, err := vm.GetSummaryInformation(SummaryRequestCommon)
+	if err != nil {
+		return nil, err
+	}
+
+	// Grabbing actual disk size
+	diskPathInfo, err := os.Stat(diskPath)
+	if err != nil {
+		return nil, err
+	}
+	diskSize = uint64(diskPathInfo.Size())
+	mem := MemorySettings{}
+	if err := vm.getMemorySettings(&mem); err != nil {
+		return nil, err
+	}
+
+	config := HyperVConfig{
+		Hardware: HardwareConfig{
+			// TODO we could implement a getProcessorSettings like we did for memory
+			CPUs:     summary.NumberOfProcessors,
+			DiskPath: diskPath,
+			DiskSize: diskSize,
+			Memory:   mem.Limit,
+		},
+		Status: Statuses{
+			Created:  vm.InstallDate,
+			LastUp:   time.Time{},
+			Running:  Enabled.equal(vm.EnabledState),
+			Starting: vm.IsStarting(),
+			State:    EnabledState(vm.EnabledState),
+		},
+	}
+	return &config, nil
+}
+
+// GetSummaryInformation returns the live VM summary information for this virtual machine.
+// The requestedFields parameter controls which fields of summary information are populated.
+// SummaryRequestCommon and SummaryRequestNearAll provide predefined combinations for this
+// parameter
+func (vm *VirtualMachine) GetSummaryInformation(requestedFields SummaryRequestSet) (*SummaryInformation, error) {
+	service, err := NewLocalHyperVService()
+	if err != nil {
+		return nil, err
+	}
+	defer service.Close()
+
+	instance, err := vm.fetchSystemSettingsInstance(service)
+	if err != nil {
+		return nil, err
+	}
+	defer instance.Close()
+
+	path, err := instance.Path()
+	if err != nil {
+		return nil, err
+	}
+
+	result, err := vm.vmm.getSummaryInformation(path, requestedFields)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(result) < 1 {
+		return nil, errors.New("summary information search returned an empty result set")
+	}
+
+	return &result[0], nil
+}
+
+// NewVirtualMachine creates a new vm in hyperv
+// decided to not return a *VirtualMachine here because of how Podman is
+// likely to use this.  this could be easily added if desirable
+func (vmm *VirtualMachineManager) NewVirtualMachine(name string, config *HardwareConfig) error {
+	exists, err := vmm.Exists(name)
+	if err != nil {
+		return err
+	}
+	if exists {
+		return ErrMachineAlreadyExists
+	}
+
+	// TODO I gotta believe there are naming restrictions for vms in hyperv?
+	// TODO If something fails during creation, do we rip things down or follow precedent from other machines?  user deletes things
+
+	systemSettings, err := NewSystemSettingsBuilder().
+		PrepareSystemSettings(name, nil).
+		PrepareMemorySettings(func(ms *MemorySettings) {
+			//ms.DynamicMemoryEnabled = false
+			//ms.VirtualQuantity = 8192 // Startup memory
+			//ms.Reservation = config.Memory // min
+
+			// The API seems to require both of these even
+			// when not using dynamic memory
+			ms.Limit = config.Memory
+			ms.VirtualQuantity = config.Memory
+		}).
+		PrepareProcessorSettings(func(ps *ProcessorSettings) {
+			ps.VirtualQuantity = uint64(config.CPUs) // 4 cores
+		}).
+		Build()
+	if err != nil {
+		return err
+	}
+
+	if err := NewDriveSettingsBuilder(systemSettings).
+		AddScsiController().
+		AddSyntheticDiskDrive(0).
+		DefineVirtualHardDisk(config.DiskPath, func(vhdss *VirtualHardDiskStorageSettings) {
+			// set extra params like
+			// vhdss.IOPSLimit = 5000
+		}).
+		Finish(). // disk
+		Finish(). // drive
+		//AddSyntheticDvdDrive(1).
+		//DefineVirtualDvdDisk(isoFile).
+		//Finish(). // disk
+		//Finish(). // drive
+		Finish(). // controller
+		Complete(); err != nil {
+		return err
+	}
+	// Add default network connection
+	if config.Network {
+		if err := NewNetworkSettingsBuilder(systemSettings).
+			AddSyntheticEthernetPort(nil).
+			AddEthernetPortAllocation(""). // "" = connect to default switch
+			Finish().                      // allocation
+			Finish().                      // port
+			Complete(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (vm *VirtualMachine) fetchSystemSettingsInstance(service *wmiext.Service) (*wmiext.Instance, error) {
+	// When a settings snapshot is taken there are multiple associations, use only the realized/active version
+	return service.FindFirstRelatedInstanceThrough(vm.Path(), "Msvm_VirtualSystemSettingData", "Msvm_SettingsDefineState")
+}
+
+func (vm *VirtualMachine) fetchExistingResourceSettings(service *wmiext.Service, resourceType string, resourceSettings interface{}) error {
+	const errFmt = "could not fetch resource settings (%s): %w"
+	// When a settings snapshot is taken there are multiple associations, use only the realized/active version
+	instance, err := vm.fetchSystemSettingsInstance(service)
+	if err != nil {
+		return fmt.Errorf(errFmt, resourceType, err)
+	}
+	defer instance.Close()
+
+	path, err := instance.Path()
+	if err != nil {
+		return fmt.Errorf(errFmt, resourceType, err)
+
+	}
+
+	return service.FindFirstRelatedObject(path, resourceType, resourceSettings)
+}
+
+func (vm *VirtualMachine) getMemorySettings(m *MemorySettings) error {
+	service, err := NewLocalHyperVService()
+	if err != nil {
+		return err
+	}
+	defer service.Close()
+	return vm.fetchExistingResourceSettings(service, "Msvm_MemorySettingData", m)
+}
+
+// Update processor and/or mem
+func (vm *VirtualMachine) UpdateProcessorMemSettings(updateProcessor func(*ProcessorSettings), updateMemory func(*MemorySettings)) error {
+	service, err := NewLocalHyperVService()
+	if err != nil {
+		return err
+	}
+	defer service.Close()
+
+	proc := &ProcessorSettings{}
+	mem := &MemorySettings{}
+
+	var settings []string
+	if updateProcessor != nil {
+		err = vm.fetchExistingResourceSettings(service, "Msvm_ProcessorSettingData", proc)
+		if err != nil {
+			return err
+		}
+
+		updateProcessor(proc)
+
+		processorStr, err := createProcessorSettings(proc)
+		if err != nil {
+			return err
+		}
+		settings = append(settings, processorStr)
+	}
+
+	if updateMemory != nil {
+		if err := vm.getMemorySettings(mem); err != nil {
+			return err
+		}
+
+		updateMemory(mem)
+
+		memStr, err := createMemorySettings(mem)
+		if err != nil {
+			return err
+		}
+
+		settings = append(settings, memStr)
+	}
+
+	if len(settings) < 1 {
+		return nil
+	}
+
+	vsms, err := service.GetSingletonInstance("Msvm_VirtualSystemManagementService")
+	if err != nil {
+		return err
+	}
+	defer vsms.Close()
+
+	var job *wmiext.Instance
+	var res int32
+	err = vsms.BeginInvoke("ModifyResourceSettings").
+		In("ResourceSettings", settings).
+		Execute().
+		Out("Job", &job).
+		Out("ReturnValue", &res).
+		End()
+
+	if err != nil {
+		return fmt.Errorf("failed to modify resource settings: %w", err)
+	}
+
+	return waitVMResult(res, service, job, "failed to modify resource settings", translateModifyError)
+}
+
+func (vm *VirtualMachine) remove() (int32, error) {
+	var (
+		err error
+		res int32
+		srv *wmiext.Service
+	)
+
+	refreshVM, err := vm.vmm.GetMachine(vm.ElementName)
+	if err != nil {
+		return 0, err
+	}
+	// Check for disabled/stopped state
+	if !Disabled.equal(refreshVM.EnabledState) {
+		return -1, ErrMachineStateInvalid
+	}
+	if srv, err = NewLocalHyperVService(); err != nil {
+		return -1, err
+	}
+
+	vsms, err := srv.GetSingletonInstance("Msvm_VirtualSystemManagementService")
+	if err != nil {
+		return -1, err
+	}
+	defer vsms.Close()
+
+	var (
+		job *wmiext.Instance
+	)
+
+	// https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/cim-virtualsystemmanagementservice-destroysystem
+	if err := vsms.BeginInvoke("DestroySystem").
+		In("AffectedSystem", vm.Path()).
+		Execute().
+		Out("Job", &job).
+		Out("ReturnValue", &res).End(); err != nil {
+		return -1, err
+	}
+
+	// do i have this correct? you can get an error without a result?
+	if err := waitVMResult(res, srv, job, "failed to remove vm", nil); err != nil {
+		return -1, err
+	}
+	return res, nil
+}
+
+func (vm *VirtualMachine) Remove(diskPath string) error {
+	if _, err := vm.remove(); err != nil {
+		return err
+	}
+
+	// Remove disk only if we were given one
+	if len(diskPath) > 0 {
+		if err := os.Remove(diskPath); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (vm *VirtualMachine) State() EnabledState {
+	return EnabledState(vm.EnabledState)
+}
+
+func (vm *VirtualMachine) IsStarting() bool {
+	return Starting.equal(vm.EnabledState)
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vm_config.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vm_config.go
new file mode 100644
index 000000000..4ea14d660
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vm_config.go
@@ -0,0 +1,117 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"time"
+)
+
+type vmState uint16
+
+const (
+	// Changes the state to 'Running'.
+	start vmState = 2
+	// Stops the job temporarily. The intention is to subsequently restart the job with 'Start'. It might be possible to
+	// enter the 'Service' state while suspended. (This is job-specific.)
+	suspend vmState = 3 //nolint: unused
+	// Stops the job cleanly, saves data, preserves the state, and shuts down all underlying processes'
+	// in an orderly manner.
+	terminate vmState = 4 //nolint: unused
+	//Terminates the job immediately with no requirement to save data or preserve the state.
+	kill vmState = 5 //nolint: unused
+)
+
+type EnabledState uint16
+
+const (
+	// Unknown The state of the element could not be determined.
+	Unknown EnabledState = 0
+	// Other No description
+	Other EnabledState = 1
+	// Enabled The element is running.
+	Enabled EnabledState = 2
+	// Disabled The element is turned off.
+	Disabled EnabledState = 3
+	// ShuttingDown Shutting_Down The element is in the process of going to a Disabled state.
+	ShuttingDown EnabledState = 4
+	// NotApplicable The element does not support being enabled or disabled.
+	NotApplicable EnabledState = 5
+	// EnabledButOffline The element might be completing commands, and it will drop any new requests.
+	EnabledButOffline EnabledState = 6
+	// InTest The element is in a test state.
+	InTest EnabledState = 7
+	// Deferred The element might be completing commands, but it will queue any new requests.
+	Deferred EnabledState = 8
+	// Quiesce The element is enabled but in a restricted mode. The behavior of the element is similar to the Enabled state
+	//(2), but it processes only a restricted set of commands. All other requests are queued.
+	Quiesce EnabledState = 9
+	// Starting The element is in the process of going to an Enabled state (2). New requests are queued.
+	Starting EnabledState = 10
+)
+
+func (es EnabledState) String() string {
+	switch es {
+	case Unknown:
+		return "unknown"
+	case Other:
+		return "other"
+	case Enabled:
+		return "enabled"
+	case Disabled:
+		return "disabled"
+	case ShuttingDown:
+		return "shutting down"
+	case NotApplicable:
+		return "not applicable"
+	case EnabledButOffline:
+		return "enabled but offline"
+	case InTest:
+		return "in test"
+	case Deferred:
+		return "deferred"
+	case Quiesce:
+		return "quiesce"
+	}
+	return "starting"
+}
+
+func (es EnabledState) equal(s uint16) bool {
+	return es == EnabledState(s)
+}
+
+// HyperVConfig describes physical attributes of the machine
+type HyperVConfig struct {
+	// Hardware configuration for HyperV
+	Hardware HardwareConfig
+	// state and descriptive info
+	Status Statuses
+}
+
+type HardwareConfig struct {
+	// CPUs to be assigned to the VM
+	CPUs uint16
+	// Diskpath is fully qualified location of the
+	// bootable disk image
+	DiskPath string
+	// Disk size in gigabytes assigned to the vm
+	DiskSize uint64
+	// Memory in megabytes assigned to the vm
+	Memory uint64
+	// Network is bool to add a Network Connection to the
+	// default network switch in Microsoft HyperV
+	Network bool
+}
+
+type Statuses struct {
+	// time vm created
+	Created time.Time
+	// last time vm ran
+	LastUp time.Time
+	// is vm running
+	Running bool
+	// is vm starting up
+	Starting bool
+	// vm state
+	State EnabledState
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go
new file mode 100644
index 000000000..ea7f23948
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go
@@ -0,0 +1,235 @@
+//go:build windows
+// +build windows
+
+package hypervctl
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/containers/libhvee/pkg/wmiext"
+)
+
+const (
+	HyperVNamespace                = "root\\virtualization\\v2"
+	VirtualSystemManagementService = "Msvm_VirtualSystemManagementService"
+	MsvmComputerSystem             = "Msvm_ComputerSystem"
+)
+
+// https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/msvm-computersystem
+
+type VirtualMachineManager struct {
+}
+
+func NewVirtualMachineManager() *VirtualMachineManager {
+	return &VirtualMachineManager{}
+}
+
+func NewLocalHyperVService() (*wmiext.Service, error) {
+	service, err := wmiext.NewLocalService(HyperVNamespace)
+	if err != nil {
+		return nil, translateCommonHyperVWmiError(err)
+	}
+
+	return service, nil
+}
+
+func (vmm *VirtualMachineManager) GetAll() ([]*VirtualMachine, error) {
+	// Fetch through settings to avoid locale sensitive properties
+	const wql = "Select * From Msvm_VirtualSystemSettingData Where VirtualSystemType = 'Microsoft:Hyper-V:System:Realized'"
+
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return []*VirtualMachine{}, err
+	}
+	defer service.Close()
+
+	var enum *wmiext.Enum
+	if enum, err = service.ExecQuery(wql); err != nil {
+		return nil, err
+	}
+	defer enum.Close()
+	var vms []*VirtualMachine
+
+	for {
+		settings, err := enum.Next()
+		if err != nil {
+			return vms, err
+		}
+
+		// Finished iterating
+		if settings == nil {
+			break
+		}
+
+		vm, err := vmm.findVMFromSettings(service, settings)
+		settings.Close()
+		if err != nil {
+			return vms, err
+		}
+
+		vms = append(vms, vm)
+	}
+
+	return vms, nil
+}
+
+func (vmm *VirtualMachineManager) Exists(name string) (bool, error) {
+	vms, err := vmm.GetAll()
+	if err != nil {
+		return false, err
+	}
+	for _, i := range vms {
+		// TODO should case be honored or ignored?
+		if i.Name == name {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+// GetMachine is a stub to lookup and get settings for a VM
+func (vmm *VirtualMachineManager) GetMachine(name string) (*VirtualMachine, error) {
+	return vmm.getMachine(name)
+}
+
+// GetMachineExists looks for a machine defined in hyperv and returns it if it exists
+func (vmm *VirtualMachineManager) GetMachineExists(name string) (bool, *VirtualMachine, error) {
+	vm, err := vmm.getMachine(name)
+	if err != nil {
+		if errors.Is(err, wmiext.ErrNoResults) {
+			return false, nil, nil
+		}
+		return false, nil, err
+	}
+	return true, vm, nil
+}
+
+// getMachine looks up a single VM by name
+func (vmm *VirtualMachineManager) getMachine(name string) (*VirtualMachine, error) {
+	const wql = "Select * From Msvm_VirtualSystemSettingData Where VirtualSystemType = 'Microsoft:Hyper-V:System:Realized' And ElementName='%s'"
+
+	vm := &VirtualMachine{}
+	var service *wmiext.Service
+	var err error
+
+	if service, err = NewLocalHyperVService(); err != nil {
+		return vm, err
+	}
+	defer service.Close()
+
+	var enum *wmiext.Enum
+	if enum, err = service.ExecQuery(fmt.Sprintf(wql, name)); err != nil {
+		return nil, err
+	}
+	defer enum.Close()
+
+	settings, err := service.FindFirstInstance(fmt.Sprintf(wql, name))
+	if err != nil {
+		if errors.Is(err, wmiext.ErrNoResults) {
+			return nil, err
+		}
+		return vm, fmt.Errorf("could not find virtual machine %q: %w", name, err)
+	}
+	defer settings.Close()
+
+	return vmm.findVMFromSettings(service, settings)
+}
+
+func (vmm *VirtualMachineManager) findVMFromSettings(service *wmiext.Service, settings *wmiext.Instance) (*VirtualMachine, error) {
+	path, err := settings.Path()
+	if err != nil {
+		return nil, err
+	}
+
+	vm := &VirtualMachine{vmm: vmm}
+	err = service.FindFirstRelatedObject(path, MsvmComputerSystem, vm)
+
+	return vm, err
+}
+
+func (*VirtualMachineManager) CreateVhdxFile(path string, maxSize uint64) error {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return err
+	}
+	defer service.Close()
+
+	settings := &VirtualHardDiskSettings{}
+	settings.Format = 3
+	settings.MaxInternalSize = maxSize
+	settings.Type = 3
+	settings.Path = path
+
+	instance, err := service.CreateInstance("Msvm_VirtualHardDiskSettingData", settings)
+	if err != nil {
+		return err
+	}
+	defer instance.Close()
+	settingsStr := instance.GetCimText()
+
+	imms, err := service.GetSingletonInstance("Msvm_ImageManagementService")
+	if err != nil {
+		return err
+	}
+	defer imms.Close()
+
+	var job *wmiext.Instance
+	var ret int32
+	err = imms.BeginInvoke("CreateVirtualHardDisk").
+		In("VirtualDiskSettingData", settingsStr).
+		Execute().
+		Out("Job", &job).
+		Out("ReturnValue", &ret).
+		End()
+
+	if err != nil {
+		return fmt.Errorf("failed to create vhdx: %w", err)
+	}
+
+	return waitVMResult(ret, service, job, "failed to create vhdx", nil)
+}
+
+// GetSummaryInformation returns the live VM summary information for all virtual machines.
+// The requestedFields parameter controls which fields of summary information are populated.
+// SummaryRequestCommon and SummaryRequestNearAll provide predefined combinations for this
+// parameter.
+func (vmm *VirtualMachineManager) GetSummaryInformation(requestedFields SummaryRequestSet) ([]SummaryInformation, error) {
+	return vmm.getSummaryInformation("", requestedFields)
+}
+
+func (vmm *VirtualMachineManager) getSummaryInformation(settingsPath string, requestedFields SummaryRequestSet) ([]SummaryInformation, error) {
+	var service *wmiext.Service
+	var err error
+	if service, err = NewLocalHyperVService(); err != nil {
+		return nil, err
+	}
+	defer service.Close()
+
+	vsms, err := service.GetSingletonInstance(VirtualSystemManagementService)
+	if err != nil {
+		return nil, err
+	}
+	defer vsms.Close()
+
+	var summary []SummaryInformation
+
+	inv := vsms.BeginInvoke("GetSummaryInformation").
+		In("RequestedInformation", []uint(requestedFields))
+
+	if len(settingsPath) > 0 {
+		inv.In("SettingData", []string{settingsPath})
+	}
+
+	err = inv.Execute().
+		Out("SummaryInformation", &summary).
+		End()
+
+	if err != nil {
+		return nil, err
+	}
+
+	return summary, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/kvp/ginsu/util.go b/vendor/github.com/containers/libhvee/pkg/kvp/ginsu/util.go
new file mode 100644
index 000000000..49e5e2748
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/kvp/ginsu/util.go
@@ -0,0 +1,46 @@
+package ginsu
+
+//
+// This function is purposely "namespaces" for easy and
+// lightweight vendoring.
+//
+
+import (
+	"bytes"
+)
+
+const (
+	// KvpValueMaxLen is the maximum real-world length of bytes that can
+	// be stored in the value of the wmi key-value pair data exchange
+	KvpValueMaxLen = int(990)
+)
+
+// Dice takes input and splits it into a string array so it can be
+// passed by hyperv and wmi. Each part must be less than the maximum size
+// of a kvp value
+func Dice(k *bytes.Reader) ([]string, error) {
+	var (
+		// done is a simple bool indicator that we no longer
+		// need to iterate
+		done  bool
+		parts []string
+	)
+	for {
+		sl := make([]byte, KvpValueMaxLen)
+		n, err := k.Read(sl)
+		if err != nil {
+			return parts, err
+		}
+		// if we read and the length is less that the max read,
+		// then we are at the end
+		if n < KvpValueMaxLen {
+			sl = sl[0:n]
+			done = true
+		}
+		parts = append(parts, string(sl))
+		if done {
+			break
+		}
+	}
+	return parts, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/array.go b/vendor/github.com/containers/libhvee/pkg/wmiext/array.go
new file mode 100644
index 000000000..3f059360c
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/array.go
@@ -0,0 +1,202 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"unsafe"
+
+	"github.com/go-ole/go-ole"
+)
+
+func CreateStringArrayVariant(array []string) (ole.VARIANT, error) {
+	safeByteArray, err := safeArrayFromStringSlice(array)
+	if err != nil {
+		return ole.VARIANT{}, err
+	}
+	arrayVariant := ole.NewVariant(ole.VT_ARRAY|ole.VT_BSTR, int64(uintptr(unsafe.Pointer(safeByteArray))))
+	return arrayVariant, nil
+}
+
+func CreateNumericArrayVariant(array interface{}, itemType ole.VT) (ole.VARIANT, error) {
+	safeArray, err := safeArrayFromNumericSlice(array, itemType)
+	if err != nil {
+		return ole.VARIANT{}, err
+	}
+	arrayVariant := ole.NewVariant(ole.VT_ARRAY|itemType, int64(uintptr(unsafe.Pointer(safeArray))))
+	return arrayVariant, nil
+}
+
+// The following safearray routines are unfortunately not yet exported from go-ole,
+// so replicate them for now
+func safeArrayCreateVector(variantType ole.VT, lowerBound int32, length uint32) (safearray *ole.SafeArray, err error) {
+	ret, _, _ := procSafeArrayCreateVector.Call(
+		uintptr(variantType),
+		uintptr(lowerBound),
+		uintptr(length))
+
+	if ret == 0 { // NULL return value
+		err = fmt.Errorf("could not create safe array")
+	}
+	safearray = (*ole.SafeArray)(unsafe.Pointer(ret))
+	return
+}
+
+func safeArrayFromNumericSlice(slice interface{}, itemType ole.VT) (*ole.SafeArray, error) {
+	sliceType := reflect.TypeOf(slice)
+	if sliceType.Kind() != reflect.Slice {
+		return nil, errors.New("expected a slice converting to safe array")
+	}
+
+	val := reflect.ValueOf(slice)
+
+	array, err := safeArrayCreateVector(itemType, 0, uint32(val.Len()))
+	if err != nil {
+		return nil, err
+	}
+
+	// assignable holders used for conversion
+	var (
+		vui1 uint8
+		vui2 uint16
+		vui4 uint32
+		vui8 uint64
+		vi1  int8
+		vi2  int16
+		vi4  int32
+		vi8  int64
+	)
+
+	for i := 0; i < val.Len(); i++ {
+		var data uintptr
+		item := val.Index(i)
+		switch itemType {
+		case ole.VT_UI1:
+			data = convertToUnsafeAddr(item, &vui1)
+		case ole.VT_UI2:
+			data = convertToUnsafeAddr(item, &vui2)
+		case ole.VT_UI4:
+			data = convertToUnsafeAddr(item, &vui4)
+		case ole.VT_UI8:
+			data = convertToUnsafeAddr(item, &vui8)
+		case ole.VT_I1:
+			data = convertToUnsafeAddr(item, &vi1)
+		case ole.VT_I2:
+			data = convertToUnsafeAddr(item, &vi2)
+		case ole.VT_I4:
+			data = convertToUnsafeAddr(item, &vi4)
+		case ole.VT_I8:
+			data = convertToUnsafeAddr(item, &vi8)
+		}
+
+		err = safeArrayPutElement(array, int64(i), data)
+		if err != nil {
+			_ = safeArrayDestroy(array)
+			return nil, err
+		}
+	}
+
+	return array, nil
+}
+
+func convertToUnsafeAddr(src reflect.Value, target interface{}) uintptr {
+	val := reflect.ValueOf(target)
+	val = val.Elem()
+	val.Set(src.Convert(val.Type()))
+	return val.UnsafeAddr()
+}
+
+func safeArrayDestroy(safearray *ole.SafeArray) (err error) {
+	ret, _, _ := procSafeArrayDestroy.Call(uintptr(unsafe.Pointer(safearray)))
+
+	if ret != 0 {
+		return NewWmiError(ret)
+	}
+
+	return nil
+}
+
+func safeArrayPutElement(safearray *ole.SafeArray, index int64, element uintptr) (err error) {
+
+	ret, _, _ := procSafeArrayPutElement.Call(
+		uintptr(unsafe.Pointer(safearray)),
+		uintptr(unsafe.Pointer(&index)),
+		element)
+
+	if ret != 0 {
+		return NewWmiError(ret)
+	}
+
+	return nil
+}
+
+func safeArrayGetElement(safearray *ole.SafeArray, index int64, element unsafe.Pointer) error {
+
+	ret, _, _ := procSafeArrayGetElement.Call(
+		uintptr(unsafe.Pointer(safearray)),
+		uintptr(unsafe.Pointer(&index)),
+		uintptr(element))
+
+	if ret != 0 {
+		return NewWmiError(ret)
+	}
+
+	return nil
+}
+
+func isVariantValConvertible(variant ole.VARIANT) bool {
+	return !(variant.VT == ole.VT_RECORD || variant.VT == ole.VT_VARIANT)
+}
+
+func safeArrayGetAsVariantVal(safeArray *ole.SafeArray, index int64, variant ole.VARIANT) (int64, error) {
+	var block int64
+
+	if !isVariantValConvertible(variant) {
+		return 0, fmt.Errorf("numeric call on a non-numeric value: %d", variant.VT)
+	}
+
+	if err := safeArrayGetElement(safeArray, index, unsafe.Pointer(&block)); err != nil {
+		return 0, err
+	}
+
+	switch variant.VT {
+	case ole.VT_UI1:
+		return int64(uint64(*(*uint8)(unsafe.Pointer(&block)))), nil
+	case ole.VT_UI2:
+		return int64(uint64(*(*uint16)(unsafe.Pointer(&block)))), nil
+	case ole.VT_UI4:
+		return int64(uint64(*(*uint32)(unsafe.Pointer(&block)))), nil
+	case ole.VT_I1:
+		return int64(*(*int8)(unsafe.Pointer(&block))), nil
+	case ole.VT_I2:
+		return int64(*(*int16)(unsafe.Pointer(&block))), nil
+	case ole.VT_I4:
+		return int64(*(*int32)(unsafe.Pointer(&block))), nil
+	case ole.VT_UI8, ole.VT_I8:
+		fallthrough
+	case ole.VT_R4, ole.VT_R8:
+		fallthrough
+	default:
+		return block, nil
+	}
+}
+
+func safeArrayFromStringSlice(slice []string) (*ole.SafeArray, error) {
+	array, err := safeArrayCreateVector(ole.VT_BSTR, 0, uint32(len(slice)))
+
+	if err != nil {
+		return nil, err
+	}
+
+	for i, v := range slice {
+		err = safeArrayPutElement(array, int64(i), uintptr(unsafe.Pointer(ole.SysAllocStringLen(v))))
+		if err != nil {
+			_ = safeArrayDestroy(array)
+			return nil, err
+		}
+	}
+	return array, nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go b/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go
new file mode 100644
index 000000000..9dc969060
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go
@@ -0,0 +1,474 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"errors"
+	"fmt"
+	"math"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+	"unsafe"
+
+	"github.com/go-ole/go-ole"
+)
+
+var (
+	unixEpoch = time.Unix(0, 0)
+	zeroTime  = time.Time{}
+)
+
+// Automation variants do not follow the OLE rules, instead they use the following mapping:
+// sint8	VT_I2	Signed 8-bit integer.
+// sint16	VT_I2	Signed 16-bit integer.
+// sint32	VT_I4	Signed 32-bit integer.
+// sint64	VT_BSTR	Signed 64-bit integer in string form. This type follows hexadecimal or decimal format
+//
+//	according to the American National Standards Institute (ANSI) C rules.
+//
+// real32	VT_R4	4-byte floating-point value that follows the Institute of Electrical and Electronics
+//
+//	Engineers, Inc. (IEEE) standard.
+//
+// real64	VT_R8	8-byte floating-point value that follows the IEEE standard.
+// uint8	VT_UI1	Unsigned 8-bit integer.
+// uint16	VT_I4	Unsigned 16-bit integer.
+// uint32	VT_I4	Unsigned 32-bit integer.
+// uint64	VT_BSTR	Unsigned 64-bit integer in string form. This type follows hexadecimal or decimal format
+//
+//	according to ANSI C rules.
+
+// NewAutomationVariant returns a new VARIANT com
+//
+//gocyclo:ignore
+func NewAutomationVariant(value interface{}) (ole.VARIANT, error) {
+	switch cast := value.(type) {
+	case bool:
+		if cast {
+			return ole.NewVariant(ole.VT_BOOL, 0xffff), nil
+		} else {
+			return ole.NewVariant(ole.VT_BOOL, 0), nil
+		}
+	case int8:
+		return ole.NewVariant(ole.VT_I2, int64(cast)), nil
+	case []int8:
+		return CreateNumericArrayVariant(cast, ole.VT_I2)
+	case int16:
+		return ole.NewVariant(ole.VT_I2, int64(cast)), nil
+	case []int16:
+		return CreateNumericArrayVariant(cast, ole.VT_I2)
+	case int32:
+		return ole.NewVariant(ole.VT_I4, int64(cast)), nil
+	case []int32:
+		return CreateNumericArrayVariant(cast, ole.VT_I4)
+	case int64:
+		s := fmt.Sprintf("%d", cast)
+		return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(s))))), nil
+	case []int64:
+		strs := make([]string, len(cast))
+		for i, num := range cast {
+			strs[i] = fmt.Sprintf("%d", num)
+		}
+		return CreateStringArrayVariant(strs)
+	case float32:
+		return ole.NewVariant(ole.VT_R4, int64(math.Float32bits(cast))), nil
+	case float64:
+		return ole.NewVariant(ole.VT_R8, int64(math.Float64bits(cast))), nil
+	case uint8:
+		return ole.NewVariant(ole.VT_UI1, int64(cast)), nil
+	case []uint8:
+		return CreateNumericArrayVariant(cast, ole.VT_UI1)
+	case uint16:
+		return ole.NewVariant(ole.VT_I4, int64(cast)), nil
+	case []uint16:
+		return CreateNumericArrayVariant(cast, ole.VT_I4)
+	case uint32:
+		return ole.NewVariant(ole.VT_I4, int64(cast)), nil
+	case []uint32:
+		return CreateNumericArrayVariant(cast, ole.VT_I4)
+	case uint64:
+		s := fmt.Sprintf("%d", cast)
+		return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(s))))), nil
+	case []uint64:
+		strs := make([]string, len(cast))
+		for i, num := range cast {
+			strs[i] = fmt.Sprintf("%d", num)
+		}
+		return CreateStringArrayVariant(strs)
+
+	// Assume 32 bit for generic (u)ints
+	case int:
+		return ole.NewVariant(ole.VT_I4, int64(cast)), nil
+	case uint:
+		return ole.NewVariant(ole.VT_I4, int64(cast)), nil
+	case []int:
+		return CreateNumericArrayVariant(cast, ole.VT_I4)
+	case []uint:
+		return CreateNumericArrayVariant(cast, ole.VT_I4)
+
+	case string:
+		return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(value.(string)))))), nil
+	case []string:
+		if len(cast) == 0 {
+			return ole.NewVariant(ole.VT_NULL, 0), nil
+		}
+		return CreateStringArrayVariant(cast)
+
+	case time.Time:
+		return convertTimeToDataTime(&cast), nil
+	case *time.Time:
+		return convertTimeToDataTime(cast), nil
+	case time.Duration:
+		return convertDurationToDateTime(cast), nil
+	case nil:
+		return ole.NewVariant(ole.VT_NULL, 0), nil
+	case *ole.IUnknown:
+		if cast == nil {
+			return ole.NewVariant(ole.VT_NULL, 0), nil
+		}
+		return ole.NewVariant(ole.VT_UNKNOWN, int64(uintptr(unsafe.Pointer(cast)))), nil
+	case *Instance:
+		if cast == nil {
+			return ole.NewVariant(ole.VT_NULL, 0), nil
+		}
+		return ole.NewVariant(ole.VT_UNKNOWN, int64(uintptr(unsafe.Pointer(cast.object)))), nil
+	default:
+		return ole.VARIANT{}, fmt.Errorf("unsupported type for automation variants %T", value)
+	}
+}
+
+func convertToGoType(variant *ole.VARIANT, outputValue reflect.Value, outputType reflect.Type) (value interface{}, err error) {
+	if variant.VT&ole.VT_ARRAY == ole.VT_ARRAY {
+		return convertVariantToArray(variant, outputType)
+	}
+
+	if variant.VT == ole.VT_UNKNOWN {
+		return convertVariantToStruct(variant, outputType)
+	}
+
+	switch cast := outputValue.Interface().(type) {
+	case bool:
+		return variant.Val != 0, nil
+	case time.Time:
+		return convertDataTimeToTime(variant)
+	case *time.Time:
+		x, err := convertDataTimeToTime(variant)
+		return &x, err
+	case time.Duration:
+		return convertIntervalToDuration(variant)
+	case uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64:
+		return convertVariantToInt(variant, outputType)
+	case float32, float64:
+		return convertVariantToFloat(variant, outputType)
+	case string:
+		return variant.ToString(), nil
+	default:
+		if variant.VT == ole.VT_NULL {
+			return nil, nil
+		}
+		return nil, fmt.Errorf("could not convert %d to %v", variant.VT, cast)
+	}
+}
+
+func convertInt64ToInt(value int64, outputType reflect.Type) (interface{}, error) {
+	switch outputType.Kind() {
+	case reflect.Int:
+		return int(value), nil
+	case reflect.Int8:
+		return int8(value), nil
+	case reflect.Int16:
+		return int16(value), nil
+	case reflect.Int32:
+		return int32(value), nil
+	case reflect.Int64:
+		return int64(value), nil
+	case reflect.Uint:
+		return uint(value), nil
+	case reflect.Uint8:
+		return uint8(value), nil
+	case reflect.Uint16:
+		return uint16(value), nil
+	case reflect.Uint32:
+		return uint32(value), nil
+	case reflect.Uint64:
+		return uint64(value), nil
+	default:
+		return 0, fmt.Errorf("could not convert int64 to %v", outputType)
+	}
+}
+
+func convertStringToInt64(str string, unsigned bool) (int64, error) {
+	if unsigned {
+		val, err := strconv.ParseUint(str, 0, 64)
+		return int64(val), err
+	}
+
+	return strconv.ParseInt(str, 0, 64)
+}
+
+func convertVariantToInt(variant *ole.VARIANT, outputType reflect.Type) (interface{}, error) {
+	var value int64
+	switch variant.VT {
+	case ole.VT_NULL:
+		fallthrough
+	case ole.VT_BOOL:
+		fallthrough
+	case ole.VT_I1, ole.VT_I2, ole.VT_I4, ole.VT_I8, ole.VT_INT:
+		fallthrough
+	case ole.VT_UI1, ole.VT_UI2, ole.VT_UI4, ole.VT_UI8, ole.VT_UINT:
+		value = variant.Val
+	case ole.VT_R4:
+		// not necessarily a useful conversion but handle it anyway
+		value = int64(*(*float32)(unsafe.Pointer(&variant.Val)))
+	case ole.VT_R8:
+		value = int64(*(*float64)(unsafe.Pointer(&variant.Val)))
+	case ole.VT_BSTR:
+		var err error
+		value, err = convertStringToInt64(variant.ToString(), outputType.Kind() == reflect.Uint64)
+		if err != nil {
+			return value, err
+		}
+	default:
+		return nil, fmt.Errorf("could not convert variant type %d to %v", variant.VT, outputType)
+	}
+
+	return convertInt64ToInt(value, outputType)
+}
+
+func convertVariantToFloat(variant *ole.VARIANT, outputType reflect.Type) (interface{}, error) {
+	var value float64
+	switch variant.VT {
+	case ole.VT_NULL:
+		fallthrough
+	case ole.VT_BOOL:
+		fallthrough
+	case ole.VT_I1, ole.VT_I2, ole.VT_I4, ole.VT_I8, ole.VT_INT:
+		fallthrough
+	case ole.VT_UI1, ole.VT_UI2, ole.VT_UI4, ole.VT_UI8, ole.VT_UINT:
+		value = float64(variant.Val)
+	case ole.VT_R4:
+		value = float64(*(*float32)(unsafe.Pointer(&variant.Val)))
+	case ole.VT_R8:
+		value = *(*float64)(unsafe.Pointer(&variant.Val))
+	case ole.VT_BSTR:
+		var err error
+		value, err = strconv.ParseFloat(variant.ToString(), 64)
+		if err != nil {
+			return value, err
+		}
+	default:
+		return nil, fmt.Errorf("could not convert variant type %d to %v", variant.VT, outputType)
+	}
+
+	if outputType.Kind() == reflect.Float32 {
+		return float32(value), nil
+	}
+
+	return value, nil
+}
+
+func convertVariantToStruct(variant *ole.VARIANT, outputType reflect.Type) (interface{}, error) {
+	if variant.VT != ole.VT_UNKNOWN {
+		return nil, fmt.Errorf("could not convert non-IUnknown variant type %d to %v", variant.VT, outputType)
+	}
+
+	ptr := variant.ToIUnknown()
+
+	var rawInstance struct {
+		*ole.IUnknown
+		*IWbemClassObjectVtbl
+	}
+
+	rawInstance.IUnknown = ptr
+	rawInstance.IWbemClassObjectVtbl = (*IWbemClassObjectVtbl)(unsafe.Pointer(ptr.RawVTable))
+
+	instance := (*Instance)(unsafe.Pointer(&rawInstance))
+	val := reflect.New(outputType)
+	err := instance.GetAll(val.Interface())
+	return val.Elem().Interface(), err
+}
+
+func convertVariantToArray(variant *ole.VARIANT, outputType reflect.Type) (interface{}, error) {
+	if variant.VT&ole.VT_ARRAY != ole.VT_ARRAY {
+		return nil, fmt.Errorf("could not convert non-array variant type %d to %v", variant.VT, outputType)
+	}
+
+	safeArrayConversion := ole.SafeArrayConversion{Array: *(**ole.SafeArray)(unsafe.Pointer(&variant.Val))}
+
+	arrayLen, err := safeArrayConversion.TotalElements(0)
+	if err != nil {
+		return nil, err
+	}
+	elemVT := (^ole.VT_ARRAY) & variant.VT
+	slice := reflect.MakeSlice(reflect.SliceOf(outputType.Elem()), int(arrayLen), int(arrayLen))
+
+	for i := 0; i < int(arrayLen); i++ {
+		elemVariant := ole.VARIANT{VT: elemVT}
+		elemSrc, err := safeArrayGetAsVariantVal(safeArrayConversion.Array, int64(i), elemVariant)
+		if err != nil {
+			return nil, err
+		}
+		elemVariant.Val = int64(elemSrc)
+		elemDest, err := convertToGoType(&elemVariant, slice.Index(i), outputType.Elem())
+		if err != nil {
+			return nil, err
+		}
+
+		slice.Index(i).Set(reflect.ValueOf(elemDest))
+	}
+
+	return slice.Interface(), nil
+}
+
+func convertToGenericValue(variant *ole.VARIANT) interface{} {
+	var result interface{}
+	if variant.VT&ole.VT_ARRAY == ole.VT_ARRAY {
+		safeArrayConversion := ole.SafeArrayConversion{Array: *(**ole.SafeArray)(unsafe.Pointer(&variant.Val))}
+		result = safeArrayConversion.ToValueArray()
+	} else {
+		result = variant.Value()
+	}
+	return result
+}
+
+func convertTimeToDataTime(time *time.Time) ole.VARIANT {
+	if time == nil || !time.After(WindowsEpoch) {
+		return ole.NewVariant(ole.VT_NULL, 0)
+	}
+	_, offset := time.Zone()
+	// convert to minutes
+	offset /= 60
+	//yyyymmddHHMMSS.mmmmmmsUUU
+	s := fmt.Sprintf("%s%+04d", time.Format("20060102150405.000000"), offset)
+	return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(s)))))
+}
+
+func convertDurationToDateTime(duration time.Duration) ole.VARIANT {
+	const daySeconds = time.Second * 86400
+
+	if duration == 0 {
+		return ole.NewVariant(ole.VT_NULL, 0)
+	}
+
+	days := duration / daySeconds
+	duration = duration % daySeconds
+
+	hours := duration / time.Hour
+	duration = duration % time.Hour
+
+	mins := duration / time.Minute
+	duration = duration % time.Minute
+
+	seconds := duration / time.Second
+	duration = duration % time.Second
+
+	micros := duration / time.Microsecond
+
+	s := fmt.Sprintf("%08d%02d%02d%02d.%06d:000", days, hours, mins, seconds, micros)
+	return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(s)))))
+}
+
+func extractDateTimeString(variant *ole.VARIANT) (string, error) {
+	switch variant.VT {
+	case ole.VT_BSTR:
+		return variant.ToString(), nil
+	case ole.VT_NULL:
+		return "", nil
+	default:
+		return "", errors.New("variant not compatible with dateTime field")
+	}
+}
+
+func convertDataTimeToTime(variant *ole.VARIANT) (time.Time, error) {
+	var err error
+	dateTime, err := extractDateTimeString(variant)
+	if err != nil || len(dateTime) == 0 {
+		return zeroTime, err
+	}
+
+	dLen := len(dateTime)
+	if dLen < 5 {
+		return zeroTime, errors.New("invalid datetime string")
+	}
+
+	if strings.HasPrefix(dateTime, "00000000000000.000000") {
+		// Zero time
+		return zeroTime, nil
+	}
+
+	zoneStart := dLen - 4
+	timePortion := dateTime[0:zoneStart]
+
+	var zoneMinutes int64
+	if dateTime[zoneStart] == ':' {
+		// interval ends in :000
+		return parseIntervalTime(dateTime)
+	}
+
+	zoneSuffix := dateTime[zoneStart:dLen]
+	zoneMinutes, err = strconv.ParseInt(zoneSuffix, 10, 0)
+	if err != nil {
+		return zeroTime, errors.New("invalid datetime string, zone did not parse")
+	}
+
+	timePortion = fmt.Sprintf("%s%+03d%02d", timePortion, zoneMinutes/60, abs(int(zoneMinutes%60)))
+	return time.Parse("20060102150405.000000-0700", timePortion)
+}
+
+// parseIntervalTime encodes an interval time as an offset to Unix time
+// allowing a duration to be computed without precision loss
+func parseIntervalTime(interval string) (time.Time, error) {
+	if len(interval) < 25 || interval[21:22] != ":" {
+		return time.Time{}, fmt.Errorf("invalid interval time: %s", interval)
+	}
+
+	days, err := parseUintChain(interval[0:8], nil)
+	hours, err := parseUintChain(interval[8:10], err)
+	mins, err := parseUintChain(interval[10:12], err)
+	secs, err := parseUintChain(interval[12:14], err)
+	micros, err := parseUintChain(interval[15:21], err)
+
+	if err != nil {
+		return time.Time{}, err
+	}
+
+	var stamp uint64 = secs
+	stamp += days * 86400
+	stamp += hours * 3600
+	stamp += mins * 60
+
+	return time.Unix(int64(stamp), int64(micros*1000)), nil
+}
+
+func convertIntervalToDuration(variant *ole.VARIANT) (time.Duration, error) {
+	var err error
+	interval, err := extractDateTimeString(variant)
+	if err != nil || len(interval) == 0 {
+		return 0, err
+	}
+
+	t, err := parseIntervalTime(interval)
+	if err != nil {
+		return 0, nil
+	}
+
+	return t.Sub(unixEpoch), nil
+}
+
+func parseUintChain(str string, err error) (uint64, error) {
+	if err != nil {
+		return 0, err
+	}
+	return strconv.ParseUint(str, 10, 0)
+}
+
+func abs(num int) int {
+	if num < 0 {
+		return -num
+	}
+
+	return num
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/enum.go b/vendor/github.com/containers/libhvee/pkg/wmiext/enum.go
new file mode 100644
index 000000000..2b6fd690b
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/enum.go
@@ -0,0 +1,94 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"fmt"
+	"syscall"
+	"unsafe"
+
+	"github.com/go-ole/go-ole"
+)
+
+type IEnumWbemClassObjectVtbl struct {
+	QueryInterface uintptr
+	AddRef         uintptr
+	Release        uintptr
+	Reset          uintptr
+	Next           uintptr
+	NextAsync      uintptr
+	Clone          uintptr
+	Skip           uintptr
+}
+
+type Enum struct {
+	enum    *ole.IUnknown
+	vTable  *IEnumWbemClassObjectVtbl
+	service *Service
+}
+
+func (e *Enum) Close() {
+	if e != nil && e.enum != nil {
+		e.enum.Release()
+	}
+}
+
+func newEnum(enumerator *ole.IUnknown, service *Service) *Enum {
+	return &Enum{
+		enum:    enumerator,
+		vTable:  (*IEnumWbemClassObjectVtbl)(unsafe.Pointer(enumerator.RawVTable)),
+		service: service,
+	}
+}
+
+// NextObject obtains the next instance in an enumeration and sets all fields
+// of the struct pointer passed through the target parameter. Otherwise, if
+// the target parameter is not a struct pointer type, an error will be
+// returned.
+func NextObject(enum *Enum, target interface{}) (bool, error) {
+	var err error
+
+	var instance *Instance
+	if instance, err = enum.Next(); err != nil {
+		return false, err
+	}
+
+	if instance == nil {
+		return true, nil
+	}
+
+	defer instance.Close()
+
+	return false, instance.GetAll(target)
+}
+
+// Next returns the next object instance in this iteration
+func (e *Enum) Next() (instance *Instance, err error) {
+	var res uintptr
+	var apObjects *ole.IUnknown
+	var uReturned uint32
+
+	res, _, _ = syscall.SyscallN(
+		e.vTable.Next,                       // IEnumWbemClassObject::Next()
+		uintptr(unsafe.Pointer(e.enum)),     // IEnumWbemClassObject   ptr
+		uintptr(WBEM_INFINITE),              // [in]  long             lTimeout,
+		uintptr(1),                          // [in]  ULONG            uCount,
+		uintptr(unsafe.Pointer(&apObjects)), // [out] IWbemClassObject **apObjects,
+		uintptr(unsafe.Pointer(&uReturned))) // [out] ULONG            *puReturned)
+	if int(res) < 0 {
+		return nil, NewWmiError(res)
+	}
+
+	if uReturned < 1 {
+		switch res {
+		case WBEM_S_NO_ERROR, WBEM_S_FALSE:
+			// No more elements
+			return nil, nil
+		default:
+			return nil, fmt.Errorf("failure advancing enumeration (%d)", res)
+		}
+	}
+
+	return newInstance(apObjects, e.service), nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/error.go b/vendor/github.com/containers/libhvee/pkg/wmiext/error.go
new file mode 100644
index 000000000..ce7a9d10b
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/error.go
@@ -0,0 +1,202 @@
+package wmiext
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"strings"
+	"syscall"
+	"unicode/utf16"
+
+	"golang.org/x/sys/windows"
+)
+
+const (
+	WBEM_NO_ERROR                          = 0
+	WBEM_S_NO_ERROR                        = 0
+	WBEM_S_SAME                            = 0
+	WBEM_S_FALSE                           = 1
+	WBEM_S_ALREADY_EXISTS                  = 0x40001
+	WBEM_S_RESET_TO_DEFAULT                = 0x40002
+	WBEM_S_DIFFERENT                       = 0x40003
+	WBEM_S_TIMEDOUT                        = 0x40004
+	WBEM_S_NO_MORE_DATA                    = 0x40005
+	WBEM_S_OPERATION_CANCELLED             = 0x40006
+	WBEM_S_PENDING                         = 0x40007
+	WBEM_S_DUPLICATE_OBJECTS               = 0x40008
+	WBEM_S_ACCESS_DENIED                   = 0x40009
+	WBEM_S_PARTIAL_RESULTS                 = 0x40010
+	WBEM_S_SOURCE_NOT_AVAILABLE            = 0x40017
+	WBEM_E_FAILED                          = 0x80041001
+	WBEM_E_NOT_FOUND                       = 0x80041002
+	WBEM_E_ACCESS_DENIED                   = 0x80041003
+	WBEM_E_PROVIDER_FAILURE                = 0x80041004
+	WBEM_E_TYPE_MISMATCH                   = 0x80041005
+	WBEM_E_OUT_OF_MEMORY                   = 0x80041006
+	WBEM_E_INVALID_CONTEXT                 = 0x80041007
+	WBEM_E_INVALID_PARAMETER               = 0x80041008
+	WBEM_E_NOT_AVAILABLE                   = 0x80041009
+	WBEM_E_CRITICAL_ERROR                  = 0x8004100a
+	WBEM_E_INVALID_STREAM                  = 0x8004100b
+	WBEM_E_NOT_SUPPORTED                   = 0x8004100c
+	WBEM_E_INVALID_SUPERCLASS              = 0x8004100d
+	WBEM_E_INVALID_NAMESPACE               = 0x8004100e
+	WBEM_E_INVALID_OBJECT                  = 0x8004100f
+	WBEM_E_INVALID_CLASS                   = 0x80041010
+	WBEM_E_PROVIDER_NOT_FOUND              = 0x80041011
+	WBEM_E_INVALID_PROVIDER_REGISTRATION   = 0x80041012
+	WBEM_E_PROVIDER_LOAD_FAILURE           = 0x80041013
+	WBEM_E_INITIALIZATION_FAILURE          = 0x80041014
+	WBEM_E_TRANSPORT_FAILURE               = 0x80041015
+	WBEM_E_INVALID_OPERATION               = 0x80041016
+	WBEM_E_INVALID_QUERY                   = 0x80041017
+	WBEM_E_INVALID_QUERY_TYPE              = 0x80041018
+	WBEM_E_ALREADY_EXISTS                  = 0x80041019
+	WBEM_E_OVERRIDE_NOT_ALLOWED            = 0x8004101a
+	WBEM_E_PROPAGATED_QUALIFIER            = 0x8004101b
+	WBEM_E_PROPAGATED_PROPERTY             = 0x8004101c
+	WBEM_E_UNEXPECTED                      = 0x8004101d
+	WBEM_E_ILLEGAL_OPERATION               = 0x8004101e
+	WBEM_E_CANNOT_BE_KEY                   = 0x8004101f
+	WBEM_E_INCOMPLETE_CLASS                = 0x80041020
+	WBEM_E_INVALID_SYNTAX                  = 0x80041021
+	WBEM_E_NONDECORATED_OBJECT             = 0x80041022
+	WBEM_E_READ_ONLY                       = 0x80041023
+	WBEM_E_PROVIDER_NOT_CAPABLE            = 0x80041024
+	WBEM_E_CLASS_HAS_CHILDREN              = 0x80041025
+	WBEM_E_CLASS_HAS_INSTANCES             = 0x80041026
+	WBEM_E_QUERY_NOT_IMPLEMENTED           = 0x80041027
+	WBEM_E_ILLEGAL_NULL                    = 0x80041028
+	WBEM_E_INVALID_QUALIFIER_TYPE          = 0x80041029
+	WBEM_E_INVALID_PROPERTY_TYPE           = 0x8004102a
+	WBEM_E_VALUE_OUT_OF_RANGE              = 0x8004102b
+	WBEM_E_CANNOT_BE_SINGLETON             = 0x8004102c
+	WBEM_E_INVALID_CIM_TYPE                = 0x8004102d
+	WBEM_E_INVALID_METHOD                  = 0x8004102e
+	WBEM_E_INVALID_METHOD_PARAMETERS       = 0x8004102f
+	WBEM_E_SYSTEM_PROPERTY                 = 0x80041030
+	WBEM_E_INVALID_PROPERTY                = 0x80041031
+	WBEM_E_CALL_CANCELLED                  = 0x80041032
+	WBEM_E_SHUTTING_DOWN                   = 0x80041033
+	WBEM_E_PROPAGATED_METHOD               = 0x80041034
+	WBEM_E_UNSUPPORTED_PARAMETER           = 0x80041035
+	WBEM_E_MISSING_PARAMETER_ID            = 0x80041036
+	WBEM_E_INVALID_PARAMETER_ID            = 0x80041037
+	WBEM_E_NONCONSECUTIVE_PARAMETER_IDS    = 0x80041038
+	WBEM_E_PARAMETER_ID_ON_RETVAL          = 0x80041039
+	WBEM_E_INVALID_OBJECT_PATH             = 0x8004103a
+	WBEM_E_OUT_OF_DISK_SPACE               = 0x8004103b
+	WBEM_E_BUFFER_TOO_SMALL                = 0x8004103c
+	WBEM_E_UNSUPPORTED_PUT_EXTENSION       = 0x8004103d
+	WBEM_E_UNKNOWN_OBJECT_TYPE             = 0x8004103e
+	WBEM_E_UNKNOWN_PACKET_TYPE             = 0x8004103f
+	WBEM_E_MARSHAL_VERSION_MISMATCH        = 0x80041040
+	WBEM_E_MARSHAL_INVALID_SIGNATURE       = 0x80041041
+	WBEM_E_INVALID_QUALIFIER               = 0x80041042
+	WBEM_E_INVALID_DUPLICATE_PARAMETER     = 0x80041043
+	WBEM_E_TOO_MUCH_DATA                   = 0x80041044
+	WBEM_E_SERVER_TOO_BUSY                 = 0x80041045
+	WBEM_E_INVALID_FLAVOR                  = 0x80041046
+	WBEM_E_CIRCULAR_REFERENCE              = 0x80041047
+	WBEM_E_UNSUPPORTED_CLASS_UPDATE        = 0x80041048
+	WBEM_E_CANNOT_CHANGE_KEY_INHERITANCE   = 0x80041049
+	WBEM_E_CANNOT_CHANGE_INDEX_INHERITANCE = 0x80041050
+	WBEM_E_TOO_MANY_PROPERTIES             = 0x80041051
+	WBEM_E_UPDATE_TYPE_MISMATCH            = 0x80041052
+	WBEM_E_UPDATE_OVERRIDE_NOT_ALLOWED     = 0x80041053
+	WBEM_E_UPDATE_PROPAGATED_METHOD        = 0x80041054
+	WBEM_E_METHOD_NOT_IMPLEMENTED          = 0x80041055
+	WBEM_E_METHOD_DISABLED                 = 0x80041056
+	WBEM_E_REFRESHER_BUSY                  = 0x80041057
+	WBEM_E_UNPARSABLE_QUERY                = 0x80041058
+	WBEM_E_NOT_EVENT_CLASS                 = 0x80041059
+	WBEM_E_MISSING_GROUP_WITHIN            = 0x8004105a
+	WBEM_E_MISSING_AGGREGATION_LIST        = 0x8004105b
+	WBEM_E_PROPERTY_NOT_AN_OBJECT          = 0x8004105c
+	WBEM_E_AGGREGATING_BY_OBJECT           = 0x8004105d
+	WBEM_E_UNINTERPRETABLE_PROVIDER_QUERY  = 0x8004105f
+	WBEM_E_BACKUP_RESTORE_WINMGMT_RUNNING  = 0x80041060
+	WBEM_E_QUEUE_OVERFLOW                  = 0x80041061
+	WBEM_E_PRIVILEGE_NOT_HELD              = 0x80041062
+	WBEM_E_INVALID_OPERATOR                = 0x80041063
+	WBEM_E_LOCAL_CREDENTIALS               = 0x80041064
+	WBEM_E_CANNOT_BE_ABSTRACT              = 0x80041065
+	WBEM_E_AMENDED_OBJECT                  = 0x80041066
+	WBEM_E_CLIENT_TOO_SLOW                 = 0x80041067
+	WBEM_E_NULL_SECURITY_DESCRIPTOR        = 0x80041068
+	WBEM_E_TIMED_OUT                       = 0x80041069
+	WBEM_E_INVALID_ASSOCIATION             = 0x8004106a
+	WBEM_E_AMBIGUOUS_OPERATION             = 0x8004106b
+	WBEM_E_QUOTA_VIOLATION                 = 0x8004106c
+	WBEM_E_RESERVED_001                    = 0x8004106d
+	WBEM_E_RESERVED_002                    = 0x8004106e
+	WBEM_E_UNSUPPORTED_LOCALE              = 0x8004106f
+	WBEM_E_HANDLE_OUT_OF_DATE              = 0x80041070
+	WBEM_E_CONNECTION_FAILED               = 0x80041071
+	WBEM_E_INVALID_HANDLE_REQUEST          = 0x80041072
+	WBEM_E_PROPERTY_NAME_TOO_WIDE          = 0x80041073
+	WBEM_E_CLASS_NAME_TOO_WIDE             = 0x80041074
+	WBEM_E_METHOD_NAME_TOO_WIDE            = 0x80041075
+	WBEM_E_QUALIFIER_NAME_TOO_WIDE         = 0x80041076
+	WBEM_E_RERUN_COMMAND                   = 0x80041077
+	WBEM_E_DATABASE_VER_MISMATCH           = 0x80041078
+	WBEM_E_VETO_DELETE                     = 0x80041079
+	WBEM_E_VETO_PUT                        = 0x8004107a
+	WBEM_E_INVALID_LOCALE                  = 0x80041080
+	WBEM_E_PROVIDER_SUSPENDED              = 0x80041081
+	WBEM_E_SYNCHRONIZATION_REQUIRED        = 0x80041082
+	WBEM_E_NO_SCHEMA                       = 0x80041083
+	WBEM_E_PROVIDER_ALREADY_REGISTERED     = 0x80041084
+	WBEM_E_PROVIDER_NOT_REGISTERED         = 0x80041085
+	WBEM_E_FATAL_TRANSPORT_ERROR           = 0x80041086
+	WBEM_E_ENCRYPTED_CONNECTION_REQUIRED   = 0x80041087
+	WBEM_E_PROVIDER_TIMED_OUT              = 0x80041088
+	WBEM_E_NO_KEY                          = 0x80041089
+	WBEM_E_PROVIDER_DISABLED               = 0x8004108a
+)
+
+var (
+	wmiModule syscall.Handle
+)
+
+// VM Lookup errors
+var (
+	ErrNoResults = errors.New("no results found")
+)
+
+func init() {
+	file := os.ExpandEnv("${windir}\\system32\\wbem\\wmiutils.dll")
+	wmiModule, _ = syscall.LoadLibrary(file)
+}
+
+type WmiError struct {
+	hres uintptr
+}
+
+func NewWmiError(hres uintptr) *WmiError {
+	return &WmiError{hres}
+}
+
+func (w *WmiError) String() string {
+	return w.Error()
+}
+
+func (w *WmiError) Code() uintptr {
+	return w.hres
+}
+
+func (w *WmiError) Error() string {
+	// ask windows for the remaining errors
+	var flags uint32 = syscall.FORMAT_MESSAGE_FROM_SYSTEM |
+		syscall.FORMAT_MESSAGE_FROM_HMODULE |
+		syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY |
+		syscall.FORMAT_MESSAGE_IGNORE_INSERTS
+
+	buf := make([]uint16, 300)
+	n, err := windows.FormatMessage(flags, uintptr(wmiModule), uint32(w.hres), 0, buf, nil)
+	if err != nil {
+		return fmt.Sprintf("WMI error [%d]: FormatMessage failed with: %v", w.hres, err)
+	}
+
+	return fmt.Sprintf("WMI error [%d]: %s", w.hres, strings.TrimRight(string(utf16.Decode(buf[:n])), "\r\n"))
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/init.go b/vendor/github.com/containers/libhvee/pkg/wmiext/init.go
new file mode 100644
index 000000000..35c5b8297
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/init.go
@@ -0,0 +1,108 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"github.com/go-ole/go-ole"
+	"github.com/sirupsen/logrus"
+	"golang.org/x/sys/windows"
+)
+
+var (
+	ole32                    = windows.NewLazySystemDLL("ole32.dll")
+	procCoSetProxyBlanket    = ole32.NewProc("CoSetProxyBlanket")
+	procCoInitializeSecurity = ole32.NewProc("CoInitializeSecurity")
+
+	modoleaut32               = windows.NewLazySystemDLL("oleaut32.dll")
+	procSafeArrayCreateVector = modoleaut32.NewProc("SafeArrayCreateVector")
+	procSafeArrayPutElement   = modoleaut32.NewProc("SafeArrayPutElement")
+	procSafeArrayGetElement   = modoleaut32.NewProc("SafeArrayGetElement")
+	procSafeArrayDestroy      = modoleaut32.NewProc("SafeArrayDestroy")
+
+	clsidWbemObjectTextSrc = ole.NewGUID("{8d1c559d-84f0-4bb3-a7d5-56a7435a9ba6}")
+	iidIWbemObjectTextSrc  = ole.NewGUID("{bfbf883a-cad7-11d3-a11b-00105a1f515a}")
+
+	wmiWbemTxtLocator *ole.IUnknown
+	wmiWbemLocator    *ole.IUnknown
+
+	clsidWbemLocator = ole.NewGUID("4590f811-1d3a-11d0-891f-00aa004b2e24")
+	iidIWbemLocator  = ole.NewGUID("dc12a687-737f-11cf-884d-00aa004b2e24")
+)
+
+const (
+	// WMI Generic flags
+	WBEM_FLAG_RETURN_WBEM_COMPLETE = 0x0
+	WBEM_FLAG_RETURN_IMMEDIATELY   = 0x10
+	WBEM_FLAG_FORWARD_ONLY         = 0x20
+
+	// WMI Query flags
+	WBEM_FLAG_SHALLOW = 1
+
+	// Timeout flags
+	WBEM_NO_WAIT  = 0
+	WBEM_INFINITE = 0xFFFFFFFF
+
+	// COM Auth Flags
+	EOAC_NONE = 0
+
+	// RPC Authentication
+	RPC_C_AUTHN_WINNT = 10
+
+	// RPC Authentication Level
+	RPC_C_AUTHN_LEVEL_DEFAULT = 0
+	RPC_C_AUTHN_LEVEL_CALL    = 3
+
+	// RPC Authorization
+	RPC_C_AUTHZ_NONE = 0
+
+	// RPC Impersonation
+	RPC_C_IMP_LEVEL_IMPERSONATE = 3
+)
+
+func init() {
+	var err error
+
+	err = ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
+	if err != nil {
+		if oleCode, ok := err.(*ole.OleError); ok {
+			code := oleCode.Code()
+			// 1 = Already init
+			if code != 0 && code != 1 {
+				logrus.Errorf("Unable to initialize COM: %s", err.Error())
+				return
+			}
+		}
+	}
+
+	initSecurity()
+
+	wmiWbemLocator, err = ole.CreateInstance(clsidWbemLocator, iidIWbemLocator)
+	if err != nil {
+		logrus.Errorf("Could not initialize Wbem components, WMI operations will likely fail %s", err.Error())
+	}
+
+	// IID_IWbemObjectTextSrc Obtain the initial locator to WMI
+	wmiWbemTxtLocator, err = ole.CreateInstance(clsidWbemObjectTextSrc, iidIWbemObjectTextSrc)
+	if err != nil {
+		logrus.Errorf("Could not initialize Wbem components, WMI operations will likely fail %s", err.Error())
+	}
+}
+
+func initSecurity() {
+	var svc int32 = -1
+
+	res, _, _ := procCoInitializeSecurity.Call( // CoInitializeSecurity
+		uintptr(0),                           // [in, optional] PSECURITY_DESCRIPTOR        pSecDesc,
+		uintptr(svc),                         // [in]           LONG                        cAuthSvc,
+		uintptr(0),                           // [in, optional] SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
+		uintptr(0),                           // [in, optional] void                        *pReserved1,
+		uintptr(RPC_C_AUTHN_LEVEL_DEFAULT),   // [in]           DWORD                       dwAuthnLevel,
+		uintptr(RPC_C_IMP_LEVEL_IMPERSONATE), // [in]           DWORD                       dwImpLevel,
+		uintptr(0),                           // [in, optional] void                        *pAuthList,
+		uintptr(EOAC_NONE),                   // [in]           DWORD                       dwCapabilities,
+		uintptr(0))                           // [in, optional] void                        *pReserved3
+	if int(res) < 0 {
+		logrus.Errorf("Unable to initialize COM security: %s", NewWmiError(res).Error())
+	}
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/instance.go b/vendor/github.com/containers/libhvee/pkg/wmiext/instance.go
new file mode 100644
index 000000000..b60d636fe
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/instance.go
@@ -0,0 +1,652 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
+	"unsafe"
+
+	"github.com/go-ole/go-ole"
+	"github.com/sirupsen/logrus"
+)
+
+const (
+	WmiPathKey = "__PATH"
+)
+
+var (
+	WindowsEpoch = time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
+)
+
+type Instance struct {
+	object  *ole.IUnknown
+	vTable  *IWbemClassObjectVtbl
+	service *Service
+}
+
+type IWbemClassObjectVtbl struct {
+	QueryInterface          uintptr
+	AddRef                  uintptr
+	Release                 uintptr
+	GetQualifierSet         uintptr
+	Get                     uintptr
+	Put                     uintptr
+	Delete                  uintptr
+	GetNames                uintptr
+	BeginEnumeration        uintptr
+	Next                    uintptr
+	EndEnumeration          uintptr
+	GetPropertyQualifierSet uintptr
+	Clone                   uintptr
+	GetObjectText           uintptr
+	SpawnDerivedClass       uintptr
+	SpawnInstance           uintptr
+	CompareTo               uintptr
+	GetPropertyOrigin       uintptr
+	InheritsFrom            uintptr
+	GetMethod               uintptr
+	PutMethod               uintptr
+	DeleteMethod            uintptr
+	BeginMethodEnumeration  uintptr
+	NextMethod              uintptr
+	EndMethodEnumeration    uintptr
+	GetMethodQualifierSet   uintptr
+	GetMethodOrigin         uintptr
+}
+
+type CIMTYPE_ENUMERATION uint32
+
+const (
+	CIM_ILLEGAL    CIMTYPE_ENUMERATION = 0xFFF
+	CIM_EMPTY      CIMTYPE_ENUMERATION = 0
+	CIM_SINT8      CIMTYPE_ENUMERATION = 16
+	CIM_UINT8      CIMTYPE_ENUMERATION = 17
+	CIM_SINT16     CIMTYPE_ENUMERATION = 2
+	CIM_UINT16     CIMTYPE_ENUMERATION = 18
+	CIM_SINT32     CIMTYPE_ENUMERATION = 3
+	CIM_UINT32     CIMTYPE_ENUMERATION = 19
+	CIM_SINT64     CIMTYPE_ENUMERATION = 20
+	CIM_UINT64     CIMTYPE_ENUMERATION = 21
+	CIM_REAL32     CIMTYPE_ENUMERATION = 4
+	CIM_REAL64     CIMTYPE_ENUMERATION = 5
+	CIM_BOOLEAN    CIMTYPE_ENUMERATION = 11
+	CIM_STRING     CIMTYPE_ENUMERATION = 8
+	CIM_DATETIME   CIMTYPE_ENUMERATION = 101
+	CIM_REFERENCE  CIMTYPE_ENUMERATION = 102
+	CIM_CHAR16     CIMTYPE_ENUMERATION = 103
+	CIM_OBJECT     CIMTYPE_ENUMERATION = 13
+	CIM_FLAG_ARRAY CIMTYPE_ENUMERATION = 0x2000
+)
+
+type WBEM_FLAVOR_TYPE uint32
+
+const (
+	WBEM_FLAVOR_DONT_PROPAGATE                  WBEM_FLAVOR_TYPE = 0
+	WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE      WBEM_FLAVOR_TYPE = 0x1
+	WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS WBEM_FLAVOR_TYPE = 0x2
+	WBEM_FLAVOR_MASK_PROPAGATION                WBEM_FLAVOR_TYPE = 0xf
+	WBEM_FLAVOR_OVERRIDABLE                     WBEM_FLAVOR_TYPE = 0
+	WBEM_FLAVOR_NOT_OVERRIDABLE                 WBEM_FLAVOR_TYPE = 0x10
+	WBEM_FLAVOR_MASK_PERMISSIONS                WBEM_FLAVOR_TYPE = 0x10
+	WBEM_FLAVOR_ORIGIN_LOCAL                    WBEM_FLAVOR_TYPE = 0
+	WBEM_FLAVOR_ORIGIN_PROPAGATED               WBEM_FLAVOR_TYPE = 0x20
+	WBEM_FLAVOR_ORIGIN_SYSTEM                   WBEM_FLAVOR_TYPE = 0x40
+	WBEM_FLAVOR_MASK_ORIGIN                     WBEM_FLAVOR_TYPE = 0x60
+	WBEM_FLAVOR_NOT_AMENDED                     WBEM_FLAVOR_TYPE = 0
+	WBEM_FLAVOR_AMENDED                         WBEM_FLAVOR_TYPE = 0x80
+	WBEM_FLAVOR_MASK_AMENDED                    WBEM_FLAVOR_TYPE = 0x80
+)
+
+func newInstance(object *ole.IUnknown, service *Service) *Instance {
+	instance := &Instance{
+		object:  object,
+		vTable:  (*IWbemClassObjectVtbl)(unsafe.Pointer(object.RawVTable)),
+		service: service,
+	}
+
+	return instance
+}
+
+// Close cleans up all memory associated with this instance.
+func (i *Instance) Close() {
+	if i != nil && i.object != nil {
+		i.object.Release()
+	}
+}
+
+// GetClassName Gets the WMI class name for this WMI object instance
+func (i *Instance) GetClassName() (className string, err error) {
+	return i.GetAsString(`__CLASS`)
+}
+
+// Path gets the WMI object path of this instance
+func (i *Instance) Path() (string, error) {
+	ref, _, _, err := i.GetAsAny(WmiPathKey)
+	return ref.(string), err
+}
+
+// IsReferenceProperty returns whether the property is of type CIM_REFERENCE, a string which points to
+// an object path of another instance.
+func (i *Instance) IsReferenceProperty(name string) (bool, error) {
+	_, cimType, _, err := i.GetAsAny(name)
+	return cimType == CIM_REFERENCE, err
+}
+
+// SpawnInstance create a new WMI object instance that is zero-initialized. The returned instance
+// will not respect expected default values, which must be populated by other means.
+func (i *Instance) SpawnInstance() (instance *Instance, err error) {
+	var res uintptr
+	var newUnknown *ole.IUnknown
+
+	res, _, _ = syscall.SyscallN(
+		i.vTable.SpawnInstance,               // IWbemClassObject::SpawnInstance(
+		uintptr(unsafe.Pointer(i.object)),    // IWbemClassObject ptr
+		uintptr(0),                           // [in]  long             lFlags,
+		uintptr(unsafe.Pointer(&newUnknown))) // [out] IWbemClassObject **ppNewInstance)
+	if res != 0 {
+		return nil, NewWmiError(res)
+	}
+
+	return newInstance(newUnknown, i.service), nil
+}
+
+// CloneInstance create a new cloned copy of this WMI instance.
+func (i *Instance) CloneInstance() (*Instance, error) {
+	classObj := i.object
+	vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
+	var cloned *ole.IUnknown
+
+	ret, _, _ := syscall.SyscallN(
+		vTable.Clone,                      // IWbemClassObject::Clone(
+		uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr
+		uintptr(unsafe.Pointer(&cloned)))  // [out] IWbemClassObject **ppCopy)
+	if ret != 0 {
+		return nil, NewWmiError(ret)
+	}
+
+	return newInstance(cloned, i.service), nil
+}
+
+// PutAll sets all fields of this instance to the passed src parameter's fields, converting accordingly.
+// The src parameter must be a pointer to a struct, otherwise an error will be returned.
+func (i *Instance) PutAll(src interface{}) error {
+	val := reflect.ValueOf(src)
+	if val.Kind() == reflect.Pointer {
+		val = val.Elem()
+	}
+
+	if val.Kind() != reflect.Struct {
+		return errors.New("not a struct or pointer to struct")
+	}
+
+	props, err := i.GetAllProperties()
+	if err != nil {
+		return err
+	}
+
+	return i.instancePutAllTraverse(val, props)
+}
+
+func (i *Instance) instancePutAllTraverse(val reflect.Value, propMap map[string]interface{}) error {
+	for j := 0; j < val.NumField(); j++ {
+		fieldVal := val.Field(j)
+		fieldType := val.Type().Field(j)
+
+		if fieldType.Type.Kind() == reflect.Struct && fieldType.Anonymous {
+			if err := i.instancePutAllTraverse(fieldVal, propMap); err != nil {
+				return err
+			}
+			continue
+		}
+		if strings.HasPrefix(fieldType.Name, "S__") {
+			continue
+		}
+
+		if !fieldType.IsExported() {
+			continue
+		}
+
+		if _, exists := propMap[fieldType.Name]; !exists {
+			continue
+		}
+
+		if fieldVal.Kind() == reflect.String && fieldVal.Len() == 0 {
+			continue
+		}
+
+		if err := i.Put(fieldType.Name, fieldVal.Interface()); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// Put sets the specified property to the passed Golang value, converting appropriately.
+func (i *Instance) Put(name string, value interface{}) (err error) {
+	var variant ole.VARIANT
+
+	switch cast := value.(type) {
+	case ole.VARIANT:
+		variant = cast
+	case *ole.VARIANT:
+		variant = *cast
+	default:
+		variant, err = NewAutomationVariant(value)
+		if err != nil {
+			return err
+		}
+	}
+
+	var wszName *uint16
+	if wszName, err = syscall.UTF16PtrFromString(name); err != nil {
+		return
+	}
+
+	classObj := i.object
+	vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
+	res, _, _ := syscall.SyscallN(
+		vTable.Put,                        // IWbemClassObject::Put(
+		uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr
+		uintptr(unsafe.Pointer(wszName)),  // [in] LPCWSTR wszName,
+		uintptr(0),                        // [in] long    lFlags,
+		uintptr(unsafe.Pointer(&variant)), // [in] VARIANT *pVal,
+		uintptr(0))                        // [in] CIMTYPE Type)
+	if res != 0 {
+		return NewWmiError(res)
+	}
+
+	_ = variant.Clear()
+	return
+}
+
+// GetCimText returns the CIM XML representation of this instance. Some WMI methods use a string
+// parameter to represent a full complex object, and this method is used to generate
+// the expected format.
+func (i *Instance) GetCimText() string {
+	type wmiWbemTxtSrcVtable struct {
+		QueryInterface uintptr
+		AddRef         uintptr
+		Release        uintptr
+		GetTxt         uintptr
+	}
+	const CIM_XML_FORMAT = 1
+
+	classObj := i.object
+
+	vTable := (*wmiWbemTxtSrcVtable)(unsafe.Pointer(wmiWbemTxtLocator.RawVTable))
+	var retString *uint16
+	res, _, _ := syscall.SyscallN(
+		vTable.GetTxt,                           // IWbemObjectTextSrc::GetText()
+		uintptr(unsafe.Pointer(wmiWbemLocator)), // IWbemObjectTextSrc ptr
+		uintptr(0),                              // [in]  long             lFlags
+		uintptr(unsafe.Pointer(classObj)),       // [in]  IWbemClassObject *pObj
+		uintptr(CIM_XML_FORMAT),                 // [in]  ULONG            uObjTextFormat,
+		uintptr(0),                              // [in]  IWbemContext     *pCtx,
+		uintptr(unsafe.Pointer(&retString)))     // [out] BSTR             *strText)
+	if res != 0 {
+		return ""
+	}
+	itemStr := ole.BstrToString(retString)
+	return itemStr
+}
+
+// GetAll gets all fields that map to a target struct and populates all struct fields according to
+// the expected type information. The target parameter should be a pointer to a struct, and
+// will return an error otherwise.
+func (i *Instance) GetAll(target interface{}) error {
+	elem := reflect.ValueOf(target)
+	if elem.Kind() != reflect.Ptr || elem.IsNil() {
+		return errors.New("invalid destination type for mapping a WMI instance to an object")
+	}
+
+	// deref pointer
+	elem = elem.Elem()
+	var err error
+
+	if err = i.BeginEnumeration(); err != nil {
+		return err
+	}
+
+	properties := make(map[string]*ole.VARIANT)
+
+	for {
+		var name string
+		var value *ole.VARIANT
+		var done bool
+
+		if done, name, value, _, _, err = i.NextAsVariant(); err != nil {
+			return err
+		}
+
+		if done {
+			break
+		}
+
+		if value != nil {
+			properties[name] = value
+		}
+	}
+
+	defer func() {
+		for _, v := range properties {
+			_ = v.Clear()
+		}
+	}()
+
+	_ = i.EndEnumeration()
+
+	return i.instanceGetAllPopulate(elem, elem.Type(), properties)
+}
+
+// GetAsAny gets a property and converts it to a Golang type that matches the internal
+// variant automation type passed back from WMI. For usage with predictable static
+// type mapping, use GetAsString(), GetAsUint(), or GetAll() instead of this method.
+func (i *Instance) GetAsAny(name string) (interface{}, CIMTYPE_ENUMERATION, WBEM_FLAVOR_TYPE, error) {
+	variant, cimType, flavor, err := i.GetAsVariant(name)
+	if err != nil {
+		return nil, cimType, flavor, err
+	}
+
+	defer func() {
+		if err := variant.Clear(); err != nil {
+			logrus.Error(err)
+		}
+	}()
+
+	// Since there is no type information only perform the stock conversion
+	result := convertToGenericValue(variant)
+
+	return result, cimType, flavor, err
+}
+
+// GetAsString gets a property value as a string value, converting if necessary
+func (i *Instance) GetAsString(name string) (value string, err error) {
+	variant, _, _, err := i.GetAsVariant(name)
+	if err != nil || variant == nil {
+		return "", err
+	}
+	defer func() {
+		if err := variant.Clear(); err != nil {
+			logrus.Error(err)
+		}
+	}()
+
+	// TODO: replace with something better
+	return fmt.Sprintf("%v", convertToGenericValue(variant)), nil
+}
+
+// GetAsUint gets a property value as a uint value, if conversion is possible. Otherwise,
+// returns an error.
+func (i *Instance) GetAsUint(name string) (uint, error) {
+	val, _, _, err := i.GetAsAny(name)
+	if err != nil {
+		return 0, err
+	}
+
+	switch ret := val.(type) {
+	case int:
+		return uint(ret), nil
+	case int8:
+		return uint(ret), nil
+	case int16:
+		return uint(ret), nil
+	case int32:
+		return uint(ret), nil
+	case int64:
+		return uint(ret), nil
+	case uint:
+		return ret, nil
+	case uint8:
+		return uint(ret), nil
+	case uint16:
+		return uint(ret), nil
+	case uint32:
+		return uint(ret), nil
+	case uint64:
+		return uint(ret), nil
+	case string:
+		parse, err := strconv.ParseUint(ret, 10, 64)
+		return uint(parse), err
+	default:
+		return 0, fmt.Errorf("type conversion from %T on param %s not supported", val, name)
+	}
+}
+
+// GetAsVariant obtains a specified property value, if it exists.
+func (i *Instance) GetAsVariant(name string) (*ole.VARIANT, CIMTYPE_ENUMERATION, WBEM_FLAVOR_TYPE, error) {
+	var variant ole.VARIANT
+	var err error
+	var wszName *uint16
+	var cimType CIMTYPE_ENUMERATION
+	var flavor WBEM_FLAVOR_TYPE
+
+	if wszName, err = syscall.UTF16PtrFromString(name); err != nil {
+		return nil, 0, 0, err
+	}
+
+	classObj := i.object
+	vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
+
+	res, _, _ := syscall.SyscallN(
+		vTable.Get,                        // IWbemClassObject::Get(
+		uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr
+		uintptr(unsafe.Pointer(wszName)),  // [in]            LPCWSTR wszName,
+		uintptr(0),                        // [in]            long    lFlags,
+		uintptr(unsafe.Pointer(&variant)), // [out]           VARIANT *pVal,
+		uintptr(unsafe.Pointer(&cimType)), // [out, optional] CIMTYPE *pType,
+		uintptr(unsafe.Pointer(&flavor)))  // [out, optional] long    *plFlavor)
+	if res != 0 {
+		return nil, 0, 0, NewWmiError(res)
+	}
+
+	return &variant, cimType, flavor, nil
+}
+
+// Next retrieves the next property as a Golang type when iterating the properties using an enumerator
+// created by BeginEnumeration(). The returned value's type represents the internal automation type
+// used by WMI. It is usually preferred to use GetAsXXX(), GetAll(), or GetAll Properties() over this
+// method.
+func (i *Instance) Next() (done bool, name string, value interface{}, cimType CIMTYPE_ENUMERATION, flavor WBEM_FLAVOR_TYPE, err error) {
+	var variant *ole.VARIANT
+	done, name, variant, cimType, flavor, err = i.NextAsVariant()
+
+	if err == nil && !done {
+		defer func() {
+			if err := variant.Clear(); err != nil {
+				logrus.Error(err)
+			}
+		}()
+		value = convertToGenericValue(variant)
+	}
+
+	return
+}
+
+// NextAsVariant retrieves the next property as a VARIANT type when iterating the properties using an enumerator
+// created by BeginEnumeration(). The returned value's type represents the internal automation type
+// used by WMI. It is usually preferred to use GetAsXXX(), GetAll(), or GetAllProperties() over this
+// method. Callers are responsible for clearing the VARIANT, otherwise associated memory will leak.
+func (i *Instance) NextAsVariant() (bool, string, *ole.VARIANT, CIMTYPE_ENUMERATION, WBEM_FLAVOR_TYPE, error) {
+	var res uintptr
+	var strName *uint16
+	var variant ole.VARIANT
+	var cimType CIMTYPE_ENUMERATION
+	var flavor WBEM_FLAVOR_TYPE
+
+	res, _, _ = syscall.SyscallN(
+		i.vTable.Next,                     // IWbemClassObject::Next(
+		uintptr(unsafe.Pointer(i.object)), // IWbemClassObject ptr
+		uintptr(0),                        // [in]            long    lFlags,
+		uintptr(unsafe.Pointer(&strName)), // [out]           BSTR    *strName,
+		uintptr(unsafe.Pointer(&variant)), // [out]           VARIANT *pVal,
+		uintptr(unsafe.Pointer(&cimType)), // [out, optional] CIMTYPE *pType,
+		uintptr(unsafe.Pointer(&flavor)))  // [out, optional] long    *plFlavor
+	if int(res) < 0 {
+		return false, "", nil, cimType, flavor, NewWmiError(res)
+	}
+
+	if res == WBEM_S_NO_MORE_DATA {
+		return true, "", nil, cimType, flavor, nil
+	}
+
+	defer ole.SysFreeString((*int16)(unsafe.Pointer(strName))) //nolint:errcheck
+	name := ole.BstrToString(strName)
+
+	return false, name, &variant, cimType, flavor, nil
+}
+
+// GetAllProperties gets all properties on this instance. The returned map is keyed by the field name and the value
+// is a Golang type which matches the WMI internal implementation. For static type conversions,
+// it's recommended to use either GetAll(), which uses struct fields for type information, or
+// the GetAsXXX() methods.
+func (i *Instance) GetAllProperties() (map[string]interface{}, error) {
+	var err error
+	properties := make(map[string]interface{})
+
+	if err = i.BeginEnumeration(); err != nil {
+		return nil, err
+	}
+
+	defer func() {
+		if err := i.EndEnumeration(); err != nil {
+			logrus.Error(err)
+		}
+	}()
+
+	for {
+		var name string
+		var value interface{}
+		var done bool
+
+		if done, name, value, _, _, err = i.Next(); err != nil || done {
+			return properties, err
+		}
+
+		properties[name] = value
+	}
+}
+
+// GetMethodParameters returns a WMI class object which represents the [in] method parameters for a method invocation.
+// This is an advanced method, used for dynamic introspection or manual method invocation. In most
+// cases it is recommended to use BeginInvoke() instead, which constructs the parameter payload
+// automatically.
+func (i *Instance) GetMethodParameters(method string) (*Instance, error) {
+	var err error
+	var res uintptr
+	var inSignature *ole.IUnknown
+
+	var wszName *uint16
+	if wszName, err = syscall.UTF16PtrFromString(method); err != nil {
+		return nil, err
+	}
+
+	res, _, _ = syscall.SyscallN(
+		i.vTable.GetMethod,                    // IWbemClassObject::GetMethod(
+		uintptr(unsafe.Pointer(i.object)),     // IWbemClassObject ptr
+		uintptr(unsafe.Pointer(wszName)),      // [in]  LPCWSTR          wszName
+		uintptr(0),                            // [in]  long             lFlags,
+		uintptr(unsafe.Pointer(&inSignature)), // [out] IWbemClassObject **ppInSignature,
+		uintptr(0))                            // [out] IWbemClassObject **ppOutSignature)
+	if res != 0 {
+		return nil, NewWmiError(res)
+	}
+
+	return newInstance(inSignature, i.service), nil
+}
+
+func (i *Instance) instanceGetAllPopulate(elem reflect.Value, elemType reflect.Type, properties map[string]*ole.VARIANT) error {
+	var err error
+
+	for j := 0; j < elemType.NumField(); j++ {
+		fieldType := elemType.Field(j)
+		fieldVal := elem.Field(j)
+
+		if !fieldType.IsExported() {
+			continue
+		}
+
+		if fieldType.Type.Kind() == reflect.Struct && fieldType.Anonymous {
+			if err := i.instanceGetAllPopulate(fieldVal, fieldType.Type, properties); err != nil {
+				return err
+			}
+			continue
+		}
+
+		fieldName := fieldType.Name
+
+		if strings.HasPrefix(fieldName, "S__") {
+			fieldName = fieldName[1:]
+		}
+		if variant, ok := properties[fieldName]; ok {
+			var val interface{}
+			if val, err = convertToGoType(variant, fieldVal, fieldType.Type); err != nil {
+				return err
+			}
+
+			if val != nil {
+				fieldVal.Set(reflect.ValueOf(val))
+			}
+		}
+	}
+
+	return nil
+}
+
+// BeginEnumeration begins iterating the property list on this instance. This is an advanced method.
+// In most cases, the GetAsXXX() methods, GetAll(), and GetAllProperties() methods should be
+// preferred.
+func (i *Instance) BeginEnumeration() error {
+	classObj := i.object
+	vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
+
+	result, _, _ := syscall.SyscallN(
+		vTable.BeginEnumeration,           // IWbemClassObject::BeginEnumeration(
+		uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr,
+		uintptr(0))                        // [in] long lEnumFlags) // 0 = defaults
+	if result != 0 {
+		return NewWmiError(result)
+	}
+
+	return nil
+}
+
+// EndEnumeration completes iterating a property list on this instance. This is an advanced method.
+// In most cases, the GetAsXXX() methods, GetAll(), and GetAllProperties() methods
+// should be preferred.
+func (i *Instance) EndEnumeration() error {
+	res, _, _ := syscall.SyscallN(
+		i.vTable.EndEnumeration,           // IWbemClassObject::EndEnumeration(
+		uintptr(unsafe.Pointer(i.object))) // IWbemClassObject ptr)
+	if res != 0 {
+		return NewWmiError(res)
+	}
+
+	return nil
+}
+
+// BeginInvoke invokes a method on this Instance. Returns a MethodExecutor builder object
+// that is used to construct the input parameters (via calls to In()), perform the
+// invocation (using calls to Execute()), retrieve output parameters (via calls to
+// Out()), and finally the method return value (using a call to End())
+func (i *Instance) BeginInvoke(method string) *MethodExecutor {
+	objPath, err := i.Path()
+	if err != nil {
+		return &MethodExecutor{err: err}
+	}
+
+	var class, inParam *Instance
+	if class, err = i.service.GetClassInstance(i); err == nil {
+		inParam, err = class.GetMethodParameters(method)
+		class.Close()
+	}
+
+	return &MethodExecutor{method: method, path: objPath, service: i.service, inParam: inParam, err: err}
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/invoke.go b/vendor/github.com/containers/libhvee/pkg/wmiext/invoke.go
new file mode 100644
index 000000000..6875e2de6
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/invoke.go
@@ -0,0 +1,132 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"fmt"
+	"reflect"
+
+	"github.com/go-ole/go-ole"
+	"github.com/sirupsen/logrus"
+)
+
+type MethodExecutor struct {
+	err      error
+	path     string
+	method   string
+	service  *Service
+	inParam  *Instance
+	outParam *Instance
+}
+
+// In sets an input parameter for the method of this invocation, converting appropriately
+func (e *MethodExecutor) In(name string, value interface{}) *MethodExecutor {
+	if e.err == nil && e.inParam != nil {
+		switch t := value.(type) {
+		case *Instance:
+			var ref bool
+			if ref, e.err = e.inParam.IsReferenceProperty(name); e.err != nil {
+				return e
+			}
+			if !ref {
+				// Embedded Object
+				break
+			}
+			if value, e.err = t.Path(); e.err != nil {
+				return e
+			}
+		}
+
+		e.err = e.inParam.Put(name, value)
+	}
+
+	return e
+}
+
+// Out sets the specified output parameter, and assigns the value parameter to the result.
+// The value parameter must be a reference to the field that should be set.
+func (e *MethodExecutor) Out(name string, value interface{}) *MethodExecutor {
+	if e.err == nil && e.outParam != nil {
+		var variant *ole.VARIANT
+		var cimType CIMTYPE_ENUMERATION
+		var result interface{}
+		dest := reflect.ValueOf(value)
+		if dest.Kind() != reflect.Ptr {
+			e.err = fmt.Errorf("Out() on %q called with %T, out parameters must be a reference", name, value)
+			return e
+		}
+		dest = dest.Elem()
+
+		variant, cimType, _, e.err = e.outParam.GetAsVariant(name)
+		if e.err != nil || variant == nil {
+			return e
+		}
+
+		defer func() {
+			if err := variant.Clear(); err != nil {
+				logrus.Error(err)
+			}
+		}()
+
+		if _, ok := value.(**Instance); ok && cimType == CIM_REFERENCE {
+			path := variant.ToString()
+			result, e.err = e.service.GetObject(path)
+			if e.err != nil {
+				return e
+			}
+		} else {
+			target := reflect.ValueOf(value).Elem()
+			result, e.err = convertToGoType(variant, target, target.Type())
+			if e.err != nil {
+				return e
+			}
+		}
+
+		newValue := reflect.ValueOf(result)
+		if result == nil {
+			// Nil must be typed to the destination
+			newValue = reflect.Zero(dest.Type())
+		}
+
+		dest.Set(newValue)
+	}
+	return e
+}
+
+// Execute executes the method after in parameters have been specified using In()
+func (e *MethodExecutor) Execute() *MethodExecutor {
+	defer e.cleanupInputs()
+
+	if e.err == nil {
+		e.outParam, e.err = e.service.ExecMethod(e.path, e.method, e.inParam)
+	}
+
+	return e
+}
+
+func (e *MethodExecutor) cleanupInputs() {
+	if e.inParam != nil {
+		e.inParam.Close()
+		e.inParam = nil
+	}
+}
+
+// End completes the method invocation and returns an error indicating the return
+// code of the underlying method
+func (e *MethodExecutor) End() error {
+	e.cleanupInputs()
+
+	if e.outParam != nil {
+		e.outParam.Close()
+		e.outParam = nil
+	}
+
+	return e.err
+}
+
+// Obtains the last error that occurred while building the invocation. Once
+// an error has occurred, all future operations are treated as a no-op.
+func (e *MethodExecutor) Error() error {
+	return e.err
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/job.go b/vendor/github.com/containers/libhvee/pkg/wmiext/job.go
new file mode 100644
index 000000000..180c1e515
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/job.go
@@ -0,0 +1,53 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"fmt"
+	"time"
+)
+
+type JobError struct {
+	ErrorCode int
+}
+
+func (err *JobError) Error() string {
+	return fmt.Sprintf("Job failed with error code: %d", err.ErrorCode)
+}
+
+// WaitJob waits on the specified job instance until it has completed and
+// returns a JobError containing the result code in the event of
+// a failure.
+func WaitJob(service *Service, job *Instance) error {
+	var jobs []*Instance
+	defer func() {
+		for _, job := range jobs {
+			job.Close()
+		}
+	}()
+	for {
+		state, _, _, err := job.GetAsAny("JobState")
+		if err != nil {
+			return err
+		}
+		time.Sleep(100 * time.Millisecond)
+		job, _ = service.RefetchObject(job)
+		jobs = append(jobs, job)
+		// 7+ = completed
+		if state.(int32) >= 7 {
+			break
+		}
+	}
+
+	result, _, _, err := job.GetAsAny("ErrorCode")
+	if err != nil {
+		return err
+	}
+
+	if result.(int32) != 0 {
+		return &JobError{ErrorCode: int(result.(int32))}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/service.go b/vendor/github.com/containers/libhvee/pkg/wmiext/service.go
new file mode 100644
index 000000000..c58d06c1a
--- /dev/null
+++ b/vendor/github.com/containers/libhvee/pkg/wmiext/service.go
@@ -0,0 +1,416 @@
+//go:build windows
+// +build windows
+
+package wmiext
+
+import (
+	"errors"
+	"fmt"
+	"syscall"
+	"unsafe"
+
+	"github.com/go-ole/go-ole"
+)
+
+type IWbemLocatorVtbl struct {
+	QueryInterface uintptr
+	AddRef         uintptr
+	Release        uintptr
+	ConnectServer  uintptr
+}
+
+type Service struct {
+	service *ole.IUnknown
+	vTable  *IWbemServicesVtbl
+}
+
+type IWbemServicesVtbl struct {
+	QueryInterface             uintptr
+	AddRef                     uintptr
+	Release                    uintptr
+	OpenNamespace              uintptr
+	CancelAsyncCall            uintptr
+	QueryObjectSink            uintptr
+	GetObject                  uintptr
+	GetObjectAsync             uintptr
+	PutClass                   uintptr
+	PutClassAsync              uintptr
+	DeleteClass                uintptr
+	DeleteClassAsync           uintptr
+	CreateClassEnum            uintptr
+	CreateClassEnumAsync       uintptr
+	PutInstance                uintptr
+	PutInstanceAsync           uintptr
+	DeleteInstance             uintptr
+	DeleteInstanceAsync        uintptr
+	CreateInstanceEnum         uintptr
+	CreateInstanceEnumAsync    uintptr
+	ExecQuery                  uintptr
+	ExecQueryAsync             uintptr
+	ExecNotificationQuery      uintptr
+	ExecNotificationQueryAsync uintptr
+	ExecMethod                 uintptr
+	ExecMethodAsync            uintptr
+}
+
+func connectService(namespace string) (*Service, error) {
+
+	if wmiWbemLocator == nil {
+		return nil, errors.New("WMI failed initialization, service calls can not proceed")
+	}
+
+	var err error
+	var res uintptr
+	var strResource *uint16
+	var strLocale *uint16
+	var service *ole.IUnknown
+
+	loc := fmt.Sprintf(`\\.\%s`, namespace)
+
+	if strResource, err = syscall.UTF16PtrFromString(loc); err != nil {
+		return nil, err
+	}
+
+	// Connect with en_US LCID since we do pattern matching against English key values
+	if strLocale, err = syscall.UTF16PtrFromString("MS_409"); err != nil {
+		return nil, err
+	}
+
+	myVTable := (*IWbemLocatorVtbl)(unsafe.Pointer(wmiWbemLocator.RawVTable))
+	res, _, _ = syscall.SyscallN(
+		myVTable.ConnectServer,                  // IWbemLocator::ConnectServer(
+		uintptr(unsafe.Pointer(wmiWbemLocator)), // IWbemLocator ptr
+		uintptr(unsafe.Pointer(strResource)),    // [in]  const BSTR    strNetworkResource,
+		uintptr(0),                              // [in]  const BSTR    strUser,
+		uintptr(0),                              // [in]  const BSTR    strPassword,
+		uintptr(unsafe.Pointer(strLocale)),      // [in]  const BSTR    strLocale,
+		uintptr(WBEM_FLAG_CONNECT_USE_MAX_WAIT), // [in]  long          lSecurityFlags,
+		uintptr(0),                              // [in]  const BSTR    strAuthority,
+		uintptr(0),                              // [in]  IWbemContext  *pCtx,
+		uintptr(unsafe.Pointer(&service)))       // [out] IWbemServices **ppNamespace)
+
+	if res != 0 {
+		return nil, NewWmiError(res)
+	}
+
+	if err = CoSetProxyBlanket(service); err != nil {
+		return nil, err
+	}
+
+	return newService(service), nil
+}
+
+func newService(service *ole.IUnknown) *Service {
+	return &Service{
+		service: service,
+		vTable:  (*IWbemServicesVtbl)(unsafe.Pointer(service.RawVTable)),
+	}
+}
+
+const (
+	WBEM_FLAG_CONNECT_USE_MAX_WAIT = 0x80
+)
+
+func CoSetProxyBlanket(service *ole.IUnknown) (err error) {
+	res, _, _ := procCoSetProxyBlanket.Call( //CoSetProxyBlanket(
+		uintptr(unsafe.Pointer(service)),     // [in]      IUnknown                 *pProxy,
+		uintptr(RPC_C_AUTHN_WINNT),           // [in]      DWORD                    dwAuthnSvc,
+		uintptr(RPC_C_AUTHZ_NONE),            // [in]      DWORD                    dwAuthzSvc,
+		uintptr(0),                           // [in, opt] OLECHAR                  *pServerPrincName,
+		uintptr(RPC_C_AUTHN_LEVEL_CALL),      // [in]      DWORD                    dwAuthnLevel,
+		uintptr(RPC_C_IMP_LEVEL_IMPERSONATE), // [in]      DWORD                    dwImpLevel,
+		uintptr(0),                           // [in, opt] RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
+		uintptr(EOAC_NONE))                   // [in]      DWORD                    dwCapabilities)
+
+	if res != 0 {
+		return NewWmiError(res)
+	}
+
+	return nil
+}
+
+// NewLocalService creates a service and connect it to the local system at the specified namespace
+func NewLocalService(namespace string) (s *Service, err error) {
+	return connectService(namespace)
+}
+
+// Close frees all associated memory with this service
+func (s *Service) Close() {
+	if s != nil && s.service != nil {
+		s.service.Release()
+	}
+}
+
+// ExecQuery executes a WQL query and returns an enumeration to iterate the result set.
+// Queries are executed in a semi-synchronous fashion.
+func (s *Service) ExecQuery(wqlQuery string) (*Enum, error) {
+	var err error
+	var pEnum *ole.IUnknown
+	var strQuery *uint16
+	var strQL *uint16
+
+	if strQL, err = syscall.UTF16PtrFromString("WQL"); err != nil {
+		return nil, err
+	}
+
+	if strQuery, err = syscall.UTF16PtrFromString(wqlQuery); err != nil {
+		return nil, err
+	}
+
+	// Semisynchronous mode = return immed + forward (for perf)
+	flags := WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY
+
+	hres, _, _ := syscall.SyscallN(
+		s.vTable.ExecQuery,                 // IWbemServices::ExecQuery(
+		uintptr(unsafe.Pointer(s.service)), // IWbemServices ptr
+		uintptr(unsafe.Pointer(strQL)),     // [in] const BSTR           strQueryLanguage,
+		uintptr(unsafe.Pointer(strQuery)),  // [in] const BSTR           strQuery,
+		uintptr(flags),                     // [in] long                 lFlags,
+		uintptr(0),                         // [in] IWbemContext         *pCtx,
+		uintptr(unsafe.Pointer(&pEnum)))    // [out] IEnumWbemClassObject **ppEnum)
+	if hres != 0 {
+		return nil, NewWmiError(hres)
+	}
+
+	if err = CoSetProxyBlanket(pEnum); err != nil {
+		return nil, err
+	}
+
+	return newEnum(pEnum, s), nil
+}
+
+// GetObject obtains a single WMI class or instance given its path
+func (s *Service) GetObject(objectPath string) (instance *Instance, err error) {
+	var pObject *ole.IUnknown
+	var strObjectPath *uint16
+
+	if strObjectPath, err = syscall.UTF16PtrFromString(objectPath); err != nil {
+		return
+	}
+
+	// Synchronous call
+	flags := WBEM_FLAG_RETURN_WBEM_COMPLETE
+
+	res, _, _ := syscall.SyscallN(
+		s.vTable.GetObject,                     // IWbemServices::GetObject(
+		uintptr(unsafe.Pointer(s.service)),     // IWbemServices ptr
+		uintptr(unsafe.Pointer(strObjectPath)), // [in]  const BSTR       strObjectPath,
+		uintptr(flags),                         // [in]  long             lFlags,
+		uintptr(0),                             // [in]  IWbemContext     *pCtx,
+		uintptr(unsafe.Pointer(&pObject)),      // [out] IWbemClassObject **ppObject,
+		uintptr(0))                             // [out] IWbemCallResult  **ppCallResult)
+	if int(res) < 0 {
+		// returns WBEM_E_PROVIDER_NOT_FOUND when no entry found
+		return nil, NewWmiError(res)
+	}
+
+	return newInstance(pObject, s), nil
+}
+
+// GetObjectAsObject gets an object by its path and set all fields of the passed in target to match the instance's
+// properties. Conversion is performed as appropriate.
+func (s *Service) GetObjectAsObject(objPath string, target interface{}) error {
+	instance, err := s.GetObject(objPath)
+	if err != nil {
+		return err
+	}
+	defer instance.Close()
+
+	return instance.GetAll(target)
+}
+
+// CreateInstanceEnum creates an enumerator that iterates all registered object instances for a given className.
+func (s *Service) CreateInstanceEnum(className string) (*Enum, error) {
+	var err error
+	var pEnum *ole.IUnknown
+	var strFilter *uint16
+
+	if strFilter, err = syscall.UTF16PtrFromString(className); err != nil {
+		return nil, err
+	}
+
+	// No subclasses in result set
+	flags := WBEM_FLAG_SHALLOW
+
+	res, _, _ := syscall.SyscallN(
+		s.vTable.CreateInstanceEnum,        // IWbemServices::CreateInstanceEnum(
+		uintptr(unsafe.Pointer(s.service)), // IWbemServices ptr
+		uintptr(unsafe.Pointer(strFilter)), // [in]  const BSTR           strFilter,
+		uintptr(flags),                     // [in]  long                 lFlags,
+		uintptr(0),                         // [in]  IWbemContext         *pCtx,
+		uintptr(unsafe.Pointer(&pEnum)))    // [out] IEnumWbemClassObject **ppEnum)
+	if int(res) < 0 {
+		return nil, NewWmiError(res)
+	}
+
+	if err = CoSetProxyBlanket(pEnum); err != nil {
+		return nil, err
+	}
+
+	return newEnum(pEnum, s), nil
+}
+
+// ExecMethod executes a method using the specified class and parameter payload instance. The parameter payload
+// instance can be constructed using Instance.GetMethodParameters(). This is an advanced method, it is
+// recommended to use BeginInvoke() instead, where possible.
+func (s *Service) ExecMethod(className string, methodName string, inParams *Instance) (*Instance, error) {
+	var err error
+	var outParams *ole.IUnknown
+	var strObjectPath *uint16
+	var strMethodName *uint16
+
+	if strObjectPath, err = syscall.UTF16PtrFromString(className); err != nil {
+		return nil, err
+	}
+
+	if strMethodName, err = syscall.UTF16PtrFromString(methodName); err != nil {
+		return nil, err
+	}
+
+	res, _, _ := syscall.SyscallN(
+		s.vTable.ExecMethod,                      // IWbemServices::ExecMethod(
+		uintptr(unsafe.Pointer(s.service)),       // IWbemServices ptr
+		uintptr(unsafe.Pointer(strObjectPath)),   // [in]  const BSTR       strObjectPath,
+		uintptr(unsafe.Pointer(strMethodName)),   // [in]  const BSTR       strMethodName,
+		uintptr(0),                               // [in]  long             lFlags,
+		uintptr(0),                               // [in]  IWbemContext     *pCtx,
+		uintptr(unsafe.Pointer(inParams.object)), // [in]  IWbemClassObject *pInParams,
+		uintptr(unsafe.Pointer(&outParams)),      // [out] IWbemClassObject **ppOutParams,
+		uintptr(0))                               // [out] IWbemCallResult  **ppCallResult)
+	if int(res) < 0 {
+		return nil, NewWmiError(res)
+	}
+
+	return newInstance(outParams, s), nil
+}
+
+// FindFirstInstance find and returns the first WMI Instance in the result set for a WSL query.
+func (s *Service) FindFirstInstance(wql string) (*Instance, error) {
+	var enum *Enum
+	var err error
+	if enum, err = s.ExecQuery(wql); err != nil {
+		return nil, err
+	}
+	defer enum.Close()
+
+	instance, err := enum.Next()
+	if err != nil {
+		return nil, err
+	}
+
+	if instance == nil {
+		return nil, ErrNoResults
+	}
+
+	return instance, nil
+}
+
+// FindFirstRelatedInstance finds and returns a related associator of the specified WMI object path of the
+// expected className type.
+func (s *Service) FindFirstRelatedInstance(objPath string, className string) (*Instance, error) {
+	wql := fmt.Sprintf("ASSOCIATORS OF {%s} WHERE ResultClass = %s", objPath, className)
+	return s.FindFirstInstance(wql)
+}
+
+// FindFirstRelatedInstanceThrough finds and returns a related associator of the specified WMI object path of the
+// expected className type, and only through the expected association type.
+func (s *Service) FindFirstRelatedInstanceThrough(objPath string, resultClass string, assocClass string) (*Instance, error) {
+	wql := fmt.Sprintf("ASSOCIATORS OF {%s} WHERE AssocClass = %s ResultClass = %s ", objPath, assocClass, resultClass)
+	return s.FindFirstInstance(wql)
+}
+
+// FindFirstRelatedObject finds and returns a related associator of the specified WMI object path of the
+// expected className type, and populates the passed in struct with its fields
+func (s *Service) FindFirstRelatedObject(objPath string, className string, target interface{}) error {
+	wql := fmt.Sprintf("ASSOCIATORS OF {%s} WHERE ResultClass = %s", objPath, className)
+	return s.FindFirstObject(wql, target)
+}
+
+// FindFirstObject finds and returns the first WMI Instance in the result set for a WSL query, and
+// populates the specified struct pointer passed in through the target parameter.
+func (s *Service) FindFirstObject(wql string, target interface{}) error {
+	var enum *Enum
+	var err error
+	if enum, err = s.ExecQuery(wql); err != nil {
+		return err
+	}
+	defer enum.Close()
+
+	done, err := NextObject(enum, target)
+	if err != nil {
+		return err
+	}
+
+	if done {
+		return errors.New("no results found")
+	}
+
+	return nil
+}
+
+// GetSingletonInstance gets the first WMI instance of the specified object class type. This is a
+// shortcut method for uses where only one instance is expected.
+func (s *Service) GetSingletonInstance(className string) (*Instance, error) {
+	var (
+		enum     *Enum
+		instance *Instance
+		err      error
+	)
+
+	if enum, err = s.CreateInstanceEnum(className); err != nil {
+		return nil, err
+	}
+	defer enum.Close()
+
+	if instance, err = enum.Next(); err != nil {
+		return nil, err
+	}
+
+	return instance, nil
+}
+
+// CreateInstance creates a new WMI object class instance of the specified className, and sets
+// all properties according to the passed in struct pointer through the src
+// parameter, converting appropriately.
+func (s *Service) CreateInstance(className string, src interface{}) (*Instance, error) {
+	instance, err := s.SpawnInstance(className)
+	if err != nil {
+		return nil, err
+	}
+
+	return instance, instance.PutAll(src)
+}
+
+// SpawnInstance creates a new zeroed WMI instance. This instance will not contain expected values.
+// Those must be retrieved and set separately, or CreateInstance() can be used instead.
+func (s *Service) SpawnInstance(className string) (*Instance, error) {
+	var class *Instance
+	var err error
+	if class, err = s.GetObject(className); err != nil {
+		return nil, err
+	}
+	defer class.Close()
+
+	return class.SpawnInstance()
+}
+
+// RefetchObject re-fetches the object and returns a new instance. The original instance will not
+// automatically Close(). Callers of this method will need to manually close the
+// original.
+func (s *Service) RefetchObject(instance *Instance) (*Instance, error) {
+	path, err := instance.Path()
+	if err != nil {
+		return instance, err
+	}
+	return s.GetObject(path)
+}
+
+// GetClassInstance gets the WMI class instance associated with the specified object instance.
+// This method is used to perform schema queries.
+func (s *Service) GetClassInstance(obj *Instance) (*Instance, error) {
+	name, err := obj.GetClassName()
+	if err != nil {
+		return nil, err
+	}
+	return s.GetObject(name)
+}
diff --git a/vendor/github.com/go-ole/go-ole/SECURITY.md b/vendor/github.com/go-ole/go-ole/SECURITY.md
new file mode 100644
index 000000000..dac281523
--- /dev/null
+++ b/vendor/github.com/go-ole/go-ole/SECURITY.md
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Supported Versions
+
+Security updates are applied only to the latest release.
+
+## Reporting a Vulnerability
+
+If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
+
+Please disclose it at [security advisory](https://github.com/go-ole/go-ole/security/advisories/new).
+
+This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
diff --git a/vendor/github.com/go-ole/go-ole/appveyor.yml b/vendor/github.com/go-ole/go-ole/appveyor.yml
index 0d557ac2f..8df7fa26e 100644
--- a/vendor/github.com/go-ole/go-ole/appveyor.yml
+++ b/vendor/github.com/go-ole/go-ole/appveyor.yml
@@ -6,14 +6,9 @@
 
 version: "1.3.0.{build}-alpha-{branch}"
 
-os: Windows Server 2012 R2
+os: Visual Studio 2019
 
-branches:
-  only:
-    - master
-    - v1.2
-    - v1.1
-    - v1.0
+build: off
 
 skip_tags: true
 
@@ -21,20 +16,40 @@ clone_folder: c:\gopath\src\github.com\go-ole\go-ole
 
 environment:
   GOPATH: c:\gopath
-  matrix:
-  - GOARCH: amd64
-    GOVERSION: 1.5
-    GOROOT: c:\go
-    DOWNLOADPLATFORM: "x64"
+  GOROOT: c:\go
+  DOWNLOADPLATFORM: "x64"
 
-install:
-  - choco install mingw
-  - SET PATH=c:\tools\mingw64\bin;%PATH%
+before_test:
   # - Download COM Server
   - ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip"
   - 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL
   - c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat
-  # - set
+
+test_script:
+  - go test -v -cover ./...
+  # go vet has false positives on unsafe.Pointer with windows/sys. Disabling since it is recommended to use go test instead.
+  # - go vet ./...
+
+branches:
+  only:
+    - master
+    - v1.2
+    - v1.1
+    - v1.0
+
+matrix:
+  allow_failures:
+    - environment:
+      GOROOT: C:\go-x86
+      DOWNLOADPLATFORM: "x86"
+    - environment:
+      GOROOT: C:\go118
+      DOWNLOADPLATFORM: "x64"
+    - environment:
+      GOROOT: C:\go118-x86
+      DOWNLOADPLATFORM: "x86"
+
+install:
   - go version
   - go env
   - go get -u golang.org/x/tools/cmd/cover
@@ -45,10 +60,9 @@ build_script:
   - cd c:\gopath\src\github.com\go-ole\go-ole
   - go get -v -t ./...
   - go build
-  - go test -v -cover ./...
 
 # disable automatic tests
-test: off
+test: on
 
 # disable deployment
 deploy: off
diff --git a/vendor/github.com/go-ole/go-ole/com.go b/vendor/github.com/go-ole/go-ole/com.go
index a9bef150a..cabbac012 100644
--- a/vendor/github.com/go-ole/go-ole/com.go
+++ b/vendor/github.com/go-ole/go-ole/com.go
@@ -11,6 +11,7 @@ import (
 var (
 	procCoInitialize            = modole32.NewProc("CoInitialize")
 	procCoInitializeEx          = modole32.NewProc("CoInitializeEx")
+	procCoInitializeSecurity    = modole32.NewProc("CoInitializeSecurity")
 	procCoUninitialize          = modole32.NewProc("CoUninitialize")
 	procCoCreateInstance        = modole32.NewProc("CoCreateInstance")
 	procCoTaskMemFree           = modole32.NewProc("CoTaskMemFree")
@@ -37,6 +38,9 @@ var (
 	procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
 )
 
+// This is to enable calling COM Security initialization multiple times
+var bSecurityInit bool = false
+
 // coInitialize initializes COM library on current thread.
 //
 // MSDN documentation suggests that this function should not be called. Call
@@ -68,6 +72,35 @@ func coInitializeEx(coinit uint32) (err error) {
 	return
 }
 
+// coInitializeSecurity: Registers security and sets the default security values
+// for the process.
+func coInitializeSecurity(cAuthSvc int32,
+	dwAuthnLevel uint32,
+	dwImpLevel uint32,
+	dwCapabilities uint32) (err error) {
+	// Check COM Security initialization has done previously
+	if !bSecurityInit {
+		// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity
+		hr, _, _ := procCoInitializeSecurity.Call(
+			uintptr(0),              // Allow *all* VSS writers to communicate back!
+			uintptr(cAuthSvc),       // Default COM authentication service
+			uintptr(0),              // Default COM authorization service
+			uintptr(0),              // Reserved parameter
+			uintptr(dwAuthnLevel),   // Strongest COM authentication level
+			uintptr(dwImpLevel),     // Minimal impersonation abilities
+			uintptr(0),              // Default COM authentication settings
+			uintptr(dwCapabilities), // Cloaking
+			uintptr(0))              // eserved parameter
+		if hr != 0 {
+			err = NewError(hr)
+		} else {
+			// COM Security initialization done make global flag true.
+			bSecurityInit = true
+		}
+	}
+	return
+}
+
 // CoInitialize initializes COM library on current thread.
 //
 // MSDN documentation suggests that this function should not be called. Call
@@ -96,6 +129,15 @@ func CoUninitialize() {
 	procCoUninitialize.Call()
 }
 
+// CoInitializeSecurity: Registers security and sets the default security values
+// for the process.
+func CoInitializeSecurity(cAuthSvc int32,
+	dwAuthnLevel uint32,
+	dwImpLevel uint32,
+	dwCapabilities uint32) (err error) {
+	return coInitializeSecurity(cAuthSvc, dwAuthnLevel, dwImpLevel, dwCapabilities)
+}
+
 // CoTaskMemFree frees memory pointer.
 func CoTaskMemFree(memptr uintptr) {
 	procCoTaskMemFree.Call(memptr)
diff --git a/vendor/github.com/go-ole/go-ole/idispatch_windows.go b/vendor/github.com/go-ole/go-ole/idispatch_windows.go
index b399f0479..649c0734f 100644
--- a/vendor/github.com/go-ole/go-ole/idispatch_windows.go
+++ b/vendor/github.com/go-ole/go-ole/idispatch_windows.go
@@ -1,3 +1,4 @@
+//go:build windows
 // +build windows
 
 package ole
@@ -92,7 +93,7 @@ func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}
 			case int8:
 				vargs[n] = NewVariant(VT_I1, int64(v.(int8)))
 			case *int8:
-				vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8)))))
+				vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int8)))))
 			case int16:
 				vargs[n] = NewVariant(VT_I2, int64(v.(int16)))
 			case *int16:
diff --git a/vendor/github.com/go-ole/go-ole/variant.go b/vendor/github.com/go-ole/go-ole/variant.go
index 967a23fea..a2c8402f7 100644
--- a/vendor/github.com/go-ole/go-ole/variant.go
+++ b/vendor/github.com/go-ole/go-ole/variant.go
@@ -99,7 +99,7 @@ func (v *VARIANT) Value() interface{} {
 	case VT_DISPATCH:
 		return v.ToIDispatch()
 	case VT_BOOL:
-		return v.Val != 0
+		return (v.Val & 0xffff) != 0
 	}
 	return nil
 }
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c906e0dfd..0771ddae6 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -92,6 +92,9 @@ github.com/cloudflare/circl/math/mlsbset
 github.com/cloudflare/circl/sign
 github.com/cloudflare/circl/sign/ed25519
 github.com/cloudflare/circl/sign/ed448
+# github.com/containers/common v0.59.1
+## explicit; go 1.21
+github.com/containers/common/pkg/strongunits
 # github.com/containers/gvisor-tap-vsock v0.7.5
 ## explicit; go 1.21
 github.com/containers/gvisor-tap-vsock/pkg/client
@@ -158,6 +161,11 @@ github.com/containers/image/v5/signature/simplesigning
 github.com/containers/image/v5/transports
 github.com/containers/image/v5/types
 github.com/containers/image/v5/version
+# github.com/containers/libhvee v0.7.1
+## explicit; go 1.18
+github.com/containers/libhvee/pkg/hypervctl
+github.com/containers/libhvee/pkg/kvp/ginsu
+github.com/containers/libhvee/pkg/wmiext
 # github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01
 ## explicit
 github.com/containers/libtrust
@@ -296,7 +304,7 @@ github.com/go-jose/go-jose/v4/json
 ## explicit; go 1.18
 github.com/go-logr/logr
 github.com/go-logr/logr/funcr
-# github.com/go-ole/go-ole v1.2.6
+# github.com/go-ole/go-ole v1.3.0
 ## explicit; go 1.12
 github.com/go-ole/go-ole
 github.com/go-ole/go-ole/oleutil



Test patch:
diff --git a/pkg/crc/machine/hyperv/driver_windows_test.go b/pkg/crc/machine/libhvee/driver_windows_test.go
similarity index 94%
rename from pkg/crc/machine/hyperv/driver_windows_test.go
rename to pkg/crc/machine/libhvee/driver_windows_test.go
index b331204e4..e757d5479 100755
--- a/pkg/crc/machine/hyperv/driver_windows_test.go
+++ b/pkg/crc/machine/libhvee/driver_windows_test.go
@@ -1,4 +1,4 @@
-package hyperv
+package libhvee
 
 import (
 	"testing"
diff --git a/pkg/crc/preflight/preflight_windows_test.go b/pkg/crc/preflight/preflight_windows_test.go
index b0b7834d7..55b1705ca 100644
--- a/pkg/crc/preflight/preflight_windows_test.go
+++ b/pkg/crc/preflight/preflight_windows_test.go
@@ -17,8 +17,8 @@ func TestCountConfigurationOptions(t *testing.T) {
 }
 
 func TestCountPreflights(t *testing.T) {
-	assert.Len(t, getPreflightChecks(false, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift, false), 24)
-	assert.Len(t, getPreflightChecks(true, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift, false), 24)
+	assert.Len(t, getPreflightChecks(false, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift, false), 22)
+	assert.Len(t, getPreflightChecks(true, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift, false), 22)
 
 	assert.Len(t, getPreflightChecks(false, network.UserNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift, false), 23)
 	assert.Len(t, getPreflightChecks(true, network.UserNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift, false), 23)