Functions/BloxOneDDI/Deploy-B1Appliance.ps1
function Deploy-B1Appliance { <# .SYNOPSIS Deploys a BloxOneDDI Virtual Appliance to VMware or Hyper-V .DESCRIPTION This function is used to deploy a BloxOneDDI Virtual Appliance to a VMware host/cluster or Hyper-V .PARAMETER Type The type of deployment to perform (VMware / Hyper-V) .PARAMETER Name The name of the virtual machine .PARAMETER IP The IP Address for the primary network interface of the virtual machine .PARAMETER Netmask The Netmask for the primary network interface of the virtual machine .PARAMETER Gateway The Gateway for the primary network interface of the virtual machine .PARAMETER DNSServers One or more DNS Servers for the virtual machine .PARAMETER NTPServers One or more NTP Servers for the virtual machine .PARAMETER DNSSuffix The DNS Suffix for the virtual machine .PARAMETER JoinToken The Join Token for registration of the BloxOneDDI Host into the Cloud Services Portal .PARAMETER OVAPath The path to the BloxOneDDI OVA Only used when -Type is VMware -OVAPath and -DownloadLatestImage are mutually exclusive. -ImagesPath should be used for selecting the appropriate image cache location. .PARAMETER vCenter The Hostname, IP or FQDN of the vCenter you want to deploy to Only used when -Type is VMware .PARAMETER Cluster The name of the cluster in vCenter Only used when -Type is VMware .PARAMETER Datastore The name of the cluster in Datastore Only used when -Type is VMware .PARAMETER PortGroupType The type of port group used for the virtual networks Only used when -Type is VMware .PARAMETER Creds The credentials used for connecting to vCenter. Only used when -Type is VMware .PARAMETER VHDPath The full path to the BloxOne VHD/VHDX file Only used when -Type is Hyper-V -VHDPath and -DownloadLatestImage are mutually exclusive. -ImagesPath should be used for selecting the appropriate image cache location. .PARAMETER HyperVServer The FQDN for the Hyper-V server where the BloxOne appliance will be deployed to Only used when -Type is Hyper-V .PARAMETER HyperVGeneration The generation of the Hyper-V VM to be created (1 or 2) Only used when -Type is Hyper-V .PARAMETER VMPath The VMPath parameter is used to define the base path for the VM to be created in. A folder will be created within this path with the VM name. Only used when -Type is Hyper-V .PARAMETER VirtualNetwork The VirtualNetwork parameter is used to define the name of the Virtual Network to connect the VM to. Only used when -Type is Hyper-V .PARAMETER VirtualNetworkVLAN The VirtualNetworkVLAN parameter is used to define the VLAN number to assign to the interface, if applicable. Only used when -Type is Hyper-V .PARAMETER CPU The CPU parameter is used to define the number of CPUs to assign to the VM. The default is 8. Only used when -Type is Hyper-V .PARAMETER Memory The Memory parameter is used to define the amount of memory to assign to the VM. The default is 16GB. Only used when -Type is Hyper-V .PARAMETER DownloadLatestImage Using this parameter will download the latest relevant image prior to deployment. -DownloadLatestImage, -OVAPath & -VHDPath are mutually exclusive. When -DownloadLatestImage is used in combination with -ImagesPath, the latest image will be downloaded to this location prior to deployment if it does not already exist. If used consistently, this will always deploy the latest image but only need to download it once; effectively caching. .PARAMETER ImagesPath Use this parameter to define the base path for images to be cached in when specifying the -DownloadLatestImage parameter. This cannot be used in conjunction with -OVAPath or -VHDPath .PARAMETER SkipCloudChecks Using this parameter will mean the deployment will not wait for the BloxOneDDI Host to become registered/available within the Cloud Services Portal .PARAMETER SkipPingChecks Using this parameter will skip ping checks during deployment, for cases where the deployment machine and host are separated by a device which blocks ICMP. NOTE: This will also skip checking of IP Addresses which are already in use. .PARAMETER SkipPowerOn Using this parameter will leave the VM in a powered off state once deployed .EXAMPLE PS> Deploy-B1Appliance -Type "VMware" ` -Name "bloxoneddihost1" -IP "10.10.100.10" ` -Netmask "255.255.255.0" ` -Gateway "10.10.100.1" ` -DNSServers "10.30.10.10,10.30.10.10" ` -NTPServers "time.mydomain.corp" ` -DNSSuffix "prod.mydomain.corp" ` -JoinToken "JoinTokenGoesHere" ` -ImagesPath .\Images ` -DownloadLatestImage ` -vCenter "vcenter.mydomain.corp" ` -Cluster "CLUSTER-001" ` -Datastore "DATASTORE-001" ` -PortGroup "PORTGROUP" ` -PortGroupType "VDS" .EXAMPLE PS> Deploy-B1Appliance -Type Hyper-V ` -Name "bloxoneddihost1" ` -IP 10.10.100.10 ` -Netmask 255.255.255.0 ` -Gateway 10.10.100.1 ` -DNSServers 10.10.100.1 ` -NTPServers ntp.ubuntu.com ` -DNSSuffix mydomain.corp ` -JoinToken "JoinTokenGoesHere" ` -VHDPath ".\BloxOne_OnPrem_VHDX_v3.8.1.vhdx" ` -HyperVServer "Host1.mycompany.corp" ` -HyperVGeneration 2 ` -VMPath "A:\VMs" ` -VirtualNetwork "Virtual Network 1" ` -VirtualNetworkVLAN 101 .FUNCTIONALITY BloxOneDDI .FUNCTIONALITY VMware .NOTES Credits: Ollie Sheridan - Assisted with development of the Hyper-V integration #> param( [Parameter(Mandatory=$true)] [ValidateSet("VMware","Hyper-V")] [String]$Type, [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$true)] [System.Object]$IP, [Parameter(Mandatory=$true)] [System.Object]$Netmask, [Parameter(Mandatory=$true)] [System.Object]$Gateway, [Parameter(Mandatory=$true)] [System.Object]$DNSServers = "52.119.40.100", [Parameter(Mandatory=$true)] [System.Object]$NTPServers, [Parameter(Mandatory=$true)] [System.Object]$DNSSuffix, [Parameter(Mandatory=$true)] [System.Object]$JoinToken, [Switch]$DownloadLatestImage, [String]$ImagesPath, [Switch]$SkipCloudChecks, [Switch]$SkipPingChecks, [Switch]$SkipPowerOn ) DynamicParam { switch($Type) { "VMware" { $OVAPathAttribute = New-Object System.Management.Automation.ParameterAttribute $OVAPathAttribute.Position = 1 $OVAPathAttribute.Mandatory = $false $OVAPathAttribute.HelpMessageBaseName = "OVAPath" $OVAPathAttribute.HelpMessage = "The OVAPath parameter is used to define the full path of the .ova image to deploy." $vCenterAttribute = New-Object System.Management.Automation.ParameterAttribute $vCenterAttribute.Position = 2 $vCenterAttribute.Mandatory = $true $vCenterAttribute.HelpMessageBaseName = "vCenter" $vCenterAttribute.HelpMessage = "The vCenter parameter is used to define the vCenter where the VM will be created." $ClusterAttribute = New-Object System.Management.Automation.ParameterAttribute $ClusterAttribute.Position = 3 $ClusterAttribute.Mandatory = $false $ClusterAttribute.HelpMessageBaseName = "Cluster" $ClusterAttribute.HelpMessage = "The Cluster parameter is used to define the Cluster the VM should be created in." $DatastoreAttribute = New-Object System.Management.Automation.ParameterAttribute $DatastoreAttribute.Position = 4 $DatastoreAttribute.Mandatory = $true $DatastoreAttribute.HelpMessageBaseName = "Datastore" $DatastoreAttribute.HelpMessage = "The Datastore parameter is used to define the name of the datastore to create the VM in." $PortGroupAttribute = New-Object System.Management.Automation.ParameterAttribute $PortGroupAttribute.Position = 5 $PortGroupAttribute.Mandatory = $true $PortGroupAttribute.HelpMessageBaseName = "PortGroup" $PortGroupAttribute.HelpMessage = "The PortGroup parameter is used to define the name of the port group to attach to the VM Network Interface(s)." $PortGroupTypeAttribute = New-Object System.Management.Automation.ParameterAttribute $PortGroupTypeAttribute.Position = 6 $PortGroupTypeAttribute.Mandatory = $true $PortGroupTypeAttribute.HelpMessageBaseName = "PortGroupType" $PortGroupTypeAttribute.HelpMessage = "The PortGroupType parameter is used to define the type of port group to use. (vDS / Standard)" $PortGroupTypeValidation = [System.Management.Automation.ValidateSetAttribute]::new("vDS","Standard") $CredsAttribute = New-Object System.Management.Automation.ParameterAttribute $CredsAttribute.Position = 7 $CredsAttribute.Mandatory = $true $CredsAttribute.HelpMessageBaseName = "Creds" $CredsAttribute.HelpMessage = "The Creds parameter is used to define the vCenter Credentials." $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($ParamItem in ($OVAPathAttribute,$vCenterAttribute,$ClusterAttribute,$DatastoreAttribute,$PortGroupAttribute,$PortGroupTypeAttribute,$CredsAttribute)) { $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttributeCollection.Add($ParamItem) if ($($ParamItem.HelpMessageBaseName -eq "Creds")) { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [pscredential], $AttributeCollection) } else { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [String], $AttributeCollection) } $paramDictionary.Add($($ParamItem.HelpMessageBaseName), $DefinedParam) } return $paramDictionary } "Hyper-V" { $VHDPathAttribute = New-Object System.Management.Automation.ParameterAttribute $VHDPathAttribute.Position = 1 $VHDPathAttribute.Mandatory = $false $VHDPathAttribute.HelpMessageBaseName = "VHDPath" $VHDPathAttribute.HelpMessage = "The VHDPath parameter is used to define the full path of the .vhd/.vhdx image to deploy." $HyperVServerAttribute = New-Object System.Management.Automation.ParameterAttribute $HyperVServerAttribute.Position = 2 $HyperVServerAttribute.Mandatory = $true $HyperVServerAttribute.HelpMessageBaseName = "HyperVServer" $HyperVServerAttribute.HelpMessage = "The HyperVServer parameter is used to define the FQDN of the Hyper-V Server to deploy the VM on." $HyperVGenerationAttribute = New-Object System.Management.Automation.ParameterAttribute $HyperVGenerationAttribute.Position = 3 $HyperVGenerationAttribute.Mandatory = $true $HyperVGenerationAttribute.HelpMessageBaseName = "HyperVGeneration" $HyperVGenerationAttribute.HelpMessage = "The HyperVGeneration parameter is used to define the Hyper-V generation of the VM to deploy (1 or 2)." $VMPathAttribute = New-Object System.Management.Automation.ParameterAttribute $VMPathAttribute.Position = 4 $VMPathAttribute.Mandatory = $true $VMPathAttribute.HelpMessageBaseName = "VMPath" $VMPathAttribute.HelpMessage = "The VMPath parameter is used to define the base path for the VM to be created in. A folder will be created within this path with the VM name." $VirtualNetworkAttribute = New-Object System.Management.Automation.ParameterAttribute $VirtualNetworkAttribute.Position = 5 $VirtualNetworkAttribute.Mandatory = $true $VirtualNetworkAttribute.HelpMessageBaseName = "VirtualNetwork" $VirtualNetworkAttribute.HelpMessage = "The VirtualNetwork parameter is used to define the Virtual Network to connect the VM to." $VirtualNetworkVLANAttribute = New-Object System.Management.Automation.ParameterAttribute $VirtualNetworkVLANAttribute.Position = 6 $VirtualNetworkVLANAttribute.Mandatory = $false $VirtualNetworkVLANAttribute.HelpMessageBaseName = "VirtualNetworkVLAN" $VirtualNetworkVLANAttribute.HelpMessage = "The VirtualNetworkVLAN parameter is used to define the name of the Virtual Network VLAN to connect the VM to (if applicable)." $CPUAttribute = New-Object System.Management.Automation.ParameterAttribute $CPUAttribute.Position = 7 $CPUAttribute.Mandatory = $false $CPUAttribute.HelpMessageBaseName = "CPU" $CPUAttribute.HelpMessage = "The CPU parameter is used to define the number of CPUs to assign to the VM. The default is 8." $MemoryAttribute = New-Object System.Management.Automation.ParameterAttribute $MemoryAttribute.Position = 8 $MemoryAttribute.Mandatory = $false $MemoryAttribute.HelpMessageBaseName = "Memory" $MemoryAttribute.HelpMessage = "The Memory parameter is used to define the amount of memory to assign to the VM. The default is 16GB." $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($ParamItem in ($VHDPathAttribute,$HyperVServerAttribute,$HyperVGenerationAttribute,$VMPathAttribute,$VirtualNetworkAttribute,$VirtualNetworkVLANAttribute,$CPUAttribute,$MemoryAttribute)) { $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttributeCollection.Add($ParamItem) if ($($ParamItem.HelpMessageBaseName -eq "CPU" -or $($ParamItem.HelpMessageBaseName) -eq "Memory")) { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [int64], $AttributeCollection) } else { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [String], $AttributeCollection) } $paramDictionary.Add($($ParamItem.HelpMessageBaseName), $DefinedParam) } return $paramDictionary } } } process { if (!($SkipPingChecks)) { if ((Test-NetConnection $IP -WarningAction SilentlyContinue -ErrorAction SilentlyContinue).PingSucceeded) { Write-Error "Error. IP Address already in use." break } } if ($DownloadLatestImage) { Write-Host "-DownloadLatestImage is selected. The latest BloxOne image will be used." -ForegroundColor Cyan if ($PSBoundParameters['OVAPath'] -or $PSBoundParameters['VHDPath']) { Write-Error "-DownloadLatestImage cannot be used in conjunction with -OVAPath or -VHDPath" } if ($ImagesPath) { Write-Host "-ImagesPath is selected. Collecting existing cached images.." -ForegroundColor Cyan if (!(Test-Path $ImagesPath)) { Write-Host "-ImagesPath: $($ImagesPath) does not exist. Attempting to create it.." -ForegroundColor Yellow if ($ImagesDir = New-Item -Type Directory $ImagesPath) { Write-Host "Successfully created $($ImagesPath)" -ForegroundColor Cyan $CurrentImages = Get-ChildItem $ImagesPath } else { Write-Error "Error. Failed to create -ImagesPath: $($ImagesPath)" } } else { $CurrentImages = Get-ChildItem $ImagesPath } } else { Write-Host "-ImagesPath not set. Downloaded images will not be cached." -ForegroundColor Yellow } $Images = Get-B1Object -Product 'Bloxone Cloud' -App BootstrapApp -Endpoint /images switch ($Type) { "VMware" { $Image = $Images | Where-Object {$_.desc -like "*OVA"} } "Hyper-V" { switch($PSBoundParameters['HyperVGeneration']) { 1 { $Image = $Images | Where-Object {$_.desc -like "*Azure/HyperV"} } 2 { $Image = $Images | Where-Object {$_.desc -like "*Hyper-V Gen 2"} } } } } if ($Image) { $($Image.link) -match "^.*\/(.*)$" | Out-Null if ($Matches) { $ImageFileName = $Matches[1] if ($ImagesPath) { if (!(Test-Path "$($ImagesPath)\$($ImageFileName)")) { Write-Host "Downloading latest image: $($ImageFileName).." -ForegroundColor Cyan Invoke-WebRequest -Method GET -Uri $($Image.link) -OutFile "$($ImagesPath)\$($ImageFileName)" } else { Write-Host "Latest image already downloaded: $($ImageFileName)" -ForegroundColor Cyan } $ImageFile = "$($ImagesPath)\$($ImageFileName)" } else { if (!(Test-Path "$($ImageFileName)")) { Write-Host "Downloading latest image: $($ImageFileName).." -ForegroundColor Cyan Invoke-WebRequest -Method GET -Uri $($Image.link) -OutFile "$($ImageFileName)" } else { Write-Host "Latest image already downloaded: $($ImageFileName)" -ForegroundColor Cyan } $ImageFile = "$($ImageFileName)" } } else { Write-Error "Error. Failed to identify image name." } } else { Write-Error "Error. Failed to find image." } } switch($Type) { "VMware" { if (!($DownloadLatestImage)) { if (!($PSBoundParameters['OVAPath'])) { Write-Error "-OVAPath must be specified if -DownloadLatestImage is not used." } else { $ImageFile = $PSBoundParameters['OVAPath'] } } Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false if (Connect-VIServer -Server $($PSBoundParameters['vCenter']) -Credential $($PSBoundParameters['Creds'])) { Write-Host "Connected to vCenter $($PSBoundParameters['vCenter']) successfully." -ForegroundColor Green } else { Write-Error "Failed to establish session with vCenter $($PSBoundParameters['vCenter'])." break } $VMCluster = Get-Cluster $($PSBoundParameters['Cluster']) -ErrorAction SilentlyContinue $VMHost = $VMCluster | Get-VMHost -State "Connected" | Select-Object -First 1 if (!($VMCluster)) { Write-Error "Error. Failed to get VM Cluster, please check details and try again." break } if (!($Datastore = Get-Datastore $($PSBoundParameters['Datastore']) -ErrorAction SilentlyContinue)) { Write-Error "Error. Failed to get VM Datastore, please check details and try again." break } switch($($PSBoundParameters['PortGroupType'])) { "vDS" { $NetworkMapping = Get-vDSwitch -VMHost $VMHost | Get-VDPortGroup $($PSBoundParameters['PortGroup']) if (!($NetworkMapping)) { Write-Error "Error. Failed to get vDS Port Group, please check details and try again." break } else { $NetworkMapping = Get-vDSwitch -VMHost $VMHost | Get-VDPortGroup $($PSBoundParameters['PortGroup']) } } "Standard" { $NetworkMapping = Get-VirtualSwitch -VMHost $VMHost | Get-VirtualPortGroup -Name $($PSBoundParameters['PortGroup']) if (!($NetworkMapping)) { Write-Error "Error. Failed to get Virtual Port Group, please check details and try again." break } else { } } "Default" { Write-Error "Invalid Port Group Type specified. Must be either `"vDS`" or `"Standard`"" break } } if (!(Test-Path $($ImageFile))) { Write-Error "Error. OVA $($ImageFile) not found." break } else { $OVFConfig = Get-OvfConfiguration -Ovf $($ImageFile) } if (Get-VM -Name $Name -ErrorAction SilentlyContinue) { Write-Host "VM Already exists. Skipping.." -ForegroundColor Yellow } else { if ($OVFConfig) { Write-Host "Generating OVFConfig file for BloxOne Appliance: $Name .." -ForegroundColor Cyan $OVFConfig.Common.address.Value = $IP $OVFConfig.Common.gateway.Value = $Gateway $OVFConfig.Common.netmask.Value = $Netmask $OVFConfig.Common.nameserver.Value = $DNSServers $OVFConfig.Common.ntp_servers.Value = $NTPServers $OVFConfig.Common.jointoken.Value = $JoinToken $OVFConfig.Common.search.Value = $DNSSuffix $OVFConfig.Common.v4_mode.Value = "static" $OVFConfig.NetworkMapping.lan.Value = $NetworkMapping } else { Write-Error "Error. Unable to retrieve OVF Configuration from $($ImageFile)." } Write-Host "Deploying BloxOne Appliance: $Name .." -ForegroundColor Cyan $VM = Import-VApp -OvfConfiguration $OVFConfig -Source $($ImageFile) -Name $Name -VMHost $VMHost -Datastore $Datastore -Force if ($VM) { Write-Host "Successfully deployed BloxOne Appliance: $Name" -ForegroundColor Green if ($Debug) {$VM | Format-Table -AutoSize} if (!($SkipPowerOn)) { Write-Host "Powering on $Name.." -ForegroundColor Cyan $VMStart = Start-VM -VM $VM $VMStartCount = 0 while ((Get-VM -Name $Name).PowerState -ne "PoweredOn") { Write-Host "Waiting for VM to start. Elapsed Time: $VMStartCount`s" -ForegroundColor Gray Wait-Event -Timeout 10 $VMStartCount = $VMStartCount + 10 if ($VMStartCount -gt 120) { Write-Error "Error. VM Failed to start." break } } } } Disconnect-VIServer * -Confirm:$false -Force Write-Host "Disconnected from vCenters." -ForegroundColor Gray } } "Hyper-V" { if (!($DownloadLatestImage)) { if (!($PSBoundParameters['VHDPath'])) { Write-Error "-VHDPath must be specified if -DownloadLatestImage is not used." } else { $ImageFile = $PSBoundParameters['VHDPath'] } } Write-Host "Generating customization metadata" -ForegroundColor Cyan $VMMetadata = New-B1Metadata -IP $IP -Netmask $Netmask -Gateway $Gateway -DNSServers $DNSServers -JoinToken $JoinToken -DNSSuffix $DNSSuffix if ($VMMetadata) { Write-Host "Customization metadata generated successfully." -ForegroundColor Cyan } else { Write-Error "Failed to generate customization metadata" } if (Test-Path 'work-dir') { Remove-Item -Path "work-dir" -Recurse } New-Item -Type Directory -Name "work-dir" | Out-Null New-Item -Type Directory -Name "work-dir/cloud-init" | Out-Null New-Item -Path "work-dir/cloud-init/user-data" -Value $VMMetadata.userdata | Out-Null New-Item -Path "work-dir/cloud-init/network-config" -Value $VMMetadata.network | Out-Null New-Item -Path "work-dir/cloud-init/meta-data" -Value $VMMetadata.metadata | Out-Null Write-Host "Creating configuration metadata ISO" -ForegroundColor Cyan $MetadataISO = New-ISOFile -Source "work-dir/cloud-init/" -Destination "work-dir/metadata.iso" -VolumeName "CIDATA" if (!(Test-Path "work-dir/metadata.iso")) { Write-Error "Error. Failed to create customization ISO." } else { Write-Host "Successfully created customization ISO." -ForegroundColor Cyan } if (!($PSBoundParameters['Memory'])) { [int64]$Memory = 16GB } else { $Memory = $PSBoundParameters['Memory'] } if (!($PSBoundParameters['CPU'])) { [int64]$CPU = 8 } else { $CPU = $PSBoundParameters['CPU'] } Write-Host "Deploying BloxOne Appliance: $Name .." -ForegroundColor Cyan $VM = New-VM -Name $Name -NoVHD -Generation $($PSBoundParameters['HyperVGeneration']) -MemoryStartupBytes $Memory -SwitchName $($PSBoundParameters['VirtualNetwork']) -ComputerName $($PSBoundParameters['HyperVServer']) -Path $($PSBoundParameters['VMPath']) if ($VM) { Write-Host "Configuring VM Resources.." -ForegroundColor Cyan Set-VM -Name $Name -ProcessorCount $CPU -ComputerName $($PSBoundParameters['HyperVServer']) -CheckpointType Disabled if ($($PSBoundParameters['VirtualNetworkVLAN'])) { Write-Host "Configuring Virtual Network VLAN.." -ForegroundColor Cyan Set-VMNetworkAdapterVlan -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']) -VlanId $($PSBoundParameters['VirtualNetworkVLAN']) -Access } $OsDiskInfo = Get-Item $($ImageFile) $RemoteBasePath = $($PSBoundParameters['VMPath']) -replace "`:","$" if (!(Test-Path "\\$($PSBoundParameters['HyperVServer'])\$($RemoteBasePath)\$($Name)\Virtual Hard Disks")) { Write-Host "Preparing VM folders.." -ForegroundColor Cyan New-Item "\\$($PSBoundParameters['HyperVServer'])\$($RemoteBasePath)\$($Name)\Virtual Hard Disks" -ItemType Directory | Out-Null } switch ($($PSBoundParameters['HyperVGeneration'])) { 1 { $VHDExtension = "vhd" } 2 { $VHDExtension = "vhdx" } } if ([System.IO.Path]::GetExtension($($ImageFile)) -ne ".$($VHDExtension)") { switch($PSBoundParameters['HyperVGeneration']) { 1 { Write-Error "Error. You must use a .vhd file format for Generation 1 Hyper-V VMs." } 2 { Write-Error "Error. You must use a .vhdx file format for Generation 2 Hyper-V VMs." } } } Write-Host "Copying $($VHDExtension).." -ForegroundColor Cyan Copy-Item -Path $OsDiskInfo -Destination "\\$($PSBoundParameters['HyperVServer'])\$($RemoteBasePath)\$($Name)\\Virtual Hard Disks\$($Name).$($VHDExtension)" | Out-Null Write-Host "Copying Metadata ISO.." -ForegroundColor Cyan Copy-Item -Path "work-dir/metadata.iso" -Destination "\\$($PSBoundParameters['HyperVServer'])\$($RemoteBasePath)\$($Name)\Virtual Hard Disks\$($Name)-metadata.iso" | Out-Null if (!(Get-VMHardDiskDrive -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']))) { Write-Host "Attaching $($VHDExtension).." -ForegroundColor Cyan Add-VMHardDiskDrive -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']) -Path "$($PSBoundParameters['VMPath'])\$($Name)\Virtual Hard Disks\$($Name).$($VHDExtension)" } Write-Host "Attaching Metadata ISO.." -ForegroundColor Cyan if (!(Get-VMDvdDrive -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']))) { Add-VMDvdDrive -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']) -Path "$($PSBoundParameters['VMPath'])\$($Name)\Virtual Hard Disks\$($Name)-metadata.iso" } else { Set-VMDvdDrive -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']) -Path "$($PSBoundParameters['VMPath'])\$($Name)\Virtual Hard Disks\$($Name)-metadata.iso" } Write-Host "Resizing $($VHDExtension).." -ForegroundColor Cyan if (Get-VHD -Path "$($PSBoundParameters['VMPath'])\$($Name)\Virtual Hard Disks\$($Name).$($VHDExtension)" -ComputerName $($PSBoundParameters['HyperVServer'])) { Resize-VHD -Path "$($PSBoundParameters['VMPath'])\$($Name)\Virtual Hard Disks\$($Name).$($VHDExtension)" -ComputerName $($PSBoundParameters['HyperVServer']) -SizeBytes 60GB } if ($PSBoundParameters['HyperVGeneration'] -eq 2) { Write-Host "Configuring Secure Boot.." -ForegroundColor Cyan Set-VMFirmware -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']) -EnableSecureBoot On -SecureBootTemplate MicrosoftUEFICertificateAuthority -BootOrder (Get-VMHardDiskDrive -ComputerName $($PSBoundParameters['HyperVServer']) -VMName $Name),(Get-VMDvdDrive -ComputerName $($PSBoundParameters['HyperVServer']) -VMName $Name) } if (!($SkipPowerOn)) { Write-Host "Powering on $Name.." -ForegroundColor Cyan $VMStart = Start-VM -Name $Name -ComputerName $($PSBoundParameters['HyperVServer']) $VMStartCount = 0 while ((Get-VM -Name $Name -ComputerName $($PSBoundParameters['HyperVServer'])).State -ne "Running") { Write-Host "Waiting for VM to start. Elapsed Time: $VMStartCount`s" -ForegroundColor Gray Wait-Event -Timeout 10 $VMStartCount = $VMStartCount + 10 if ($VMStartCount -gt 120) { Write-Error "Error. VM Failed to start." break } } } } } } if ($VM) { if (!($SkipPowerOn)) { if (!($SkipPingChecks)) { while (!(Test-NetConnection $IP -WarningAction SilentlyContinue -ErrorAction SilentlyContinue).PingSucceeded) { $PingStartCount = $PingStartCount + 10 Write-Host "Waiting for network to become reachable. Elapsed Time: $PingStartCount`s" -ForegroundColor Gray Wait-Event -Timeout 10 if ($PingStartCount -gt 120) { Write-Error "Error. Network Failed to become reachable on $IP." break } } } if (!($SkipCloudChecks)) { while (!(Get-B1Host -IP $IP)) { $CSPStartCount = $CSPStartCount + 10 Write-Host "Waiting for BloxOne Appliance to become registered within BloxOne CSP. Elapsed Time: $CSPStartCount`s" -ForegroundColor Gray Wait-Event -Timeout 10 if ($CSPStartCount -gt 120) { Write-Error "Error. VM failed to register with the BloxOne CSP. Please check VM Console for details." $Failed = $true break } } } if ($Type -eq "Hyper-V") { Set-VMDvdDrive -VMName $Name -ComputerName $($PSBoundParameters['HyperVServer']) -Path $null ## Cleanup metadata ISO } if (!$Failed) { Write-Host "BloxOne Appliance is now available, check the CSP portal for registration of the device" -ForegroundColor Gray if (!($SkipCloudChecks)) { Get-B1Host -IP $IP | Format-Table display_name,ip_address,host_version -AutoSize } Write-Host "BloxOne Appliance deployed successfully." -ForegroundColor Green } else { Write-Error "Failed to deploy BloxOne Appliance." } } else { Write-Host "BloxOne Appliance deployed successfully." -ForegroundColor Green } } else { Write-Error "Failed to deploy BloxOne Appliance." break } if (Test-Path 'work-dir') { Remove-Item -Path "work-dir" -Recurse } ## Cleanup work directory } } |