Functions/BloxOne/BloxOnePlatform/Deploy-B1Appliance.ps1
function Deploy-B1Appliance { <# .SYNOPSIS Deploys a BloxOneDDI Virtual Appliance to VMware, Hyper-V or Azure. .DESCRIPTION This function is used to deploy a BloxOneDDI Virtual Appliance to a VMware host/cluster, Hyper-V or Azure. .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 Only used when -Type is VMware or Hyper-V .PARAMETER Netmask The Netmask for the primary network interface of the virtual machine Only used when -Type is VMware or Hyper-V .PARAMETER Gateway The Gateway for the primary network interface of the virtual machine Only used when -Type is VMware or Hyper-V .PARAMETER DNSServers One or more DNS Servers for the virtual machine Only used when -Type is VMware or Hyper-V .PARAMETER NTPServers One or more NTP Servers for the virtual machine Only used when -Type is VMware or Hyper-V .PARAMETER DNSSuffix The DNS Suffix for the virtual machine Only used when -Type is VMware or Hyper-V .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 VMHost The name of the host in vCenter to deploy the VM to Only used when -Type is VMware .PARAMETER Datastore The name of the cluster in Datastore Only used when -Type is VMware .PARAMETER PortGroup The name of the port group to connect the VM's network adapters to 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 AzTenant The AzTenant parameter is used to define the Azure Tenant ID to connect to during deployment. Only used when -Type is Azure .PARAMETER AzSubscription The AzSubscription parameter is used to define the Azure Subscription ID to connect to during deployment. Only used when -Type is Azure .PARAMETER AzLocation The AzLocation parameter is used to define the Azure Location to deploy the new VM to. Only used when -Type is Azure .PARAMETER AzResourceGroup The AzResourceGroup parameter is used to define the Azure Resource Group to deploy the new VM in. Only used when -Type is Azure .PARAMETER AzVirtualNetwork The AzVirtualNetwork parameter is used to define the Azure Virtual Network to deploy the new VM in. Only used when -Type is Azure .PARAMETER AzSubnet The AzSubnet parameter is used to define the Subnet in the selected Azure Virtual Network to deploy the new VM in. Only used when -Type is Azure .PARAMETER AzOffer The AzOffer parameter is used to define the Azure Marketplace Image Offer to deploy the new VM with. Only used when -Type is Azure .PARAMETER AzSku The AzSku parameter is used to define the Azure Marketplace Image SKU to deploy the new VM with. Only used when -Type is Azure .PARAMETER AzSize The AzSize parameter is used to define the Azure VM Size to use when deploying the new VM. Only used when -Type is Azure .PARAMETER AzAcceptTerms The AzAcceptTerms parameter is used to accept the marketplace terms required when deploying a BloxOne DDI Host. Only used when -Type is Azure .PARAMETER AzBootDiagnostics The AzBootDiagnostics parameter is used to enable Boot Diagnostics for the VM during build. This features requires a storage account be specified using -AzStorageAccount. Only used when -Type is Azure .PARAMETER AzStorageAccount The AzStorageAccount is used to define the name of the storage account to use for Boot Diagnostics. This must be in the same Azure Resource Group and is only available when -AzBootDiagnostics is specified. Only used when -Type is Azure and when -AzBootDiagnostics is specified. .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 CloudCheckTimeout The duration of time allowed for the B1 Host to register with the Cloud Services Portal before timing out. This defaults to 300s (5 Minutes) .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 .PARAMETER Force Perform the operation without prompting for confirmation. By default, this function will not prompt for confirmation unless $ConfirmPreference is set to Medium. .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.20.10" ` -NTPServers "time.mydomain.corp","time2.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 .EXAMPLE PS> Deploy-B1Appliance -Type "Azure" ` -Name "bloxoneddihost1" ` -JoinToken "JoinTokenGoesHere" ` -AzTenant 'g54gdeg5-gdf4-4434-dff4-7fdeswgf54ff' ` -AzSubscription '1234d123-abc1-4f33-r43f-5gredgrgdsdv4' ` -AzLocation 'UK South' ` -AzOffer 'infoblox-bloxone-34' ` -AzSku 'infoblox-bloxone' ` -AzResourceGroup 'rg-infoblox' ` -AzVirtualNetwork 'infoblox_vnet' ` -AzSubnet 'infoblox_snet' ` -AzSize 'Standard_F8s_v2' ` -AzBootDiagnostics ` -AzStorageAccount 'ibbootdiags' ` -AzAcceptTerms .FUNCTIONALITY BloxOneDDI .FUNCTIONALITY VMware .FUNCTIONALITY Hyper-V .FUNCTIONALITY Azure .NOTES Credits: Ollie Sheridan - Assisted with development of the Hyper-V integration #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification='Required to generate random dummy Azure SSH Credentials.')] [CmdletBinding( SupportsShouldProcess, ConfirmImpact = 'Medium' )] param( [Parameter(Mandatory=$true)] [ValidateSet("VMware","Hyper-V","Azure")] [String]$Type, [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$true)] [String]$JoinToken, [Parameter(Mandatory=$false)] [Int]$CloudCheckTimeout = 300, [Parameter(Mandatory=$false)] [Switch]$SkipCloudChecks, [Parameter(Mandatory=$false)] [Switch]$SkipPingChecks, [Switch]$Force ) DynamicParam { $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary ## Define Common Parameters if ($Type -in @('VMware','Hyper-V')) { $IPAttribute = New-Object System.Management.Automation.ParameterAttribute $IPAttribute.Position = 1 $IPAttribute.Mandatory = $true $IPAttribute.HelpMessageBaseName = "IP" $IPAttribute.HelpMessage = "The IP Address for the primary network interface of the virtual machine being deployed. Only used when -Type is VMware or Hyper-V." $NetmaskAttribute = New-Object System.Management.Automation.ParameterAttribute $NetmaskAttribute.Position = 2 $NetmaskAttribute.Mandatory = $true $NetmaskAttribute.HelpMessageBaseName = "Netmask" $NetmaskAttribute.HelpMessage = "The Subnet Mask for the primary network interface of the virtual machine being deployed. Only used when -Type is VMware or Hyper-V." $GatewayAttribute = New-Object System.Management.Automation.ParameterAttribute $GatewayAttribute.Position = 3 $GatewayAttribute.Mandatory = $true $GatewayAttribute.HelpMessageBaseName = "Gateway" $GatewayAttribute.HelpMessage = "The Gateway IP Address for the primary network interface of the virtual machine being deployed. Only used when -Type is VMware or Hyper-V." $DNSServersAttribute = New-Object System.Management.Automation.ParameterAttribute $DNSServersAttribute.Position = 4 $DNSServersAttribute.Mandatory = $true $DNSServersAttribute.HelpMessageBaseName = "DNSServers" $DNSServersAttribute.HelpMessage = "A list of DNS Servers for the primary network interface of the virtual machine being deployed. Only used when -Type is VMware or Hyper-V." $NTPServersAttribute = New-Object System.Management.Automation.ParameterAttribute $NTPServersAttribute.Position = 5 $NTPServersAttribute.Mandatory = $true $NTPServersAttribute.HelpMessageBaseName = "NTPServers" $NTPServersAttribute.HelpMessage = "A list of NTP Servers for the virtual machine being deployed. Only used when -Type is VMware or Hyper-V." $DNSSuffixAttribute = New-Object System.Management.Automation.ParameterAttribute $DNSSuffixAttribute.Position = 6 $DNSSuffixAttribute.Mandatory = $true $DNSSuffixAttribute.HelpMessageBaseName = "DNSSuffix" $DNSSuffixAttribute.HelpMessage = "The DNS Suffix for the primary network interface of the virtual machine being deployed. Only used when -Type is VMware or Hyper-V." $DownloadLatestImageAttribute = New-Object System.Management.Automation.ParameterAttribute $DownloadLatestImageAttribute.Position = 7 $DownloadLatestImageAttribute.Mandatory = $false $DownloadLatestImageAttribute.HelpMessageBaseName = "DownloadLatestImage" $DownloadLatestImageAttribute.HelpMessage = "Using -DownloadLatestImage will download the latest BloxOne image prior to deployment. Only used when -Type is VMware or Hyper-V." $ImagesPathAttribute = New-Object System.Management.Automation.ParameterAttribute $ImagesPathAttribute.Position = 8 $ImagesPathAttribute.Mandatory = $false $ImagesPathAttribute.HelpMessageBaseName = "ImagesPath" $ImagesPathAttribute.HelpMessage = "Specify a path for cached BloxOne images to be stored when combined with -DownloadLatestImage. Only used when -Type is VMware or Hyper-V." $SkipPowerOnAttribute = New-Object System.Management.Automation.ParameterAttribute $SkipPowerOnAttribute.Position = 9 $SkipPowerOnAttribute.Mandatory = $false $SkipPowerOnAttribute.HelpMessageBaseName = "SkipPowerOn" $SkipPowerOnAttribute.HelpMessage = "Using this parameter will leave the VM in a powered off state once deployed. Only used when -Type is VMware or Hyper-V." foreach ($ParamItem in ($IPAttribute,$NetmaskAttribute,$GatewayAttribute,$DNSServersAttribute,$NTPServersAttribute,$DNSSuffixAttribute,$DownloadLatestImageAttribute,$ImagesPathAttribute,$SkipPowerOnAttribute)) { $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttributeCollection.Add($ParamItem) Switch($ParamItem.HelpMessageBaseName) { {$_ -in @('DownloadLatestImage','SkipPowerOn')} { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [Switch], $AttributeCollection) } {$_ -in @('IP','Gateway')} { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [IPAddress], $AttributeCollection) } 'NTPServers' { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [String[]], $AttributeCollection) } 'DNSServers' { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [IPAddress[]], $AttributeCollection) } Default { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [String], $AttributeCollection) } } $paramDictionary.Add($($ParamItem.HelpMessageBaseName), $DefinedParam) } } ## Define Deployment Specific Parameters 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." $VMHostAttribute = New-Object System.Management.Automation.ParameterAttribute $VMHostAttribute.Position = 4 $VMHostAttribute.Mandatory = $false $VMHostAttribute.HelpMessageBaseName = "VMHost" $VMHostAttribute.HelpMessage = "The VMHost parameter is used to define the Host the VM should be created on." $DatastoreAttribute = New-Object System.Management.Automation.ParameterAttribute $DatastoreAttribute.Position = 5 $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 = 6 $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 = 7 $PortGroupTypeAttribute.Mandatory = $true $PortGroupTypeAttribute.HelpMessageBaseName = "PortGroupType" $PortGroupTypeAttribute.HelpMessage = "The PortGroupType parameter is used to define the type of port group to use. (vDS / Standard)" $CredsAttribute = New-Object System.Management.Automation.ParameterAttribute $CredsAttribute.Position = 8 $CredsAttribute.Mandatory = $true $CredsAttribute.HelpMessageBaseName = "Creds" $CredsAttribute.HelpMessage = "The Creds parameter is used to define the vCenter Credentials." foreach ($ParamItem in ($OVAPathAttribute,$vCenterAttribute,$ClusterAttribute,$VMHostAttribute,$DatastoreAttribute,$PortGroupAttribute,$PortGroupTypeAttribute,$CredsAttribute)) { $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttributeCollection.Add($ParamItem) if ($($ParamItem.HelpMessageBaseName -eq "PortGroupType")) { $AttributeCollection.Add((New-Object System.Management.Automation.ValidateSetAttribute("vDS","Standard"))) } 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) } } "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." 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) } } "Azure" { $AzTenantAttribute = New-Object System.Management.Automation.ParameterAttribute $AzTenantAttribute.Position = 1 $AzTenantAttribute.Mandatory = $true $AzTenantAttribute.HelpMessageBaseName = "AzTenant" $AzTenantAttribute.HelpMessage = "The AzTenant parameter is used to define the Azure Tenant ID to connect to during deployment." $AzSubscriptionAttribute = New-Object System.Management.Automation.ParameterAttribute $AzSubscriptionAttribute.Position = 2 $AzSubscriptionAttribute.Mandatory = $true $AzSubscriptionAttribute.HelpMessageBaseName = "AzSubscription" $AzSubscriptionAttribute.HelpMessage = "The AzSubscription parameter is used to define the Azure Subscription ID to connect to during deployment." $AzLocationAttribute = New-Object System.Management.Automation.ParameterAttribute $AzLocationAttribute.Position = 3 $AzLocationAttribute.Mandatory = $true $AzLocationAttribute.HelpMessageBaseName = "AzLocation" $AzLocationAttribute.HelpMessage = "The AzLocation parameter is used to define the Azure Location to deploy the new VM to." $AzResourceGroupAttribute = New-Object System.Management.Automation.ParameterAttribute $AzResourceGroupAttribute.Position = 4 $AzResourceGroupAttribute.Mandatory = $true $AzResourceGroupAttribute.HelpMessageBaseName = "AzResourceGroup" $AzResourceGroupAttribute.HelpMessage = "The AzResourceGroup parameter is used to define the Azure Resource Group to deploy the new VM in." $AzVirtualNetworkAttribute = New-Object System.Management.Automation.ParameterAttribute $AzVirtualNetworkAttribute.Position = 5 $AzVirtualNetworkAttribute.Mandatory = $true $AzVirtualNetworkAttribute.HelpMessageBaseName = "AzVirtualNetwork" $AzVirtualNetworkAttribute.HelpMessage = "The AzVirtualNetwork parameter is used to define the Azure Virtual Network to deploy the new VM in." $AzSubnetAttribute = New-Object System.Management.Automation.ParameterAttribute $AzSubnetAttribute.Position = 5 $AzSubnetAttribute.Mandatory = $true $AzSubnetAttribute.HelpMessageBaseName = "AzSubnet" $AzSubnetAttribute.HelpMessage = "The AzSubnet parameter is used to define the Subnet in the selected Azure Virtual Network to deploy the new VM in." $AzOfferAttribute = New-Object System.Management.Automation.ParameterAttribute $AzOfferAttribute.Position = 6 $AzOfferAttribute.Mandatory = $true $AzOfferAttribute.HelpMessageBaseName = "AzOffer" $AzOfferAttribute.HelpMessage = "The AzOffer parameter is used to define the Azure Marketplace Image Offer to deploy the new VM with." $AzSkuAttribute = New-Object System.Management.Automation.ParameterAttribute $AzSkuAttribute.Position = 7 $AzSkuAttribute.Mandatory = $true $AzSkuAttribute.HelpMessageBaseName = "AzSku" $AzSkuAttribute.HelpMessage = "The AzSku parameter is used to define the Azure Marketplace Image SKU to deploy the new VM with." $AzSizeAttribute = New-Object System.Management.Automation.ParameterAttribute $AzSizeAttribute.Position = 8 $AzSizeAttribute.Mandatory = $true $AzSizeAttribute.HelpMessageBaseName = "AzSize" $AzSizeAttribute.HelpMessage = "The AzSize parameter is used to define the Azure VM Size to use when deploying the new VM." $AzAcceptTermsAttribute = New-Object System.Management.Automation.ParameterAttribute $AzAcceptTermsAttribute.Position = 9 $AzAcceptTermsAttribute.Mandatory = $false $AzAcceptTermsAttribute.HelpMessageBaseName = "AzAcceptTerms" $AzAcceptTermsAttribute.HelpMessage = "The AzAcceptTerms parameter is used to accept the marketplace terms required when deploying a BloxOne DDI Host." $AzBootDiagnosticsAttribute = New-Object System.Management.Automation.ParameterAttribute $AzBootDiagnosticsAttribute.Position = 10 $AzBootDiagnosticsAttribute.Mandatory = $false $AzBootDiagnosticsAttribute.HelpMessageBaseName = "AzBootDiagnostics" $AzBootDiagnosticsAttribute.HelpMessage = "The AzBootDiagnostics parameter is used to enable Boot Diagnostics for the VM during build. This features requires a storage account be specified using -AzStorageAccount." $AzStorageAccountAttribute = New-Object System.Management.Automation.ParameterAttribute $AzStorageAccountAttribute.Position = 11 $AzStorageAccountAttribute.Mandatory = $false $AzStorageAccountAttribute.HelpMessageBaseName = "AzStorageAccount" $AzStorageAccountAttribute.HelpMessage = "The AzStorageAccount is used to define the name of the storage account to use for Boot Diagnostics. This is only used when -AzBootDiagnostics is specified." foreach ($ParamItem in ($AzTenantAttribute,$AzSubscriptionAttribute,$AzLocationAttribute,$AzOfferAttribute,$AzSkuAttribute,$AzResourceGroupAttribute,$AzVirtualNetworkAttribute,$AzSubnetAttribute,$AzSizeAttribute,$AzAcceptTermsAttribute,$AzBootDiagnosticsAttribute,$AzStorageAccountAttribute)) { $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttributeCollection.Add($ParamItem) Switch($ParamItem.HelpMessageBaseName) { {$_ -in @('AzAcceptTerms','AzBootDiagnostics')} { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [switch], $AttributeCollection) } Default { $DefinedParam = New-Object System.Management.Automation.RuntimeDefinedParameter($($ParamItem.HelpMessageBaseName), [String], $AttributeCollection) } } $paramDictionary.Add($($ParamItem.HelpMessageBaseName), $DefinedParam) } } } return $paramDictionary } process { $ConfirmPreference = Confirm-ShouldProcess $PSBoundParameters $ShouldProcess = $true $CurrentOS = Detect-OS switch ($Type) { "VMware" { if (!(Get-Module -ListAvailable -Name VMware.PowerCLI -ErrorAction SilentlyContinue -WarningAction SilentlyContinue)) { Write-Error "You must have the VMware PowerCLI Module installed to deploy to vCenter / ESXi." return $null } } "Hyper-V" { if (($CurrentOS) -eq "Windows") { if ((Get-WindowsFeature -Name "Hyper-V-PowerShell").'InstallState' -ne "Installed") { Write-Error "You must have the Hyper-V PowerShell Module installed to deploy to Hyper-V." return $null } } else { Write-Error "You must be running ibPS on Windows to deploy to Hyper-V" return $null } } "Azure" { $MissingPackages = @() #,'Az.Resources' @('Az.Accounts','Az.Compute','Az.Network','Az.MarketplaceOrdering') | ForEach-Object { if (!(Get-Module -ListAvailable -Name $_)) { $MissingPackages += $_ } } if ($MissingPackages) { Write-Error 'You must have the following PowerShell Modules installed to deploy to Azure.' $($MissingPackages -split ',') Write-Error "You can install them using this command: Install-Module -Name $($MissingPackages -join ',')" return $null } $SkipPingChecks = $true } } if (!($SkipPingChecks)) { if ($CurrentOS -eq "Windows") { if ((Test-NetConnection $($PSBoundParameters.IP.IPAddressToString) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue).PingSucceeded) { Write-Error "Error. IP Address already in use." return $null } } else { if ((Test-Connection -IPv4 $($PSBoundParameters.IP.IPAddressToString) -Count 1 -WarningAction SilentlyContinue -ErrorAction SilentlyContinue).Status -eq "Success") { Write-Error "Error. IP Address already in use." return $null } } } if ($Type -in @('VMware','Hyper-V')) { if ($PSBoundParameters.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" return $null } if ($PSBoundParameters.ImagesPath) { Write-Host "-ImagesPath is selected. Collecting existing cached images.." -ForegroundColor Cyan if (!(Test-Path $PSBoundParameters.ImagesPath)) { Write-Host "-ImagesPath: $($PSBoundParameters.ImagesPath) does not exist. Attempting to create it.." -ForegroundColor Yellow if ($ImagesDir = New-Item -Type Directory $PSBoundParameters.ImagesPath) { Write-Host "Successfully created $($PSBoundParameters.ImagesPath)" -ForegroundColor Cyan $CurrentImages = Get-ChildItem $PSBoundParameters.ImagesPath } else { Write-Error "Error. Failed to create -ImagesPath: $($PSBoundParameters.ImagesPath)" return $null } } else { $CurrentImages = Get-ChildItem $PSBoundParameters.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 ($PSBoundParameters.ImagesPath) { $ImageFilePath = Join-Path $($PSBoundParameters.ImagesPath) $($ImageFileName) if (!(Test-Path "$($ImageFilePath)")) { Write-Host "Downloading latest image: $($ImageFileName).." -ForegroundColor Cyan Invoke-WebRequest -Method GET -Uri $($Image.link) -OutFile "$($ImageFilePath)" } else { Write-Host "Latest image already downloaded: $($ImageFileName)" -ForegroundColor Cyan } $ImageFile = "$($ImageFilePath)" } 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." return $null } } else { Write-Error "Error. Failed to find image." return $null } } } switch($Type) { "VMware" { if (!($PSBoundParameters.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 ($VMwareConnect = 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'])." return $null } if ($PSBoundParameters['Cluster']) { $VMCluster = Get-Cluster $($PSBoundParameters['Cluster']) -ErrorAction SilentlyContinue if (!($VMCluster)) { Write-Error "Error. Failed to get VM Cluster, please check details and try again." return $null } else { if ($PSBoundParameters['VMHost']) { $VMHostObj = $VMCluster | Get-VMHost -Name $PSBoundParameters['VMHost'] -State "Connected" if (!$VMHostObj) { Write-Error "Error. Failed to find Host: $($PSBoundParameters['VMHost']) on Cluster: $($Cluster)" return $null } } else { $VMHostObj = $VMCluster | Get-VMHost -State "Connected" | Select-Object -First 1 } } } elseif ($PSBoundParameters['VMHost']) { $VMHostObj = Get-VMHost -Name $PSBoundParameters['VMHost'] -State "Connected" if (!$VMHostObj) { Write-Error "Error. Failed to find Host: $($PSBoundParameters['VMHost']) on Cluster: $($Cluster)" return $null } } else { Write-Error 'Error. You must specify either -Cluster or -VMHost.' return $null } if (!($Datastore = Get-Datastore $($PSBoundParameters['Datastore']) -ErrorAction SilentlyContinue)) { Write-Error "Error. Failed to get VM Datastore, please check details and try again." return $null } switch($($PSBoundParameters['PortGroupType'])) { "vDS" { $NetworkMapping = Get-vDSwitch -VMHost $VMHostObj | Get-VDPortGroup $($PSBoundParameters['PortGroup']) if (!($NetworkMapping)) { Write-Error "Error. Failed to get vDS Port Group, please check details and try again." return $null } else { $NetworkMapping = Get-vDSwitch -VMHost $VMHostObj | Get-VDPortGroup $($PSBoundParameters['PortGroup']) } } "Standard" { $NetworkMapping = Get-VirtualSwitch -VMHost $VMHostObj | Get-VirtualPortGroup -Name $($PSBoundParameters['PortGroup']) if (!($NetworkMapping)) { Write-Error "Error. Failed to get Virtual Port Group, please check details and try again." return $null } else { } } "Default" { Write-Error "Invalid Port Group Type specified. Must be either `"vDS`" or `"Standard`"" return $null } } if (!(Test-Path $($ImageFile))) { Write-Error "Error. OVA $($ImageFile) not found." return $null } 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 = $PSBoundParameters.IP.IPAddressToString $OVFConfig.Common.gateway.Value = $PSBoundParameters.Gateway.IPAddressToString $OVFConfig.Common.netmask.Value = $PSBoundParameters.Netmask $OVFConfig.Common.nameserver.Value = $PSBoundParameters.DNSServers.IPAddressToString -join ',' $OVFConfig.Common.ntp_servers.Value = $PSBoundParameters.NTPServers -join ',' $OVFConfig.Common.jointoken.Value = $JoinToken $OVFConfig.Common.search.Value = $PSBoundParameters.DNSSuffix $OVFConfig.Common.v4_mode.Value = "static" $OVFConfig.NetworkMapping.lan.Value = $NetworkMapping } else { Write-Error "Error. Unable to retrieve OVF Configuration from $($ImageFile)." return $null } if($PSCmdlet.ShouldProcess("Deploy BloxOne VMware Appliance: $($Name)","Deploy BloxOne VMware Appliance: $($Name)",$MyInvocation.MyCommand)){ Write-Host "Deploying BloxOne Appliance: $Name .." -ForegroundColor Cyan $VM = Import-VApp -OvfConfiguration $OVFConfig -Source $($ImageFile) -Name $Name -VMHost $VMHostObj -Datastore $Datastore -Force if ($VM) { Write-Host "Successfully deployed BloxOne Appliance: $Name" -ForegroundColor Green if ($ENV:IBPSDebug -eq "Enabled") {$VM | Format-Table -AutoSize} if (!($PSBoundParameters.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 } else { $ShouldProcess = $false } } } "Hyper-V" { if (!($PSBoundParameters.DownloadLatestImage)) { if (!($PSBoundParameters['VHDPath'])) { Write-Error "-VHDPath must be specified if -DownloadLatestImage is not used." return $null } else { $ImageFile = $PSBoundParameters['VHDPath'] } } Write-Host "Generating customization metadata" -ForegroundColor Cyan $VMMetadata = New-B1Metadata -IP $($PSBoundParameters.IP.IPAddressToString) -Netmask $PSBoundParameters.Netmask -Gateway $($PSBoundParameters.Gateway.IPAddressToString) -DNSServers $($PSBoundParameters.DNSServers.IPAddressToString -join ',') -JoinToken $JoinToken -DNSSuffix $PSBoundParameters.DNSSuffix if ($VMMetadata) { Write-Host "Customization metadata generated successfully." -ForegroundColor Cyan } else { Write-Error "Failed to generate customization metadata" return $null } if($PSCmdlet.ShouldProcess("Deploy BloxOne Hyper-V Appliance: $($Name)","Deploy BloxOne Hyper-V Appliance: $($Name)",$MyInvocation.MyCommand)){ 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." return $null } 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." return $null } 2 { Write-Error "Error. You must use a .vhdx file format for Generation 2 Hyper-V VMs." return $null } } } 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 (!($PSBoundParameters.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 } } } } } else { $ShouldProcess = $false } } "Azure" { $AzContext = Get-AzContext if (!($AzContext)) { try { $AzConnect = Connect-AzAccount -Tenant $($PSBoundParameters.AzTenant) -Subscription $($PSBoundParameters.AzSubscription) Write-Host "Connected to Azure. (Tenant: $($PSBoundParameters.AzTenant)) (Subscription: $($PSBoundParameters.AzSubscription))" -ForegroundColor Cyan } catch { return $_.Exception.Message } } elseif (($AzContext.Tenant -ne $($PSBoundParameters.AzTenant)) -or ($AzContext.Subscription -ne $($PSBoundParameters.AzSubscription))) { try { $AzContext = Set-AzContext -Tenant $($PSBoundParameters.AzTenant) -Subscription $($PSBoundParameters.AzSubscription) } catch { return $_.Exception.Message } } $AzureOffer = Get-AzVMImageOffer -PublisherName 'infoblox' -Location $($PSBoundParameters.AzLocation) | Where-Object {$_.Offer -eq $PSBoundParameters.AzOffer} if ($AzureOffer) { $AzureSku = Get-AzVMImageSku -Location $($PSBoundParameters.AzLocation) -PublisherName 'infoblox' -Offer $AzureOffer.Offer | Where-Object {$_.Skus -eq $PSBoundParameters.AzSku} if ($AzureSku) { $AzureImage = Get-AzVMImage -Location $($PSBoundParameters.AzLocation) -PublisherName 'infoblox' -Offer $AzureOffer.Offer -Sku $($AzureSku.Skus) if ($AzureImage) { if($PSCmdlet.ShouldProcess("Deploy BloxOne VMware Appliance: $($Name)","Deploy BloxOne VMware Appliance: $($Name)",$MyInvocation.MyCommand)){ ## Check if marketplace terms have been accepted. $MarketplaceTerms = Get-AzMarketplaceTerms -Name $($AzureSku.Skus) -Product $($AzureOffer.Offer) -Publisher 'infoblox' -EA SilentlyContinue -WA SilentlyContinue if (!($MarketplaceTerms.Accepted)) { if ($PSBoundParameters.AzAcceptTerms) { $MarketplaceTermsAcceptance = Set-AzMarketplaceTerms -Name $($AzureSku.Skus) -Product $($AzureOffer.Offer) -Publisher 'infoblox' -Accept if (!($MarketplaceTermsAcceptance.Accepted)) { Write-Error 'Failed to accept the Marketplace Terms.' return $null } } else { Write-Error 'The Azure Marketplace Terms for BloxOne Deployment is not accepted. To accept these terms, use the -AzAcceptTerms switch.' return $null } } # Initialize VM Config $VMConfig = New-AzVMConfig -VMName $($PSBoundParameters.Name) -VMSize $($PSBoundParameters.AzSize) -SecurityType Standard # Update VM Config with VM Plan $VMConfig = $VMConfig | Set-AzVMPlan -Name $($AzureSku.Skus) -Product $($AzureOffer.Offer) -Publisher 'infoblox' # Update VM Config with Diagnostic Info if ($PSBoundParameters.AzBootDiagnostics) { if ($PSBoundParameters.AzStorageAccount) { $VMConfig = $VMConfig | Set-AzVMBootDiagnostic -Enable -ResourceGroupName $($PSBoundParameters.AzResourceGroup) -StorageAccountName $($PSBoundParameters.AzStorageAccount) } else { Write-Error "Error. -AzStorageAccount must be specified when using -AzBootDiagnostics" return $null } } else { $VMConfig = $VMConfig | Set-AzVMBootDiagnostic -Disable } # Update VM Config with VM Source Image $VMConfig = $VMConfig | Set-AzVMSourceImage -PublisherName 'infoblox' -Offer $($PSBoundParameters.AzOffer) -Skus $($AzureSku.Skus) -Version $($AzureImage.Version) # Update VM Config with OS Information & Custom Data $UserData = New-B1Metadata -JoinToken $($PSBoundParameters.JoinToken) | Select-Object -ExpandProperty userdata # Define Random Credential, this is only used as a placeholder and not actually configured on the deployed VM. $AzVMUser = "AzDeploy"; $AzVMPassword = (-join ((32..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})) | ConvertTo-SecureString -AsPlainText -Force; $AzVMCredential = New-Object System.Management.Automation.PSCredential ($AzVMUser, $AzVMPassword); $VMConfig = $VMConfig | Set-AzVMOperatingSystem -Linux -CustomData $UserData -Credential $AzVMCredential -ComputerName $($PSBoundParameters.Name) # Update VM Config with Azure Virtual Network / Subnet $AzureVirtualNetwork = Get-AzVirtualNetwork -Name $($PSBoundParameters.AzVirtualNetwork) -ResourceGroupName $($PSBoundParameters.AzResourceGroup) if ($AzureVirtualNetwork) { $AzureSubnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $AzureVirtualNetwork -Name $($PSBoundParameters.AzSubnet) if ($AzureSubnet) { # Create a virtual network interface try { Write-Host "Creating Virtual Network Interface: $($PSBoundParameters.Name)-nic.." -ForegroundColor Cyan $AzureNetworkInterface = New-AzNetworkInterface -Name "$($PSBoundParameters.Name)-nic" -ResourceGroupName $($PSBoundParameters.AzResourceGroup) -Location $($PSBoundParameters.AzLocation) -SubnetId $AzureSubnet.Id -EnableAcceleratedNetworking; } catch { return $_.Exception.Message } $VMConfig = $VMConfig | Add-AzVMNetworkInterface -Id $AzureNetworkInterface.Id ## Deploy VM try { Write-Host "Creating Virtual Machine: $($PSBoundParameters.Name).." -ForegroundColor Cyan $VM = New-AzVM -VM $VMConfig -ResourceGroupName $($PSBoundParameters.AzResourceGroup) -Location $($PSBoundParameters.AzLocation) $VMInfo = Get-AzVM -Name $($PSBoundParameters.Name) -ResourceGroupName $($PSBoundParameters.AzResourceGroup) } catch { return $_.Exception.Message } } else { Write-Error "Unable to find Azure Subnet with name: $($PSBoundParameters.AzVirtualNetwork)" return $null } } else { Write-Error "Unable to find Azure Virtual Network with name: $($PSBoundParameters.AzVirtualNetwork)" return $null } } else { $ShouldProcess = $false } } else { Write-Error "Unable to find Azure Image." return @{ "Location" = $($PSBoundParameters.AzLocation) "PublisherName" = 'infoblox' "Offer" = $AzureOffer.Offer "Sku" = $AzureSku.Skus } } } else { Write-Error "Unable to find Azure SKU with name: $($PSBoundParameters.AzSku)" return $null } } else { Write-Error "Unable to find Azure Offer with name: $($PSBoundParameters.AzOffer)" return $null } } } if ($VM) { if (!($PSBoundParameters.SkipPowerOn)) { if (!($SkipPingChecks)) { $PingStartCount = 0 while (!$PingSuccess) { Write-Host -NoNewLine "`rWaiting for network to become reachable. Elapsed Time: $PingStartCount`s" -ForegroundColor Gray $PingStartCount = $PingStartCount + 10 if ($CurrentOS -eq "Windows") { $PingSuccess = (Test-NetConnection $($PSBoundParameters.IP.IPAddressToString) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue).PingSucceeded } else { $PingSuccess = (Test-Connection $($PSBoundParameters.IP.IPAddressToString) -Count 1 -WarningAction SilentlyContinue -ErrorAction SilentlyContinue) | Where-Object {$_.Status -eq 'Success'} } Wait-Event -Timeout 10 if ($PingStartCount -gt 120) { Write-Error "Error. Network Failed to become reachable on $($PSBoundParameters.IP.IPAddressToString)." break } } Write-Host "" } if (!($SkipCloudChecks)) { Switch($Type) { {$_ -in @('VMware','Hyper-V')} { $B1HostProps = @{ 'IP' = $($PSBoundParameters.IP.IPAddressToString) } } 'Azure' { $AzurePrivateIP = (Get-AzNetworkInterface -ResourceId ($VMInfo).NetworkProfile.NetworkInterfaces.Id).IpConfigurations.PrivateIpAddress $B1HostProps = @{ 'IP' = $AzurePrivateIP } } } while (!(Get-B1Host @B1HostProps)) { $CSPStartCount = $CSPStartCount + 10 Write-Host -NoNewLine "`rWaiting for BloxOne Appliance to become registered within BloxOne CSP. Elapsed Time: $CSPStartCount`s" -ForegroundColor Gray Wait-Event -Timeout 10 if ($CSPStartCount -gt $CloudCheckTimeout) { 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 "" Write-Host "BloxOne Appliance is now available, check the CSP portal for registration of the device" -ForegroundColor Green if (!($SkipCloudChecks)) { Get-B1Host @B1HostProps | 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 } } elseif ($ShouldProcess) { Write-Error "Failed to deploy BloxOne Appliance." break } if (Test-Path 'work-dir') { Remove-Item -Path "work-dir" -Recurse } ## Cleanup work directory } } |