Overhaul the Hyper-V provider
This commit is contained in:
parent
dbba41a7ec
commit
e6457d5061
|
@ -47,13 +47,17 @@ module Vagrant
|
|||
if opts.delete(:sudo) || opts.delete(:runas)
|
||||
powerup_command(path, args, opts)
|
||||
else
|
||||
env = opts.delete(:env)
|
||||
if env
|
||||
env = env.map{|k,v| "$env:#{k}=#{v}"}.join(";") + "; "
|
||||
end
|
||||
command = [
|
||||
executable,
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy", "Bypass",
|
||||
"&('#{path}')",
|
||||
"#{env}&('#{path}')",
|
||||
args
|
||||
].flatten
|
||||
|
||||
|
|
|
@ -140,6 +140,8 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
b2.use Provision
|
||||
b2.use Configure
|
||||
b2.use SetName
|
||||
b2.use NetSetVLan
|
||||
b2.use NetSetMac
|
||||
b2.use StartInstance
|
||||
|
@ -288,6 +290,7 @@ module VagrantPlugins
|
|||
autoload :Export, action_root.join("export")
|
||||
|
||||
autoload :CheckEnabled, action_root.join("check_enabled")
|
||||
autoload :Configure, action_root.join("configure")
|
||||
autoload :DeleteVM, action_root.join("delete_vm")
|
||||
autoload :Import, action_root.join("import")
|
||||
autoload :Package, action_root.join("package")
|
||||
|
@ -304,6 +307,7 @@ module VagrantPlugins
|
|||
autoload :SnapshotDelete, action_root.join("snapshot_delete")
|
||||
autoload :SnapshotRestore, action_root.join("snapshot_restore")
|
||||
autoload :SnapshotSave, action_root.join("snapshot_save")
|
||||
autoload :SetName, action_root.join("set_name")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
require "fileutils"
|
||||
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module HyperV
|
||||
module Action
|
||||
class Configure
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::hyperv::configure")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
switches = env[:machine].provider.driver.execute(:get_switches)
|
||||
if switches.empty?
|
||||
raise Errors::NoSwitches
|
||||
end
|
||||
|
||||
switch = nil
|
||||
env[:machine].config.vm.networks.each do |type, opts|
|
||||
next if type != :public_network && type != :private_network
|
||||
|
||||
if opts[:bridge]
|
||||
@logger.debug("Looking for switch with name or ID: #{opts[:bridge]}")
|
||||
switch = switches.find{ |s|
|
||||
s["Name"].downcase == opts[:bridge] ||
|
||||
s["Id"].downcase == opts[:bridge]
|
||||
}
|
||||
if switch
|
||||
@logger.debug("Found switch - Name: #{switch["Name"]} ID: #{switch["Id"]}")
|
||||
switch = switch["Id"]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If we already configured previously don't prompt for switch
|
||||
sentinel = env[:machine].data_dir.join("action_configure")
|
||||
|
||||
if !switch && !sentinel.file?
|
||||
if switches.length > 1
|
||||
env[:ui].detail(I18n.t("vagrant_hyperv.choose_switch") + "\n ")
|
||||
switches.each_index do |i|
|
||||
switch = switches[i]
|
||||
env[:ui].detail("#{i+1}) #{switch["Name"]}")
|
||||
end
|
||||
env[:ui].detail(" ")
|
||||
|
||||
switch = nil
|
||||
while !switch
|
||||
switch = env[:ui].ask("What switch would you like to use? ")
|
||||
next if !switch
|
||||
switch = switch.to_i - 1
|
||||
switch = nil if switch < 0 || switch >= switches.length
|
||||
end
|
||||
switch = switches[switch]["Id"]
|
||||
else
|
||||
switch = switches.first["Id"]
|
||||
@logger.debug("Only single switch available so using that.")
|
||||
end
|
||||
end
|
||||
|
||||
options = {
|
||||
"VMID" => env[:machine].id,
|
||||
"SwitchID" => switch,
|
||||
"Memory" => env[:machine].provider_config.memory,
|
||||
"MaxMemory" => env[:machine].provider_config.maxmemory,
|
||||
"Processors" => env[:machine].provider_config.cpus,
|
||||
"AutoStartAction" => env[:machine].provider_config.auto_start_action,
|
||||
"AutoStopAction" => env[:machine].provider_config.auto_stop_action,
|
||||
"EnableCheckpoints" => env[:machine].provider_config.enable_checkpoints,
|
||||
"VirtualizationExtensions" => !!env[:machine].provider_config.enable_virtualization_extensions,
|
||||
}
|
||||
options.delete_if{|_,v| v.nil? }
|
||||
|
||||
env[:ui].detail("Configuring the VM...")
|
||||
env[:machine].provider.driver.execute(:configure_vm, options)
|
||||
|
||||
# Create the sentinel
|
||||
sentinel.open("w") do |f|
|
||||
f.write(Time.now.to_i.to_s)
|
||||
end
|
||||
|
||||
if env[:machine].provider_config.vm_integration_services
|
||||
env[:ui].detail("Setting VM Integration Services")
|
||||
|
||||
env[:machine].provider_config.vm_integration_services.each do |key, value|
|
||||
state = value ? "enabled" : "disabled"
|
||||
env[:ui].output("#{key} is #{state}")
|
||||
end
|
||||
|
||||
env[:machine].provider.driver.set_vm_integration_services(
|
||||
env[:machine].provider_config.vm_integration_services)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +1,13 @@
|
|||
require "fileutils"
|
||||
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module HyperV
|
||||
module Action
|
||||
class Import
|
||||
|
||||
VALID_HD_EXTENSIONS = [".vhd".freeze, ".vhdx".freeze].freeze
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::hyperv::import")
|
||||
|
@ -14,160 +16,64 @@ module VagrantPlugins
|
|||
def call(env)
|
||||
vm_dir = env[:machine].box.directory.join("Virtual Machines")
|
||||
hd_dir = env[:machine].box.directory.join("Virtual Hard Disks")
|
||||
memory = env[:machine].provider_config.memory
|
||||
maxmemory = env[:machine].provider_config.maxmemory
|
||||
cpus = env[:machine].provider_config.cpus
|
||||
vmname = env[:machine].provider_config.vmname
|
||||
differencing_disk = env[:machine].provider_config.differencing_disk
|
||||
auto_start_action = env[:machine].provider_config.auto_start_action
|
||||
auto_stop_action = env[:machine].provider_config.auto_stop_action
|
||||
enable_virtualization_extensions = env[:machine].provider_config.enable_virtualization_extensions
|
||||
vm_integration_services = env[:machine].provider_config.vm_integration_services
|
||||
|
||||
env[:ui].output("Configured Dynamic memory allocation, maxmemory is #{maxmemory}") if maxmemory
|
||||
env[:ui].output("Configured startup memory is #{memory}") if memory
|
||||
env[:ui].output("Configured cpus number is #{cpus}") if cpus
|
||||
env[:ui].output("Configured enable virtualization extensions is #{enable_virtualization_extensions}") if enable_virtualization_extensions
|
||||
env[:ui].output("Configured vmname is #{vmname}") if vmname
|
||||
env[:ui].output("Configured differencing disk instead of cloning") if differencing_disk
|
||||
env[:ui].output("Configured automatic start action is #{auto_start_action}") if auto_start_action
|
||||
env[:ui].output("Configured automatic stop action is #{auto_stop_action}") if auto_stop_action
|
||||
|
||||
if !vm_dir.directory? || !hd_dir.directory?
|
||||
@logger.error("Required virtual machine directory not found!")
|
||||
raise Errors::BoxInvalid
|
||||
end
|
||||
|
||||
valid_config_ext = [".xml"]
|
||||
if env[:machine].provider.driver.has_vmcx_support?
|
||||
valid_config_ext << ".vmcx"
|
||||
end
|
||||
|
||||
config_path = nil
|
||||
config_type = nil
|
||||
vm_dir.each_child do |f|
|
||||
if f.extname.downcase == '.xml'
|
||||
@logger.debug("Found XML config...")
|
||||
config_path = f
|
||||
config_type = 'xml'
|
||||
vm_dir.each_child do |file|
|
||||
if valid_config_ext.include?(file.extname.downcase)
|
||||
config_path = file
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
vmcx_support = env[:machine].provider.driver.execute("has_vmcx_support.ps1", {})['result']
|
||||
if vmcx_support
|
||||
vm_dir.each_child do |f|
|
||||
if f.extname.downcase == '.vmcx'
|
||||
@logger.debug("Found VMCX config and support...")
|
||||
config_path = f
|
||||
config_type = 'vmcx'
|
||||
break
|
||||
end
|
||||
end
|
||||
if !config_path
|
||||
@logger.error("Failed to locate box configuration path")
|
||||
raise Errors::BoxInvalid
|
||||
else
|
||||
@logger.info("Found box configuration path: #{config_path}")
|
||||
end
|
||||
|
||||
image_path = nil
|
||||
image_ext = nil
|
||||
image_filename = nil
|
||||
hd_dir.each_child do |f|
|
||||
if %w{.vhd .vhdx}.include?(f.extname.downcase)
|
||||
image_path = f
|
||||
image_ext = f.extname.downcase
|
||||
image_filename = File.basename(f, image_ext)
|
||||
hd_dir.each_child do |file|
|
||||
if VALID_HD_EXTENSIONS.include?(file.extname.downcase)
|
||||
image_path = file
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if !config_path || !image_path
|
||||
if !image_path
|
||||
@logger.error("Failed to locate box image path")
|
||||
raise Errors::BoxInvalid
|
||||
else
|
||||
@logger.info("Found box image path: #{image_path}")
|
||||
end
|
||||
|
||||
env[:ui].output("Importing a Hyper-V instance")
|
||||
dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join(image_path.basename).to_s
|
||||
|
||||
switches = env[:machine].provider.driver.execute("get_switches.ps1", {})
|
||||
raise Errors::NoSwitches if switches.empty?
|
||||
|
||||
switch = nil
|
||||
env[:machine].config.vm.networks.each do |type, opts|
|
||||
next if type != :public_network && type != :private_network
|
||||
|
||||
switchToFind = opts[:bridge]
|
||||
|
||||
if switchToFind
|
||||
@logger.debug("Looking for switch with name: #{switchToFind}")
|
||||
switch = switches.find { |s| s["Name"].downcase == switchToFind.downcase }["Id"]
|
||||
@logger.debug("Found switch: #{switch}")
|
||||
end
|
||||
end
|
||||
|
||||
if switch.nil?
|
||||
if switches.length > 1
|
||||
env[:ui].detail(I18n.t("vagrant_hyperv.choose_switch") + "\n ")
|
||||
switches.each_index do |i|
|
||||
switch = switches[i]
|
||||
env[:ui].detail("#{i+1}) #{switch["Name"]}")
|
||||
end
|
||||
env[:ui].detail(" ")
|
||||
|
||||
switch = nil
|
||||
while !switch
|
||||
switch = env[:ui].ask("What switch would you like to use? ")
|
||||
next if !switch
|
||||
switch = switch.to_i - 1
|
||||
switch = nil if switch < 0 || switch >= switches.length
|
||||
end
|
||||
switch = switches[switch]["Id"]
|
||||
else
|
||||
switch = switches[0]["Id"]
|
||||
end
|
||||
end
|
||||
|
||||
env[:ui].detail("Cloning virtual hard drive...")
|
||||
source_path = image_path.to_s
|
||||
dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join("#{image_filename}#{image_ext}").to_s
|
||||
|
||||
# Still hard copy the disk of old XML configurations
|
||||
if config_type == 'xml'
|
||||
if differencing_disk
|
||||
env[:machine].provider.driver.execute("clone_vhd.ps1", {Source: source_path, Destination: dest_path})
|
||||
else
|
||||
FileUtils.mkdir_p(env[:machine].data_dir.join("Virtual Hard Disks"))
|
||||
FileUtils.cp(source_path, dest_path)
|
||||
end
|
||||
end
|
||||
image_path = dest_path
|
||||
|
||||
# We have to normalize the paths to be Windows paths since
|
||||
# we're executing PowerShell.
|
||||
options = {
|
||||
vm_config_file: config_path.to_s.gsub("/", "\\"),
|
||||
vm_config_type: config_type,
|
||||
source_path: source_path.to_s,
|
||||
dest_path: dest_path,
|
||||
data_path: env[:machine].data_dir.to_s.gsub("/", "\\")
|
||||
"VMConfigFile" => config_path.to_s.gsub("/", "\\"),
|
||||
"DestinationPath" => dest_path.to_s.gsub("/", "\\"),
|
||||
"DataPath" => env[:machine].data_dir.to_s.gsub("/", "\\"),
|
||||
"LinkedClone" => !!env[:machine].provider_config.linked_clone,
|
||||
"SourcePath" => image_path.to_s.gsub("/", "\\"),
|
||||
"VMName" => env[:machine].provider_config.vmname,
|
||||
}
|
||||
options[:switchid] = switch if switch
|
||||
options[:memory] = memory if memory
|
||||
options[:maxmemory] = maxmemory if maxmemory
|
||||
options[:cpus] = cpus if cpus
|
||||
options[:vmname] = vmname if vmname
|
||||
options[:auto_start_action] = auto_start_action if auto_start_action
|
||||
options[:auto_stop_action] = auto_stop_action if auto_stop_action
|
||||
options[:differencing_disk] = differencing_disk if differencing_disk
|
||||
options[:enable_virtualization_extensions] = "True" if enable_virtualization_extensions and enable_virtualization_extensions == true
|
||||
|
||||
|
||||
env[:ui].detail("Creating and registering the VM...")
|
||||
server = env[:machine].provider.driver.import(options)
|
||||
|
||||
env[:ui].detail("Setting VM Integration Services")
|
||||
vm_integration_services.each do |key, value|
|
||||
state = false
|
||||
if value === true
|
||||
state = "enabled"
|
||||
elsif value === false
|
||||
state = "disabled"
|
||||
end
|
||||
env[:ui].output("#{key} is #{state}") if state
|
||||
end
|
||||
|
||||
vm_integration_services[:VmId] = server["id"]
|
||||
env[:machine].provider.driver.set_vm_integration_services(vm_integration_services)
|
||||
|
||||
env[:ui].detail("Successfully imported a VM with name: #{server['name']}")
|
||||
env[:ui].detail("Successfully imported VM")
|
||||
env[:machine].id = server["id"]
|
||||
@app.call(env)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module HyperV
|
||||
module Action
|
||||
class SetName
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::hyperv::set_name")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
name = env[:machine].provider_config.vmname
|
||||
|
||||
# If we already set the name before, then don't do anything
|
||||
sentinel = env[:machine].data_dir.join("action_set_name")
|
||||
if !name && sentinel.file?
|
||||
@logger.info("Default name was already set before, not doing it again.")
|
||||
return @app.call(env)
|
||||
end
|
||||
|
||||
# If no name was manually set, then use a default
|
||||
if !name
|
||||
prefix = "#{env[:root_path].basename.to_s}_#{env[:machine].name}"
|
||||
prefix.gsub!(/[^-a-z0-9_]/i, "")
|
||||
|
||||
# milliseconds + random number suffix to allow for simultaneous
|
||||
# `vagrant up` of the same box in different dirs
|
||||
name = prefix + "_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
||||
end
|
||||
|
||||
env[:machine].provider.driver.set_name(name)
|
||||
|
||||
# Create the sentinel
|
||||
sentinel.open("w") do |f|
|
||||
f.write(Time.now.to_i.to_s)
|
||||
end
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,18 +3,49 @@ require "vagrant"
|
|||
module VagrantPlugins
|
||||
module HyperV
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
attr_accessor :ip_address_timeout # Time to wait for an IP address when booting, in seconds @return [Integer]
|
||||
attr_accessor :memory # Memory size in mb @return [Integer]
|
||||
attr_accessor :maxmemory # Maximal memory size in mb enables dynamical memory allocation @return [Integer]
|
||||
attr_accessor :cpus # Number of cpu's @return [Integer]
|
||||
attr_accessor :vmname # Name that will be shoen in Hyperv Manager @return [String]
|
||||
attr_accessor :vlan_id # VLAN ID for network interface for the virtual machine. @return [Integer]
|
||||
attr_accessor :mac # MAC address for network interface for the virtual machine. @return [String]
|
||||
attr_accessor :differencing_disk # Create differencing disk instead of cloning whole VHD [Boolean]
|
||||
attr_accessor :auto_start_action #action on automatic start of VM. Values: Nothing, StartIfRunning, Start
|
||||
attr_accessor :auto_stop_action #action on automatic stop of VM. Values: ShutDown, TurnOff, Save
|
||||
attr_accessor :enable_virtualization_extensions # Enable virtualization extensions (nested virtualization). Values: true, false
|
||||
attr_accessor :vm_integration_services # Options for VMServiceIntegration [Hash]
|
||||
# Allowed automatic start actions for VM
|
||||
ALLOWED_AUTO_START_ACTIONS = [
|
||||
"Nothing".freeze,
|
||||
"StartIfRunning".freeze,
|
||||
"Start".freeze
|
||||
].freeze
|
||||
|
||||
# Allowed automatic stop actions for VM
|
||||
ALLOWED_AUTO_STOP_ACTIONS = [
|
||||
"ShutDown".freeze,
|
||||
"TurnOff".freeze,
|
||||
"Save".freeze
|
||||
].freeze
|
||||
|
||||
# @return [Integer] Seconds to wait for an IP address when booting
|
||||
attr_accessor :ip_address_timeout
|
||||
# @return [Integer] Memory size in MB
|
||||
attr_accessor :memory
|
||||
# @return [Integer] Maximum memory size in MB. Enables dynamic memory.
|
||||
attr_accessor :maxmemory
|
||||
# @return [Integer] Number of CPUs
|
||||
attr_accessor :cpus
|
||||
# @return [String] Name of the VM (Shown in the Hyper-V Manager)
|
||||
attr_accessor :vmname
|
||||
# @return [Integer] VLAN ID for network interface
|
||||
attr_accessor :vlan_id
|
||||
# @return [String] MAC address for network interface
|
||||
attr_accessor :mac
|
||||
# @return [Boolean] Create linked clone instead of full clone
|
||||
# @note **DEPRECATED** use #linked_clone instead
|
||||
attr_accessor :differencing_disk
|
||||
# @return [Boolean] Create linked clone instead of full clone
|
||||
attr_accessor :linked_clone
|
||||
# @return [String] Automatic action on start of host. Default: Nothing (Nothing, StartIfRunning, Start)
|
||||
attr_accessor :auto_start_action
|
||||
# @return [String] Automatic action on stop of host. Default: ShutDown (ShutDown, TurnOff, Save)
|
||||
attr_accessor :auto_stop_action
|
||||
# @return [Boolean] Enable automatic checkpoints. Default: false
|
||||
attr_accessor :enable_checkpoints
|
||||
# @return [Boolean] Enable virtualization extensions
|
||||
attr_accessor :enable_virtualization_extensions
|
||||
# @return [Hash] Options for VMServiceIntegration
|
||||
attr_accessor :vm_integration_services
|
||||
|
||||
def initialize
|
||||
@ip_address_timeout = UNSET_VALUE
|
||||
|
@ -24,10 +55,12 @@ module VagrantPlugins
|
|||
@vmname = UNSET_VALUE
|
||||
@vlan_id = UNSET_VALUE
|
||||
@mac = UNSET_VALUE
|
||||
@linked_clone = UNSET_VALUE
|
||||
@differencing_disk = UNSET_VALUE
|
||||
@auto_start_action = UNSET_VALUE
|
||||
@auto_stop_action = UNSET_VALUE
|
||||
@enable_virtualization_extensions = UNSET_VALUE
|
||||
@enable_checkpoints = UNSET_VALUE
|
||||
@vm_integration_services = {
|
||||
guest_service_interface: UNSET_VALUE,
|
||||
heartbeat: UNSET_VALUE,
|
||||
|
@ -39,6 +72,10 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def finalize!
|
||||
@linked_clone = false if @linked_clone == UNSET_VALUE
|
||||
@differencing_disk = false if @differencing_disk == UNSET_VALUE
|
||||
@linked_clone ||= @differencing_disk
|
||||
@differencing_disk ||= @linked_clone
|
||||
if @ip_address_timeout == UNSET_VALUE
|
||||
@ip_address_timeout = 120
|
||||
end
|
||||
|
@ -48,20 +85,32 @@ module VagrantPlugins
|
|||
@vmname = nil if @vmname == UNSET_VALUE
|
||||
@vlan_id = nil if @vlan_id == UNSET_VALUE
|
||||
@mac = nil if @mac == UNSET_VALUE
|
||||
@differencing_disk = false if @differencing_disk == UNSET_VALUE
|
||||
@auto_start_action = nil if @auto_start_action == UNSET_VALUE
|
||||
@auto_stop_action = nil if @auto_stop_action == UNSET_VALUE
|
||||
@enable_virtualization_extensions = false if @enable_virtualization_extensions == UNSET_VALUE # TODO will this work?
|
||||
|
||||
@vm_integration_services.each { |key, value|
|
||||
@vm_integration_services[key] = nil if value == UNSET_VALUE
|
||||
}
|
||||
@vm_integration_services = nil if @vm_integration_services.length == 0
|
||||
@auto_start_action = "Nothing" if @auto_start_action == UNSET_VALUE
|
||||
@auto_stop_action = "ShutDown" if @auto_stop_action == UNSET_VALUE
|
||||
@enable_virtualization_extensions = false if @enable_virtualization_extensions == UNSET_VALUE
|
||||
if @enable_checkpoints == UNSET_VALUE
|
||||
@enable_checkpoints = false
|
||||
else
|
||||
@enable_checkpoints = !!@enable_checkpoints
|
||||
end
|
||||
@vm_integration_services.delete_if{|_, v| v == UNSET_VALUE }
|
||||
@vm_integration_services = nil if @vm_integration_services.empty?
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
if !ALLOWED_AUTO_START_ACTIONS.include?(auto_start_action)
|
||||
errors << I18n.t("vagrant.hyperv.config.invalid_auto_start_action", action: auto_start_action,
|
||||
allowed_actions: ALLOWED_AUTO_START_ACTIONS.join(", "))
|
||||
end
|
||||
|
||||
if !ALLOWED_AUTO_STOP_ACTIONS.include?(auto_stop_action)
|
||||
errors << I18n.t("vagrant.hyperv.config.invalid_auto_stop_action", action: auto_stop_action,
|
||||
allowed_actions: ALLOWED_AUTO_STOP_ACTIONS.join(", "))
|
||||
end
|
||||
|
||||
{"Hyper-V" => errors}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,19 +10,41 @@ module VagrantPlugins
|
|||
ERROR_REGEXP = /===Begin-Error===(.+?)===End-Error===/m
|
||||
OUTPUT_REGEXP = /===Begin-Output===(.+?)===End-Output===/m
|
||||
|
||||
# Name mapping for integration services for nicer keys
|
||||
INTEGRATION_SERVICES_MAP = {
|
||||
guest_service_interface: "Guest Service Interface",
|
||||
heartbeat: "Heartbeat",
|
||||
key_value_pair_exchange: "Key-Value Pair Exchange",
|
||||
shutdown: "Shutdown",
|
||||
time_synchronization: "Time Synchronization",
|
||||
vss: "VSS",
|
||||
}
|
||||
|
||||
# @return [String] VM ID
|
||||
attr_reader :vm_id
|
||||
|
||||
def initialize(id)
|
||||
@vm_id = id
|
||||
end
|
||||
|
||||
def execute(path, options)
|
||||
r = execute_powershell(path, options)
|
||||
if r.exit_code != 0
|
||||
raise Errors::PowerShellError,
|
||||
script: path,
|
||||
stderr: r.stderr
|
||||
# @return [Boolean] Supports VMCX
|
||||
def has_vmcx_support?
|
||||
!!execute(:has_vmcx_support)["result"]
|
||||
end
|
||||
|
||||
# Execute a PowerShell command and process the results
|
||||
#
|
||||
# @param [String] path Path to PowerShell script
|
||||
# @param [Hash] options Options to pass to command
|
||||
#
|
||||
# @return [Object, nil] If the command returned JSON content
|
||||
# it will be parsed and returned, otherwise
|
||||
# nil will be returned
|
||||
def execute(path, options={})
|
||||
if path.is_a?(Symbol)
|
||||
path = "#{path}.ps1"
|
||||
end
|
||||
r = execute_powershell(path, options)
|
||||
|
||||
# We only want unix-style line endings within Vagrant
|
||||
r.stdout.gsub!("\r\n", "\n")
|
||||
|
@ -40,104 +62,185 @@ module VagrantPlugins
|
|||
stderr: data["error"]
|
||||
end
|
||||
|
||||
if r.exit_code != 0
|
||||
raise Errors::PowerShellError,
|
||||
script: path,
|
||||
stderr: r.stderr
|
||||
end
|
||||
|
||||
# Nothing
|
||||
return nil if !output_match
|
||||
return JSON.parse(output_match[1])
|
||||
end
|
||||
|
||||
# Fetch current state of the VM
|
||||
#
|
||||
# @return [Hash<state, status>]
|
||||
def get_current_state
|
||||
execute('get_vm_status.ps1', { VmId: vm_id })
|
||||
execute(:get_vm_status, { VmId: vm_id })
|
||||
end
|
||||
|
||||
def delete_vm
|
||||
execute('delete_vm.ps1', { VmId: vm_id })
|
||||
end
|
||||
# Delete the VM
|
||||
#
|
||||
# @return [nil]
|
||||
def delete_vm
|
||||
execute(:delete_vm, { VmId: vm_id })
|
||||
end
|
||||
|
||||
# Export the VM to the given path
|
||||
#
|
||||
# @param [String] path Path for export
|
||||
# @return [nil]
|
||||
def export(path)
|
||||
execute('export_vm.ps1', {VmId: vm_id, Path: path})
|
||||
execute(:export_vm, {VmId: vm_id, Path: path})
|
||||
end
|
||||
|
||||
def read_guest_ip
|
||||
execute('get_network_config.ps1', { VmId: vm_id })
|
||||
end
|
||||
# Get the IP address of the VM
|
||||
#
|
||||
# @return [Hash<ip>]
|
||||
def read_guest_ip
|
||||
execute(:get_network_config, { VmId: vm_id })
|
||||
end
|
||||
|
||||
# Get the MAC address of the VM
|
||||
#
|
||||
# @return [Hash<mac>]
|
||||
def read_mac_address
|
||||
execute('get_network_mac.ps1', { VmId: vm_id })
|
||||
execute(:get_network_mac, { VmId: vm_id })
|
||||
end
|
||||
|
||||
def resume
|
||||
execute('resume_vm.ps1', { VmId: vm_id })
|
||||
end
|
||||
# Resume the VM from suspension
|
||||
#
|
||||
# @return [nil]
|
||||
def resume
|
||||
execute(:resume_vm, { VmId: vm_id })
|
||||
end
|
||||
|
||||
def start
|
||||
execute('start_vm.ps1', { VmId: vm_id })
|
||||
end
|
||||
# Start the VM
|
||||
#
|
||||
# @return [nil]
|
||||
def start
|
||||
execute(:start_vm, { VmId: vm_id })
|
||||
end
|
||||
|
||||
def stop
|
||||
execute('stop_vm.ps1', { VmId: vm_id })
|
||||
end
|
||||
# Stop the VM
|
||||
#
|
||||
# @return [nil]
|
||||
def stop
|
||||
execute(:stop_vm, { VmId: vm_id })
|
||||
end
|
||||
|
||||
def suspend
|
||||
execute("suspend_vm.ps1", { VmId: vm_id })
|
||||
end
|
||||
# Suspend the VM
|
||||
#
|
||||
# @return [nil]
|
||||
def suspend
|
||||
execute(:suspend_vm, { VmId: vm_id })
|
||||
end
|
||||
|
||||
def import(options)
|
||||
config_type = options.delete(:vm_config_type)
|
||||
if config_type === "vmcx"
|
||||
execute('import_vm_vmcx.ps1', options)
|
||||
else
|
||||
options.delete(:data_path)
|
||||
options.delete(:source_path)
|
||||
options.delete(:differencing_disk)
|
||||
execute('import_vm_xml.ps1', options)
|
||||
end
|
||||
end
|
||||
# Import a new VM
|
||||
#
|
||||
# @param [Hash] options Configuration options
|
||||
# @return [Hash<id>] New VM ID
|
||||
def import(options)
|
||||
execute(:import_vm, options)
|
||||
end
|
||||
|
||||
def net_set_vlan(vlan_id)
|
||||
execute("set_network_vlan.ps1", { VmId: vm_id, VlanId: vlan_id })
|
||||
end
|
||||
# Set the VLAN ID
|
||||
#
|
||||
# @param [String] vlan_id VLAN ID
|
||||
# @return [nil]
|
||||
def net_set_vlan(vlan_id)
|
||||
execute(:set_network_vlan, { VmId: vm_id, VlanId: vlan_id })
|
||||
end
|
||||
|
||||
def net_set_mac(mac_addr)
|
||||
execute("set_network_mac.ps1", { VmId: vm_id, Mac: mac_addr })
|
||||
end
|
||||
# Set the VM adapter MAC address
|
||||
#
|
||||
# @param [String] mac_addr MAC address
|
||||
# @return [nil]
|
||||
def net_set_mac(mac_addr)
|
||||
execute(:set_network_mac, { VmId: vm_id, Mac: mac_addr })
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot_name)
|
||||
execute("create_snapshot.ps1", { VmId: vm_id, SnapName: (snapshot_name) } )
|
||||
end
|
||||
# Create a new snapshot with the given name
|
||||
#
|
||||
# @param [String] snapshot_name Name of the new snapshot
|
||||
# @return [nil]
|
||||
def create_snapshot(snapshot_name)
|
||||
execute(:create_snapshot, { VmId: vm_id, SnapName: (snapshot_name) } )
|
||||
end
|
||||
|
||||
def restore_snapshot(snapshot_name)
|
||||
execute("restore_snapshot.ps1", { VmId: vm_id, SnapName: (snapshot_name) } )
|
||||
end
|
||||
# Restore the given snapshot
|
||||
#
|
||||
# @param [String] snapshot_name Name of snapshot to restore
|
||||
# @return [nil]
|
||||
def restore_snapshot(snapshot_name)
|
||||
execute(:restore_snapshot, { VmId: vm_id, SnapName: (snapshot_name) } )
|
||||
end
|
||||
|
||||
def list_snapshots()
|
||||
snaps = execute("list_snapshots.ps1", { VmID: vm_id } )
|
||||
snaps.map { |s| s['Name'] }
|
||||
end
|
||||
# Get list of current snapshots
|
||||
#
|
||||
# @return [Array<String>] snapshot names
|
||||
def list_snapshots
|
||||
snaps = execute(:list_snapshots, { VmID: vm_id } )
|
||||
snaps.map { |s| s['Name'] }
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot_name)
|
||||
execute("delete_snapshot.ps1", {VmID: vm_id, SnapName: snapshot_name})
|
||||
end
|
||||
# Delete snapshot with the given name
|
||||
#
|
||||
# @param [String] snapshot_name Name of snapshot to delete
|
||||
# @return [nil]
|
||||
def delete_snapshot(snapshot_name)
|
||||
execute(:delete_snapshot, {VmID: vm_id, SnapName: snapshot_name})
|
||||
end
|
||||
|
||||
# Enable or disable VM integration services
|
||||
#
|
||||
# @param [Hash] config Integration services to enable or disable
|
||||
# @return [nil]
|
||||
# @note Keys in the config hash will be remapped if found in the
|
||||
# INTEGRATION_SERVICES_MAP. If they are not, the name will
|
||||
# be passed directly. This allows new integration services
|
||||
# to configurable even if Vagrant is not aware of them.
|
||||
def set_vm_integration_services(config)
|
||||
execute("set_vm_integration_services.ps1", config)
|
||||
config.each_pair do |srv_name, srv_enable|
|
||||
args = {VMID: vm_id, Name: INTEGRATION_SERVICES_MAP.fetch(srv_name.to_sym, srv_name)}
|
||||
args[:Name] = true if srv_enable
|
||||
execute(:set_vm_integration_services, args)
|
||||
end
|
||||
end
|
||||
|
||||
# Set the name of the VM
|
||||
#
|
||||
# @param [String] vmname Name of the VM
|
||||
# @return [nil]
|
||||
def set_name(vmname)
|
||||
execute(:set_name, VMID: vm_id, VMName: vmname)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def execute_powershell(path, options, &block)
|
||||
lib_path = Pathname.new(File.expand_path("../scripts", __FILE__))
|
||||
mod_path = lib_path.join("utils").to_s.gsub("/", "\\")
|
||||
path = lib_path.join(path).to_s.gsub("/", "\\")
|
||||
options = options || {}
|
||||
ps_options = []
|
||||
options.each do |key, value|
|
||||
next if value == false
|
||||
ps_options << "-#{key}"
|
||||
# If the value is a TrueClass assume switch
|
||||
next if value == true
|
||||
ps_options << "'#{value}'"
|
||||
end
|
||||
|
||||
# Always have a stop error action for failures
|
||||
ps_options << "-ErrorAction" << "Stop"
|
||||
|
||||
opts = { notify: [:stdout, :stderr, :stdin] }
|
||||
# Include our module path so we can nicely load helper modules
|
||||
opts = {
|
||||
notify: [:stdout, :stderr, :stdin],
|
||||
env: {"PSModulePath" => "$env:PSModulePath+';#{mod_path}'"}
|
||||
}
|
||||
Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
$check = $(-Not (-Not (Get-Command "Hyper-V\Get-VMSwitch" -errorAction SilentlyContinue)))
|
||||
$check = $(-Not (-Not (Get-Command "Hyper-V\Get-VMSwitch" -ErrorAction SilentlyContinue)))
|
||||
$result = @{
|
||||
result = $check
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Source,
|
||||
|
||||
|
@ -6,4 +8,11 @@ Param(
|
|||
[string]$Destination
|
||||
)
|
||||
|
||||
Hyper-V\New-VHD -Path $Destination -ParentPath $Source -ErrorAction Stop
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
Hyper-V\New-VHD -Path $Destination -ParentPath $Source
|
||||
} catch {
|
||||
Write-Error-Message "Failed to clone drive: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
#Requires -Modules VagrantVM, VagrantMessages
|
||||
|
||||
param(
|
||||
[parameter (Mandatory=$true)]
|
||||
[Guid] $VMID,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $SwitchID=$null,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $Memory=$null,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $MaxMemory=$null,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $Processors=$null,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $AutoStartAction=$null,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $AutoStopAction=$null,
|
||||
[parameter (Mandatory=$false)]
|
||||
[switch] $VirtualizationExtensions,
|
||||
[parameter (Mandatory=$false)]
|
||||
[switch] $EnableCheckpoints
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VMID
|
||||
} catch {
|
||||
Write-Error-Message "Failed to locate VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if($Processors) {
|
||||
try {
|
||||
Set-VagrantVMCPUS -VM $VM -CPUCount ($Processors -as [int])
|
||||
} catch {
|
||||
Write-Error-Message "Failed to configure CPUs: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if($Memory -or $MaxMemory) {
|
||||
try {
|
||||
Set-VagrantVMMemory -VM $VM -Memory $Memory -MaxMemory $MaxMemory
|
||||
} catch {
|
||||
Write-Error-Message "Failed to configure memory: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if($AutoStartAction -or $AutoStopAction) {
|
||||
try {
|
||||
Set-VagrantVMAutoActions -VM $VM -AutoStartAction $AutoStartAction -AutoStopAction $AutoStopAction
|
||||
} catch {
|
||||
Write-Error-Message "Failed to configure automatic actions: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if($VirtualizationExtensions) {
|
||||
$virtex = $true
|
||||
} else {
|
||||
$virtex = $false
|
||||
}
|
||||
|
||||
try {
|
||||
Set-VagrantVMVirtExtensions -VM $VM -Enabled $virtex
|
||||
} catch {
|
||||
Write-Error-Message "Failed to configure virtualization extensions: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if($SwitchID) {
|
||||
try {
|
||||
$SwitchName = Get-VagrantVMSwitch -NameOrID $SwitchID
|
||||
Set-VagrantVMSwitch -VM $VM -SwitchName $SwitchName
|
||||
} catch {
|
||||
Write-Error-Message "Failed to configure network adapter: ${PSItem}"
|
||||
}
|
||||
}
|
||||
|
||||
if($EnableCheckpoints) {
|
||||
$checkpoints = "Standard"
|
||||
$CheckpointAction = "enable"
|
||||
} else {
|
||||
$checkpoints = "Disabled"
|
||||
$CheckpointAction = "disable"
|
||||
}
|
||||
|
||||
try {
|
||||
Hyper-V\Set-VM -VM $VM -CheckpointType $checkpoints
|
||||
} catch {
|
||||
Write-Error-Message "Failed to ${CheckpointAction} checkpoints on VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
|
@ -1,8 +1,17 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId,
|
||||
[string]$SnapName
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Checkpoint-VM $VM -SnapshotName $SnapName
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Checkpoint-VM $VM -SnapshotName $SnapName
|
||||
} catch {
|
||||
Write-Error-Message "Failed to create snapshot: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId,
|
||||
[string]$SnapName
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Remove-VMSnapshot $VM -Name $SnapName
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Remove-VMSnapshot $VM -Name $SnapName
|
||||
} catch {
|
||||
Write-Error-Message "Failed to delete snapshot: ${PSItem}"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Remove-VM $VM -Force
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Remove-VM $VM -Force
|
||||
} catch {
|
||||
Write-Error-Message "Failed to delete VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$vm = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
$vm | Hyper-V\Export-VM -Path $Path
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$vm = Hyper-V\Get-VM -Id $VmId
|
||||
$vm | Hyper-V\Export-VM -Path $Path
|
||||
} catch {
|
||||
Write-Error-Message "Failed to export VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Prepare directory structure for box import
|
||||
$name = $vm.Name
|
||||
Move-Item $Path/$name/* $Path
|
||||
Remove-Item -Path $Path/Snapshots -Force -Recurse
|
||||
Remove-Item -Path $Path/$name -Force
|
||||
try {
|
||||
$name = $vm.Name
|
||||
Move-Item $Path/$name/* $Path
|
||||
Remove-Item -Path $Path/Snapshots -Force -Recurse
|
||||
Remove-Item -Path $Path/$name -Force
|
||||
} catch {
|
||||
Write-Error-Message "Failed to format exported box: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
#Requires -Modules VagrantMessages
|
||||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the MIT License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
param (
|
||||
[string]$vm_id = $(throw "-vm_id is required."),
|
||||
[string]$guest_ip = $(throw "-guest_ip is required."),
|
||||
[string]$username = $(throw "-guest_username is required."),
|
||||
[string]$password = $(throw "-guest_password is required."),
|
||||
[string]$host_path = $(throw "-host_path is required."),
|
||||
[string]$guest_path = $(throw "-guest_path is required.")
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
$modules = @()
|
||||
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||
forEach ($module in $modules) { . $module }
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$vm_id,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$guest_ip,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$username,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$password,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$host_path,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$guest_path
|
||||
)
|
||||
|
||||
function Get-file-hash($source_path, $delimiter) {
|
||||
$source_files = @()
|
||||
|
@ -120,4 +121,3 @@ $resultHash = @{
|
|||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
||||
|
||||
|
|
|
@ -1,56 +1,68 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$vm = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
$networks = Hyper-V\Get-VMNetworkAdapter -VM $vm
|
||||
foreach ($network in $networks) {
|
||||
if ($network.IpAddresses.Length -gt 0) {
|
||||
foreach ($ip_address in $network.IpAddresses) {
|
||||
if ($ip_address.Contains(".") -And [string]::IsNullOrEmpty($ip4_address)) {
|
||||
$ip4_address = $ip_address
|
||||
} elseif ($ip_address.Contains(":") -And [string]::IsNullOrEmpty($ip6_address)) {
|
||||
$ip6_address = $ip_address
|
||||
try {
|
||||
$vm = Hyper-V\Get-VM -Id $VmId
|
||||
} catch {
|
||||
Write-Error-Message "Failed to locate VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
try {
|
||||
$networks = Hyper-V\Get-VMNetworkAdapter -VM $vm
|
||||
foreach ($network in $networks) {
|
||||
if ($network.IpAddresses.Length -gt 0) {
|
||||
foreach ($ip_address in $network.IpAddresses) {
|
||||
if ($ip_address.Contains(".") -And [string]::IsNullOrEmpty($ip4_address)) {
|
||||
$ip4_address = $ip_address
|
||||
} elseif ($ip_address.Contains(":") -And [string]::IsNullOrEmpty($ip6_address)) {
|
||||
$ip6_address = $ip_address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If no address was found in the network settings, check for
|
||||
# neighbor with mac address and see if an IP exists
|
||||
if (([string]::IsNullOrEmpty($ip4_address)) -And ([string]::IsNullOrEmpty($ip6_address))) {
|
||||
$macaddresses = $vm | select -ExpandProperty NetworkAdapters | select MacAddress
|
||||
foreach ($macaddr in $macaddresses) {
|
||||
$macaddress = $macaddr.MacAddress -replace '(.{2})(?!$)', '${1}-'
|
||||
$addr = Get-NetNeighbor -LinkLayerAddress $macaddress -ErrorAction SilentlyContinue | select IPAddress
|
||||
if ($ip_address) {
|
||||
$ip_address = $addr.IPAddress
|
||||
if ($ip_address.Contains(".")) {
|
||||
$ip4_address = $ip_address
|
||||
} elseif ($ip_address.Contains(":")) {
|
||||
$ip6_address = $ip_address
|
||||
# If no address was found in the network settings, check for
|
||||
# neighbor with mac address and see if an IP exists
|
||||
if (([string]::IsNullOrEmpty($ip4_address)) -And ([string]::IsNullOrEmpty($ip6_address))) {
|
||||
$macaddresses = $vm | select -ExpandProperty NetworkAdapters | select MacAddress
|
||||
foreach ($macaddr in $macaddresses) {
|
||||
$macaddress = $macaddr.MacAddress -replace '(.{2})(?!$)', '${1}-'
|
||||
$addr = Get-NetNeighbor -LinkLayerAddress $macaddress -ErrorAction SilentlyContinue | select IPAddress
|
||||
if ($ip_address) {
|
||||
$ip_address = $addr.IPAddress
|
||||
if ($ip_address.Contains(".")) {
|
||||
$ip4_address = $ip_address
|
||||
} elseif ($ip_address.Contains(":")) {
|
||||
$ip6_address = $ip_address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-Not ([string]::IsNullOrEmpty($ip4_address))) {
|
||||
$guest_ipaddress = $ip4_address
|
||||
} elseif (-Not ([string]::IsNullOrEmpty($ip6_address))) {
|
||||
$guest_ipaddress = $ip6_address
|
||||
}
|
||||
|
||||
if (-Not ([string]::IsNullOrEmpty($guest_ipaddress))) {
|
||||
$resultHash = @{
|
||||
ip = $guest_ipaddress
|
||||
if (-Not ([string]::IsNullOrEmpty($ip4_address))) {
|
||||
$guest_ipaddress = $ip4_address
|
||||
} elseif (-Not ([string]::IsNullOrEmpty($ip6_address))) {
|
||||
$guest_ipaddress = $ip6_address
|
||||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
||||
} else {
|
||||
Write-Error-Message "Failed to determine IP address"
|
||||
|
||||
if (-Not ([string]::IsNullOrEmpty($guest_ipaddress))) {
|
||||
$resultHash = @{
|
||||
ip = $guest_ipaddress
|
||||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
||||
} else {
|
||||
Write-Error-Message "Failed to determine IP address"
|
||||
exit 1
|
||||
}
|
||||
} catch {
|
||||
Write-Error-Message "Unexpected error while detecting network configuration: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$ip_address = ""
|
||||
$vm = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
$networks = Hyper-V\Get-VMNetworkAdapter -VM $vm
|
||||
foreach ($network in $networks) {
|
||||
if ($network.MacAddress -gt 0) {
|
||||
$mac_address = $network.MacAddress
|
||||
if (-Not ([string]::IsNullOrEmpty($mac_address))) {
|
||||
# We found our mac address!
|
||||
break
|
||||
try {
|
||||
$ip_address = ""
|
||||
$vm = Hyper-V\Get-VM -Id $VmId
|
||||
$networks = Hyper-V\Get-VMNetworkAdapter -VM $vm
|
||||
foreach ($network in $networks) {
|
||||
if ($network.MacAddress -gt 0) {
|
||||
$mac_address = $network.MacAddress
|
||||
if (-Not ([string]::IsNullOrEmpty($mac_address))) {
|
||||
# We found our mac address!
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$resultHash = @{
|
||||
mac = "$mac_address"
|
||||
$resultHash = @{
|
||||
mac = "$mac_address"
|
||||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
||||
} catch {
|
||||
Write-Error-Message "Unexpected error while fetching MAC: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
|
@ -1,11 +1,9 @@
|
|||
#Requires -Modules VagrantMessages
|
||||
# This will have a SwitchType property. As far as I know the values are:
|
||||
#
|
||||
# 0 - Private
|
||||
# 1 - Internal
|
||||
#
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
|
||||
$Switches = @(Hyper-V\Get-VMSwitch `
|
||||
| Select-Object Name,SwitchType,NetAdapterInterfaceDescription,Id)
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
|
||||
# Make sure the exception type is loaded
|
||||
try
|
||||
{
|
||||
|
@ -37,7 +35,7 @@ try {
|
|||
$State = "not_created"
|
||||
$Status = $State
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
# Windows version 10 and up have support for binary format
|
||||
$check = [System.Environment]::OSVersion.Version.Major -ge 10
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#Requires -Modules VagrantVM, VagrantMessages
|
||||
|
||||
param(
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $VMConfigFile,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $DestinationPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $DataPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $SourcePath,
|
||||
[parameter (Mandatory=$false)]
|
||||
[switch] $LinkedClone,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $VMName=$null
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
if($LinkedClone) {
|
||||
$linked = $true
|
||||
} else {
|
||||
$linked = $false
|
||||
}
|
||||
|
||||
$VM = New-VagrantVM -VMConfigFile $VMConfigFile -DestinationPath $DestinationPath `
|
||||
-DataPath $DataPath -SourcePath $SourcePath -LinkedClone $linked -VMName $VMName
|
||||
|
||||
$Result = @{
|
||||
id = $VM.Id.Guid;
|
||||
}
|
||||
Write-Output-Message (ConvertTo-Json $Result)
|
||||
} catch {
|
||||
Write-Error-Message "${PSItem}"
|
||||
exit 1
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
Param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$vm_config_file,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$source_path,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$dest_path,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$data_path,
|
||||
|
||||
[string]$switchid=$null,
|
||||
[string]$memory=$null,
|
||||
[string]$maxmemory=$null,
|
||||
[string]$cpus=$null,
|
||||
[string]$vmname=$null,
|
||||
[string]$auto_start_action=$null,
|
||||
[string]$auto_stop_action=$null,
|
||||
[string]$differencing_disk=$null,
|
||||
[string]$enable_virtualization_extensions=$False
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
|
||||
$VmProperties = @{
|
||||
Path = $vm_config_file
|
||||
SnapshotFilePath = Join-Path $data_path 'Snapshots'
|
||||
VhdDestinationPath = Join-Path $data_path 'Virtual Hard Disks'
|
||||
VirtualMachinePath = $data_path
|
||||
}
|
||||
|
||||
$vmConfig = (Hyper-V\Compare-VM -Copy -GenerateNewID @VmProperties)
|
||||
|
||||
$generation = $vmConfig.VM.Generation
|
||||
|
||||
if (!$vmname) {
|
||||
# Get the name of the vm
|
||||
$vm_name = $vmconfig.VM.VMName
|
||||
} else {
|
||||
$vm_name = $vmname
|
||||
}
|
||||
|
||||
if (!$cpus) {
|
||||
# Get the processorcount of the VM
|
||||
$processors = (Hyper-V\Get-VMProcessor -VM $vmConfig.VM).Count
|
||||
}else {
|
||||
$processors = $cpus
|
||||
}
|
||||
|
||||
function GetUniqueName($name) {
|
||||
Hyper-V\Get-VM | ForEach-Object -Process {
|
||||
if ($name -eq $_.Name) {
|
||||
$name = $name + "_1"
|
||||
}
|
||||
}
|
||||
return $name
|
||||
}
|
||||
|
||||
do {
|
||||
$name = $vm_name
|
||||
$vm_name = GetUniqueName $name
|
||||
} while ($vm_name -ne $name)
|
||||
|
||||
if (!$memory) {
|
||||
$configMemory = Hyper-V\Get-VMMemory -VM $vmConfig.VM
|
||||
$dynamicmemory = $configMemory.DynamicMemoryEnabled
|
||||
|
||||
$MemoryMaximumBytes = ($configMemory.Maximum)
|
||||
$MemoryStartupBytes = ($configMemory.Startup)
|
||||
$MemoryMinimumBytes = ($configMemory.Minimum)
|
||||
} else {
|
||||
if (!$maxmemory){
|
||||
$dynamicmemory = $False
|
||||
$MemoryMaximumBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory -as [int]) * 1MB
|
||||
} else {
|
||||
$dynamicmemory = $True
|
||||
$MemoryMaximumBytes = ($maxmemory -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory -as [int]) * 1MB
|
||||
}
|
||||
}
|
||||
|
||||
if (!$switchid) {
|
||||
$switchname = (Hyper-V\Get-VMNetworkAdapter -VM $vmConfig.VM).SwitchName
|
||||
} else {
|
||||
$switchname = $(Hyper-V\Get-VMSwitch -Id $switchid).Name
|
||||
}
|
||||
|
||||
# Enable nested virtualization if configured
|
||||
if ($enable_virtualization_extensions -eq "True") {
|
||||
Hyper-V\Set-VMProcessor -VM $vmConfig.VM -ExposeVirtualizationExtensions $true
|
||||
}
|
||||
|
||||
$vmNetworkAdapter = Hyper-V\Get-VMNetworkAdapter -VM $vmConfig.VM
|
||||
Hyper-V\Connect-VMNetworkAdapter -VMNetworkAdapter $vmNetworkAdapter -SwitchName $switchname
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -NewVMName $vm_name
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -ErrorAction "Stop"
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -ProcessorCount $processors
|
||||
|
||||
if ($dynamicmemory) {
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -DynamicMemory
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -MemoryMinimumBytes $MemoryMinimumBytes -MemoryMaximumBytes $MemoryMaximumBytes -MemoryStartupBytes $MemoryStartupBytes
|
||||
} else {
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -StaticMemory
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -MemoryStartupBytes $MemoryStartupBytes
|
||||
}
|
||||
|
||||
if ($notes) {
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -Notes $notes
|
||||
}
|
||||
|
||||
if ($auto_start_action) {
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -AutomaticStartAction $auto_start_action
|
||||
}
|
||||
|
||||
if ($auto_stop_action) {
|
||||
Hyper-V\Set-VM -VM $vmConfig.VM -AutomaticStopAction $auto_stop_action
|
||||
}
|
||||
|
||||
# Only set EFI secure boot for Gen 2 machines, not gen 1
|
||||
if ($generation -ne 1) {
|
||||
Hyper-V\Set-VMFirmware -VM $vmConfig.VM -EnableSecureBoot (Hyper-V\Get-VMFirmware -VM $vmConfig.VM).SecureBoot
|
||||
}
|
||||
|
||||
$report = Hyper-V\Compare-VM -CompatibilityReport $vmConfig
|
||||
|
||||
# Stop if there are incompatibilities
|
||||
if($report.Incompatibilities.Length -gt 0){
|
||||
Write-Error-Message $(ConvertTo-Json $($report.Incompatibilities | Select -ExpandProperty Message))
|
||||
exit 0
|
||||
}
|
||||
|
||||
if($differencing_disk){
|
||||
# Get all controller on the VM, first scsi, then IDE if it is a Gen 1 device
|
||||
$controllers = Hyper-V\Get-VMScsiController -VM $vmConfig.VM
|
||||
if($generation -eq 1){
|
||||
$controllers = @($controllers) + @(Hyper-V\Get-VMIdeController -VM $vmConfig.VM)
|
||||
}
|
||||
|
||||
foreach($controller in $controllers){
|
||||
foreach($drive in $controller.Drives){
|
||||
if([System.IO.Path]::GetFileName($drive.Path) -eq [System.IO.Path]::GetFileName($source_path)){
|
||||
# Remove the old disk and replace it with a differencing version
|
||||
$path = $drive.Path
|
||||
Hyper-V\Remove-VMHardDiskDrive $drive
|
||||
Hyper-V\New-VHD -Path $dest_path -ParentPath $source_path -ErrorAction Stop
|
||||
Hyper-V\Add-VMHardDiskDrive -VM $vmConfig.VM -Path $dest_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Hyper-V\Import-VM -CompatibilityReport $vmConfig
|
||||
|
||||
$vm_id = (Hyper-V\Get-VM $vm_name).id.guid
|
||||
$resultHash = @{
|
||||
name = $vm_name
|
||||
id = $vm_id
|
||||
}
|
||||
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
|
@ -1,221 +0,0 @@
|
|||
Param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$vm_config_file,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$dest_path,
|
||||
|
||||
[string]$switchname=$null,
|
||||
[string]$memory=$null,
|
||||
[string]$maxmemory=$null,
|
||||
[string]$cpus=$null,
|
||||
[string]$vmname=$null,
|
||||
[string]$auto_start_action=$null,
|
||||
[string]$auto_stop_action=$null,
|
||||
[string]$enable_virtualization_extensions=$False
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
|
||||
[xml]$vmconfig = Get-Content -Path $vm_config_file
|
||||
|
||||
$generation = [int]($vmconfig.configuration.properties.subtype.'#text')+1
|
||||
|
||||
if (!$vmname) {
|
||||
# Get the name of the vm
|
||||
$vm_name = $vmconfig.configuration.properties.name.'#text'
|
||||
}else {
|
||||
$vm_name = $vmname
|
||||
}
|
||||
|
||||
if (!$cpus) {
|
||||
# Get the name of the vm
|
||||
$processors = $vmconfig.configuration.settings.processors.count.'#text'
|
||||
}else {
|
||||
$processors = $cpus
|
||||
}
|
||||
|
||||
function GetUniqueName($name) {
|
||||
Hyper-V\Get-VM | ForEach-Object -Process {
|
||||
if ($name -eq $_.Name) {
|
||||
$name = $name + "_1"
|
||||
}
|
||||
}
|
||||
return $name
|
||||
}
|
||||
|
||||
do {
|
||||
$name = $vm_name
|
||||
$vm_name = GetUniqueName $name
|
||||
} while ($vm_name -ne $name)
|
||||
|
||||
if (!$memory) {
|
||||
$xmlmemory = (Select-Xml -xml $vmconfig -XPath "//memory").node.Bank
|
||||
if ($xmlmemory.dynamic_memory_enabled."#text" -eq "True") {
|
||||
$dynamicmemory = $True
|
||||
}
|
||||
else {
|
||||
$dynamicmemory = $False
|
||||
}
|
||||
# Memory values need to be in bytes
|
||||
$MemoryMaximumBytes = ($xmlmemory.limit."#text" -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($xmlmemory.size."#text" -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($xmlmemory.reservation."#text" -as [int]) * 1MB
|
||||
}
|
||||
else {
|
||||
if (!$maxmemory){
|
||||
$dynamicmemory = $False
|
||||
$MemoryMaximumBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory -as [int]) * 1MB
|
||||
}
|
||||
else {
|
||||
$dynamicmemory = $True
|
||||
$MemoryMaximumBytes = ($maxmemory -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory -as [int]) * 1MB
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!$switchname) {
|
||||
# Get the name of the virtual switch
|
||||
$switchname = (Select-Xml -xml $vmconfig -XPath "//AltSwitchName").node."#text"
|
||||
}
|
||||
|
||||
if ($generation -eq 1) {
|
||||
# Determine boot device
|
||||
Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") {
|
||||
"Floppy" { $bootdevice = "Floppy" }
|
||||
"HardDrive" { $bootdevice = "IDE" }
|
||||
"Optical" { $bootdevice = "CD" }
|
||||
"Network" { $bootdevice = "LegacyNetworkAdapter" }
|
||||
"Default" { $bootdevice = "IDE" }
|
||||
} #switch
|
||||
} else {
|
||||
# Determine boot device
|
||||
Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") {
|
||||
"HardDrive" { $bootdevice = "VHD" }
|
||||
"Optical" { $bootdevice = "CD" }
|
||||
"Network" { $bootdevice = "NetworkAdapter" }
|
||||
"Default" { $bootdevice = "VHD" }
|
||||
} #switch
|
||||
}
|
||||
|
||||
# Determine secure boot options
|
||||
$secure_boot_enabled = (Select-Xml -xml $vmconfig -XPath "//secure_boot_enabled").Node."#text"
|
||||
|
||||
# Define a hash map of parameter values for New-VM
|
||||
|
||||
$vm_params = @{
|
||||
Name = $vm_name
|
||||
NoVHD = $True
|
||||
MemoryStartupBytes = $MemoryStartupBytes
|
||||
SwitchName = $switchname
|
||||
BootDevice = $bootdevice
|
||||
ErrorAction = "Stop"
|
||||
}
|
||||
|
||||
# Generation parameter was added in ps v4
|
||||
if((get-command Hyper-V\New-VM).Parameters.Keys.Contains("generation")) {
|
||||
$vm_params.Generation = $generation
|
||||
}
|
||||
|
||||
# Create the VM using the values in the hash map
|
||||
|
||||
$vm = Hyper-V\New-VM @vm_params
|
||||
|
||||
$notes = (Select-Xml -xml $vmconfig -XPath "//notes").node.'#text'
|
||||
|
||||
# Set-VM parameters to configure new VM with old values
|
||||
|
||||
$more_vm_params = @{
|
||||
ProcessorCount = $processors
|
||||
MemoryStartupBytes = $MemoryStartupBytes
|
||||
}
|
||||
|
||||
If ($dynamicmemory) {
|
||||
$more_vm_params.Add("DynamicMemory",$True)
|
||||
$more_vm_params.Add("MemoryMinimumBytes",$MemoryMinimumBytes)
|
||||
$more_vm_params.Add("MemoryMaximumBytes", $MemoryMaximumBytes)
|
||||
} else {
|
||||
$more_vm_params.Add("StaticMemory",$True)
|
||||
}
|
||||
|
||||
if ($notes) {
|
||||
$more_vm_params.Add("Notes",$notes)
|
||||
}
|
||||
|
||||
if ($auto_start_action) {
|
||||
$more_vm_params.Add("AutomaticStartAction",$auto_start_action)
|
||||
}
|
||||
|
||||
if ($auto_stop_action) {
|
||||
$more_vm_params.Add("AutomaticStopAction",$auto_stop_action)
|
||||
}
|
||||
|
||||
# Set the values on the VM
|
||||
$vm | Hyper-V\Set-VM @more_vm_params -Passthru
|
||||
|
||||
# Add drives to the virtual machine
|
||||
$controllers = Select-Xml -xml $vmconfig -xpath "//*[starts-with(name(.),'controller')]"
|
||||
|
||||
# Only set EFI secure boot for Gen 2 machines, not gen 1
|
||||
if ($generation -ne 1) {
|
||||
# Set EFI secure boot
|
||||
if ($secure_boot_enabled -eq "True") {
|
||||
Hyper-V\Set-VMFirmware -VM $vm -EnableSecureBoot On
|
||||
} else {
|
||||
Hyper-V\Set-VMFirmware -VM $vm -EnableSecureBoot Off
|
||||
}
|
||||
}
|
||||
|
||||
# Enable nested virtualization if configured
|
||||
if ($enable_virtualization_extensions -eq "True") {
|
||||
Hyper-V\Set-VMProcessor -VM $vm -ExposeVirtualizationExtensions $true
|
||||
}
|
||||
|
||||
# A regular expression pattern to pull the number from controllers
|
||||
[regex]$rx="\d"
|
||||
|
||||
foreach ($controller in $controllers) {
|
||||
$node = $controller.Node
|
||||
|
||||
# Check for SCSI
|
||||
if ($node.ParentNode.ChannelInstanceGuid) {
|
||||
$ControllerType = "SCSI"
|
||||
} else {
|
||||
$ControllerType = "IDE"
|
||||
}
|
||||
|
||||
$drives = $node.ChildNodes | where {$_.pathname."#text"}
|
||||
foreach ($drive in $drives) {
|
||||
#if drive type is ISO then set DVD Drive accordingly
|
||||
$driveType = $drive.type."#text"
|
||||
|
||||
$addDriveParam = @{
|
||||
ControllerNumber = $rx.Match($controller.node.name).value
|
||||
Path = $dest_path
|
||||
}
|
||||
|
||||
if ($drive.pool_id."#text") {
|
||||
$ResourcePoolName = $drive.pool_id."#text"
|
||||
$addDriveParam.Add("ResourcePoolname",$ResourcePoolName)
|
||||
}
|
||||
|
||||
if ($drivetype -eq 'VHD') {
|
||||
$addDriveParam.add("ControllerType",$ControllerType)
|
||||
$vm | Hyper-V\Add-VMHardDiskDrive @AddDriveparam
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$vm_id = (Hyper-V\Get-VM $vm_name).id.guid
|
||||
$resultHash = @{
|
||||
name = $vm_name
|
||||
id = $vm_id
|
||||
}
|
||||
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
|
@ -1,12 +1,19 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
$Snapshots = @(Hyper-V\Get-VMSnapshot $VM | Select-Object Name)
|
||||
$result = ConvertTo-json $Snapshots
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "===Begin-Output==="
|
||||
Write-Host $result
|
||||
Write-Host "===End-Output==="
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
$Snapshots = @(Hyper-V\Get-VMSnapshot $VM | Select-Object Name)
|
||||
} catch {
|
||||
Write-Error-Message "Failed to get snapshot list: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$result = ConvertTo-json $Snapshots
|
||||
Write-Output-Message $result
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId,
|
||||
[string]$SnapName
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Restore-VMSnapshot $VM -Name $SnapName -Confirm:$false
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Restore-VMSnapshot $VM -Name $SnapName -Confirm:$false
|
||||
} catch {
|
||||
Write-Error-Message "Failed to restore snapshot: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Resume-VM $VM
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Resume-VM $VM
|
||||
} catch {
|
||||
Write-Error-Message "Failed to resume VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#Requires -Modules VagrantMessages
|
||||
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Guid] $VMID,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $VMName
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VMID
|
||||
} catch {
|
||||
Write-Error-Message "Failed to locate VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
try {
|
||||
Hyper-V\Set-VM -VM $VM -NewVMName $VMName
|
||||
} catch {
|
||||
Write-Error-Message "Failed to assign new VM name ${VMName}: ${PSItem}"
|
||||
exit 1
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
param (
|
||||
[string]$VmId = $(throw "-VmId is required."),
|
||||
[string]$Mac = $(throw "-Mac ")
|
||||
)
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
$modules = @()
|
||||
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||
forEach ($module in $modules) { . $module }
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$VmId,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$Mac
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$vm = Hyper-V\Get-VM -Id $VmId -ErrorAction "stop"
|
||||
Hyper-V\Set-VMNetworkAdapter $vm -StaticMacAddress $Mac -ErrorAction "stop"
|
||||
}
|
||||
catch {
|
||||
Write-Error-Message "Failed to set VM's MAC address $_"
|
||||
$vm = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Set-VMNetworkAdapter $vm -StaticMacAddress $Mac
|
||||
} catch {
|
||||
Write-Error-Message "Failed to set VM MAC address: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#Requires -Modules VagrantMessages
|
||||
|
||||
param (
|
||||
[string]$VmId = $(throw "-VmId is required."),
|
||||
[int]$VlanId = $(throw "-VlanId ")
|
||||
)
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$VmId,
|
||||
[parameter (Mandatory=$true)]
|
||||
[int]$VlanId
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
|
|
|
@ -1,37 +1,27 @@
|
|||
#Requires -Modules VagrantVM, VagrantMessages
|
||||
|
||||
param (
|
||||
[string] $VmId,
|
||||
[string] $guest_service_interface = $null,
|
||||
[string] $heartbeat = $null,
|
||||
[string] $key_value_pair_exchange = $null,
|
||||
[string] $shutdown = $null,
|
||||
[string] $time_synchronization = $null,
|
||||
[string] $vss = $null
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $VMID,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $Name,
|
||||
[parameter (Mandatory=$false)]
|
||||
[switch] $Enable
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$vm = Hyper-V\Get-VM -Id $VmId -ErrorAction "stop"
|
||||
|
||||
# Set the service based on value
|
||||
function VmSetService
|
||||
{
|
||||
param ([string] $Name, [string] $Value, [Microsoft.HyperV.PowerShell.VirtualMachine] $Vm)
|
||||
|
||||
if ($Value -ne $null){
|
||||
if($Value -eq "true"){
|
||||
Hyper-V\Enable-VMIntegrationService -VM $Vm -Name $Name
|
||||
}
|
||||
if($Value -eq "false"){
|
||||
Hyper-V\Disable-VMIntegrationService -VM $Vm -Name $Name
|
||||
}
|
||||
}
|
||||
try {
|
||||
$VM = Hyper-V\Get-VM -Id $VMID
|
||||
} catch {
|
||||
Write-Error-Message "Failed to locate VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
VmSetService -Name "Guest Service Interface" -Value $guest_service_interface -Vm $vm
|
||||
VmSetService -Name "Heartbeat" -Value $heartbeat -Vm $vm
|
||||
VmSetService -Name "Key-Value Pair Exchange" -Value $key_value_pair_exchange -Vm $vm
|
||||
VmSetService -Name "Shutdown" -Value $shutdown -Vm $vm
|
||||
VmSetService -Name "Time Synchronization" -Value $time_synchronization -Vm $vm
|
||||
VmSetService -Name "VSS" -Value $vss -Vm $vm
|
||||
try {
|
||||
Set-VagrantVMService -VM $VM -Name $Name -Enable $enabled
|
||||
} catch {
|
||||
if($enabled){ $action = "enable" } else { $action = "disable" }
|
||||
Write-Error-Message "Failed to ${action} VM integration service ${Name}: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
param (
|
||||
[string]$VmId = $(throw "-VmId is required.")
|
||||
)
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
$modules = @()
|
||||
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||
forEach ($module in $modules) { . $module }
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try {
|
||||
$vm = Hyper-V\Get-VM -Id $VmId -ErrorAction "stop"
|
||||
Hyper-V\Start-VM $vm -ErrorAction "stop"
|
||||
$state = $vm.state
|
||||
$status = $vm.status
|
||||
$name = $vm.name
|
||||
$resultHash = @{
|
||||
state = "$state"
|
||||
status = "$status"
|
||||
name = "$name"
|
||||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
||||
$vm = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Start-VM $vm
|
||||
$state = $vm.state
|
||||
$status = $vm.status
|
||||
$name = $vm.name
|
||||
$resultHash = @{
|
||||
state = "$state"
|
||||
status = "$status"
|
||||
name = "$name"
|
||||
}
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
||||
} catch {
|
||||
Write-Error-Message "Failed to start VM ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
catch {
|
||||
Write-Error-Message "Failed to start a VM $_"
|
||||
}
|
|
@ -1,8 +1,17 @@
|
|||
#Requires -Modules VagrantMessages
|
||||
|
||||
Param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
# Shuts down virtual machine regardless of any unsaved application data
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Stop-VM $VM -Force
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try{
|
||||
# Shuts down virtual machine regardless of any unsaved application data
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Stop-VM $VM -Force
|
||||
} catch {
|
||||
Write-Error-Message "Failed to stop VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
Param(
|
||||
#Requires -Modules VagrantMessages
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$VmId
|
||||
)
|
||||
|
||||
$VM = Hyper-V\Get-VM -Id $VmId -ErrorAction "Stop"
|
||||
Hyper-V\Suspend-VM $VM
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
try{
|
||||
$VM = Hyper-V\Get-VM -Id $VmId
|
||||
Hyper-V\Suspend-VM $VM
|
||||
} catch {
|
||||
Write-Error-Message "Failed to suspend VM: ${PSItem}"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the MIT License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
function Write-Error-Message {
|
||||
param (
|
||||
[parameter (Mandatory=$true,Position=0)]
|
||||
[string] $Message
|
||||
)
|
||||
$error_message = @{
|
||||
error = $Message
|
||||
}
|
||||
Write-Host "===Begin-Error==="
|
||||
Write-Host (ConvertTo-Json $error_message)
|
||||
Write-Host "===End-Error==="
|
||||
}
|
||||
|
||||
function Write-Output-Message {
|
||||
param (
|
||||
[parameter (Mandatory=$true,Position=0)]
|
||||
[string] $Message
|
||||
)
|
||||
Write-Host "===Begin-Output==="
|
||||
Write-Host $Message
|
||||
Write-Host "===End-Output==="
|
||||
}
|
|
@ -0,0 +1,616 @@
|
|||
# Vagrant VM creation functions
|
||||
|
||||
function New-VagrantVM {
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[string] $VMConfigFile,
|
||||
[parameter(Mandatory=$true)]
|
||||
[string] $DestinationPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $DataPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $SourcePath,
|
||||
[parameter (Mandatory=$false)]
|
||||
[bool] $LinkedClone = $false,
|
||||
[parameter(Mandatory=$false)]
|
||||
[string] $VMName
|
||||
)
|
||||
if([IO.Path]::GetExtension($VMConfigFile).ToLower() -eq ".xml") {
|
||||
return New-VagrantVMXML @PSBoundParameters
|
||||
} else {
|
||||
return New-VagrantVMVMCX @PSBoundParameters
|
||||
}
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Create a new Vagrant Hyper-V VM by cloning original. This
|
||||
is the general use function with will call the specialized
|
||||
function based on the extension of the configuration file.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Using an existing Hyper-V VM a new Hyper-V VM is created
|
||||
by cloning the original.
|
||||
|
||||
.PARAMETER VMConfigFile
|
||||
Path to the original Hyper-V VM configuration file.
|
||||
|
||||
.PARAMETER DestinationPath
|
||||
Path to new Hyper-V VM hard drive.
|
||||
|
||||
.PARAMETER DataPath
|
||||
Directory path of the original Hyper-V VM to be cloned.
|
||||
|
||||
.PARAMETER SourcePath
|
||||
Path to the original Hyper-V VM hard drive.
|
||||
|
||||
.PARAMETER LinkedClone
|
||||
New Hyper-V VM should be linked clone instead of complete copy.
|
||||
|
||||
.PARAMETER VMName
|
||||
Name of the new Hyper-V VM.
|
||||
|
||||
.INPUTS
|
||||
|
||||
None.
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
VirtualMachine. The cloned Hyper-V VM.
|
||||
#>
|
||||
}
|
||||
|
||||
function New-VagrantVMVMCX {
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[string] $VMConfigFile,
|
||||
[parameter(Mandatory=$true)]
|
||||
[string] $DestinationPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $DataPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $SourcePath,
|
||||
[parameter (Mandatory=$false)]
|
||||
[bool] $LinkedClone = $false,
|
||||
[parameter(Mandatory=$false)]
|
||||
[string] $VMName
|
||||
)
|
||||
|
||||
$NewVMConfig = @{
|
||||
Path = $VMConfigFile;
|
||||
SnapshotFilePath = Join-Path $DataPath "Snapshots";
|
||||
VhdDestinationPath = Join-Path $DataPath "Virtual Hard Disks";
|
||||
VirtualMachinePath = $DataPath;
|
||||
}
|
||||
$VMConfig = (Hyper-V\Compare-VM -Copy -GenerateNewID @NewVMConfig)
|
||||
$VM = $VMConfig.VM
|
||||
$Gen = $VM.Generation
|
||||
|
||||
# Set VM name if name has been provided
|
||||
if($VMName) {
|
||||
Hyper-V\Set-VM -VM $VM -NewVMName $VMName
|
||||
}
|
||||
|
||||
# Set EFI secure boot on machines after Gen 1
|
||||
if($Gen -gt 1) {
|
||||
Hyper-V\Set-VMFirmware -VM $VM -EnableSecureBoot (Hyper-V\Get-VMFirmware -VM $VM).SecureBoot
|
||||
}
|
||||
|
||||
# Verify new VM
|
||||
$Report = Hyper-V\Compare-VM -CompatibilityReport $VMConfig
|
||||
if($Report.Incompatibilities.Length -gt 0){
|
||||
throw $(ConvertTo-Json $($Report.Incompatibilities | Select -ExpandProperty Message))
|
||||
}
|
||||
|
||||
if($LinkedClone) {
|
||||
$Controllers = Hyper-V\Get-VMScsiController -VM $VM
|
||||
if($Gen -eq 1){
|
||||
$Controllers = @($Controllers) + @(Hyper-V\Get-VMIdeController -VM $VM)
|
||||
}
|
||||
foreach($Controller in $Controllers) {
|
||||
foreach($Drive in $Controller.Drives) {
|
||||
if([System.IO.Path]::GetFileName($Drive.Path) -eq [System.IO.Path]::GetFileName($SourcePath)) {
|
||||
$Path = $Drive.Path
|
||||
Hyper-V\Remove-VMHardDiskDrive $Drive
|
||||
Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath
|
||||
Hyper-V\AddVMHardDiskDrive -VM $VM -Path $DestinationPath
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Hyper-V\Import-VM -CompatibilityReport $VMConfig
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Create a new Vagrant Hyper-V VM by cloning original (VMCX based).
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Using an existing Hyper-V VM a new Hyper-V VM is created
|
||||
by cloning the original.
|
||||
|
||||
.PARAMETER VMConfigFile
|
||||
Path to the original Hyper-V VM configuration file.
|
||||
|
||||
.PARAMETER DestinationPath
|
||||
Path to new Hyper-V VM hard drive.
|
||||
|
||||
.PARAMETER DataPath
|
||||
Directory path of the original Hyper-V VM to be cloned.
|
||||
|
||||
.PARAMETER SourcePath
|
||||
Path to the original Hyper-V VM hard drive.
|
||||
|
||||
.PARAMETER LinkedClone
|
||||
New Hyper-V VM should be linked clone instead of complete copy.
|
||||
|
||||
.PARAMETER VMName
|
||||
Name of the new Hyper-V VM.
|
||||
|
||||
.INPUTS
|
||||
|
||||
None.
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
VirtualMachine. The cloned Hyper-V VM.
|
||||
#>
|
||||
}
|
||||
|
||||
function New-VagrantVMXML {
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[string] $VMConfigFile,
|
||||
[parameter(Mandatory=$true)]
|
||||
[string] $DestinationPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $DataPath,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $SourcePath,
|
||||
[parameter (Mandatory=$false)]
|
||||
[bool] $LinkedClone = $false,
|
||||
[parameter(Mandatory=$false)]
|
||||
[string] $VMName
|
||||
)
|
||||
|
||||
$DestinationDirectory = [System.IO.Path]::GetDirectoryName($DestinationPath)
|
||||
New-Item -ItemType Directory -Force -Path $DestinationDirectory
|
||||
|
||||
if($LinkedClone){
|
||||
Hyper-V\New-VHD -Path $DestinationPath -ParentPath $SourcePath -ErrorAction Stop
|
||||
} else {
|
||||
Copy-Item $SourcePath -Destination $DestinationPath -ErrorAction Stop
|
||||
}
|
||||
|
||||
[xml]$VMConfig = Get-Content -Path $VMConfigFile
|
||||
$Gen = [int]($VMConfig.configuration.properties.subtype."#text") + 1
|
||||
if(!$VMName) {
|
||||
$VMName = $VMConfig.configuration.properties.name."#text"
|
||||
}
|
||||
|
||||
# Determine boot device
|
||||
if($Gen -eq 1) {
|
||||
Switch ((Select-Xml -xml $VMConfig -XPath "//boot").node.device0."#text") {
|
||||
"Floppy" { $BootDevice = "Floppy" }
|
||||
"HardDrive" { $BootDevice = "IDE" }
|
||||
"Optical" { $BootDevice = "CD" }
|
||||
"Network" { $BootDevice = "LegacyNetworkAdapter" }
|
||||
"Default" { $BootDevice = "IDE" }
|
||||
}
|
||||
} else {
|
||||
Switch ((Select-Xml -xml $VMConfig -XPath "//boot").node.device0."#text") {
|
||||
"HardDrive" { $BootDevice = "VHD" }
|
||||
"Optical" { $BootDevice = "CD" }
|
||||
"Network" { $BootDevice = "NetworkAdapter" }
|
||||
"Default" { $BootDevice = "VHD" }
|
||||
}
|
||||
}
|
||||
|
||||
# Determine if secure boot is enabled
|
||||
$SecureBoot = (Select-Xml -XML $VMConfig -XPath "//secure_boot_enabled").Node."#text"
|
||||
|
||||
$NewVMConfig = @{
|
||||
Name = $VMName;
|
||||
NoVHD = $true;
|
||||
BootDevice = $BootDevice;
|
||||
}
|
||||
|
||||
# Generation parameter in PS4 so validate before using
|
||||
if((Get-Command Hyper-V\New-VM).Parameters.Keys.Contains("generation")) {
|
||||
$NewVMConfig.Generation = $Gen
|
||||
}
|
||||
|
||||
# Create new VM instance
|
||||
$VM = Hyper-V\New-VM @NewVMConfig
|
||||
|
||||
# Configure secure boot
|
||||
if($Gen -gt 1) {
|
||||
if($SecureBoot -eq "True") {
|
||||
Hyper-V\Set-VMFirmware -VM $VM -EnableSecureBoot On
|
||||
} else {
|
||||
Hyper-V\Set-VMFirmware -VM $VM -EnableSecureBoot Off
|
||||
}
|
||||
}
|
||||
|
||||
# Configure drives
|
||||
[regex]$DriveNumberMatcher = "\d"
|
||||
$Controllers = Select-Xml -XML $VMConfig -XPath "//*[starts-with(name(.),'controller')]"
|
||||
|
||||
foreach($Controller in $Controllers) {
|
||||
$Node = $Controller.Node
|
||||
if($Node.ParentNode.ChannelInstanceGuid) {
|
||||
$ControllerType = "SCSI"
|
||||
} else {
|
||||
$ControllerType = "IDE"
|
||||
}
|
||||
$Drives = $Node.ChildNodes | where {$_.pathname."#text"}
|
||||
foreach($Drive in $Drives) {
|
||||
$DriveType = $Drive.type."#text"
|
||||
if($DriveType -ne "VHD") {
|
||||
continue
|
||||
}
|
||||
|
||||
$NewDriveConfig = @{
|
||||
ControllerNumber = $DriveNumberMatcher.Match($Controller.node.name).value;
|
||||
Path = $DestinationPath;
|
||||
ControllerType = $ControllerType;
|
||||
}
|
||||
if($Drive.pool_id."#text") {
|
||||
$NewDriveConfig.ResourcePoolname = $Drive.pool_id."#text"
|
||||
}
|
||||
$VM | Hyper-V\Add-VMHardDiskDrive @NewDriveConfig
|
||||
}
|
||||
}
|
||||
|
||||
# Apply original VM configuration to new VM instance
|
||||
|
||||
$processors = $VMConfig.configuration.settings.processors.count."#text"
|
||||
$notes = (Select-Xml -XML $VMConfig -XPath "//notes").node."#text"
|
||||
$memory = (Select-Xml -XML $VMConfig -XPath "//memory").node.Bank
|
||||
if ($memory.dynamic_memory_enabled."#text" -eq "True") {
|
||||
$dynamicmemory = $True
|
||||
}
|
||||
else {
|
||||
$dynamicmemory = $False
|
||||
}
|
||||
# Memory values need to be in bytes
|
||||
$MemoryMaximumBytes = ($memory.limit."#text" -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory.size."#text" -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory.reservation."#text" -as [int]) * 1MB
|
||||
|
||||
$Config = @{
|
||||
ProcessorCount = $processors;
|
||||
MemoryStartupBytes = $MemoryStartupBytes
|
||||
}
|
||||
if($dynamicmemory) {
|
||||
$Config.DynamicMemory = $true
|
||||
$Config.MemoryMinimumBytes = $MemoryMinimumBytes
|
||||
$Config.MemoryMaximumBytes = $MemoryMaximumBytes
|
||||
} else {
|
||||
$Config.StaticMemory = $true
|
||||
}
|
||||
if($notes) {
|
||||
$Config.Notes = $notes
|
||||
}
|
||||
Hyper-V\Set-VM -VM $VM @Config
|
||||
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Create a new Vagrant Hyper-V VM by cloning original (XML based).
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Using an existing Hyper-V VM a new Hyper-V VM is created
|
||||
by cloning the original.
|
||||
|
||||
.PARAMETER VMConfigFile
|
||||
Path to the original Hyper-V VM configuration file.
|
||||
|
||||
.PARAMETER DestinationPath
|
||||
Path to new Hyper-V VM hard drive.
|
||||
|
||||
.PARAMETER DataPath
|
||||
Directory path of the original Hyper-V VM to be cloned.
|
||||
|
||||
.PARAMETER SourcePath
|
||||
Path to the original Hyper-V VM hard drive.
|
||||
|
||||
.PARAMETER LinkedClone
|
||||
New Hyper-V VM should be linked clone instead of complete copy.
|
||||
|
||||
.PARAMETER VMName
|
||||
Name of the new Hyper-V VM.
|
||||
|
||||
.INPUTS
|
||||
|
||||
None.
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
VirtualMachine. The cloned Hyper-V VM.
|
||||
#>
|
||||
}
|
||||
|
||||
# Vagrant VM configuration functions
|
||||
|
||||
function Set-VagrantVMMemory {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
|
||||
[parameter (Mandatory=$false)]
|
||||
[int] $Memory,
|
||||
[parameter (Mandatory=$false)]
|
||||
[int] $MaxMemory
|
||||
)
|
||||
|
||||
$ConfigMemory = Hyper-V\Get-VMMemory -VM $VM
|
||||
|
||||
if(!$Memory) {
|
||||
$MemoryStartupBytes = ($ConfigMemory.Startup)
|
||||
$MemoryMinimumBytes = ($ConfigMemory.Minimum)
|
||||
$MemoryMaximumBytes = ($ConfigMemory.Maximum)
|
||||
} else {
|
||||
$MemoryStartupBytes = $Memory * 1MB
|
||||
$MemoryMinimumBytes = $Memory * 1MB
|
||||
$MemoryMaximumBytes = $Memory * 1MB
|
||||
}
|
||||
|
||||
if($MaxMemory) {
|
||||
$DynamicMemory = $true
|
||||
$MemoryMaximumBytes = $MaxMemory * 1MB
|
||||
}
|
||||
|
||||
if($DynamicMemory) {
|
||||
Hyper-V\Set-VM -VM $VM -DynamicMemory
|
||||
Hyper-V\Set-VM -VM $VM -MemoryMinimumBytes $MemoryMinimumBytes -MemoryMaximumBytes `
|
||||
$MemoryMaximumBytes -MemoryStartupBytes $MemoryStartupBytes
|
||||
} else {
|
||||
Hyper-V\Set-VM -VM $VM -StaticMemory
|
||||
Hyper-V\Set-VM -VM $VM -MemoryStartupBytes $MemoryStartupBytes
|
||||
}
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Configure VM memory settings.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Adjusts the VM memory settings. If MaxMemory is defined, dynamic memory
|
||||
is enabled on the VM.
|
||||
|
||||
.PARAMETER VM
|
||||
|
||||
Hyper-V VM for modification.
|
||||
|
||||
.Parameter Memory
|
||||
|
||||
Memory to allocate to the given VM in MB.
|
||||
|
||||
.Parameter MaxMemory
|
||||
|
||||
Maximum memory to allocate to the given VM in MB. When this value is
|
||||
provided dynamic memory is enabled for the VM. The Memory value or
|
||||
the currently configured memory of the VM will be used as the minimum
|
||||
and startup memory value.
|
||||
|
||||
.Output
|
||||
|
||||
VirtualMachine.
|
||||
#>
|
||||
}
|
||||
|
||||
function Set-VagrantVMCPUS {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
|
||||
[parameter (Mandatory=$false)]
|
||||
[int] $CPUCount
|
||||
)
|
||||
|
||||
if($CPUCount) {
|
||||
Hyper-V\Set-VM -VM $VM -ProcessorCount $CPUCount
|
||||
}
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Configure VM CPU count.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Configure the number of CPUs on the given VM.
|
||||
|
||||
.PARAMETER VM
|
||||
|
||||
Hyper-V VM for modification.
|
||||
|
||||
.PARAMETER CPUCount
|
||||
|
||||
Number of CPUs.
|
||||
|
||||
.Output
|
||||
|
||||
VirtualMachine.
|
||||
#>
|
||||
}
|
||||
|
||||
function Set-VagrantVMVirtExtensions {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
|
||||
[parameter (Mandatory=$false)]
|
||||
[bool] $Enabled=$false
|
||||
)
|
||||
|
||||
Hyper-V\Set-VMProcessor -VM $VM -ExposeVirtualizationExtensions $Enabled
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Enable virtualization extensions on VM.
|
||||
|
||||
.PARAMETER VM
|
||||
|
||||
Hyper-V VM for modification.
|
||||
|
||||
.PARAMETER Enabled
|
||||
|
||||
Enable virtualization extensions on given VM.
|
||||
|
||||
.OUTPUT
|
||||
|
||||
VirtualMachine.
|
||||
#>
|
||||
}
|
||||
|
||||
function Set-VagrantVMAutoActions {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $AutoStartAction="Nothing",
|
||||
[parameter (Mandatory=$false)]
|
||||
[string] $AutoStopAction="ShutDown"
|
||||
)
|
||||
|
||||
Hyper-V\Set-VM -VM $VM -AutomaticStartAction $AutoStartAction
|
||||
Hyper-V\Set-VM -VM $VM -AutomaticStopAction $AutoStopAction
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Configure automatic start and stop actions for VM
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Configures the automatic start and automatic stop actions for
|
||||
the given VM.
|
||||
|
||||
.PARAMETER VM
|
||||
|
||||
Hyper-V VM for modification.
|
||||
|
||||
.PARAMETER AutoStartAction
|
||||
|
||||
Action the VM should automatically take when the host is started.
|
||||
|
||||
.PARAMETER AutoStopAction
|
||||
|
||||
Action the VM should automatically take when the host is stopped.
|
||||
|
||||
.OUTPUT
|
||||
|
||||
VirtualMachine.
|
||||
#>
|
||||
}
|
||||
|
||||
function Set-VagrantVMService {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $Name,
|
||||
[parameter (Mandatory=$true)]
|
||||
[bool] $Enable
|
||||
)
|
||||
|
||||
if($Enable) {
|
||||
Hyper-V\Enable-VMIntegrationService -VM $VM -Name $Name
|
||||
} else {
|
||||
Hyper-V\Disable-VMIntegrationService -VM $VM -Name $Name
|
||||
}
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Enable or disable Hyper-V VM integration services.
|
||||
|
||||
.PARAMETER VM
|
||||
|
||||
Hyper-V VM for modification.
|
||||
|
||||
.PARAMETER Name
|
||||
|
||||
Name of the integration service.
|
||||
|
||||
.PARAMETER Enable
|
||||
|
||||
Enable or disable the service.
|
||||
|
||||
.OUTPUT
|
||||
|
||||
VirtualMachine.
|
||||
#>
|
||||
}
|
||||
|
||||
# Vagrant networking functions
|
||||
|
||||
function Get-VagrantVMSwitch {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[string] $NameOrID
|
||||
)
|
||||
$SwitchName = $(Hyper-V\Get-VMSwitch -Id $NameOrID).Name
|
||||
if(!$SwitchName) {
|
||||
$SwitchName = $(Hyper-V\Get-VMSwitch -Name $NameOrID).Name
|
||||
}
|
||||
if(!$SwitchName) {
|
||||
throw "Failed to locate switch with name or ID: ${NameOrID}"
|
||||
}
|
||||
return $SwitchName
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Get name of VMSwitch.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Find VMSwitch by name or ID and return name.
|
||||
|
||||
.PARAMETER NameOrID
|
||||
|
||||
Name or ID of VMSwitch.
|
||||
|
||||
.OUTPUT
|
||||
|
||||
Name of VMSwitch.
|
||||
#>
|
||||
}
|
||||
|
||||
function Set-VagrantVMSwitch {
|
||||
param (
|
||||
[parameter (Mandatory=$true)]
|
||||
[Microsoft.HyperV.PowerShell.VirtualMachine] $VM,
|
||||
[parameter (Mandatory=$true)]
|
||||
[String] $SwitchName
|
||||
)
|
||||
$Adapter = Hyper-V\Get-VMNetworkAdapter -VM $VM
|
||||
Hyper-V\Connect-VMNetworkAdapter -VMNetworkAdapter $Adapter -SwitchName $SwitchName
|
||||
return $VM
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Configure VM to use given switch.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Configures VM adapter to use the the VMSwitch with the given name.
|
||||
|
||||
.PARAMETER VM
|
||||
|
||||
Hyper-V VM for modification.
|
||||
|
||||
.PARAMETER SwitchName
|
||||
|
||||
Name of the VMSwitch.
|
||||
|
||||
.OUTPUT
|
||||
|
||||
VirtualMachine.
|
||||
#>
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the MIT License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
function Write-Error-Message($message) {
|
||||
$error_message = @{
|
||||
error = "$message"
|
||||
}
|
||||
Write-Host "===Begin-Error==="
|
||||
$result = ConvertTo-json $error_message
|
||||
Write-Host $result
|
||||
Write-Host "===End-Error==="
|
||||
}
|
||||
|
||||
function Write-Output-Message($message) {
|
||||
Write-Host "===Begin-Output==="
|
||||
Write-Host $message
|
||||
Write-Host "===End-Output==="
|
||||
}
|
Loading…
Reference in New Issue