├── README.md ├── vsphere-6.0-self-manage-lab-deployment.ps1 ├── vsphere-6.0standard-lab-deployment.ps1 ├── vsphere-6.5-lab-deployment-0.png ├── vsphere-6.5-lab-deployment-1-new.png ├── vsphere-6.5-lab-deployment-2.png ├── vsphere-6.5-lab-deployment-4-new.png ├── vsphere-6.5-lab-deployment-5.png ├── vsphere-6.5-lab-deployment-6.png ├── vsphere-6.5-self-manage-lab-deployment.ps1 ├── vsphere-6.5-standard-lab-deployment.ps1 └── vsphere-6.7-standard-lab-deployment.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # vSphere Automated Lab Deployment 2 | 3 | ## Table of Contents 4 | 5 | * [Description](#description) 6 | * [Changelog](#changelog) 7 | * [Requirements](#requirements) 8 | * [Supported Deployments](#supported-deployments) 9 | * [Scripts](#scripts) 10 | * [Configuration](#configuration) 11 | * [Logging](#logging) 12 | * [Verification](#verification) 13 | * [Sample Execution](#sample-execution) 14 | 15 | ## Description 16 | 17 | Automated deployment of a fully functional vSphere 6.x environment that includes a set of Nested ESXi Virtual Appliance(s) configured w/vSAN as well as a vCenter Server Appliance (VCSA) using PowerCLI. For information, you can refer to this blog post [here](http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html) for more details. 18 | 19 | ## Changelog 20 | 21 | * **11/22/16** 22 | * Automatically handle Nested ESXi on vSAN 23 | 24 | * **01/20/17** 25 | * Resolved "Another task in progress" thanks to Jason M 26 | 27 | * **02/12/17** 28 | 29 | * Support for deploying to VC Target 30 | * Support for enabling SSH on VCSA 31 | * Added option to auto-create vApp Container for VMs 32 | * Added pre-check for required files 33 | 34 | * **02/17/17** 35 | 36 | * Added missing dvFilter param to eth1 (missing in Nested ESXi OVA) 37 | 38 | * **02/21/17** 39 | 40 | * Support for deploying NSX 6.3 & registering with vCenter Server 41 | * Support for updating Nested ESXi VM to ESXi 6.5a (required for NSX 6.3) 42 | * Support for VDS + VXLAN VMkernel configuration (required for NSX 6.3) 43 | * Support for "Private" Portgroup on eth1 for Nested ESXi VM used for VXLAN traffic (required for NSX 6.3) 44 | * Support for both Virtual & Distributed Portgroup on $VMNetwork 45 | * Support for adding ESXi hosts into VC using DNS name (disabled by default) 46 | * Added CPU/MEM/Storage resource requirements in confirmation screen 47 | 48 | * **05/08/17** 49 | * Support for patching ESXi using VMware Online repo thanks to Matt Lichstein for contribution 50 | * Added fix to test ESXi endpoint before trying to patch 51 | 52 | * **04/18/18** 53 | * Added support for vCenter Server 6.7, some of the JSON params have changed for consistency purposes which needed to be updated 54 | * Added support for new Nested ESXi 6.7 Virtual Appliance (will need to download that first) 55 | * vMotion is now enabled by default on vmk0 for all Nested ESXi hosts 56 | 57 | * **02/10/2020** 58 | * Added support for deploying basic vSphere environment (ESXi VM + VCSA) into VMware Cloud on AWS (Nested vSAN not supported) 59 | 60 | 61 | ## Requirements 62 | * 1 x Physical ESXi host or vCenter Server running at least vSphere 6.0u2 or later 63 | * DRS-enabled Cluster (not required but vApp creation will not be possible) 64 | * Windows system 65 | * [PowerCLI 6.5 R1](https://my.vmware.com/group/vmware/details?downloadGroup=PCLI650R1&productId=568) 66 | * [PowerNSX](https://github.com/vmware/powernsx) installed and loaded (required if you plan to do NSX 6.3 deployment) 67 | * vCenter Server Appliance (VCSA) 6.x extracted ISO 68 | * [Nested ESXi 6.x Virtual Appliance OVA](http://vmwa.re/nestedesxi) 69 | * [NSX 6.3 OVA](https://my.vmware.com/web/vmware/details?downloadGroup=NSXV_630&productId=417&rPId=14427) (optional) 70 | * [ESXi 6.5a offline patch bundle](https://my.vmware.com/web/vmware/details?downloadGroup=ESXI650A&productId=614&rPId=14229) (extracted) 71 | 72 | ## Supported Deployments 73 | 74 | The scripts support deploying both a vSphere 6.x environment and there are two types of deployments for each: 75 | * **Standard** - All VMs are deployed directly to the physical ESXi host 76 | * **Self Managed** - Only the Nested ESXi VMs are deployed to physical ESXi host. The VCSA is then bootstrapped onto the first Nested ESXi VM 77 | 78 | Here is a quick diagram to help illustrate the two deployment scenarios. The pESXi in gray is what you already have deployed which must be running at least ESXi 6.0 Update 2. The rest of the boxes is what the scripts will deploy. In the "Standard" deployment, three Nested ESXi VMs will be deployed to the pESXi host and configured with vSAN. The VCSA will also be deployed directly to the pESXi host and the vCenter Server will be configured to add the three Nested ESXi VMs into its inventory. This is a pretty straight forward and basic deployment, it should not surprise anyone. The "Self Managed" deployment is simliar, however the biggest difference is that rather than the VCSA being deployed directly to the pESXi host like the "Standard" deployment, it will actually be running within the Nested ESXi VM. The way that this deployment scenario works is that we will still deploy three Nested ESXi VM onto the pESXi host, however, the first Nested ESXi VM will be selected as a ["Bootstrap"](http://www.virtuallyghetto.com/2013/09/how-to-bootstrap-vcenter-server-onto_9.html) node which we will then construct a single-node vSAN to then deploy the VCSA. Once the vCenter Server is setup, we will then add the remainder Nested ESXi VMs into its inventory. 79 | 80 | ![](vsphere-6.5-lab-deployment-0.png) 81 | 82 | ## Scripts 83 | | Script Function | Script Download | 84 | |-----------------|-----------------| 85 | | vSphere 6.5 Standard Deployment | [vsphere-6.5-standard-lab-deployment.ps1](vsphere-6.5-standard-lab-deployment.ps1) | 86 | | vSphere 6.0u2 Standard Deployment | [vsphere-6.0-standard-lab-deployment.ps1](vsphere-6.0-standard-lab-deployment.ps1) | 87 | | vSphere 6.5 Self Managed Deployment | [vsphere-6.5-self-manage-lab-deployment.ps1](vsphere-6.5-self-manage-lab-deployment.ps1) | 88 | | vSphere 6.0u2 Self Managed Deployment | [vsphere-6.0-self-manage-lab-deployment.ps1](vsphere-6.0-self-manage-lab-deployment.ps1) | 89 | | vSphere 6.7 Standard Managed Deployment | [vsphere-6.7-standard-lab-deployment.ps1](vsphere-6.7-standard-lab-deployment.ps1) | 90 | 91 | ## Configuration 92 | 93 | This section describes the location of the files required for deployment. The first two are mandatory for the basic deployment. For advanced deployments such as NSX 6.3, you will need to download additional files and below are examples of what is required. 94 | 95 | ```console 96 | $NestedESXiApplianceOVA = 'C:\Users\Administrator\Desktop\VMC-Customer0\Nested_ESXi6.7u3_Appliance_Template_v1.ova' 97 | $VCSAInstallerPath = 'C:\Users\Administrator\Desktop\VMC-Customer0\VMware-VCSA-all-6.7.0-15132721' 98 | $NSXOVA = "C:\Users\primp\Desktop\VMware-NSX-Manager-6.3.0-5007049.ova" 99 | $ESXi65aOfflineBundle = "C:\Users\primp\Desktop\ESXi650-201701001\vmw-ESXi-6.5.0-metadata.zip" 100 | ``` 101 | 102 | This section describes the credentials to your physical ESXi server or vCenter Server in which the vSphere lab environment will be deployed to: 103 | ```console 104 | $VIServer = "himalaya.primp-industries.com" 105 | $VIUsername = "root" 106 | $VIPassword = "vmware123" 107 | ``` 108 | 109 | This section describes whether your deployment environment (destination) will be an ESXi host, vCenter Server or VMware Cloud on AWS. You will need to specify either **ESXI**, **VCENTER** or **VMC** keyword: 110 | ```console 111 | $DeploymentTarget = "ESXI" 112 | ``` 113 | 114 | This section defines the number of Nested ESXi VMs to deploy along with their associated IP Address(s). The names are merely the display name of the VMs when deployed. At a minimum, you should deploy at least three hosts, but you can always add additional hosts and the script will automatically take care of provisioning them correctly. 115 | ```console 116 | $NestedESXiHostnameToIPs = @{ 117 | "vesxi67-1" = "192.168.1.51" 118 | "vesxi67-2" = "192.168.1.52" 119 | "vesxi67-3" = "192.168.1.53" 120 | } 121 | ``` 122 | 123 | This section describes the resources allocated to each of the Nested ESXi VM(s). Depending on the deployment type, you may need to increase the resources. For Memory and Disk configuration, the unit is in GB. 124 | ```console 125 | $NestedESXivCPU = "2" 126 | $NestedESXivMEM = "6" 127 | $NestedESXiCachingvDisk = "4" 128 | $NestedESXiCapacityvDisk = "8" 129 | ``` 130 | 131 | This section describes the VCSA deployment configuration such as the VCSA deployment size, Networking & SSO configurations. If you have ever used the VCSA CLI Installer, these options should look familiar. 132 | ```console 133 | $VCSADeploymentSize = "tiny" 134 | $VCSADisplayName = "vcenter67-1" 135 | $VCSAIPAddress = "192.168.1.50" 136 | $VCSAHostname = "vcenter67-1.vmware.corp" #Change to IP if you don't have valid DNS 137 | $VCSAPrefix = "24" 138 | $VCSASSODomainName = "vsphere.local" 139 | $VCSASSOPassword = "VMware1!" 140 | $VCSARootPassword = "VMware1!" 141 | $VCSASSHEnable = "true" 142 | ``` 143 | 144 | This section describes the location as well as the generic networking settings applied to BOTH the Nested ESXi VM and VCSA. 145 | ```console 146 | $VirtualSwitchType = "VDS" # VSS or VDS 147 | $VMNetwork = "sddc-cgw-network-1" 148 | $VMDatastore = "WorkloadDatastore" 149 | $VMNetmask = "255.255.255.0" 150 | $VMGateway = "192.168.1.1" 151 | $VMDNS = "192.168.1.100" 152 | $VMNTP = "pool.ntp.org" 153 | $VMPassword = "VMware1!" 154 | $VMDomain = "vmware.corp" 155 | $VMSyslog = "192.168.1.200" 156 | 157 | # Applicable to Nested ESXi only 158 | $VMSSH = "true" 159 | $VMVMFS = "false" 160 | 161 | # Applicable to VC Deployment Target only 162 | $VMCluster = "Cluster-1" 163 | 164 | # Defaults for VMC 165 | $VMDatacenter = "SDDC-Datacenter" 166 | $VMFolder = "Workloads" 167 | $VMResourcePool = "Compute-ResourcePool" 168 | ``` 169 | 170 | This section describes the configuration of the new vCenter Server from the deployed VCSA. 171 | ```console 172 | $NewVCDatacenterName = "Datacenter" 173 | $NewVCVSANClusterName = "vSphere-Cluster" 174 | ``` 175 | 176 | This section describes the NSX configuration if you choose to deploy which will require you to set $DeployNSX property to 1 and fill out all fields. 177 | ```console 178 | $DeployNSX = 0 179 | $NSXvCPU = "2" # Reconfigure NSX vCPU 180 | $NSXvMEM = "8" # Reconfigure NSX vMEM (GB) 181 | $NSXDisplayName = "nsx63-1" 182 | $NSXHostname = "nsx63-1.primp-industries.com" 183 | $NSXIPAddress = "172.30.0.250" 184 | $NSXNetmask = "255.255.255.0" 185 | $NSXGateway = "172.30.0.1" 186 | $NSXSSHEnable = "true" 187 | $NSXCEIPEnable = "false" 188 | $NSXUIPassword = "VMw@re123!" 189 | $NSXCLIPassword = "VMw@re123!" 190 | ``` 191 | 192 | This section describes the VDS and VXLAN configurations which is required for NSX deployment. The only mandatory field here is $PrivateVXLANVMnetwork which is a private portgroup that must already exists which will be used to connect the second network adapter of the Nested ESXi VM for VXLAN traffic. You do not need a routable portgroup and the other properties can be left as default or you can modify them if you wish. 193 | ```console 194 | # VDS / VXLAN Configurations 195 | $PrivateVXLANVMNetwork = "dv-private-network" # Existing Portgroup 196 | $VDSName = "VDS-6.5" 197 | $VXLANDVPortgroup = "VXLAN" 198 | $VXLANSubnet = "172.16.66." 199 | $VXLANNetmask = "255.255.255.0" 200 | ``` 201 | 202 | This section describes some advanced options for the deployment. Th first setting adds the ESXi hosts into vCenter Server using DNS names (must have both forward/reverse DNS working in your environment). The second option will upgrade the Nested ESXi 6.5 VMs to ESXi 6.5a which is required if you are deploying NSX 6.3 or if you just want to run the latest version of ESXi, you can also enable this. Both of these settings are disabled by default 203 | ```console 204 | # Set to 1 only if you have DNS (forward/reverse) for ESXi hostnames 205 | $addHostByDnsName = 0 206 | # Upgrade vESXi hosts to 6.5a 207 | $upgradeESXiTo65a = 0 208 | ``` 209 | 210 | Once you have saved your changes, you can now run the PowerCLI script as you normally would. 211 | 212 | ## Logging 213 | 214 | There is additional verbose logging that outputs as a log file in your current working directory either **vsphere60-lab-deployment.log** or **vsphere65-lab-deployment.log** depending on the deployment you have selected. 215 | 216 | ## Verification 217 | 218 | Once you have saved all your changes, you can then run the script. You will be provided with a summary of what will be deployed and you can verify that everything is correct before attempting the deployment. Below is a screenshot on what this would look like: 219 | 220 | ![](vsphere-6.5-lab-deployment-4-new.png) 221 | 222 | ## Sample Executions 223 | 224 | Here is an example of running a vSphere 6.5 "Standard" deployment including NSX 6.3: 225 | 226 | ![](vsphere-6.5-lab-deployment-1-new.png) 227 | 228 | Here is an example of running a vSphere 6.5 "Self Managed" deployment: 229 | 230 | ![](vsphere-6.5-lab-deployment-2.png) 231 | 232 | If everything is succesful, you can now login to your new vCenter Server and you should either see the following for a **"Standard"** deployment: 233 | 234 | ![](vsphere-6.5-lab-deployment-5.png) 235 | 236 | or the following for **"Self Managed"** deployment: 237 | 238 | ![](vsphere-6.5-lab-deployment-6.png) 239 | -------------------------------------------------------------------------------- /vsphere-6.0-self-manage-lab-deployment.ps1: -------------------------------------------------------------------------------- 1 | # Author: William Lam 2 | # Website: www.virtuallyghetto.com 3 | # Description: PowerCLI script to deploy a fully functional vSphere 6.0 lab consisting of 3 4 | # Nested ESXi hosts enable w/vSAN + VCSA 6.0. Expects a single physical ESXi host 5 | # as the endpoint and all three Nested ESXi VMs will be deployed to physical ESXi host 6 | # with the VCSA then being deployed to the inner-Nested ESXi VMs as a self-managed VC 7 | # Reference: http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html 8 | # Credit: Thanks to Alan Renouf as I borrowed some of his PCLI code snippets :) 9 | # 10 | # Changelog 11 | # 11/22/16 12 | # * Automatically handle Nested ESXi on vSAN 13 | # 01/20/17 14 | # * Resolved "Another task in progress" thanks to Jason M 15 | # 02/12/17 16 | # * Support for deploying to VC Target 17 | # * Support for enabling SSH on VCSA 18 | # * Added option to auto-create vApp Container for VMs 19 | # * Added pre-check for required files 20 | # 02/17/17 21 | # * Added missing dvFilter param to eth1 (missing in Nested ESXi OVA) 22 | 23 | # Physical ESXi host or vCenter Server to deploy vSphere 6.0 lab 24 | $VIServer = "vcenter.primp-industries.com" 25 | $VIUsername = "administrator@vsphere.local" 26 | $VIPassword = "!!!MySuperDuperSecurePassword!!!" 27 | 28 | # Specifies whether deployment is to an ESXi host or vCenter Server 29 | # Use either ESXI or VCENTER 30 | $DeploymentTarget = "VCENTER" 31 | 32 | # Full Path to both the Nested ESXi 6.0 VA + extracted VCSA 6.0 ISO 33 | $NestedESXiApplianceOVA = "C:\Users\primp\Desktop\Nested_ESXi6.x_Appliance_Template_v5.ova" 34 | $VCSAInstallerPath = "C:\Users\primp\Desktop\VMware-VCSA-all-6.0.0-3634788" 35 | 36 | # Nested ESXi VMs to deploy 37 | $NestedESXiHostnameToIPs = @{ 38 | "vesxi60-1" = "172.30.0.85" 39 | "vesxi60-2" = "172.30.0.86" 40 | "vesxi60-3" = "172.30.0.87" 41 | } 42 | 43 | #Nested ESXi Bootstrap Node 44 | $bootStrapNode = "172.30.0.85" 45 | 46 | # Nested ESXi VM Resources 47 | $NestedESXivCPU = "2" 48 | $NestedESXivMEM = "32" #GB 49 | $NestedESXiCachingvDisk = "16" #GB 50 | $NestedESXiCapacityvDisk = "200" #GB 51 | 52 | # VCSA Deployment Configuration 53 | $VCSADeploymentSize = "tiny" 54 | $VCSADisplayName = "vcenter60-1" 55 | $VCSAIPAddress = "172.30.0.50" 56 | $VCSAHostname = "vcenter60-1.primp-industries.com" #Change to IP if you don't have valid DNS 57 | $VCSAPrefix = "24" 58 | $VCSASSODomainName = "vsphere.local" 59 | $VCSASSOSiteName = "virtuallyGhetto" 60 | $VCSASSOPassword = "VMware1!" 61 | $VCSARootPassword = "VMware1!" 62 | 63 | # General Deployment Configuration for both Nested ESXi VMs + VCSA 64 | $VMNetwork = "access333" 65 | $VMDatastore = "himalaya-local-SATA-dc3500-2" 66 | $VMNetmask = "255.255.255.0" 67 | $VMGateway = "172.30.0.1" 68 | $VMDNS = "172.30.0.100" 69 | $VMNTP = "pool.ntp.org" 70 | $VMPassword = "vmware123" 71 | $VMDomain = "primp-industries.com" 72 | $VMSyslog = "172.30.0.170" 73 | # Applicable to Nested ESXi only 74 | $VMSSH = "true" 75 | $VMVMFS = "false" 76 | # Applicable to VC Deployment Target only 77 | $VMCluster = "Primp-Cluster" 78 | 79 | # Name of new vSphere Datacenter/Cluster when VCSA is deployed 80 | $NewVCDatacenterName = "Datacenter" 81 | $NewVCVSANClusterName = "VSAN-Cluster" 82 | 83 | #### DO NOT EDIT BEYOND HERE #### 84 | 85 | $verboseLogFile = "vsphere60-lab-deployment.log" 86 | $vSphereVersion = "6.0u2" 87 | $deploymentType = "Self Managed" 88 | $random_string = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_}) 89 | $VAppName = "Nested-vSphere-Lab-$vSphereVersion-$random_string" 90 | 91 | $preCheck = 1 92 | $confirmDeployment = 1 93 | $deployNestedESXiVMs = 1 94 | $bootStrapFirstNestedESXiVM = 1 95 | $deployVCSA = 1 96 | $setupNewVC = 1 97 | $addESXiHostsToVC = 1 98 | $configureVSANDiskGroups = 1 99 | $clearVSANHealthCheckAlarm = 1 100 | 101 | $StartTime = Get-Date 102 | 103 | Function My-Logger { 104 | param( 105 | [Parameter(Mandatory=$true)] 106 | [String]$message 107 | ) 108 | 109 | $timeStamp = Get-Date -Format "MM-dd-yyyy_hh-mm-ss" 110 | 111 | Write-Host -NoNewline -ForegroundColor White "[$timestamp]" 112 | Write-Host -ForegroundColor Green " $message" 113 | $logMessage = "[$timeStamp] $message" 114 | $logMessage | Out-File -Append -LiteralPath $verboseLogFile 115 | } 116 | 117 | if($preCheck -eq 1) { 118 | if(!(Test-Path $NestedESXiApplianceOVA)) { 119 | Write-Host -ForegroundColor Red "`nUnable to find $NestedESXiApplianceOVA ...`nexiting" 120 | exit 121 | } 122 | 123 | if(!(Test-Path $VCSAInstallerPath)) { 124 | Write-Host -ForegroundColor Red "`nUnable to find $VCSAInstallerPath ...`nexiting" 125 | exit 126 | } 127 | } 128 | 129 | if($confirmDeployment -eq 1) { 130 | Write-Host -ForegroundColor Magenta "`nPlease confirm the following configuration will be deployed:`n" 131 | 132 | Write-Host -ForegroundColor Yellow "---- vSphere Automated Lab Deployment Configuration ---- " 133 | Write-Host -NoNewline -ForegroundColor Green "Deployment Type: " 134 | Write-Host -ForegroundColor White $deploymentType 135 | Write-Host -NoNewline -ForegroundColor Green "vSphere Version: " 136 | Write-Host -ForegroundColor White "vSphere $vSphereVersion" 137 | Write-Host -NoNewline -ForegroundColor Green "Nested ESXi Image Path: " 138 | Write-Host -ForegroundColor White $NestedESXiApplianceOVA 139 | Write-Host -NoNewline -ForegroundColor Green "VCSA Image Path: " 140 | Write-Host -ForegroundColor White $VCSAInstallerPath 141 | 142 | if($DeploymentTarget -eq "ESXI") { 143 | Write-Host -ForegroundColor Yellow "`n---- Physical ESXi Configuration ----" 144 | Write-Host -NoNewline -ForegroundColor Green "ESXi Address: " 145 | } else { 146 | Write-Host -ForegroundColor Yellow "`n---- vCenter Server Configuration ----" 147 | Write-Host -NoNewline -ForegroundColor Green "vCenter Server Address: " 148 | } 149 | 150 | Write-Host -ForegroundColor White $VIServer 151 | Write-Host -NoNewline -ForegroundColor Green "Username: " 152 | Write-Host -ForegroundColor White $VIUsername 153 | Write-Host -NoNewline -ForegroundColor Green "VM Network: " 154 | Write-Host -ForegroundColor White $VMNetwork 155 | Write-Host -NoNewline -ForegroundColor Green "VM Storage: " 156 | Write-Host -ForegroundColor White $VMDatastore 157 | 158 | if($DeploymentTarget -eq "VCENTER") { 159 | Write-Host -NoNewline -ForegroundColor Green "VM Cluster: " 160 | Write-Host -ForegroundColor White $VMCluster 161 | Write-Host -NoNewline -ForegroundColor Green "VM vApp: " 162 | Write-Host -ForegroundColor White $VAppName 163 | } 164 | 165 | Write-Host -ForegroundColor Yellow "`n---- vESXi Configuration ----" 166 | Write-Host -NoNewline -ForegroundColor Green "# of Nested ESXi VMs: " 167 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.count 168 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 169 | Write-Host -ForegroundColor White $NestedESXivCPU 170 | Write-Host -NoNewline -ForegroundColor Green "vMEM: " 171 | Write-Host -ForegroundColor White "$NestedESXivMEM GB" 172 | Write-Host -NoNewline -ForegroundColor Green "Caching VMDK: " 173 | Write-Host -ForegroundColor White "$NestedESXiCachingvDisk GB" 174 | Write-Host -NoNewline -ForegroundColor Green "Capacity VMDK: " 175 | Write-Host -ForegroundColor White "$NestedESXiCapacityvDisk GB" 176 | Write-Host -NoNewline -ForegroundColor Green "IP Address(s): " 177 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.Values 178 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 179 | Write-Host -ForegroundColor White $VMNetmask 180 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 181 | Write-Host -ForegroundColor White $VMGateway 182 | Write-Host -NoNewline -ForegroundColor Green "DNS: " 183 | Write-Host -ForegroundColor White $VMDNS 184 | Write-Host -NoNewline -ForegroundColor Green "NTP: " 185 | Write-Host -ForegroundColor White $VMNTP 186 | Write-Host -NoNewline -ForegroundColor Green "Syslog: " 187 | Write-Host -ForegroundColor White $VMSyslog 188 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 189 | Write-Host -ForegroundColor White $VMSSH 190 | Write-Host -NoNewline -ForegroundColor Green "Create VMFS Volume: " 191 | Write-Host -ForegroundColor White $VMVMFS 192 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 193 | Write-Host -ForegroundColor White $VMPassword 194 | Write-Host -NoNewline -ForegroundColor Green "Bootstrap ESXi Node: " 195 | Write-Host -ForegroundColor White $bootStrapNode 196 | 197 | Write-Host -ForegroundColor Yellow "`n---- VCSA Configuration ----" 198 | Write-Host -NoNewline -ForegroundColor Green "Deployment Size: " 199 | Write-Host -ForegroundColor White $VCSADeploymentSize 200 | Write-Host -NoNewline -ForegroundColor Green "SSO Domain: " 201 | Write-Host -ForegroundColor White $VCSASSODomainName 202 | Write-Host -NoNewline -ForegroundColor Green "SSO Site: " 203 | Write-Host -ForegroundColor White $VCSASSOSiteName 204 | Write-Host -NoNewline -ForegroundColor Green "SSO Password: " 205 | Write-Host -ForegroundColor White $VCSASSOPassword 206 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 207 | Write-Host -ForegroundColor White $VCSARootPassword 208 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 209 | Write-Host -ForegroundColor White $VCSASSHEnable 210 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 211 | Write-Host -ForegroundColor White $VCSAHostname 212 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 213 | Write-Host -ForegroundColor White $VCSAIPAddress 214 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 215 | Write-Host -ForegroundColor White $VMNetmask 216 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 217 | Write-Host -ForegroundColor White $VMGateway 218 | 219 | Write-Host -ForegroundColor Magenta "`nWould you like to proceed with this deployment?`n" 220 | $answer = Read-Host -Prompt "Do you accept (Y or N)" 221 | if($answer -ne "Y" -or $answer -ne "y") { 222 | exit 223 | } 224 | Clear-Host 225 | } 226 | 227 | if($deployNestedESXiVMs -eq 1) { 228 | My-Logger "Connecting to $VIServer ..." 229 | $viConnection = Connect-VIServer $VIServer -User $VIUsername -Password $VIPassword -WarningAction SilentlyContinue 230 | 231 | if($DeploymentTarget -eq "ESXI") { 232 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore 233 | $vmhost = Get-VMHost -Server $viConnection 234 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork -VMHost $vmhost 235 | 236 | if($datastore.Type -eq "vsan") { 237 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 238 | Get-AdvancedSetting -Entity $vmhost -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 239 | } 240 | } else { 241 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore | Select -First 1 242 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork | Select -First 1 243 | $cluster = Get-Cluster -Server $viConnection -Name $VMCluster 244 | $datacenter = $cluster | Get-Datacenter 245 | $vmhost = $cluster | Get-VMHost | Select -First 1 246 | } 247 | 248 | if($DeploymentTarget -eq "ESXI") { 249 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 250 | $VMName = $_.Key 251 | $VMIPAddress = $_.Value 252 | 253 | My-Logger "Deploying Nested ESXi VM $VMName ..." 254 | $vm = Import-VApp -Server $viConnection -Source $NestedESXiApplianceOVA -Name $VMName -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 255 | 256 | My-Logger "Updating VM Network ..." 257 | foreach($networkAdapter in ($vm | Get-NetworkAdapter)) 258 | { 259 | My-Logger "Configuring adapter $networkAdapter in $vm" 260 | $networkAdapter | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 261 | sleep 5 262 | } 263 | 264 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 265 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 266 | 267 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 268 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 269 | 270 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 271 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 272 | 273 | $orignalExtraConfig = $vm.ExtensionData.Config.ExtraConfig 274 | $a = New-Object VMware.Vim.OptionValue 275 | $a.key = "guestinfo.hostname" 276 | $a.value = $VMName 277 | $b = New-Object VMware.Vim.OptionValue 278 | $b.key = "guestinfo.ipaddress" 279 | $b.value = $VMIPAddress 280 | $c = New-Object VMware.Vim.OptionValue 281 | $c.key = "guestinfo.netmask" 282 | $c.value = $VMNetmask 283 | $d = New-Object VMware.Vim.OptionValue 284 | $d.key = "guestinfo.gateway" 285 | $d.value = $VMGateway 286 | $e = New-Object VMware.Vim.OptionValue 287 | $e.key = "guestinfo.dns" 288 | $e.value = $VMDNS 289 | $f = New-Object VMware.Vim.OptionValue 290 | $f.key = "guestinfo.domain" 291 | $f.value = $VMDomain 292 | $g = New-Object VMware.Vim.OptionValue 293 | $g.key = "guestinfo.ntp" 294 | $g.value = $VMNTP 295 | $h = New-Object VMware.Vim.OptionValue 296 | $h.key = "guestinfo.syslog" 297 | $h.value = $VMSyslog 298 | $i = New-Object VMware.Vim.OptionValue 299 | $i.key = "guestinfo.password" 300 | $i.value = $VMPassword 301 | $j = New-Object VMware.Vim.OptionValue 302 | $j.key = "guestinfo.ssh" 303 | $j.value = $VMSSH 304 | $k = New-Object VMware.Vim.OptionValue 305 | $k.key = "guestinfo.createvmfs" 306 | $k.value = $VMVMFS 307 | $l = New-Object VMware.Vim.OptionValue 308 | $l.key = "ethernet1.filter4.name" 309 | $l.value = "dvfilter-maclearn" 310 | $m = New-Object VMware.Vim.OptionValue 311 | $m.key = "ethernet1.filter4.onFailure" 312 | $m.value = "failOpen" 313 | $orignalExtraConfig+=$a 314 | $orignalExtraConfig+=$b 315 | $orignalExtraConfig+=$c 316 | $orignalExtraConfig+=$d 317 | $orignalExtraConfig+=$e 318 | $orignalExtraConfig+=$f 319 | $orignalExtraConfig+=$g 320 | $orignalExtraConfig+=$h 321 | $orignalExtraConfig+=$i 322 | $orignalExtraConfig+=$j 323 | $orignalExtraConfig+=$k 324 | $orignalExtraConfig+=$l 325 | $orignalExtraConfig+=$m 326 | 327 | $spec = New-Object VMware.Vim.VirtualMachineConfigSpec 328 | $spec.ExtraConfig = $orignalExtraConfig 329 | 330 | My-Logger "Adding guestinfo customization properties to $vmname ..." 331 | $task = $vm.ExtensionData.ReconfigVM_Task($spec) 332 | $task1 = Get-Task -Id ("Task-$($task.value)") 333 | $task1 | Wait-Task | Out-File -Append -LiteralPath $verboseLogFile 334 | 335 | My-Logger "Powering On $vmname ..." 336 | Start-VM -Server $viConnection -VM $vm -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 337 | } 338 | } else { 339 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 340 | $VMName = $_.Key 341 | $VMIPAddress = $_.Value 342 | 343 | $ovfconfig = Get-OvfConfiguration $NestedESXiApplianceOVA 344 | $networkMapLabel = ($ovfconfig.ToHashTable().keys | where {$_ -Match "NetworkMapping"}).replace("NetworkMapping.","").replace("-","_").replace(" ","_") 345 | $ovfconfig.NetworkMapping.$networkMapLabel.value = $VMNetwork 346 | 347 | $ovfconfig.common.guestinfo.hostname.value = $VMName 348 | $ovfconfig.common.guestinfo.ipaddress.value = $VMIPAddress 349 | $ovfconfig.common.guestinfo.netmask.value = $VMNetmask 350 | $ovfconfig.common.guestinfo.gateway.value = $VMGateway 351 | $ovfconfig.common.guestinfo.dns.value = $VMDNS 352 | $ovfconfig.common.guestinfo.domain.value = $VMDomain 353 | $ovfconfig.common.guestinfo.ntp.value = $VMNTP 354 | $ovfconfig.common.guestinfo.syslog.value = $VMSyslog 355 | $ovfconfig.common.guestinfo.password.value = $VMPassword 356 | if($VMSSH -eq "true") { 357 | $VMSSHVar = $true 358 | } else { 359 | $VMSSHVar = $false 360 | } 361 | $ovfconfig.common.guestinfo.ssh.value = $VMSSHVar 362 | 363 | My-Logger "Deploying Nested ESXi VM $VMName ..." 364 | $vm = Import-VApp -Source $NestedESXiApplianceOVA -OvfConfiguration $ovfconfig -Name $VMName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 365 | 366 | # Add the dvfilter settings to the exisiting ethernet1 (not part of ova template) 367 | My-Logger "Correcting missing dvFilter settings for Ethernet[1] ..." 368 | $vm | New-AdvancedSetting -name "ethernet1.filter4.name" -value "dvfilter-maclearn" -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 369 | $vm | New-AdvancedSetting -Name "ethernet1.filter4.onFailure" -value "failOpen" -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 370 | 371 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 372 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 373 | 374 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 375 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 376 | 377 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 378 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 379 | 380 | My-Logger "Powering On $vmname ..." 381 | $vm | Start-Vm -RunAsync | Out-Null 382 | } 383 | } 384 | 385 | if($moveVMsIntovApp -eq 1 -and $DeploymentTarget -eq "VCENTER") { 386 | # Check whether DRS is enabled as that is required to create vApp 387 | if((Get-Cluster -Server $viConnection $cluster).DrsEnabled) { 388 | My-Logger "Creating vApp $VAppName ..." 389 | $VApp = New-VApp -Name $VAppName -Server $viConnection -Location $cluster 390 | 391 | if($deployNestedESXiVMs -eq 1) { 392 | My-Logger "Moving Nested ESXi VMs into $VAppName vApp ..." 393 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 394 | $vm = Get-VM -Name $_.Key -Server $viConnection 395 | Move-VM -VM $vm -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 396 | } 397 | } 398 | } else { 399 | My-Logger "vApp $VAppName will NOT be created as DRS is NOT enabled on vSphere Cluster ${cluster} ..." 400 | } 401 | } 402 | 403 | My-Logger "Disconnecting from $VIServer ..." 404 | Disconnect-VIServer $viConnection -Confirm:$false 405 | } 406 | 407 | if($bootStrapFirstNestedESXiVM -eq 1) { 408 | do { 409 | My-Logger "Waiting for $bootStrapNode to be ready on network ..." 410 | $ping = test-connection $bootStrapNode -Quiet 411 | sleep 60 412 | } until ($ping -contains "True") 413 | 414 | My-Logger "Connecting to ESXi bootstrap node ..." 415 | $vEsxi = Connect-VIServer -Server $bootStrapNode -User root -Password $VMPassword -WarningAction SilentlyContinue 416 | 417 | My-Logger "Updating the ESXi host VSAN Policy to allow Force Provisioning ..." 418 | $esxcli = Get-EsxCli -Server $vEsxi -V2 419 | $VSANPolicy = '(("hostFailuresToTolerate" i1) ("forceProvisioning" i1))' 420 | $VSANPolicyDefaults = $esxcli.vsan.policy.setdefault.CreateArgs() 421 | $VSANPolicyDefaults.policy = $VSANPolicy 422 | $VSANPolicyDefaults.policyclass = "vdisk" 423 | $esxcli.vsan.policy.setdefault.Invoke($VSANPolicyDefaults) | Out-File -Append -LiteralPath $verboseLogFile 424 | $VSANPolicyDefaults.policyclass = "vmnamespace" 425 | $esxcli.vsan.policy.setdefault.Invoke($VSANPolicyDefaults) | Out-File -Append -LiteralPath $verboseLogFile 426 | 427 | My-Logger "Creating a new VSAN Cluster" 428 | $esxcli.vsan.cluster.new.Invoke() | Out-File -Append -LiteralPath $verboseLogFile 429 | 430 | $luns = Get-ScsiLun -Server $vEsxi | select CanonicalName, CapacityGB 431 | 432 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 433 | foreach ($lun in $luns) { 434 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 435 | $vsanCacheDisk = $lun.CanonicalName 436 | } 437 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 438 | $vsanCapacityDisk = $lun.CanonicalName 439 | } 440 | } 441 | 442 | My-Logger "Tagging Capacity Disk ..." 443 | $capacitytag = $esxcli.vsan.storage.tag.add.CreateArgs() 444 | $capacitytag.disk = $vsanCapacityDisk 445 | $capacitytag.tag = "capacityFlash" 446 | $esxcli.vsan.storage.tag.add.Invoke($capacitytag) | Out-File -Append -LiteralPath $verboseLogFile 447 | 448 | My-Logger "Creating VSAN Diskgroup ..." 449 | $addvsanstorage = $esxcli.vsan.storage.add.CreateArgs() 450 | $addvsanstorage.ssd = $vsanCacheDisk 451 | $addvsanstorage.disks = $vsanCapacityDisk 452 | $esxcli.vsan.storage.add.Invoke($addvsanstorage) | Out-File -Append -LiteralPath $verboseLogFile 453 | 454 | My-Logger "Disconnecting from $esxi ..." 455 | Disconnect-VIServer $vEsxi -Confirm:$false 456 | } 457 | 458 | if($deployVCSA -eq 1) { 459 | My-Logger "Connecting to first ESXi bootstrap node ..." 460 | $vEsxi = Connect-VIServer -Server $bootStrapNode -User root -Password $VMPassword -WarningAction SilentlyContinue 461 | 462 | # Deploy using the VCSA CLI Installer 463 | $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_ESXi.json") | convertfrom-json 464 | $config.'target.vcsa'.esx.hostname = $bootStrapNode 465 | $config.'target.vcsa'.esx.username = "root" 466 | $config.'target.vcsa'.esx.password = $VMPassword 467 | $config.'target.vcsa'.esx.datastore = "vsanDatastore" 468 | $config.'target.vcsa'.appliance.'deployment.network' = "VM Network" 469 | $config.'target.vcsa'.appliance.'thin.disk.mode' = $true 470 | $config.'target.vcsa'.appliance.'deployment.option' = $VCSADeploymentSize 471 | $config.'target.vcsa'.appliance.name = $VCSADisplayName 472 | $config.'target.vcsa'.network.'ip.family' = "ipv4" 473 | $config.'target.vcsa'.network.mode = "static" 474 | $config.'target.vcsa'.network.ip = $VCSAIPAddress 475 | $config.'target.vcsa'.network.'dns.servers'[0] = $VMDNS 476 | $config.'target.vcsa'.network.'dns.servers'[1] = $null 477 | $config.'target.vcsa'.network.prefix = $VCSAPrefix 478 | $config.'target.vcsa'.network.gateway = $VMGateway 479 | $config.'target.vcsa'.network.hostname = $VCSAHostname 480 | if($VCSASSHEnable -eq "true") { 481 | $VCSASSHEnableVar = $true 482 | } else { 483 | $VCSASSHEnableVar = $false 484 | } 485 | $config.'target.vcsa'.os.'ssh.enable' = $VCSASSHEnableVar 486 | $config.'target.vcsa'.os.password = $VCSARootPassword 487 | $config.'target.vcsa'.sso.password = $VCSASSOPassword 488 | $config.'target.vcsa'.sso.'domain-name' = $VCSASSODomainName 489 | $config.'target.vcsa'.sso.'site-name' = $VCSASSOSiteName 490 | 491 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 492 | $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" 493 | 494 | My-Logger "Deploying the VCSA ..." 495 | $output = Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula $($ENV:Temp)\jsontemplate.json" -ErrorVariable vcsaDeployOutput 2>&1 496 | $vcsaDeployOutput | Out-File -Append -LiteralPath $verboseLogFile 497 | 498 | My-Logger "Disconnecting from $bootStrapNode ..." 499 | Disconnect-VIServer $vEsxi -Confirm:$false 500 | } 501 | 502 | if($setupNewVC -eq 1) { 503 | My-Logger "Connecting to the new VCSA ..." 504 | $vc = Connect-VIServer $VCSAIPAddress -User "administrator@$VCSASSODomainName" -Password $VCSASSOPassword -WarningAction SilentlyContinue 505 | 506 | My-Logger "Creating Datacenter $NewVCDatacenterName ..." 507 | New-Datacenter -Server $vc -Name $NewVCDatacenterName -Location (Get-Folder -Type Datacenter -Server $vc) | Out-File -Append -LiteralPath $verboseLogFile 508 | 509 | My-Logger "Creating VSAN Cluster $NewVCVSANClusterName ..." 510 | New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -VsanEnabled -VsanDiskClaimMode 'Manual' | Out-File -Append -LiteralPath $verboseLogFile 511 | 512 | if($addESXiHostsToVC -eq 1) { 513 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 514 | $VMName = $_.Key 515 | $VMIPAddress = $_.Value 516 | 517 | My-Logger "Adding ESXi host $VMIPAddress to Cluster ..." 518 | Add-VMHost -Server $vc -Location (Get-Cluster -Name $NewVCVSANClusterName) -User "root" -Password $VMPassword -Name $VMIPAddress -Force | Out-File -Append -LiteralPath $verboseLogFile 519 | } 520 | 521 | } 522 | 523 | if($configureVSANDiskGroups -eq 1) { 524 | # New vSAN cmdlets only works on 6.0u3+ 525 | $VmhostToCheckVersion = (Get-Cluster -Server $vc | Get-VMHost)[0] 526 | $MajorVersion = $VmhostToCheckVersion.Version 527 | $UpdateVersion = (Get-AdvancedSetting -Entity $VmhostToCheckVersion -Name Misc.HostAgentUpdateLevel).value 528 | 529 | if( ($MajorVersion -eq "6.0.0" -and $UpdateVersion -eq "3") -or $MajorVersion -eq "6.5.0") { 530 | My-Logger "Enabling VSAN Space Efficiency/De-Dupe & disabling VSAN Health Check ..." 531 | Get-VsanClusterConfiguration -Server $vc -Cluster $NewVCVSANClusterName | Set-VsanClusterConfiguration -SpaceEfficiencyEnabled $true -HealthCheckIntervalMinutes 0 | Out-File -Append -LiteralPath $verboseLogFile 532 | } 533 | 534 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 535 | if((Get-VsanDiskGroup -VMHost $vmhost) -eq $null) { 536 | $luns = $vmhost | Get-ScsiLun | select CanonicalName, CapacityGB 537 | 538 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 539 | foreach ($lun in $luns) { 540 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 541 | $vsanCacheDisk = $lun.CanonicalName 542 | } 543 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 544 | $vsanCapacityDisk = $lun.CanonicalName 545 | } 546 | } 547 | My-Logger "Creating VSAN DiskGroup for $vmhost ..." 548 | New-VsanDiskGroup -Server $vc -VMHost $vmhost -SsdCanonicalName $vsanCacheDisk -DataDiskCanonicalName $vsanCapacityDisk | Out-File -Append -LiteralPath $verboseLogFile 549 | } 550 | } 551 | } 552 | 553 | if($clearVSANHealthCheckAlarm -eq 1) { 554 | My-Logger "Clearing default VSAN Health Check Alarms, not applicable in Nested ESXi env ..." 555 | $alarmMgr = Get-View AlarmManager -Server $vc 556 | Get-Cluster -Server $vc | where {$_.ExtensionData.TriggeredAlarmState} | %{ 557 | $cluster = $_ 558 | $Cluster.ExtensionData.TriggeredAlarmState | %{ 559 | $alarmMgr.AcknowledgeAlarm($_.Alarm,$cluster.ExtensionData.MoRef) 560 | } 561 | } 562 | 563 | My-Logger "Updating VSAN Default VM Storage Policy back to its defaults ..." 564 | $VSANPolicy = Get-SpbmStoragePolicy "Virtual SAN Default Storage Policy" 565 | $Ruleset = New-SpbmRuleSet -Name "Rule-set 1" -AllOfRules @((New-SpbmRule -Capability VSAN.forceProvisioning $false), (New-SpbmRule -Capability VSAN.hostFailuresToTolerate 1)) 566 | $VSANPolicy | Set-SpbmStoragePolicy -RuleSet $Ruleset | Out-File -Append -LiteralPath $verboseLogFile 567 | } 568 | 569 | My-Logger "Disconnecting from new VCSA ..." 570 | Disconnect-VIServer $vc -Confirm:$false 571 | } 572 | $EndTime = Get-Date 573 | $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2) 574 | 575 | My-Logger "vSphere $vSphereVersion Lab Deployment Complete!" 576 | My-Logger "StartTime: $StartTime" 577 | My-Logger " EndTime: $EndTime" 578 | My-Logger " Duration: $duration minutes" 579 | -------------------------------------------------------------------------------- /vsphere-6.0standard-lab-deployment.ps1: -------------------------------------------------------------------------------- 1 | # Author: William Lam 2 | # Website: www.virtuallyghetto.com 3 | # Description: PowerCLI script to deploy a fully functional vSphere 6.0 lab consisting of 3 4 | # Nested ESXi hosts enable w/vSAN + VCSA 6.0u2. Expects a single physical ESXi host 5 | # as the endpoint and all four VMs will be deployed to physical ESXi host 6 | # Reference: http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html 7 | # Credit: Thanks to Alan Renouf as I borrowed some of his PCLI code snippets :) 8 | # 9 | # Changelog 10 | # 11/22/16 11 | # * Automatically handle Nested ESXi on vSAN 12 | # 01/20/17 13 | # * Resolved "Another task in progress" thanks to Jason M 14 | # 02/12/17 15 | # * Support for deploying to VC Target 16 | # * Support for enabling SSH on VCSA 17 | # * Added option to auto-create vApp Container for VMs 18 | # * Added pre-check for required files 19 | # 02/17/17 20 | # * Added missing dvFilter param to eth1 (missing in Nested ESXi OVA) 21 | 22 | # Physical ESXi host or vCenter Server to deploy vSphere 6.0 lab 23 | $VIServer = "vcenter.primp-industries.com" 24 | $VIUsername = "administrator@vsphere.local" 25 | $VIPassword = "!!!MySuperDuperSecurePassword!!!" 26 | 27 | # Specifies whether deployment is to an ESXi host or vCenter Server 28 | # Use either ESXI or VCENTER 29 | $DeploymentTarget = "VCENTER" 30 | 31 | # Full Path to both the Nested ESXi 6.0 VA + extracted VCSA 6.0 ISO 32 | $NestedESXiApplianceOVA = "C:\Users\primp\Desktop\Nested_ESXi6.x_Appliance_Template_v5.ova" 33 | $VCSAInstallerPath = "C:\Users\primp\Desktop\VMware-VCSA-all-6.0.0-3634788" 34 | 35 | # Nested ESXi VMs to deploy 36 | $NestedESXiHostnameToIPs = @{ 37 | "vesxi60-1" = "172.30.0.85" 38 | "vesxi60-2" = "172.30.0.86" 39 | "vesxi60-3" = "172.30.0.87" 40 | } 41 | 42 | # Nested ESXi VM Resources 43 | $NestedESXivCPU = "2" 44 | $NestedESXivMEM = "6" #GB 45 | $NestedESXiCachingvDisk = "4" #GB 46 | $NestedESXiCapacityvDisk = "8" #GB 47 | 48 | # VCSA Deployment Configuration 49 | $VCSADeploymentSize = "tiny" 50 | $VCSADisplayName = "vcenter60-1" 51 | $VCSAIPAddress = "172.30.0.50" 52 | $VCSAHostname = "vcenter60-1.primp-industries.com" #Change to IP if you don't have valid DNS 53 | $VCSAPrefix = "24" 54 | $VCSASSODomainName = "vsphere.local" 55 | $VCSASSOSiteName = "virtuallyGhetto" 56 | $VCSASSOPassword = "VMware1!" 57 | $VCSARootPassword = "VMware1!" 58 | $VCSASSHEnable = "true" 59 | 60 | # General Deployment Configuration for both Nested ESXi VMs + VCSA 61 | $VMNetwork = "access333" 62 | $VMDatastore = "himalaya-local-SATA-dc3500-3" 63 | $VMNetmask = "255.255.255.0" 64 | $VMGateway = "172.30.0.1" 65 | $VMDNS = "172.30.0.100" 66 | $VMNTP = "pool.ntp.org" 67 | $VMPassword = "vmware123" 68 | $VMDomain = "primp-industries.com" 69 | $VMSyslog = "172.30.0.50" 70 | # Applicable to Nested ESXi only 71 | $VMSSH = "true" 72 | $VMVMFS = "false" 73 | # Applicable to VC Deployment Target only 74 | $VMCluster = "Primp-Cluster" 75 | 76 | # Name of new vSphere Datacenter/Cluster when VCSA is deployed 77 | $NewVCDatacenterName = "Datacenter" 78 | $NewVCVSANClusterName = "VSAN-Cluster" 79 | 80 | #### DO NOT EDIT BEYOND HERE #### 81 | 82 | $verboseLogFile = "vsphere60-lab-deployment.log" 83 | $vSphereVersion = "6.0u2" 84 | $deploymentType = "Standard" 85 | $random_string = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_}) 86 | $VAppName = "Nested-vSphere-Lab-$vSphereVersion-$random_string" 87 | 88 | $preCheck = 1 89 | $confirmDeployment = 1 90 | $deployNestedESXiVMs = 1 91 | $deployVCSA = 1 92 | $setupNewVC = 1 93 | $addESXiHostsToVC = 1 94 | $configureVSANDiskGroups = 1 95 | $clearVSANHealthCheckAlarm = 1 96 | $moveVMsIntovApp = 1 97 | 98 | $StartTime = Get-Date 99 | 100 | Function My-Logger { 101 | param( 102 | [Parameter(Mandatory=$true)] 103 | [String]$message 104 | ) 105 | 106 | $timeStamp = Get-Date -Format "MM-dd-yyyy_hh:mm:ss" 107 | 108 | Write-Host -NoNewline -ForegroundColor White "[$timestamp]" 109 | Write-Host -ForegroundColor Green " $message" 110 | $logMessage = "[$timeStamp] $message" 111 | $logMessage | Out-File -Append -LiteralPath $verboseLogFile 112 | } 113 | 114 | if($preCheck -eq 1) { 115 | if(!(Test-Path $NestedESXiApplianceOVA)) { 116 | Write-Host -ForegroundColor Red "`nUnable to find $NestedESXiApplianceOVA ...`nexiting" 117 | exit 118 | } 119 | 120 | if(!(Test-Path $VCSAInstallerPath)) { 121 | Write-Host -ForegroundColor Red "`nUnable to find $VCSAInstallerPath ...`nexiting" 122 | exit 123 | } 124 | } 125 | 126 | if($confirmDeployment -eq 1) { 127 | Write-Host -ForegroundColor Magenta "`nPlease confirm the following configuration will be deployed:`n" 128 | 129 | Write-Host -ForegroundColor Yellow "---- vSphere Automated Lab Deployment Configuration ---- " 130 | Write-Host -NoNewline -ForegroundColor Green "Deployment Type: " 131 | Write-Host -ForegroundColor White $deploymentType 132 | Write-Host -NoNewline -ForegroundColor Green "vSphere Version: " 133 | Write-Host -ForegroundColor White "vSphere $vSphereVersion" 134 | Write-Host -NoNewline -ForegroundColor Green "Nested ESXi Image Path: " 135 | Write-Host -ForegroundColor White $NestedESXiApplianceOVA 136 | Write-Host -NoNewline -ForegroundColor Green "VCSA Image Path: " 137 | Write-Host -ForegroundColor White $VCSAInstallerPath 138 | 139 | if($DeploymentTarget -eq "ESXI") { 140 | Write-Host -ForegroundColor Yellow "`n---- Physical ESXi Configuration ----" 141 | Write-Host -NoNewline -ForegroundColor Green "ESXi Address: " 142 | } else { 143 | Write-Host -ForegroundColor Yellow "`n---- vCenter Server Configuration ----" 144 | Write-Host -NoNewline -ForegroundColor Green "vCenter Server Address: " 145 | } 146 | 147 | Write-Host -ForegroundColor White $VIServer 148 | Write-Host -NoNewline -ForegroundColor Green "Username: " 149 | Write-Host -ForegroundColor White $VIUsername 150 | Write-Host -NoNewline -ForegroundColor Green "VM Network: " 151 | Write-Host -ForegroundColor White $VMNetwork 152 | Write-Host -NoNewline -ForegroundColor Green "VM Storage: " 153 | Write-Host -ForegroundColor White $VMDatastore 154 | 155 | if($DeploymentTarget -eq "VCENTER") { 156 | Write-Host -NoNewline -ForegroundColor Green "VM Cluster: " 157 | Write-Host -ForegroundColor White $VMCluster 158 | Write-Host -NoNewline -ForegroundColor Green "VM vApp: " 159 | Write-Host -ForegroundColor White $VAppName 160 | } 161 | 162 | Write-Host -ForegroundColor Yellow "`n---- vESXi Configuration ----" 163 | Write-Host -NoNewline -ForegroundColor Green "# of Nested ESXi VMs: " 164 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.count 165 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 166 | Write-Host -ForegroundColor White $NestedESXivCPU 167 | Write-Host -NoNewline -ForegroundColor Green "vMEM: " 168 | Write-Host -ForegroundColor White "$NestedESXivMEM GB" 169 | Write-Host -NoNewline -ForegroundColor Green "Caching VMDK: " 170 | Write-Host -ForegroundColor White "$NestedESXiCachingvDisk GB" 171 | Write-Host -NoNewline -ForegroundColor Green "Capacity VMDK: " 172 | Write-Host -ForegroundColor White "$NestedESXiCapacityvDisk GB" 173 | Write-Host -NoNewline -ForegroundColor Green "IP Address(s): " 174 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.Values 175 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 176 | Write-Host -ForegroundColor White $VMNetmask 177 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 178 | Write-Host -ForegroundColor White $VMGateway 179 | Write-Host -NoNewline -ForegroundColor Green "DNS: " 180 | Write-Host -ForegroundColor White $VMDNS 181 | Write-Host -NoNewline -ForegroundColor Green "NTP: " 182 | Write-Host -ForegroundColor White $VMNTP 183 | Write-Host -NoNewline -ForegroundColor Green "Syslog: " 184 | Write-Host -ForegroundColor White $VMSyslog 185 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 186 | Write-Host -ForegroundColor White $VMSSH 187 | Write-Host -NoNewline -ForegroundColor Green "Create VMFS Volume: " 188 | Write-Host -ForegroundColor White $VMVMFS 189 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 190 | Write-Host -ForegroundColor White $VMPassword 191 | 192 | Write-Host -ForegroundColor Yellow "`n---- VCSA Configuration ----" 193 | Write-Host -NoNewline -ForegroundColor Green "Deployment Size: " 194 | Write-Host -ForegroundColor White $VCSADeploymentSize 195 | Write-Host -NoNewline -ForegroundColor Green "SSO Domain: " 196 | Write-Host -ForegroundColor White $VCSASSODomainName 197 | Write-Host -NoNewline -ForegroundColor Green "SSO Site: " 198 | Write-Host -ForegroundColor White $VCSASSOSiteName 199 | Write-Host -NoNewline -ForegroundColor Green "SSO Password: " 200 | Write-Host -ForegroundColor White $VCSASSOPassword 201 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 202 | Write-Host -ForegroundColor White $VCSARootPassword 203 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 204 | Write-Host -ForegroundColor White $VCSASSHEnable 205 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 206 | Write-Host -ForegroundColor White $VCSAHostname 207 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 208 | Write-Host -ForegroundColor White $VCSAIPAddress 209 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 210 | Write-Host -ForegroundColor White $VMNetmask 211 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 212 | Write-Host -ForegroundColor White $VMGateway 213 | 214 | Write-Host -ForegroundColor Magenta "`nWould you like to proceed with this deployment?`n" 215 | $answer = Read-Host -Prompt "Do you accept (Y or N)" 216 | if($answer -ne "Y" -or $answer -ne "y") { 217 | exit 218 | } 219 | Clear-Host 220 | } 221 | 222 | My-Logger "Connecting to $VIServer ..." 223 | $viConnection = Connect-VIServer $VIServer -User $VIUsername -Password $VIPassword -WarningAction SilentlyContinue 224 | 225 | if($DeploymentTarget -eq "ESXI") { 226 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore 227 | $vmhost = Get-VMHost -Server $viConnection 228 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork -VMHost $vmhost 229 | 230 | if($datastore.Type -eq "vsan") { 231 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 232 | Get-AdvancedSetting -Entity $vmhost -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 233 | } 234 | } else { 235 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore | Select -First 1 236 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork | Select -First 1 237 | $cluster = Get-Cluster -Server $viConnection -Name $VMCluster 238 | $datacenter = $cluster | Get-Datacenter 239 | $vmhost = $cluster | Get-VMHost | Select -First 1 240 | } 241 | 242 | if($deployNestedESXiVMs -eq 1) { 243 | if($DeploymentTarget -eq "ESXI") { 244 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 245 | $VMName = $_.Key 246 | $VMIPAddress = $_.Value 247 | 248 | My-Logger "Deploying Nested ESXi VM $VMName ..." 249 | $vm = Import-VApp -Server $viConnection -Source $NestedESXiApplianceOVA -Name $VMName -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 250 | 251 | My-Logger "Updating VM Network ..." 252 | foreach($networkAdapter in ($vm | Get-NetworkAdapter)) 253 | { 254 | My-Logger "Configuring adapter $networkAdapter in $vm" 255 | $networkAdapter | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 256 | sleep 5 257 | } 258 | 259 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 260 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 261 | 262 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 263 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 264 | 265 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 266 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 267 | 268 | $orignalExtraConfig = $vm.ExtensionData.Config.ExtraConfig 269 | $a = New-Object VMware.Vim.OptionValue 270 | $a.key = "guestinfo.hostname" 271 | $a.value = $VMName 272 | $b = New-Object VMware.Vim.OptionValue 273 | $b.key = "guestinfo.ipaddress" 274 | $b.value = $VMIPAddress 275 | $c = New-Object VMware.Vim.OptionValue 276 | $c.key = "guestinfo.netmask" 277 | $c.value = $VMNetmask 278 | $d = New-Object VMware.Vim.OptionValue 279 | $d.key = "guestinfo.gateway" 280 | $d.value = $VMGateway 281 | $e = New-Object VMware.Vim.OptionValue 282 | $e.key = "guestinfo.dns" 283 | $e.value = $VMDNS 284 | $f = New-Object VMware.Vim.OptionValue 285 | $f.key = "guestinfo.domain" 286 | $f.value = $VMDomain 287 | $g = New-Object VMware.Vim.OptionValue 288 | $g.key = "guestinfo.ntp" 289 | $g.value = $VMNTP 290 | $h = New-Object VMware.Vim.OptionValue 291 | $h.key = "guestinfo.syslog" 292 | $h.value = $VMSyslog 293 | $i = New-Object VMware.Vim.OptionValue 294 | $i.key = "guestinfo.password" 295 | $i.value = $VMPassword 296 | $j = New-Object VMware.Vim.OptionValue 297 | $j.key = "guestinfo.ssh" 298 | $j.value = $VMSSH 299 | $k = New-Object VMware.Vim.OptionValue 300 | $k.key = "guestinfo.createvmfs" 301 | $k.value = $VMVMFS 302 | $l = New-Object VMware.Vim.OptionValue 303 | $l.key = "ethernet1.filter4.name" 304 | $l.value = "dvfilter-maclearn" 305 | $m = New-Object VMware.Vim.OptionValue 306 | $m.key = "ethernet1.filter4.onFailure" 307 | $m.value = "failOpen" 308 | $orignalExtraConfig+=$a 309 | $orignalExtraConfig+=$b 310 | $orignalExtraConfig+=$c 311 | $orignalExtraConfig+=$d 312 | $orignalExtraConfig+=$e 313 | $orignalExtraConfig+=$f 314 | $orignalExtraConfig+=$g 315 | $orignalExtraConfig+=$h 316 | $orignalExtraConfig+=$i 317 | $orignalExtraConfig+=$j 318 | $orignalExtraConfig+=$k 319 | $orignalExtraConfig+=$l 320 | $orignalExtraConfig+=$m 321 | 322 | $spec = New-Object VMware.Vim.VirtualMachineConfigSpec 323 | $spec.ExtraConfig = $orignalExtraConfig 324 | 325 | My-Logger "Adding guestinfo customization properties to $vmname ..." 326 | $task = $vm.ExtensionData.ReconfigVM_Task($spec) 327 | $task1 = Get-Task -Id ("Task-$($task.value)") 328 | $task1 | Wait-Task | Out-Null 329 | 330 | My-Logger "Powering On $vmname ..." 331 | Start-VM -Server $viConnection -VM $vm -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 332 | } 333 | } else { 334 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 335 | $VMName = $_.Key 336 | $VMIPAddress = $_.Value 337 | 338 | $ovfconfig = Get-OvfConfiguration $NestedESXiApplianceOVA 339 | $networkMapLabel = ($ovfconfig.ToHashTable().keys | where {$_ -Match "NetworkMapping"}).replace("NetworkMapping.","").replace("-","_").replace(" ","_") 340 | $ovfconfig.NetworkMapping.$networkMapLabel.value = $VMNetwork 341 | 342 | $ovfconfig.common.guestinfo.hostname.value = $VMName 343 | $ovfconfig.common.guestinfo.ipaddress.value = $VMIPAddress 344 | $ovfconfig.common.guestinfo.netmask.value = $VMNetmask 345 | $ovfconfig.common.guestinfo.gateway.value = $VMGateway 346 | $ovfconfig.common.guestinfo.dns.value = $VMDNS 347 | $ovfconfig.common.guestinfo.domain.value = $VMDomain 348 | $ovfconfig.common.guestinfo.ntp.value = $VMNTP 349 | $ovfconfig.common.guestinfo.syslog.value = $VMSyslog 350 | $ovfconfig.common.guestinfo.password.value = $VMPassword 351 | if($VMSSH -eq "true") { 352 | $VMSSHVar = $true 353 | } else { 354 | $VMSSHVar = $false 355 | } 356 | $ovfconfig.common.guestinfo.ssh.value = $VMSSHVar 357 | 358 | My-Logger "Deploying Nested ESXi VM $VMName ..." 359 | $vm = Import-VApp -Source $NestedESXiApplianceOVA -OvfConfiguration $ovfconfig -Name $VMName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 360 | 361 | # Add the dvfilter settings to the exisiting ethernet1 (not part of ova template) 362 | My-Logger "Correcting missing dvFilter settings for Ethernet[1] ..." 363 | $vm | New-AdvancedSetting -name "ethernet1.filter4.name" -value "dvfilter-maclearn" -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 364 | $vm | New-AdvancedSetting -Name "ethernet1.filter4.onFailure" -value "failOpen" -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 365 | 366 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 367 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 368 | 369 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 370 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 371 | 372 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 373 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 374 | 375 | My-Logger "Powering On $vmname ..." 376 | $vm | Start-Vm -RunAsync | Out-Null 377 | } 378 | } 379 | } 380 | 381 | 382 | if($deployVCSA -eq 1) { 383 | # Deploy using the VCSA CLI Installer 384 | if($DeploymentTarget -eq "ESXI") { 385 | $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_ESXi.json") | convertfrom-json 386 | $config.'target.vcsa'.esx.hostname = $VIServer 387 | $config.'target.vcsa'.esx.username = $VIUsername 388 | $config.'target.vcsa'.esx.password = $VIPassword 389 | $config.'target.vcsa'.esx.datastore = $datastore 390 | $config.'target.vcsa'.appliance.'deployment.network' = $VMNetwork 391 | $config.'target.vcsa'.appliance.'thin.disk.mode' = $true 392 | $config.'target.vcsa'.appliance.'deployment.option' = $VCSADeploymentSize 393 | $config.'target.vcsa'.appliance.name = $VCSADisplayName 394 | $config.'target.vcsa'.network.'ip.family' = "ipv4" 395 | $config.'target.vcsa'.network.mode = "static" 396 | $config.'target.vcsa'.network.ip = $VCSAIPAddress 397 | $config.'target.vcsa'.network.'dns.servers'[0] = $VMDNS 398 | $config.'target.vcsa'.network.'dns.servers'[1] = $null 399 | $config.'target.vcsa'.network.prefix = $VCSAPrefix 400 | $config.'target.vcsa'.network.gateway = $VMGateway 401 | $config.'target.vcsa'.network.hostname = $VCSAHostname 402 | $config.'target.vcsa'.os.password = $VCSARootPassword 403 | if($VCSASSHEnable -eq "true") { 404 | $VCSASSHEnableVar = $true 405 | } else { 406 | $VCSASSHEnableVar = $false 407 | } 408 | $config.'target.vcsa'.os.'ssh.enable' = $VCSASSHEnableVar 409 | $config.'target.vcsa'.sso.password = $VCSASSOPassword 410 | $config.'target.vcsa'.sso.'domain-name' = $VCSASSODomainName 411 | $config.'target.vcsa'.sso.'site-name' = $VCSASSOSiteName 412 | 413 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 414 | $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" 415 | 416 | My-Logger "Deploying the VCSA ..." 417 | $output = Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula $($ENV:Temp)\jsontemplate.json" -ErrorVariable vcsaDeployOutput 2>&1 418 | $vcsaDeployOutput | Out-File -Append -LiteralPath $verboseLogFile 419 | } else { 420 | $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_VC.json") | convertfrom-json 421 | $config.'target.vcsa'.vc.hostname = $VIServer 422 | $config.'target.vcsa'.vc.username = $VIUsername 423 | $config.'target.vcsa'.vc.password = $VIPassword 424 | $config.'target.vcsa'.vc.datastore = $datastore 425 | $config.'target.vcsa'.vc.datacenter = $datacenter.name 426 | $config.'target.vcsa'.vc.target = $VMCluster 427 | $config.'target.vcsa'.appliance.'deployment.network' = $VMNetwork 428 | $config.'target.vcsa'.appliance.'thin.disk.mode' = $true 429 | $config.'target.vcsa'.appliance.'deployment.option' = $VCSADeploymentSize 430 | $config.'target.vcsa'.appliance.name = $VCSADisplayName 431 | $config.'target.vcsa'.network.'ip.family' = "ipv4" 432 | $config.'target.vcsa'.network.mode = "static" 433 | $config.'target.vcsa'.network.ip = $VCSAIPAddress 434 | $config.'target.vcsa'.network.'dns.servers'[0] = $VMDNS 435 | $config.'target.vcsa'.network.'dns.servers'[1] = $null 436 | $config.'target.vcsa'.network.prefix = $VCSAPrefix 437 | $config.'target.vcsa'.network.gateway = $VMGateway 438 | $config.'target.vcsa'.network.hostname = $VCSAHostname 439 | $config.'target.vcsa'.os.password = $VCSARootPassword 440 | if($VCSASSHEnable -eq "true") { 441 | $VCSASSHEnableVar = $true 442 | } else { 443 | $VCSASSHEnableVar = $false 444 | } 445 | $config.'target.vcsa'.os.'ssh.enable' = $VCSASSHEnableVar 446 | $config.'target.vcsa'.sso.password = $VCSASSOPassword 447 | $config.'target.vcsa'.sso.'domain-name' = $VCSASSODomainName 448 | $config.'target.vcsa'.sso.'site-name' = $VCSASSOSiteName 449 | 450 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 451 | $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" 452 | 453 | My-Logger "Deploying the VCSA ..." 454 | $output = Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula $($ENV:Temp)\jsontemplate.json" -ErrorVariable vcsaDeployOutput 2>&1 455 | $vcsaDeployOutput | Out-File -Append -LiteralPath $verboseLogFile 456 | } 457 | } 458 | 459 | if($moveVMsIntovApp -eq 1 -and $DeploymentTarget -eq "VCENTER") { 460 | # Check whether DRS is enabled as that is required to create vApp 461 | if((Get-Cluster -Server $viConnection $cluster).DrsEnabled) { 462 | My-Logger "Creating vApp $VAppName ..." 463 | $VApp = New-VApp -Name $VAppName -Server $viConnection -Location $cluster 464 | 465 | if($deployNestedESXiVMs -eq 1) { 466 | My-Logger "Moving Nested ESXi VMs into $VAppName vApp ..." 467 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 468 | $vm = Get-VM -Name $_.Key -Server $viConnection 469 | Move-VM -VM $vm -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 470 | } 471 | } 472 | 473 | if($deployVCSA -eq 1) { 474 | $vcsaVM = Get-VM -Name $VCSADisplayName 475 | My-Logger "Moving $vcsaVM into $VAppName vApp ..." 476 | Move-VM -VM $vcsaVM -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 477 | } 478 | } else { 479 | My-Logger "vApp $VAppName will NOT be created as DRS is NOT enabled on vSphere Cluster ${cluster} ..." 480 | } 481 | } 482 | 483 | My-Logger "Disconnecting from $VIServer ..." 484 | Disconnect-VIServer $viConnection -Confirm:$false 485 | 486 | if($setupNewVC -eq 1) { 487 | My-Logger "Connecting to the new VCSA ..." 488 | $vc = Connect-VIServer $VCSAIPAddress -User "administrator@$VCSASSODomainName" -Password $VCSASSOPassword -WarningAction SilentlyContinue 489 | 490 | My-Logger "Creating Datacenter $NewVCDatacenterName ..." 491 | New-Datacenter -Server $vc -Name $NewVCDatacenterName -Location (Get-Folder -Type Datacenter -Server $vc) | Out-File -Append -LiteralPath $verboseLogFile 492 | 493 | My-Logger "Creating VSAN Cluster $NewVCVSANClusterName ..." 494 | New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -VsanEnabled -VsanDiskClaimMode 'Manual' | Out-File -Append -LiteralPath $verboseLogFile 495 | 496 | if($addESXiHostsToVC -eq 1) { 497 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 498 | $VMName = $_.Key 499 | $VMIPAddress = $_.Value 500 | 501 | My-Logger "Adding ESXi host $VMIPAddress to Cluster ..." 502 | Add-VMHost -Server $vc -Location (Get-Cluster -Name $NewVCVSANClusterName) -User "root" -Password $VMPassword -Name $VMIPAddress -Force | Out-File -Append -LiteralPath $verboseLogFile 503 | } 504 | 505 | } 506 | 507 | if($configureVSANDiskGroups -eq 1) { 508 | # New vSAN cmdlets only works on 6.0u3+ 509 | $VmhostToCheckVersion = (Get-Cluster -Server $vc | Get-VMHost)[0] 510 | $MajorVersion = $VmhostToCheckVersion.Version 511 | $UpdateVersion = (Get-AdvancedSetting -Entity $VmhostToCheckVersion -Name Misc.HostAgentUpdateLevel).value 512 | 513 | if( ($MajorVersion -eq "6.0.0" -and $UpdateVersion -eq "3") -or $MajorVersion -eq "6.5.0") { 514 | My-Logger "Enabling VSAN Space Efficiency/De-Dupe & disabling VSAN Health Check ..." 515 | Get-VsanClusterConfiguration -Server $vc -Cluster $NewVCVSANClusterName | Set-VsanClusterConfiguration -SpaceEfficiencyEnabled $true -HealthCheckIntervalMinutes 0 | Out-File -Append -LiteralPath $verboseLogFile 516 | } 517 | 518 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 519 | $luns = $vmhost | Get-ScsiLun | select CanonicalName, CapacityGB 520 | 521 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 522 | foreach ($lun in $luns) { 523 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 524 | $vsanCacheDisk = $lun.CanonicalName 525 | } 526 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 527 | $vsanCapacityDisk = $lun.CanonicalName 528 | } 529 | } 530 | My-Logger "Creating VSAN DiskGroup for $vmhost ..." 531 | New-VsanDiskGroup -Server $vc -VMHost $vmhost -SsdCanonicalName $vsanCacheDisk -DataDiskCanonicalName $vsanCapacityDisk | Out-File -Append -LiteralPath $verboseLogFile 532 | } 533 | } 534 | 535 | if($clearVSANHealthCheckAlarm -eq 1) { 536 | My-Logger "Clearing default VSAN Health Check Alarms, not applicable in Nested ESXi env ..." 537 | $alarmMgr = Get-View AlarmManager -Server $vc 538 | Get-Cluster -Server $vc | where {$_.ExtensionData.TriggeredAlarmState} | %{ 539 | $cluster = $_ 540 | $Cluster.ExtensionData.TriggeredAlarmState | %{ 541 | $alarmMgr.AcknowledgeAlarm($_.Alarm,$cluster.ExtensionData.MoRef) 542 | } 543 | } 544 | } 545 | 546 | My-Logger "Disconnecting from new VCSA ..." 547 | Disconnect-VIServer $vc -Confirm:$false 548 | } 549 | $EndTime = Get-Date 550 | $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2) 551 | 552 | My-Logger "vSphere $vSphereVersion Lab Deployment Complete!" 553 | My-Logger "StartTime: $StartTime" 554 | My-Logger " EndTime: $EndTime" 555 | My-Logger " Duration: $duration minutes" 556 | -------------------------------------------------------------------------------- /vsphere-6.5-lab-deployment-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamw/vsphere-automated-lab-deployment/7807e8a50f82f319b07a256bfd1c764856a9aa44/vsphere-6.5-lab-deployment-0.png -------------------------------------------------------------------------------- /vsphere-6.5-lab-deployment-1-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamw/vsphere-automated-lab-deployment/7807e8a50f82f319b07a256bfd1c764856a9aa44/vsphere-6.5-lab-deployment-1-new.png -------------------------------------------------------------------------------- /vsphere-6.5-lab-deployment-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamw/vsphere-automated-lab-deployment/7807e8a50f82f319b07a256bfd1c764856a9aa44/vsphere-6.5-lab-deployment-2.png -------------------------------------------------------------------------------- /vsphere-6.5-lab-deployment-4-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamw/vsphere-automated-lab-deployment/7807e8a50f82f319b07a256bfd1c764856a9aa44/vsphere-6.5-lab-deployment-4-new.png -------------------------------------------------------------------------------- /vsphere-6.5-lab-deployment-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamw/vsphere-automated-lab-deployment/7807e8a50f82f319b07a256bfd1c764856a9aa44/vsphere-6.5-lab-deployment-5.png -------------------------------------------------------------------------------- /vsphere-6.5-lab-deployment-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lamw/vsphere-automated-lab-deployment/7807e8a50f82f319b07a256bfd1c764856a9aa44/vsphere-6.5-lab-deployment-6.png -------------------------------------------------------------------------------- /vsphere-6.5-self-manage-lab-deployment.ps1: -------------------------------------------------------------------------------- 1 | # Author: William Lam 2 | # Website: www.virtuallyghetto.com 3 | # Description: PowerCLI script to deploy a fully functional vSphere 6.5 lab consisting of 3 4 | # Nested ESXi hosts enable w/vSAN + VCSA 6.5. Expects a single physical ESXi host 5 | # as the endpoint and all three Nested ESXi VMs will be deployed to physical ESXi host 6 | # with the VCSA then being deployed to the inner-Nested ESXi VMs as a self-managed VC 7 | # Reference: http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html 8 | # Credit: Thanks to Alan Renouf as I borrowed some of his PCLI code snippets :) 9 | # 10 | # Changelog 11 | # 11/22/16 12 | # * Automatically handle Nested ESXi on vSAN 13 | # 01/20/17 14 | # * Resolved "Another task in progress" thanks to Jason M 15 | # 02/12/17 16 | # * Support for deploying to VC Target 17 | # * Support for enabling SSH on VCSA 18 | # * Added option to auto-create vApp Container for VMs 19 | # * Added pre-check for required files 20 | # 02/17/17 21 | # * Added missing dvFilter param to eth1 (missing in Nested ESXi OVA) 22 | 23 | # Physical ESXi host or vCenter Server to deploy vSphere 6.5 lab 24 | $VIServer = "vcenter.primp-industries.com" 25 | $VIUsername = "administrator@vsphere.local" 26 | $VIPassword = "!!!MySuperDuperSecurePassword!!!" 27 | 28 | # Specifies whether deployment is to an ESXi host or vCenter Server 29 | # Use either ESXI or VCENTER 30 | $DeploymentTarget = "VCENTER" 31 | 32 | # Full Path to both the Nested ESXi 6.5 VA + extracted VCSA 6.5 ISO 33 | $NestedESXiApplianceOVA = "C:\Users\primp\Desktop\Nested_ESXi6.5_Appliance_Template_v1.ova" 34 | $VCSAInstallerPath = "C:\Users\primp\Desktop\VMware-VCSA-all-6.5.0-4944578" 35 | 36 | # Nested ESXi VMs to deploy 37 | $NestedESXiHostnameToIPs = @{ 38 | "vesxi65-1" = "172.30.0.171" 39 | "vesxi65-2" = "172.30.0.172" 40 | "vesxi65-3" = "172.30.0.173" 41 | } 42 | 43 | #Nested ESXi Bootstrap Node 44 | $bootStrapNode = "172.30.0.171" 45 | 46 | # Nested ESXi VM Resources 47 | $NestedESXivCPU = "2" 48 | $NestedESXivMEM = "32" #GB 49 | $NestedESXiCachingvDisk = "16" #GB 50 | $NestedESXiCapacityvDisk = "200" #GB 51 | 52 | # VCSA Deployment Configuration 53 | $VCSADeploymentSize = "tiny" 54 | $VCSADisplayName = "vcenter65-1" 55 | $VCSAIPAddress = "172.30.0.170" 56 | $VCSAHostname = "vcenter65-1.primp-industries.com" #Change to IP if you don't have valid DNS 57 | $VCSAPrefix = "24" 58 | $VCSASSODomainName = "vsphere.local" 59 | $VCSASSOSiteName = "virtuallyGhetto" 60 | $VCSASSOPassword = "VMware1!" 61 | $VCSARootPassword = "VMware1!" 62 | $VCSASSHEnable = "true" 63 | 64 | # General Deployment Configuration for both Nested ESXi VMs + VCSA 65 | $VMNetwork = "access333" 66 | $VMDatastore = "himalaya-local-SATA-dc3500-2" 67 | $VMNetmask = "255.255.255.0" 68 | $VMGateway = "172.30.0.1" 69 | $VMDNS = "172.30.0.100" 70 | $VMNTP = "pool.ntp.org" 71 | $VMPassword = "vmware123" 72 | $VMDomain = "primp-industries.com" 73 | $VMSyslog = "172.30.0.170" 74 | # Applicable to Nested ESXi only 75 | $VMSSH = "true" 76 | $VMVMFS = "false" 77 | # Applicable to VC Deployment Target only 78 | $VMCluster = "Primp-Cluster" 79 | 80 | # Name of new vSphere Datacenter/Cluster when VCSA is deployed 81 | $NewVCDatacenterName = "Datacenter" 82 | $NewVCVSANClusterName = "VSAN-Cluster" 83 | 84 | #### DO NOT EDIT BEYOND HERE #### 85 | 86 | $verboseLogFile = "vsphere65-lab-deployment.log" 87 | $vSphereVersion = "6.5" 88 | $deploymentType = "Self Managed" 89 | $random_string = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_}) 90 | $VAppName = "Nested-vSphere-Lab-$vSphereVersion-$random_string" 91 | 92 | $preCheck = 1 93 | $confirmDeployment = 1 94 | $deployNestedESXiVMs = 1 95 | $bootStrapFirstNestedESXiVM = 1 96 | $deployVCSA = 1 97 | $setupNewVC = 1 98 | $addESXiHostsToVC = 1 99 | $configureVSANDiskGroups = 1 100 | $clearVSANHealthCheckAlarm = 1 101 | $moveVMsIntovApp = 1 102 | 103 | $StartTime = Get-Date 104 | 105 | Function My-Logger { 106 | param( 107 | [Parameter(Mandatory=$true)] 108 | [String]$message 109 | ) 110 | 111 | $timeStamp = Get-Date -Format "MM-dd-yyyy_hh-mm-ss" 112 | 113 | Write-Host -NoNewline -ForegroundColor White "[$timestamp]" 114 | Write-Host -ForegroundColor Green " $message" 115 | $logMessage = "[$timeStamp] $message" 116 | $logMessage | Out-File -Append -LiteralPath $verboseLogFile 117 | } 118 | 119 | if($preCheck -eq 1) { 120 | if(!(Test-Path $NestedESXiApplianceOVA)) { 121 | Write-Host -ForegroundColor Red "`nUnable to find $NestedESXiApplianceOVA ...`nexiting" 122 | exit 123 | } 124 | 125 | if(!(Test-Path $VCSAInstallerPath)) { 126 | Write-Host -ForegroundColor Red "`nUnable to find $VCSAInstallerPath ...`nexiting" 127 | exit 128 | } 129 | } 130 | 131 | if($confirmDeployment -eq 1) { 132 | Write-Host -ForegroundColor Magenta "`nPlease confirm the following configuration will be deployed:`n" 133 | 134 | Write-Host -ForegroundColor Yellow "---- vSphere Automated Lab Deployment Configuration ---- " 135 | Write-Host -NoNewline -ForegroundColor Green "Deployment Target: " 136 | Write-Host -ForegroundColor White $DeploymentTarget 137 | Write-Host -NoNewline -ForegroundColor Green "Deployment Type: " 138 | Write-Host -ForegroundColor White $deploymentType 139 | Write-Host -NoNewline -ForegroundColor Green "vSphere Version: " 140 | Write-Host -ForegroundColor White "vSphere $vSphereVersion" 141 | Write-Host -NoNewline -ForegroundColor Green "Nested ESXi Image Path: " 142 | Write-Host -ForegroundColor White $NestedESXiApplianceOVA 143 | Write-Host -NoNewline -ForegroundColor Green "VCSA Image Path: " 144 | Write-Host -ForegroundColor White $VCSAInstallerPath 145 | 146 | if($DeploymentTarget -eq "ESXI") { 147 | Write-Host -ForegroundColor Yellow "`n---- Physical ESXi Configuration ----" 148 | Write-Host -NoNewline -ForegroundColor Green "ESXi Address: " 149 | } else { 150 | Write-Host -ForegroundColor Yellow "`n---- vCenter Server Configuration ----" 151 | Write-Host -NoNewline -ForegroundColor Green "vCenter Server Address: " 152 | } 153 | 154 | Write-Host -ForegroundColor White $VIServer 155 | Write-Host -NoNewline -ForegroundColor Green "Username: " 156 | Write-Host -ForegroundColor White $VIUsername 157 | Write-Host -NoNewline -ForegroundColor Green "VM Network: " 158 | Write-Host -ForegroundColor White $VMNetwork 159 | Write-Host -NoNewline -ForegroundColor Green "VM Storage: " 160 | Write-Host -ForegroundColor White $VMDatastore 161 | 162 | if($DeploymentTarget -eq "VCENTER") { 163 | Write-Host -NoNewline -ForegroundColor Green "VM Cluster: " 164 | Write-Host -ForegroundColor White $VMCluster 165 | Write-Host -NoNewline -ForegroundColor Green "VM vApp: " 166 | Write-Host -ForegroundColor White $VAppName 167 | } 168 | 169 | Write-Host -ForegroundColor Yellow "`n---- vESXi Configuration ----" 170 | Write-Host -NoNewline -ForegroundColor Green "# of Nested ESXi VMs: " 171 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.count 172 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 173 | Write-Host -ForegroundColor White $NestedESXivCPU 174 | Write-Host -NoNewline -ForegroundColor Green "vMEM: " 175 | Write-Host -ForegroundColor White "$NestedESXivMEM GB" 176 | Write-Host -NoNewline -ForegroundColor Green "Caching VMDK: " 177 | Write-Host -ForegroundColor White "$NestedESXiCachingvDisk GB" 178 | Write-Host -NoNewline -ForegroundColor Green "Capacity VMDK: " 179 | Write-Host -ForegroundColor White "$NestedESXiCapacityvDisk GB" 180 | Write-Host -NoNewline -ForegroundColor Green "IP Address(s): " 181 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.Values 182 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 183 | Write-Host -ForegroundColor White $VMNetmask 184 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 185 | Write-Host -ForegroundColor White $VMGateway 186 | Write-Host -NoNewline -ForegroundColor Green "DNS: " 187 | Write-Host -ForegroundColor White $VMDNS 188 | Write-Host -NoNewline -ForegroundColor Green "NTP: " 189 | Write-Host -ForegroundColor White $VMNTP 190 | Write-Host -NoNewline -ForegroundColor Green "Syslog: " 191 | Write-Host -ForegroundColor White $VMSyslog 192 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 193 | Write-Host -ForegroundColor White $VMSSH 194 | Write-Host -NoNewline -ForegroundColor Green "Create VMFS Volume: " 195 | Write-Host -ForegroundColor White $VMVMFS 196 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 197 | Write-Host -ForegroundColor White $VMPassword 198 | Write-Host -NoNewline -ForegroundColor Green "Bootstrap ESXi Node: " 199 | Write-Host -ForegroundColor White $bootStrapNode 200 | 201 | Write-Host -ForegroundColor Yellow "`n---- VCSA Configuration ----" 202 | Write-Host -NoNewline -ForegroundColor Green "Deployment Size: " 203 | Write-Host -ForegroundColor White $VCSADeploymentSize 204 | Write-Host -NoNewline -ForegroundColor Green "SSO Domain: " 205 | Write-Host -ForegroundColor White $VCSASSODomainName 206 | Write-Host -NoNewline -ForegroundColor Green "SSO Site: " 207 | Write-Host -ForegroundColor White $VCSASSOSiteName 208 | Write-Host -NoNewline -ForegroundColor Green "SSO Password: " 209 | Write-Host -ForegroundColor White $VCSASSOPassword 210 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 211 | Write-Host -ForegroundColor White $VCSARootPassword 212 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 213 | Write-Host -ForegroundColor White $VCSASSHEnable 214 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 215 | Write-Host -ForegroundColor White $VCSAHostname 216 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 217 | Write-Host -ForegroundColor White $VCSAIPAddress 218 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 219 | Write-Host -ForegroundColor White $VMNetmask 220 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 221 | Write-Host -ForegroundColor White $VMGateway 222 | 223 | Write-Host -ForegroundColor Magenta "`nWould you like to proceed with this deployment?`n" 224 | $answer = Read-Host -Prompt "Do you accept (Y or N)" 225 | if($answer -ne "Y" -or $answer -ne "y") { 226 | exit 227 | } 228 | Clear-Host 229 | } 230 | 231 | if($deployNestedESXiVMs -eq 1) { 232 | My-Logger "Connecting to $VIServer ..." 233 | $viConnection = Connect-VIServer $VIServer -User $VIUsername -Password $VIPassword -WarningAction SilentlyContinue 234 | 235 | if($DeploymentTarget -eq "ESXI") { 236 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore 237 | $vmhost = Get-VMHost -Server $viConnection 238 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork -VMHost $vmhost 239 | 240 | if($datastore.Type -eq "vsan") { 241 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 242 | Get-AdvancedSetting -Entity $vmhost -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 243 | } 244 | } else { 245 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore | Select -First 1 246 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork | Select -First 1 247 | $cluster = Get-Cluster -Server $viConnection -Name $VMCluster 248 | $datacenter = $cluster | Get-Datacenter 249 | $vmhost = $cluster | Get-VMHost | Select -First 1 250 | } 251 | 252 | if($DeploymentTarget -eq "ESXI") { 253 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 254 | $VMName = $_.Key 255 | $VMIPAddress = $_.Value 256 | 257 | My-Logger "Deploying Nested ESXi VM $VMName ..." 258 | $vm = Import-VApp -Server $viConnection -Source $NestedESXiApplianceOVA -Name $VMName -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 259 | 260 | My-Logger "Updating VM Network ..." 261 | foreach($networkAdapter in ($vm | Get-NetworkAdapter)) 262 | { 263 | My-Logger "Configuring adapter $networkAdapter in $vm" 264 | $networkAdapter | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 265 | sleep 5 266 | } 267 | 268 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 269 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 270 | 271 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 272 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 273 | 274 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 275 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 276 | 277 | $orignalExtraConfig = $vm.ExtensionData.Config.ExtraConfig 278 | $a = New-Object VMware.Vim.OptionValue 279 | $a.key = "guestinfo.hostname" 280 | $a.value = $VMName 281 | $b = New-Object VMware.Vim.OptionValue 282 | $b.key = "guestinfo.ipaddress" 283 | $b.value = $VMIPAddress 284 | $c = New-Object VMware.Vim.OptionValue 285 | $c.key = "guestinfo.netmask" 286 | $c.value = $VMNetmask 287 | $d = New-Object VMware.Vim.OptionValue 288 | $d.key = "guestinfo.gateway" 289 | $d.value = $VMGateway 290 | $e = New-Object VMware.Vim.OptionValue 291 | $e.key = "guestinfo.dns" 292 | $e.value = $VMDNS 293 | $f = New-Object VMware.Vim.OptionValue 294 | $f.key = "guestinfo.domain" 295 | $f.value = $VMDomain 296 | $g = New-Object VMware.Vim.OptionValue 297 | $g.key = "guestinfo.ntp" 298 | $g.value = $VMNTP 299 | $h = New-Object VMware.Vim.OptionValue 300 | $h.key = "guestinfo.syslog" 301 | $h.value = $VMSyslog 302 | $i = New-Object VMware.Vim.OptionValue 303 | $i.key = "guestinfo.password" 304 | $i.value = $VMPassword 305 | $j = New-Object VMware.Vim.OptionValue 306 | $j.key = "guestinfo.ssh" 307 | $j.value = $VMSSH 308 | $k = New-Object VMware.Vim.OptionValue 309 | $k.key = "guestinfo.createvmfs" 310 | $k.value = $VMVMFS 311 | $l = New-Object VMware.Vim.OptionValue 312 | $l.key = "ethernet1.filter4.name" 313 | $l.value = "dvfilter-maclearn" 314 | $m = New-Object VMware.Vim.OptionValue 315 | $m.key = "ethernet1.filter4.onFailure" 316 | $m.value = "failOpen" 317 | $orignalExtraConfig+=$a 318 | $orignalExtraConfig+=$b 319 | $orignalExtraConfig+=$c 320 | $orignalExtraConfig+=$d 321 | $orignalExtraConfig+=$e 322 | $orignalExtraConfig+=$f 323 | $orignalExtraConfig+=$g 324 | $orignalExtraConfig+=$h 325 | $orignalExtraConfig+=$i 326 | $orignalExtraConfig+=$j 327 | $orignalExtraConfig+=$k 328 | $orignalExtraConfig+=$l 329 | $orignalExtraConfig+=$m 330 | 331 | $spec = New-Object VMware.Vim.VirtualMachineConfigSpec 332 | $spec.ExtraConfig = $orignalExtraConfig 333 | 334 | My-Logger "Adding guestinfo customization properties to $vmname ..." 335 | $task = $vm.ExtensionData.ReconfigVM_Task($spec) 336 | $task1 = Get-Task -Id ("Task-$($task.value)") 337 | $task1 | Wait-Task | Out-File -Append -LiteralPath $verboseLogFile 338 | 339 | My-Logger "Powering On $vmname ..." 340 | Start-VM -Server $viConnection -VM $vm -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 341 | } 342 | } else { 343 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 344 | $VMName = $_.Key 345 | $VMIPAddress = $_.Value 346 | 347 | $ovfconfig = Get-OvfConfiguration $NestedESXiApplianceOVA 348 | $networkMapLabel = ($ovfconfig.ToHashTable().keys | where {$_ -Match "NetworkMapping"}).replace("NetworkMapping.","").replace("-","_").replace(" ","_") 349 | $ovfconfig.NetworkMapping.$networkMapLabel.value = $VMNetwork 350 | 351 | $ovfconfig.common.guestinfo.hostname.value = $VMName 352 | $ovfconfig.common.guestinfo.ipaddress.value = $VMIPAddress 353 | $ovfconfig.common.guestinfo.netmask.value = $VMNetmask 354 | $ovfconfig.common.guestinfo.gateway.value = $VMGateway 355 | $ovfconfig.common.guestinfo.dns.value = $VMDNS 356 | $ovfconfig.common.guestinfo.domain.value = $VMDomain 357 | $ovfconfig.common.guestinfo.ntp.value = $VMNTP 358 | $ovfconfig.common.guestinfo.syslog.value = $VMSyslog 359 | $ovfconfig.common.guestinfo.password.value = $VMPassword 360 | if($VMSSH -eq "true") { 361 | $VMSSHVar = $true 362 | } else { 363 | $VMSSHVar = $false 364 | } 365 | $ovfconfig.common.guestinfo.ssh.value = $VMSSHVar 366 | 367 | My-Logger "Deploying Nested ESXi VM $VMName ..." 368 | $vm = Import-VApp -Source $NestedESXiApplianceOVA -OvfConfiguration $ovfconfig -Name $VMName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 369 | 370 | # Add the dvfilter settings to the exisiting ethernet1 (not part of ova template) 371 | My-Logger "Correcting missing dvFilter settings for Ethernet[1] ..." 372 | $vm | New-AdvancedSetting -name "ethernet1.filter4.name" -value "dvfilter-maclearn" -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 373 | $vm | New-AdvancedSetting -Name "ethernet1.filter4.onFailure" -value "failOpen" -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 374 | 375 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 376 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 377 | 378 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 379 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 380 | 381 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 382 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 383 | 384 | My-Logger "Powering On $vmname ..." 385 | $vm | Start-Vm -RunAsync | Out-Null 386 | } 387 | } 388 | 389 | if($moveVMsIntovApp -eq 1 -and $DeploymentTarget -eq "VCENTER") { 390 | # Check whether DRS is enabled as that is required to create vApp 391 | if((Get-Cluster -Server $viConnection $cluster).DrsEnabled) { 392 | My-Logger "Creating vApp $VAppName ..." 393 | $VApp = New-VApp -Name $VAppName -Server $viConnection -Location $cluster 394 | 395 | if($deployNestedESXiVMs -eq 1) { 396 | My-Logger "Moving Nested ESXi VMs into $VAppName vApp ..." 397 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 398 | $vm = Get-VM -Name $_.Key -Server $viConnection 399 | Move-VM -VM $vm -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 400 | } 401 | } 402 | } else { 403 | My-Logger "vApp $VAppName will NOT be created as DRS is NOT enabled on vSphere Cluster ${cluster} ..." 404 | } 405 | } 406 | 407 | My-Logger "Disconnecting from $VIServer ..." 408 | Disconnect-VIServer $viConnection -Confirm:$false 409 | } 410 | 411 | if($bootStrapFirstNestedESXiVM -eq 1) { 412 | do { 413 | My-Logger "Waiting for $bootStrapNode to be ready on network ..." 414 | $ping = test-connection $bootStrapNode -Quiet 415 | sleep 60 416 | } until ($ping -contains "True") 417 | 418 | My-Logger "Connecting to ESXi bootstrap node ..." 419 | $vEsxi = Connect-VIServer -Server $bootStrapNode -User root -Password $VMPassword -WarningAction SilentlyContinue 420 | 421 | My-Logger "Updating the ESXi host VSAN Policy to allow Force Provisioning ..." 422 | $esxcli = Get-EsxCli -Server $vEsxi -V2 423 | $VSANPolicy = '(("hostFailuresToTolerate" i1) ("forceProvisioning" i1))' 424 | $VSANPolicyDefaults = $esxcli.vsan.policy.setdefault.CreateArgs() 425 | $VSANPolicyDefaults.policy = $VSANPolicy 426 | $VSANPolicyDefaults.policyclass = "vdisk" 427 | $esxcli.vsan.policy.setdefault.Invoke($VSANPolicyDefaults) | Out-File -Append -LiteralPath $verboseLogFile 428 | $VSANPolicyDefaults.policyclass = "vmnamespace" 429 | $esxcli.vsan.policy.setdefault.Invoke($VSANPolicyDefaults) | Out-File -Append -LiteralPath $verboseLogFile 430 | 431 | My-Logger "Creating a new VSAN Cluster" 432 | $esxcli.vsan.cluster.new.Invoke() | Out-File -Append -LiteralPath $verboseLogFile 433 | 434 | $luns = Get-ScsiLun -Server $vEsxi | select CanonicalName, CapacityGB 435 | 436 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 437 | foreach ($lun in $luns) { 438 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 439 | $vsanCacheDisk = $lun.CanonicalName 440 | } 441 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 442 | $vsanCapacityDisk = $lun.CanonicalName 443 | } 444 | } 445 | 446 | My-Logger "Tagging Capacity Disk ..." 447 | $capacitytag = $esxcli.vsan.storage.tag.add.CreateArgs() 448 | $capacitytag.disk = $vsanCapacityDisk 449 | $capacitytag.tag = "capacityFlash" 450 | $esxcli.vsan.storage.tag.add.Invoke($capacitytag) | Out-File -Append -LiteralPath $verboseLogFile 451 | 452 | My-Logger "Creating VSAN Diskgroup ..." 453 | $addvsanstorage = $esxcli.vsan.storage.add.CreateArgs() 454 | $addvsanstorage.ssd = $vsanCacheDisk 455 | $addvsanstorage.disks = $vsanCapacityDisk 456 | $esxcli.vsan.storage.add.Invoke($addvsanstorage) | Out-File -Append -LiteralPath $verboseLogFile 457 | 458 | My-Logger "Disconnecting from $esxi ..." 459 | Disconnect-VIServer $vEsxi -Confirm:$false 460 | } 461 | 462 | if($deployVCSA -eq 1) { 463 | My-Logger "Connecting to first ESXi bootstrap node ..." 464 | $vEsxi = Connect-VIServer -Server $bootStrapNode -User root -Password $VMPassword -WarningAction SilentlyContinue 465 | 466 | # Deploy using the VCSA CLI Installer 467 | $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_ESXi.json") | convertfrom-json 468 | $config.'new.vcsa'.esxi.hostname = $bootStrapNode 469 | $config.'new.vcsa'.esxi.username = "root" 470 | $config.'new.vcsa'.esxi.password = $VMPassword 471 | $config.'new.vcsa'.esxi.'deployment.network' = "VM Network" 472 | $config.'new.vcsa'.esxi.datastore = "vsanDatastore" 473 | $config.'new.vcsa'.appliance.'thin.disk.mode' = $true 474 | $config.'new.vcsa'.appliance.'deployment.option' = $VCSADeploymentSize 475 | $config.'new.vcsa'.appliance.name = $VCSADisplayName 476 | $config.'new.vcsa'.network.'ip.family' = "ipv4" 477 | $config.'new.vcsa'.network.mode = "static" 478 | $config.'new.vcsa'.network.ip = $VCSAIPAddress 479 | $config.'new.vcsa'.network.'dns.servers'[0] = $VMDNS 480 | $config.'new.vcsa'.network.prefix = $VCSAPrefix 481 | $config.'new.vcsa'.network.gateway = $VMGateway 482 | $config.'new.vcsa'.network.'system.name' = $VCSAHostname 483 | $config.'new.vcsa'.os.password = $VCSARootPassword 484 | if($VCSASSHEnable -eq "true") { 485 | $VCSASSHEnableVar = $true 486 | } else { 487 | $VCSASSHEnableVar = $false 488 | } 489 | $config.'new.vcsa'.os.'ssh.enable' = $VCSASSHEnableVar 490 | $config.'new.vcsa'.sso.password = $VCSASSOPassword 491 | $config.'new.vcsa'.sso.'domain-name' = $VCSASSODomainName 492 | $config.'new.vcsa'.sso.'site-name' = $VCSASSOSiteName 493 | 494 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 495 | $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" 496 | 497 | My-Logger "Deploying the VCSA ..." 498 | Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula --acknowledge-ceip $($ENV:Temp)\jsontemplate.json" | Out-File -Append -LiteralPath $verboseLogFile 499 | 500 | My-Logger "Disconnecting from $bootStrapNode ..." 501 | Disconnect-VIServer $vEsxi -Confirm:$false 502 | } 503 | 504 | if($setupNewVC -eq 1) { 505 | My-Logger "Connecting to the new VCSA ..." 506 | $vc = Connect-VIServer $VCSAIPAddress -User "administrator@$VCSASSODomainName" -Password $VCSASSOPassword -WarningAction SilentlyContinue 507 | 508 | My-Logger "Creating Datacenter $NewVCDatacenterName ..." 509 | New-Datacenter -Server $vc -Name $NewVCDatacenterName -Location (Get-Folder -Type Datacenter -Server $vc) | Out-File -Append -LiteralPath $verboseLogFile 510 | 511 | My-Logger "Creating VSAN Cluster $NewVCVSANClusterName ..." 512 | New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -VsanEnabled -VsanDiskClaimMode 'Manual' | Out-File -Append -LiteralPath $verboseLogFile 513 | 514 | if($addESXiHostsToVC -eq 1) { 515 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 516 | $VMName = $_.Key 517 | $VMIPAddress = $_.Value 518 | 519 | My-Logger "Adding ESXi host $VMIPAddress to Cluster ..." 520 | Add-VMHost -Server $vc -Location (Get-Cluster -Name $NewVCVSANClusterName) -User "root" -Password $VMPassword -Name $VMIPAddress -Force | Out-File -Append -LiteralPath $verboseLogFile 521 | } 522 | 523 | } 524 | 525 | if($configureVSANDiskGroups -eq 1) { 526 | My-Logger "Enabling VSAN Space Efficiency/De-Dupe & disabling VSAN Health Check ..." 527 | Get-VsanClusterConfiguration -Server $vc -Cluster $NewVCVSANClusterName | Set-VsanClusterConfiguration -SpaceEfficiencyEnabled $true -HealthCheckIntervalMinutes 0 | Out-File -Append -LiteralPath $verboseLogFile 528 | 529 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 530 | if((Get-VsanDiskGroup -VMHost $vmhost) -eq $null) { 531 | $luns = $vmhost | Get-ScsiLun | select CanonicalName, CapacityGB 532 | 533 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 534 | foreach ($lun in $luns) { 535 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 536 | $vsanCacheDisk = $lun.CanonicalName 537 | } 538 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 539 | $vsanCapacityDisk = $lun.CanonicalName 540 | } 541 | } 542 | My-Logger "Creating VSAN DiskGroup for $vmhost ..." 543 | New-VsanDiskGroup -Server $vc -VMHost $vmhost -SsdCanonicalName $vsanCacheDisk -DataDiskCanonicalName $vsanCapacityDisk | Out-File -Append -LiteralPath $verboseLogFile 544 | } 545 | } 546 | } 547 | 548 | if($clearVSANHealthCheckAlarm -eq 1) { 549 | My-Logger "Clearing default VSAN Health Check Alarms, not applicable in Nested ESXi env ..." 550 | $alarmMgr = Get-View AlarmManager -Server $vc 551 | Get-Cluster -Server $vc | where {$_.ExtensionData.TriggeredAlarmState} | %{ 552 | $cluster = $_ 553 | $Cluster.ExtensionData.TriggeredAlarmState | %{ 554 | $alarmMgr.AcknowledgeAlarm($_.Alarm,$cluster.ExtensionData.MoRef) 555 | } 556 | } 557 | 558 | My-Logger "Updating VSAN Default VM Storage Policy back to its defaults ..." 559 | $VSANPolicy = Get-SpbmStoragePolicy "Virtual SAN Default Storage Policy" 560 | $Ruleset = New-SpbmRuleSet -Name "Rule-set 1" -AllOfRules @((New-SpbmRule -Capability VSAN.forceProvisioning $false), (New-SpbmRule -Capability VSAN.hostFailuresToTolerate 1)) 561 | $VSANPolicy | Set-SpbmStoragePolicy -RuleSet $Ruleset | Out-File -Append -LiteralPath $verboseLogFile 562 | } 563 | 564 | My-Logger "Disconnecting from new VCSA ..." 565 | Disconnect-VIServer $vc -Confirm:$false 566 | } 567 | $EndTime = Get-Date 568 | $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2) 569 | 570 | My-Logger "vSphere $vSphereVersion Lab Deployment Complete!" 571 | My-Logger "StartTime: $StartTime" 572 | My-Logger " EndTime: $EndTime" 573 | My-Logger " Duration: $duration minutes" 574 | -------------------------------------------------------------------------------- /vsphere-6.5-standard-lab-deployment.ps1: -------------------------------------------------------------------------------- 1 | # Author: William Lam 2 | # Website: www.virtuallyghetto.com 3 | # Description: PowerCLI script to deploy a fully functional vSphere 6.5 lab consisting of 3 4 | # Nested ESXi hosts enable w/vSAN + VCSA 6.5. Expects a single physical ESXi host 5 | # as the endpoint and all four VMs will be deployed to physical ESXi host 6 | # Reference: http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html 7 | # Credit: Thanks to Alan Renouf as I borrowed some of his PCLI code snippets :) 8 | # 9 | # Changelog 10 | # 11/22/16 11 | # * Automatically handle Nested ESXi on vSAN 12 | # 01/20/17 13 | # * Resolved "Another task in progress" thanks to Jason M 14 | # 02/12/17 15 | # * Support for deploying to VC Target 16 | # * Support for enabling SSH on VCSA 17 | # * Added option to auto-create vApp Container for VMs 18 | # * Added pre-check for required files 19 | # 02/17/17 20 | # * Added missing dvFilter param to eth1 (missing in Nested ESXi OVA) 21 | # 02/21/17 22 | # * Support for deploying NSX 6.3 & registering with vCenter Server 23 | # * Support for updating Nested ESXi VM to ESXi 6.5a (required for NSX 6.3) 24 | # * Support for VDS + VXLAN VMkernel configuration (required for NSX 6.3) 25 | # * Support for "Private" Portgroup on eth1 for Nested ESXi VM used for VXLAN traffic (required for NSX 6.3) 26 | # * Support for both Virtual & Distributed Portgroup on $VMNetwork 27 | # * Support for adding ESXi hosts into VC using DNS name (disabled by default) 28 | # * Added CPU/MEM/Storage resource requirements in confirmation screen 29 | # 05/08/17 30 | # * Support for patching ESXi using VMware Online repo thanks to Matt Lichstein for contribution 31 | # * Added fix to test ESXi endpoint before trying to patch 32 | 33 | # Physical ESXi host or vCenter Server to deploy vSphere 6.5 lab 34 | $VIServer = "vcenter.primp-industries.com" 35 | $VIUsername = "administrator@vsphere.local" 36 | $VIPassword = "!!!MySuperDuperSecurePassword!!!" 37 | 38 | # Specifies whether deployment is to an ESXi host or vCenter Server 39 | # Use either ESXI or VCENTER 40 | $DeploymentTarget = "VCENTER" 41 | 42 | # Full Path to both the Nested ESXi 6.5 VA + extracted VCSA 6.5 ISO 43 | $NestedESXiApplianceOVA = "C:\Users\primp\Desktop\Nested_ESXi6.5_Appliance_Template_v1.ova" 44 | $VCSAInstallerPath = "C:\Users\primp\Desktop\VMware-VCSA-all-6.5.0-4944578" 45 | $NSXOVA = "C:\Users\primp\Desktop\VMware-NSX-Manager-6.3.0-5007049.ova" 46 | $ESXi65OfflineBundle = "C:\Users\primp\Desktop\ESXi650-201701001\vmw-ESXi-6.5.0-metadata.zip" # Used for offline upgrade only 47 | $ESXiProfileName = "ESXi-6.5.0-20170404001-standard" # Used for online upgrade only 48 | 49 | # Nested ESXi VMs to deploy 50 | $NestedESXiHostnameToIPs = @{ 51 | "vesxi65-1" = "172.30.0.171" 52 | "vesxi65-2" = "172.30.0.172" 53 | "vesxi65-3" = "172.30.0.173" 54 | } 55 | 56 | # Nested ESXi VM Resources 57 | $NestedESXivCPU = "2" 58 | $NestedESXivMEM = "6" #GB 59 | $NestedESXiCachingvDisk = "4" #GB 60 | $NestedESXiCapacityvDisk = "8" #GB 61 | 62 | # VCSA Deployment Configuration 63 | $VCSADeploymentSize = "tiny" 64 | $VCSADisplayName = "vcenter65-1" 65 | $VCSAIPAddress = "172.30.0.170" 66 | $VCSAHostname = "vcenter65-1.primp-industries.com" #Change to IP if you don't have valid DNS 67 | $VCSAPrefix = "24" 68 | $VCSASSODomainName = "vsphere.local" 69 | $VCSASSOSiteName = "virtuallyGhetto" 70 | $VCSASSOPassword = "VMware1!" 71 | $VCSARootPassword = "VMware1!" 72 | $VCSASSHEnable = "true" 73 | 74 | # General Deployment Configuration for Nested ESXi, VCSA & NSX VMs 75 | $VirtualSwitchType = "VDS" # VSS or VDS 76 | $VMNetwork = "dv-access333-dev" 77 | $VMDatastore = "himalaya-local-SATA-dc3500-3" 78 | $VMNetmask = "255.255.255.0" 79 | $VMGateway = "172.30.0.1" 80 | $VMDNS = "172.30.0.100" 81 | $VMNTP = "pool.ntp.org" 82 | $VMPassword = "vmware123" 83 | $VMDomain = "primp-industries.com" 84 | $VMSyslog = "172.30.0.170" 85 | # Applicable to Nested ESXi only 86 | $VMSSH = "true" 87 | $VMVMFS = "false" 88 | # Applicable to VC Deployment Target only 89 | $VMCluster = "Primp-Cluster" 90 | 91 | # Name of new vSphere Datacenter/Cluster when VCSA is deployed 92 | $NewVCDatacenterName = "Datacenter" 93 | $NewVCVSANClusterName = "VSAN-Cluster" 94 | 95 | # NSX Manager Configuration 96 | $DeployNSX = 0 97 | $NSXvCPU = "2" # Reconfigure NSX vCPU 98 | $NSXvMEM = "8" # Reconfigure NSX vMEM (GB) 99 | $NSXDisplayName = "nsx63-1" 100 | $NSXHostname = "nsx63-1.primp-industries.com" 101 | $NSXIPAddress = "172.30.0.250" 102 | $NSXNetmask = "255.255.255.0" 103 | $NSXGateway = "172.30.0.1" 104 | $NSXSSHEnable = "true" 105 | $NSXCEIPEnable = "false" 106 | $NSXUIPassword = "VMw@re123!" 107 | $NSXCLIPassword = "VMw@re123!" 108 | 109 | # VDS / VXLAN Configurations 110 | $PrivateVXLANVMNetwork = "dv-private-network" # Existing Portgroup 111 | $VDSName = "VDS-6.5" 112 | $VXLANDVPortgroup = "VXLAN" 113 | $VXLANSubnet = "172.16.66." 114 | $VXLANNetmask = "255.255.255.0" 115 | 116 | # Advanced Configurations 117 | # Set to 1 only if you have DNS (forward/reverse) for ESXi hostnames 118 | $addHostByDnsName = 0 119 | # Upgrade vESXi hosts (defaults to pulling upgrade from VMware using profile specified in $ESXiProfileName) 120 | $upgradeESXi = 0 121 | # Set to 1 only if you want to upgrade using local bundle specified in $ESXi65OfflineBundle 122 | $offlineUpgrade = 0 123 | 124 | #### DO NOT EDIT BEYOND HERE #### 125 | 126 | $verboseLogFile = "vsphere65-lab-deployment.log" 127 | $vSphereVersion = "6.5" 128 | $deploymentType = "Standard" 129 | $random_string = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_}) 130 | $VAppName = "Nested-vSphere-Lab-$vSphereVersion-$random_string" 131 | $depotServer = "https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml" 132 | 133 | $vcsaSize2MemoryStorageMap = @{ 134 | "tiny"=@{"cpu"="2";"mem"="10";"disk"="250"}; 135 | "small"=@{"cpu"="4";"mem"="16";"disk"="290"}; 136 | "medium"=@{"cpu"="8";"mem"="24";"disk"="425"}; 137 | "large"=@{"cpu"="16";"mem"="32";"disk"="640"}; 138 | "xlarge"=@{"cpu"="24";"mem"="48";"disk"="980"} 139 | } 140 | 141 | $esxiTotalCPU = 0 142 | $vcsaTotalCPU = 0 143 | $nsxTotalCPU = 0 144 | $esxiTotalMemory = 0 145 | $vcsaTotalMemory = 0 146 | $nsxTotalMemory = 0 147 | $esxiTotStorage = 0 148 | $vcsaTotalStorage = 0 149 | $nsxTotalStorage = 0 150 | 151 | $preCheck = 1 152 | $confirmDeployment = 1 153 | $deployNestedESXiVMs = 1 154 | $deployVCSA = 1 155 | $setupNewVC = 1 156 | $addESXiHostsToVC = 1 157 | $configureVSANDiskGroups = 1 158 | $clearVSANHealthCheckAlarm = 1 159 | $setupVXLAN = 1 160 | $configureNSX = 1 161 | $moveVMsIntovApp = 1 162 | 163 | $StartTime = Get-Date 164 | 165 | Function My-Logger { 166 | param( 167 | [Parameter(Mandatory=$true)] 168 | [String]$message 169 | ) 170 | 171 | $timeStamp = Get-Date -Format "MM-dd-yyyy_hh:mm:ss" 172 | 173 | Write-Host -NoNewline -ForegroundColor White "[$timestamp]" 174 | Write-Host -ForegroundColor Green " $message" 175 | $logMessage = "[$timeStamp] $message" 176 | $logMessage | Out-File -Append -LiteralPath $verboseLogFile 177 | } 178 | 179 | Function URL-Check([string] $url) { 180 | $isWorking = $true 181 | 182 | try { 183 | $request = [System.Net.WebRequest]::Create($url) 184 | $request.Method = "HEAD" 185 | $request.UseDefaultCredentials = $true 186 | 187 | $response = $request.GetResponse() 188 | $httpStatus = $response.StatusCode 189 | 190 | $isWorking = ($httpStatus -eq "OK") 191 | } 192 | catch { 193 | $isWorking = $false 194 | } 195 | return $isWorking 196 | } 197 | 198 | if($preCheck -eq 1) { 199 | if(!(Test-Path $NestedESXiApplianceOVA)) { 200 | Write-Host -ForegroundColor Red "`nUnable to find $NestedESXiApplianceOVA ...`nexiting" 201 | exit 202 | } 203 | 204 | if(!(Test-Path $VCSAInstallerPath)) { 205 | Write-Host -ForegroundColor Red "`nUnable to find $VCSAInstallerPath ...`nexiting" 206 | exit 207 | } 208 | 209 | if($DeployNSX -eq 1) { 210 | if(!(Test-Path $NSXOVA)) { 211 | Write-Host -ForegroundColor Red "`nUnable to find $NSXOVA ...`nexiting" 212 | exit 213 | } 214 | 215 | if(-not (Get-Module -Name "PowerNSX")) { 216 | Write-Host -ForegroundColor Red "`nPowerNSX Module is not loaded, please install and load PowerNSX before running script ...`nexiting" 217 | exit 218 | } 219 | $upgradeESXi = 1 220 | } 221 | 222 | if($upgradeESXi -eq 1) { 223 | if($offlineUpgrade -eq 1) { 224 | if(!(Test-Path $ESXi65OfflineBundle)) { 225 | Write-Host -ForegroundColor Red "`nUnable to find $ESXi65OfflineBundle ...`nexiting" 226 | exit 227 | } 228 | else { 229 | if(!(URL-Check($depotServer))) { 230 | Write-Host -ForegroundColor Red "`nVMware depot server is unavailable ...`nexiting" 231 | exit 232 | } 233 | } 234 | } 235 | } 236 | } 237 | 238 | if($confirmDeployment -eq 1) { 239 | Write-Host -ForegroundColor Magenta "`nPlease confirm the following configuration will be deployed:`n" 240 | 241 | Write-Host -ForegroundColor Yellow "---- vSphere Automated Lab Deployment Configuration ---- " 242 | Write-Host -NoNewline -ForegroundColor Green "Deployment Target: " 243 | Write-Host -ForegroundColor White $DeploymentTarget 244 | Write-Host -NoNewline -ForegroundColor Green "Deployment Type: " 245 | Write-Host -ForegroundColor White $deploymentType 246 | Write-Host -NoNewline -ForegroundColor Green "vSphere Version: " 247 | Write-Host -ForegroundColor White "vSphere $vSphereVersion" 248 | Write-Host -NoNewline -ForegroundColor Green "Nested ESXi Image Path: " 249 | Write-Host -ForegroundColor White $NestedESXiApplianceOVA 250 | Write-Host -NoNewline -ForegroundColor Green "VCSA Image Path: " 251 | Write-Host -ForegroundColor White $VCSAInstallerPath 252 | 253 | if($DeployNSX -eq 1) { 254 | Write-Host -NoNewline -ForegroundColor Green "NSX Image Path: " 255 | Write-Host -ForegroundColor White $NSXOVA 256 | } 257 | 258 | if($DeploymentTarget -eq "ESXI") { 259 | Write-Host -ForegroundColor Yellow "`n---- Physical ESXi Deployment Target Configuration ----" 260 | Write-Host -NoNewline -ForegroundColor Green "ESXi Address: " 261 | } else { 262 | Write-Host -ForegroundColor Yellow "`n---- vCenter Server Deployment Target Configuration ----" 263 | Write-Host -NoNewline -ForegroundColor Green "vCenter Server Address: " 264 | } 265 | 266 | Write-Host -ForegroundColor White $VIServer 267 | Write-Host -NoNewline -ForegroundColor Green "Username: " 268 | Write-Host -ForegroundColor White $VIUsername 269 | Write-Host -NoNewline -ForegroundColor Green "VM Network: " 270 | Write-Host -ForegroundColor White $VMNetwork 271 | 272 | if($DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 273 | Write-Host -NoNewline -ForegroundColor Green "Private VXLAN VM Network: " 274 | Write-Host -ForegroundColor White $PrivateVXLANVMNetwork 275 | } 276 | 277 | Write-Host -NoNewline -ForegroundColor Green "VM Storage: " 278 | Write-Host -ForegroundColor White $VMDatastore 279 | 280 | if($DeploymentTarget -eq "VCENTER") { 281 | Write-Host -NoNewline -ForegroundColor Green "VM Cluster: " 282 | Write-Host -ForegroundColor White $VMCluster 283 | Write-Host -NoNewline -ForegroundColor Green "VM vApp: " 284 | Write-Host -ForegroundColor White $VAppName 285 | } 286 | 287 | Write-Host -ForegroundColor Yellow "`n---- vESXi Configuration ----" 288 | Write-Host -NoNewline -ForegroundColor Green "# of Nested ESXi VMs: " 289 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.count 290 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 291 | Write-Host -ForegroundColor White $NestedESXivCPU 292 | Write-Host -NoNewline -ForegroundColor Green "vMEM: " 293 | Write-Host -ForegroundColor White "$NestedESXivMEM GB" 294 | Write-Host -NoNewline -ForegroundColor Green "Caching VMDK: " 295 | Write-Host -ForegroundColor White "$NestedESXiCachingvDisk GB" 296 | Write-Host -NoNewline -ForegroundColor Green "Capacity VMDK: " 297 | Write-Host -ForegroundColor White "$NestedESXiCapacityvDisk GB" 298 | Write-Host -NoNewline -ForegroundColor Green "IP Address(s): " 299 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.Values 300 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 301 | Write-Host -ForegroundColor White $VMNetmask 302 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 303 | Write-Host -ForegroundColor White $VMGateway 304 | Write-Host -NoNewline -ForegroundColor Green "DNS: " 305 | Write-Host -ForegroundColor White $VMDNS 306 | Write-Host -NoNewline -ForegroundColor Green "NTP: " 307 | Write-Host -ForegroundColor White $VMNTP 308 | Write-Host -NoNewline -ForegroundColor Green "Syslog: " 309 | Write-Host -ForegroundColor White $VMSyslog 310 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 311 | Write-Host -ForegroundColor White $VMSSH 312 | Write-Host -NoNewline -ForegroundColor Green "Create VMFS Volume: " 313 | Write-Host -ForegroundColor White $VMVMFS 314 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 315 | Write-Host -ForegroundColor White $VMPassword 316 | 317 | Write-Host -ForegroundColor Yellow "`n---- VCSA Configuration ----" 318 | Write-Host -NoNewline -ForegroundColor Green "Deployment Size: " 319 | Write-Host -ForegroundColor White $VCSADeploymentSize 320 | Write-Host -NoNewline -ForegroundColor Green "SSO Domain: " 321 | Write-Host -ForegroundColor White $VCSASSODomainName 322 | Write-Host -NoNewline -ForegroundColor Green "SSO Site: " 323 | Write-Host -ForegroundColor White $VCSASSOSiteName 324 | Write-Host -NoNewline -ForegroundColor Green "SSO Password: " 325 | Write-Host -ForegroundColor White $VCSASSOPassword 326 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 327 | Write-Host -ForegroundColor White $VCSARootPassword 328 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 329 | Write-Host -ForegroundColor White $VCSASSHEnable 330 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 331 | Write-Host -ForegroundColor White $VCSAHostname 332 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 333 | Write-Host -ForegroundColor White $VCSAIPAddress 334 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 335 | Write-Host -ForegroundColor White $VMNetmask 336 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 337 | Write-Host -ForegroundColor White $VMGateway 338 | 339 | if($DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 340 | Write-Host -NoNewline -ForegroundColor Green "VDS Name: " 341 | Write-Host -ForegroundColor White $VDSName 342 | Write-Host -NoNewline -ForegroundColor Green "VXLAN Portgroup Name: " 343 | Write-Host -ForegroundColor White $VXLANDVPortgroup 344 | Write-Host -NoNewline -ForegroundColor Green "VXLAN Subnet: " 345 | Write-Host -ForegroundColor White $VXLANSubnet 346 | Write-Host -NoNewline -ForegroundColor Green "VXLAN Netmask: " 347 | Write-Host -ForegroundColor White $VXLANNetmask 348 | } 349 | 350 | if($DeployNSX -eq 1) { 351 | Write-Host -ForegroundColor Yellow "`n---- NSX Configuration ----" 352 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 353 | Write-Host -ForegroundColor White $NSXvCPU 354 | Write-Host -NoNewline -ForegroundColor Green "Memory (GB): " 355 | Write-Host -ForegroundColor White $NSXvMEM 356 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 357 | Write-Host -ForegroundColor White $NSXHostname 358 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 359 | Write-Host -ForegroundColor White $NSXIPAddress 360 | Write-Host -NoNewline -ForegroundColor Green "Netmask: " 361 | Write-Host -ForegroundColor White $NSXNetmask 362 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 363 | Write-Host -ForegroundColor White $NSXGateway 364 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 365 | Write-Host -ForegroundColor White $NSXSSHEnable 366 | Write-Host -NoNewline -ForegroundColor Green "Enable CEIP: " 367 | Write-Host -ForegroundColor White $NSXCEIPEnable 368 | Write-Host -NoNewline -ForegroundColor Green "UI Password: " 369 | Write-Host -ForegroundColor White $NSXUIPassword 370 | Write-Host -NoNewline -ForegroundColor Green "CLI Password: " 371 | Write-Host -ForegroundColor White $NSXCLIPassword 372 | } 373 | 374 | $esxiTotalCPU = $NestedESXiHostnameToIPs.count * [int]$NestedESXivCPU 375 | $esxiTotalMemory = $NestedESXiHostnameToIPs.count * [int]$NestedESXivMEM 376 | $esxiTotalStorage = ($NestedESXiHostnameToIPs.count * [int]$NestedESXiCachingvDisk) + ($NestedESXiHostnameToIPs.count * [int]$NestedESXiCapacityvDisk) 377 | $vcsaTotalCPU = $vcsaSize2MemoryStorageMap.$VCSADeploymentSize.cpu 378 | $vcsaTotalMemory = $vcsaSize2MemoryStorageMap.$VCSADeploymentSize.mem 379 | $vcsaTotalStorage = $vcsaSize2MemoryStorageMap.$VCSADeploymentSize.disk 380 | 381 | Write-Host -ForegroundColor Yellow "`n---- Resource Requirements ----" 382 | Write-Host -NoNewline -ForegroundColor Green "ESXi VM CPU: " 383 | Write-Host -NoNewline -ForegroundColor White $esxiTotalCPU 384 | Write-Host -NoNewline -ForegroundColor Green " ESXi VM Memory: " 385 | Write-Host -NoNewline -ForegroundColor White $esxiTotalMemory "GB " 386 | Write-Host -NoNewline -ForegroundColor Green "ESXi VM Storage: " 387 | Write-Host -ForegroundColor White $esxiTotalStorage "GB" 388 | Write-Host -NoNewline -ForegroundColor Green "VCSA VM CPU: " 389 | Write-Host -NoNewline -ForegroundColor White $vcsaTotalCPU 390 | Write-Host -NoNewline -ForegroundColor Green " VCSA VM Memory: " 391 | Write-Host -NoNewline -ForegroundColor White $vcsaTotalMemory "GB " 392 | Write-Host -NoNewline -ForegroundColor Green "VCSA VM Storage: " 393 | Write-Host -ForegroundColor White $vcsaTotalStorage "GB" 394 | 395 | if($DeployNSX -eq 1) { 396 | $nsxTotalCPU = [int]$NSXvCPU 397 | $nsxTotalMemory = [int]$NSXvMEM 398 | $nsxTotalStorage = 60 399 | Write-Host -NoNewline -ForegroundColor Green "NSX VM CPU: " 400 | Write-Host -NoNewline -ForegroundColor White $nsxTotalCPU 401 | Write-Host -NoNewline -ForegroundColor Green " NSX VM Memory: " 402 | Write-Host -NoNewline -ForegroundColor White $nsxTotalMemory "GB " 403 | Write-Host -NoNewline -ForegroundColor Green " NSX VM Storage: " 404 | Write-Host -ForegroundColor White $nsxTotalStorage "GB" 405 | } 406 | 407 | Write-Host -ForegroundColor White "---------------------------------------------" 408 | Write-Host -NoNewline -ForegroundColor Green "Total CPU: " 409 | Write-Host -ForegroundColor White ($esxiTotalCPU + $vcsaTotalCPU + $nsxTotalCPU) 410 | Write-Host -NoNewline -ForegroundColor Green "Total Memory: " 411 | Write-Host -ForegroundColor White ($esxiTotalMemory + $vcsaTotalMemory + $nsxTotalMemory) "GB" 412 | Write-Host -NoNewline -ForegroundColor Green "Total Storage: " 413 | Write-Host -ForegroundColor White ($esxiTotalStorage + $vcsaTotalStorage + $nsxTotalStorage) "GB" 414 | 415 | Write-Host -ForegroundColor Magenta "`nWould you like to proceed with this deployment?`n" 416 | $answer = Read-Host -Prompt "Do you accept (Y or N)" 417 | if($answer -ne "Y" -or $answer -ne "y") { 418 | exit 419 | } 420 | Clear-Host 421 | } 422 | 423 | My-Logger "Connecting to $VIServer ..." 424 | $viConnection = Connect-VIServer $VIServer -User $VIUsername -Password $VIPassword -WarningAction SilentlyContinue 425 | 426 | if($DeploymentTarget -eq "ESXI") { 427 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore 428 | if($VirtualSwitchType -eq "VSS") { 429 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork 430 | if($DeployNSX -eq 1) { 431 | $privateNetwork = Get-VirtualPortGroup -Server $viConnection -Name $PrivateVXLANVMNetwork 432 | } 433 | } else { 434 | $network = Get-VDPortgroup -Server $viConnection -Name $VMNetwork 435 | if($DeployNSX -eq 1) { 436 | $privateNetwork = Get-VDPortgroup -Server $viConnection -Name $PrivateVXLANVMNetwork 437 | } 438 | } 439 | $vmhost = Get-VMHost -Server $viConnection 440 | 441 | if($datastore.Type -eq "vsan") { 442 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 443 | Get-AdvancedSetting -Entity $vmhost -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 444 | } 445 | } else { 446 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore | Select -First 1 447 | if($VirtualSwitchType -eq "VSS") { 448 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork | Select -First 1 449 | if($DeployNSX -eq 1) { 450 | $privateNetwork = Get-VirtualPortGroup -Server $viConnection -Name $PrivateVXLANVMNetwork | Select -First 1 451 | } 452 | } else { 453 | $network = Get-VDPortgroup -Server $viConnection -Name $VMNetwork | Select -First 1 454 | if($DeployNSX -eq 1) { 455 | $privateNetwork = Get-VDPortgroup -Server $viConnection -Name $PrivateVXLANVMNetwork | Select -First 1 456 | } 457 | } 458 | $cluster = Get-Cluster -Server $viConnection -Name $VMCluster 459 | $datacenter = $cluster | Get-Datacenter 460 | $vmhost = $cluster | Get-VMHost | Select -First 1 461 | 462 | if($datastore.Type -eq "vsan") { 463 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 464 | Get-AdvancedSetting -Entity $vmhost -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 465 | } 466 | } 467 | 468 | if($deployNestedESXiVMs -eq 1) { 469 | if($DeploymentTarget -eq "ESXI") { 470 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 471 | $VMName = $_.Key 472 | $VMIPAddress = $_.Value 473 | 474 | My-Logger "Deploying Nested ESXi VM $VMName ..." 475 | $vm = Import-VApp -Server $viConnection -Source $NestedESXiApplianceOVA -Name $VMName -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 476 | 477 | # Add the dvfilter settings to the exisiting ethernet1 (not part of ova template) 478 | My-Logger "Correcting missing dvFilter settings for Eth1 ..." 479 | $vm | New-AdvancedSetting -name "ethernet1.filter4.name" -value "dvfilter-maclearn" -confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile 480 | $vm | New-AdvancedSetting -Name "ethernet1.filter4.onFailure" -value "failOpen" -confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile 481 | 482 | My-Logger "Updating VM Network ..." 483 | $vm | Get-NetworkAdapter -Name "Network adapter 1" | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 484 | sleep 5 485 | 486 | if($DeployNSX -eq 1) { 487 | $vm | Get-NetworkAdapter -Name "Network adapter 2" | Set-NetworkAdapter -Portgroup $privateNetwork -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 488 | } else { 489 | $vm | Get-NetworkAdapter -Name "Network adapter 2" | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 490 | } 491 | 492 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 493 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 494 | 495 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 496 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 497 | 498 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 499 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 500 | 501 | $orignalExtraConfig = $vm.ExtensionData.Config.ExtraConfig 502 | $a = New-Object VMware.Vim.OptionValue 503 | $a.key = "guestinfo.hostname" 504 | $a.value = $VMName 505 | $b = New-Object VMware.Vim.OptionValue 506 | $b.key = "guestinfo.ipaddress" 507 | $b.value = $VMIPAddress 508 | $c = New-Object VMware.Vim.OptionValue 509 | $c.key = "guestinfo.netmask" 510 | $c.value = $VMNetmask 511 | $d = New-Object VMware.Vim.OptionValue 512 | $d.key = "guestinfo.gateway" 513 | $d.value = $VMGateway 514 | $e = New-Object VMware.Vim.OptionValue 515 | $e.key = "guestinfo.dns" 516 | $e.value = $VMDNS 517 | $f = New-Object VMware.Vim.OptionValue 518 | $f.key = "guestinfo.domain" 519 | $f.value = $VMDomain 520 | $g = New-Object VMware.Vim.OptionValue 521 | $g.key = "guestinfo.ntp" 522 | $g.value = $VMNTP 523 | $h = New-Object VMware.Vim.OptionValue 524 | $h.key = "guestinfo.syslog" 525 | $h.value = $VMSyslog 526 | $i = New-Object VMware.Vim.OptionValue 527 | $i.key = "guestinfo.password" 528 | $i.value = $VMPassword 529 | $j = New-Object VMware.Vim.OptionValue 530 | $j.key = "guestinfo.ssh" 531 | $j.value = $VMSSH 532 | $k = New-Object VMware.Vim.OptionValue 533 | $k.key = "guestinfo.createvmfs" 534 | $k.value = $VMVMFS 535 | $l = New-Object VMware.Vim.OptionValue 536 | $l.key = "ethernet1.filter4.name" 537 | $l.value = "dvfilter-maclearn" 538 | $m = New-Object VMware.Vim.OptionValue 539 | $m.key = "ethernet1.filter4.onFailure" 540 | $m.value = "failOpen" 541 | $orignalExtraConfig+=$a 542 | $orignalExtraConfig+=$b 543 | $orignalExtraConfig+=$c 544 | $orignalExtraConfig+=$d 545 | $orignalExtraConfig+=$e 546 | $orignalExtraConfig+=$f 547 | $orignalExtraConfig+=$g 548 | $orignalExtraConfig+=$h 549 | $orignalExtraConfig+=$i 550 | $orignalExtraConfig+=$j 551 | $orignalExtraConfig+=$k 552 | $orignalExtraConfig+=$l 553 | $orignalExtraConfig+=$m 554 | 555 | $spec = New-Object VMware.Vim.VirtualMachineConfigSpec 556 | $spec.ExtraConfig = $orignalExtraConfig 557 | 558 | My-Logger "Adding guestinfo customization properties to $vmname ..." 559 | $task = $vm.ExtensionData.ReconfigVM_Task($spec) 560 | $task1 = Get-Task -Id ("Task-$($task.value)") 561 | $task1 | Wait-Task | Out-Null 562 | 563 | My-Logger "Powering On $vmname ..." 564 | Start-VM -Server $viConnection -VM $vm -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 565 | } 566 | } else { 567 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 568 | $VMName = $_.Key 569 | $VMIPAddress = $_.Value 570 | 571 | $ovfconfig = Get-OvfConfiguration $NestedESXiApplianceOVA 572 | $networkMapLabel = ($ovfconfig.ToHashTable().keys | where {$_ -Match "NetworkMapping"}).replace("NetworkMapping.","").replace("-","_").replace(" ","_") 573 | $ovfconfig.NetworkMapping.$networkMapLabel.value = $VMNetwork 574 | 575 | $ovfconfig.common.guestinfo.hostname.value = $VMName 576 | $ovfconfig.common.guestinfo.ipaddress.value = $VMIPAddress 577 | $ovfconfig.common.guestinfo.netmask.value = $VMNetmask 578 | $ovfconfig.common.guestinfo.gateway.value = $VMGateway 579 | $ovfconfig.common.guestinfo.dns.value = $VMDNS 580 | $ovfconfig.common.guestinfo.domain.value = $VMDomain 581 | $ovfconfig.common.guestinfo.ntp.value = $VMNTP 582 | $ovfconfig.common.guestinfo.syslog.value = $VMSyslog 583 | $ovfconfig.common.guestinfo.password.value = $VMPassword 584 | if($VMSSH -eq "true") { 585 | $VMSSHVar = $true 586 | } else { 587 | $VMSSHVar = $false 588 | } 589 | $ovfconfig.common.guestinfo.ssh.value = $VMSSHVar 590 | 591 | My-Logger "Deploying Nested ESXi VM $VMName ..." 592 | $vm = Import-VApp -Source $NestedESXiApplianceOVA -OvfConfiguration $ovfconfig -Name $VMName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 593 | 594 | # Add the dvfilter settings to the exisiting ethernet1 (not part of ova template) 595 | My-Logger "Correcting missing dvFilter settings for Eth1 ..." 596 | $vm | New-AdvancedSetting -name "ethernet1.filter4.name" -value "dvfilter-maclearn" -confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile 597 | $vm | New-AdvancedSetting -Name "ethernet1.filter4.onFailure" -value "failOpen" -confirm:$false -ErrorAction SilentlyContinue | Out-File -Append -LiteralPath $verboseLogFile 598 | 599 | if($DeployNSX -eq 1) { 600 | My-Logger "Connecting Eth1 to $privateNetwork ..." 601 | $vm | Get-NetworkAdapter -Name "Network adapter 2" | Set-NetworkAdapter -Portgroup $privateNetwork -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 602 | } 603 | 604 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 605 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 606 | 607 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 608 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 609 | 610 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 611 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 612 | 613 | My-Logger "Powering On $vmname ..." 614 | $vm | Start-Vm -RunAsync | Out-Null 615 | } 616 | } 617 | } 618 | 619 | if($DeployNSX -eq 1) { 620 | if($DeploymentTarget -eq "VCENTER") { 621 | $ovfconfig = Get-OvfConfiguration $NSXOVA 622 | $ovfconfig.NetworkMapping.VSMgmt.value = $VMNetwork 623 | 624 | $ovfconfig.common.vsm_hostname.value = $NSXHostname 625 | $ovfconfig.common.vsm_ip_0.value = $NSXIPAddress 626 | $ovfconfig.common.vsm_netmask_0.value = $NSXNetmask 627 | $ovfconfig.common.vsm_gateway_0.value = $NSXGateway 628 | $ovfconfig.common.vsm_dns1_0.value = $VMDNS 629 | $ovfconfig.common.vsm_domain_0.value = $VMDomain 630 | $ovfconfig.common.vsm_ntp_0 = $VMNTP 631 | if($NSXSSHEnable -eq "true") { 632 | $NSXSSHEnableVar = $true 633 | } else { 634 | $NSXSSHEnableVar = $false 635 | } 636 | $ovfconfig.common.vsm_isSSHEnabled.value = $NSXSSHEnableVar 637 | if($NSXCEIPEnable -eq "true") { 638 | $NSXCEIPEnableVar = $true 639 | } else { 640 | $NSXCEIPEnableVar = $false 641 | } 642 | $ovfconfig.common.vsm_isCEIPEnabled.value = $NSXCEIPEnableVar 643 | $ovfconfig.common.vsm_cli_passwd_0.value = $NSXUIPassword 644 | $ovfconfig.common.vsm_cli_en_passwd_0.value = $NSXCLIPassword 645 | 646 | My-Logger "Deploying NSX VM $NSXDisplayName ..." 647 | $vm = Import-VApp -Source $NSXOVA -OvfConfiguration $ovfconfig -Name $NSXDisplayName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 648 | 649 | My-Logger "Updating vCPU Count to $NSXvCPU & vMEM to $NSXvMEM GB ..." 650 | Set-VM -Server $viConnection -VM $vm -NumCpu $NSXvCPU -MemoryGB $NSXvMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 651 | 652 | My-Logger "Powering On $NSXDisplayName ..." 653 | $vm | Start-Vm -RunAsync | Out-Null 654 | } 655 | } 656 | 657 | if($upgradeESXi -eq 1) { 658 | sleep 60 659 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 660 | $VMName = $_.Key 661 | $VMIPAddress = $_.Value 662 | 663 | My-Logger "Connecting directly to $VMName for ESXi upgrade ..." 664 | while(1) { 665 | try { 666 | $results = Invoke-WebRequest -Uri https://$VMIPAddress/ui -Method GET 667 | if($results.StatusCode -eq 200) { 668 | break 669 | } 670 | } 671 | catch { 672 | My-Logger "$VMName is not ready yet, sleeping 30seconds ..." 673 | sleep 30 674 | } 675 | } 676 | # This is apparently needed due to patching using online image profile taking longer 677 | Set-PowerCLIConfiguration -WebOperationTimeoutSeconds 900 -Scope Session -Confirm:$false | Out-Null 678 | 679 | $vESXi = Connect-VIServer -Server $VMIPAddress -User root -Password $VMPassword -WarningAction SilentlyContinue 680 | 681 | My-Logger "Entering Maintenance Mode ..." 682 | Set-VMHost -VMhost $VMIPAddress -State Maintenance -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 683 | 684 | if($offlineUpgrade -eq 1) { 685 | My-Logger "Upgrading $VMname using offline bundle $ESXi65OfflineBundle ..." 686 | Install-VMHostPatch -VMHost $VMIPAddress -LocalPath $ESXi65OfflineBundle -HostUsername root -HostPassword $VMPassword -WarningAction SilentlyContinue -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 687 | } 688 | else { 689 | My-Logger "Upgrading $VMName using Image Profile $ESXiProfileName ..." 690 | $esxcli = Get-EsxCli -VMHost $VMIPAddress -V2 691 | $esxcli.network.firewall.ruleset.set.Invoke(@{enabled = 'true' ; rulesetid = 'httpClient'}) | Out-Null 692 | $esxcli.software.profile.update.Invoke(@{profile = $ESXiProfileName; depot = $depotServer}) | Out-File -Append -LiteralPath $verboseLogFile 693 | } 694 | 695 | My-Logger "Rebooting $VMName ..." 696 | Restart-VMHost $VMIPAddress -RunAsync -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 697 | 698 | My-Logger "Disconnecting from new ESXi host ..." 699 | Disconnect-VIServer $vESXi -Confirm:$false 700 | } 701 | } 702 | 703 | if($deployVCSA -eq 1) { 704 | if($DeploymentTarget -eq "ESXI") { 705 | # Deploy using the VCSA CLI Installer 706 | $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_ESXi.json") | convertfrom-json 707 | $config.'new.vcsa'.esxi.hostname = $VIServer 708 | $config.'new.vcsa'.esxi.username = $VIUsername 709 | $config.'new.vcsa'.esxi.password = $VIPassword 710 | $config.'new.vcsa'.esxi.'deployment.network' = $VMNetwork 711 | $config.'new.vcsa'.esxi.datastore = $datastore 712 | $config.'new.vcsa'.appliance.'thin.disk.mode' = $true 713 | $config.'new.vcsa'.appliance.'deployment.option' = $VCSADeploymentSize 714 | $config.'new.vcsa'.appliance.name = $VCSADisplayName 715 | $config.'new.vcsa'.network.'ip.family' = "ipv4" 716 | $config.'new.vcsa'.network.mode = "static" 717 | $config.'new.vcsa'.network.ip = $VCSAIPAddress 718 | $config.'new.vcsa'.network.'dns.servers'[0] = $VMDNS 719 | $config.'new.vcsa'.network.prefix = $VCSAPrefix 720 | $config.'new.vcsa'.network.gateway = $VMGateway 721 | $config.'new.vcsa'.network.'system.name' = $VCSAHostname 722 | $config.'new.vcsa'.os.password = $VCSARootPassword 723 | if($VCSASSHEnable -eq "true") { 724 | $VCSASSHEnableVar = $true 725 | } else { 726 | $VCSASSHEnableVar = $false 727 | } 728 | $config.'new.vcsa'.os.'ssh.enable' = $VCSASSHEnableVar 729 | $config.'new.vcsa'.sso.password = $VCSASSOPassword 730 | $config.'new.vcsa'.sso.'domain-name' = $VCSASSODomainName 731 | $config.'new.vcsa'.sso.'site-name' = $VCSASSOSiteName 732 | 733 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 734 | $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" 735 | 736 | My-Logger "Deploying the VCSA ..." 737 | Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula --acknowledge-ceip $($ENV:Temp)\jsontemplate.json"| Out-File -Append -LiteralPath $verboseLogFile 738 | } else { 739 | $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_VC.json") | convertfrom-json 740 | $config.'new.vcsa'.vc.hostname = $VIServer 741 | $config.'new.vcsa'.vc.username = $VIUsername 742 | $config.'new.vcsa'.vc.password = $VIPassword 743 | $config.'new.vcsa'.vc.'deployment.network' = $VMNetwork 744 | $config.'new.vcsa'.vc.datastore = $datastore 745 | $config.'new.vcsa'.vc.datacenter = $datacenter.name 746 | $config.'new.vcsa'.vc.target = $VMCluster 747 | $config.'new.vcsa'.appliance.'thin.disk.mode' = $true 748 | $config.'new.vcsa'.appliance.'deployment.option' = $VCSADeploymentSize 749 | $config.'new.vcsa'.appliance.name = $VCSADisplayName 750 | $config.'new.vcsa'.network.'ip.family' = "ipv4" 751 | $config.'new.vcsa'.network.mode = "static" 752 | $config.'new.vcsa'.network.ip = $VCSAIPAddress 753 | $config.'new.vcsa'.network.'dns.servers'[0] = $VMDNS 754 | $config.'new.vcsa'.network.prefix = $VCSAPrefix 755 | $config.'new.vcsa'.network.gateway = $VMGateway 756 | $config.'new.vcsa'.network.'system.name' = $VCSAHostname 757 | $config.'new.vcsa'.os.password = $VCSARootPassword 758 | if($VCSASSHEnable -eq "true") { 759 | $VCSASSHEnableVar = $true 760 | } else { 761 | $VCSASSHEnableVar = $false 762 | } 763 | $config.'new.vcsa'.os.'ssh.enable' = $VCSASSHEnableVar 764 | $config.'new.vcsa'.sso.password = $VCSASSOPassword 765 | $config.'new.vcsa'.sso.'domain-name' = $VCSASSODomainName 766 | $config.'new.vcsa'.sso.'site-name' = $VCSASSOSiteName 767 | 768 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 769 | $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" 770 | 771 | My-Logger "Deploying the VCSA ..." 772 | Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula --acknowledge-ceip $($ENV:Temp)\jsontemplate.json"| Out-File -Append -LiteralPath $verboseLogFile 773 | } 774 | } 775 | 776 | if($moveVMsIntovApp -eq 1 -and $DeploymentTarget -eq "VCENTER") { 777 | # Check whether DRS is enabled as that is required to create vApp 778 | if((Get-Cluster -Server $viConnection $cluster).DrsEnabled) { 779 | My-Logger "Creating vApp $VAppName ..." 780 | $VApp = New-VApp -Name $VAppName -Server $viConnection -Location $cluster 781 | 782 | if($deployNestedESXiVMs -eq 1) { 783 | My-Logger "Moving Nested ESXi VMs into $VAppName vApp ..." 784 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 785 | $vm = Get-VM -Name $_.Key -Server $viConnection 786 | Move-VM -VM $vm -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 787 | } 788 | } 789 | 790 | if($deployVCSA -eq 1) { 791 | $vcsaVM = Get-VM -Name $VCSADisplayName -Server $viConnection 792 | My-Logger "Moving $VCSADisplayName into $VAppName vApp ..." 793 | Move-VM -VM $vcsaVM -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 794 | } 795 | 796 | if($DeployNSX -eq 1) { 797 | $nsxVM = Get-VM -Name $NSXDisplayName -Server $viConnection 798 | My-Logger "Moving $NSXDisplayName into $VAppName vApp ..." 799 | Move-VM -VM $nsxVM -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 800 | } 801 | } else { 802 | My-Logger "vApp $VAppName will NOT be created as DRS is NOT enabled on vSphere Cluster ${cluster} ..." 803 | } 804 | } 805 | 806 | My-Logger "Disconnecting from $VIServer ..." 807 | Disconnect-VIServer $viConnection -Confirm:$false 808 | 809 | 810 | if($setupNewVC -eq 1) { 811 | My-Logger "Connecting to the new VCSA ..." 812 | $vc = Connect-VIServer $VCSAIPAddress -User "administrator@$VCSASSODomainName" -Password $VCSASSOPassword -WarningAction SilentlyContinue 813 | 814 | My-Logger "Creating Datacenter $NewVCDatacenterName ..." 815 | New-Datacenter -Server $vc -Name $NewVCDatacenterName -Location (Get-Folder -Type Datacenter -Server $vc) | Out-File -Append -LiteralPath $verboseLogFile 816 | 817 | My-Logger "Creating VSAN Cluster $NewVCVSANClusterName ..." 818 | New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -VsanEnabled -VsanDiskClaimMode 'Manual' | Out-File -Append -LiteralPath $verboseLogFile 819 | 820 | if($addESXiHostsToVC -eq 1) { 821 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 822 | $VMName = $_.Key 823 | $VMIPAddress = $_.Value 824 | 825 | $targetVMHost = $VMIPAddress 826 | if($addHostByDnsName -eq 1) { 827 | $targetVMHost = $VMName 828 | } 829 | My-Logger "Adding ESXi host $targetVMHost to Cluster ..." 830 | Add-VMHost -Server $vc -Location (Get-Cluster -Name $NewVCVSANClusterName) -User "root" -Password $VMPassword -Name $targetVMHost -Force | Out-File -Append -LiteralPath $verboseLogFile 831 | } 832 | } 833 | 834 | if($DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 835 | My-Logger "Creating VDS $VDSName ..." 836 | $vds = New-VDSwitch -Server $vc -Name $VDSName -Location (Get-Datacenter -Name $NewVCDatacenterName) 837 | 838 | My-Logger "Creating new VXLAN DVPortgroup $VXLANDVPortgroup ..." 839 | $vxlanDVPG = New-VDPortgroup -Server $vc -Name $VXLANDVPortgroup -Vds $vds 840 | 841 | $vmhosts = Get-Cluster -Server $vc -Name $NewVCVSANClusterName | Get-VMHost 842 | foreach ($vmhost in $vmhosts) { 843 | $vmhostname = $vmhost.name 844 | 845 | My-Logger "Adding $vmhostname to VDS ..." 846 | Add-VDSwitchVMHost -Server $vc -VDSwitch $vds -VMHost $vmhost | Out-File -Append -LiteralPath $verboseLogFile 847 | 848 | My-Logger "Adding vmmnic1 to VDS ..." 849 | $vmnic = $vmhost | Get-VMHostNetworkAdapter -Physical -Name vmnic1 850 | Add-VDSwitchPhysicalNetworkAdapter -Server $vc -DistributedSwitch $vds -VMHostPhysicalNic $vmnic -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 851 | 852 | $vmk0 = Get-VMHostNetworkAdapter -Server $vc -Name vmk0 -VMHost $vmhost 853 | $lastNetworkOcet = $vmk0.ip.Split('.')[-1] 854 | $vxlanVmkIP = $VXLANSubnet + $lastNetworkOcet 855 | 856 | My-Logger "Adding VXLAN VMKernel $vxlanVmkIP to VDS ..." 857 | New-VMHostNetworkAdapter -VMHost $vmhost -PortGroup $VXLANDVPortgroup -VirtualSwitch $vds -IP $vxlanVmkIP -SubnetMask $VXLANNetmask -Mtu 1600 | Out-File -Append -LiteralPath $verboseLogFile 858 | } 859 | } 860 | 861 | if($configureVSANDiskGroups -eq 1) { 862 | My-Logger "Enabling VSAN Space Efficiency/De-Dupe & disabling VSAN Health Check ..." 863 | Get-VsanClusterConfiguration -Server $vc -Cluster $NewVCVSANClusterName | Set-VsanClusterConfiguration -SpaceEfficiencyEnabled $true -HealthCheckIntervalMinutes 0 | Out-File -Append -LiteralPath $verboseLogFile 864 | 865 | 866 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 867 | $luns = $vmhost | Get-ScsiLun | select CanonicalName, CapacityGB 868 | 869 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 870 | foreach ($lun in $luns) { 871 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 872 | $vsanCacheDisk = $lun.CanonicalName 873 | } 874 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 875 | $vsanCapacityDisk = $lun.CanonicalName 876 | } 877 | } 878 | My-Logger "Creating VSAN DiskGroup for $vmhost ..." 879 | New-VsanDiskGroup -Server $vc -VMHost $vmhost -SsdCanonicalName $vsanCacheDisk -DataDiskCanonicalName $vsanCapacityDisk | Out-File -Append -LiteralPath $verboseLogFile 880 | } 881 | } 882 | 883 | if($clearVSANHealthCheckAlarm -eq 1) { 884 | My-Logger "Clearing default VSAN Health Check Alarms, not applicable in Nested ESXi env ..." 885 | $alarmMgr = Get-View AlarmManager -Server $vc 886 | Get-Cluster -Server $vc | where {$_.ExtensionData.TriggeredAlarmState} | %{ 887 | $cluster = $_ 888 | $Cluster.ExtensionData.TriggeredAlarmState | %{ 889 | $alarmMgr.AcknowledgeAlarm($_.Alarm,$cluster.ExtensionData.MoRef) 890 | } 891 | } 892 | } 893 | 894 | # Exit maintanence mode in case patching was done earlier 895 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 896 | if($vmhost.ConnectionState -eq "Maintenance") { 897 | Set-VMHost -VMhost $vmhost -State Connected -RunAsync -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 898 | } 899 | } 900 | 901 | My-Logger "Disconnecting from new VCSA ..." 902 | Disconnect-VIServer $vc -Confirm:$false 903 | } 904 | 905 | if($configureNSX -eq 1 -and $DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 906 | if(!(Connect-NSXServer -Server $NSXHostname -Username admin -Password $NSXUIPassword -DisableVIAutoConnect -WarningAction SilentlyContinue)) { 907 | Write-Host -ForegroundColor Red "Unable to connect to NSX Manager, please check the deployment" 908 | exit 909 | } else { 910 | My-Logger "Successfully logged into NSX Manager $NSXHostname ..." 911 | } 912 | 913 | $ssoUsername = "administrator@$VCSASSODomainName" 914 | My-Logger "Registering NSX Manager with vCenter Server $VCSAHostname ..." 915 | $vcConfig = Set-NsxManager -vCenterServer $VCSAHostname -vCenterUserName $ssoUsername -vCenterPassword $VCSASSOPassword 916 | 917 | My-Logger "Registering NSX Manager with vCenter SSO $VCSAHostname ..." 918 | $ssoConfig = Set-NsxManager -SsoServer $VCSAHostname -SsoUserName $ssoUsername -SsoPassword $VCSASSOPassword -AcceptAnyThumbprint 919 | 920 | My-Logger "Disconnecting from NSX Manager ..." 921 | Disconnect-NsxServer 922 | } 923 | 924 | $EndTime = Get-Date 925 | $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2) 926 | 927 | My-Logger "vSphere $vSphereVersion Lab Deployment Complete!" 928 | My-Logger "StartTime: $StartTime" 929 | My-Logger " EndTime: $EndTime" 930 | My-Logger " Duration: $duration minutes" -------------------------------------------------------------------------------- /vsphere-6.7-standard-lab-deployment.ps1: -------------------------------------------------------------------------------- 1 | # Author: William Lam 2 | # Website: www.virtuallyghetto.com 3 | # Description: PowerCLI script to deploy a fully functional vSphere 6.5 lab consisting of 3 4 | # Nested ESXi hosts enable w/vSAN + VCSA 6.5. Expects a single physical ESXi host 5 | # as the endpoint and all four VMs will be deployed to physical ESXi host 6 | # Reference: http://www.virtuallyghetto.com/2016/11/vghetto-automated-vsphere-lab-deployment-for-vsphere-6-0u2-vsphere-6-5.html 7 | # Credit: Thanks to Alan Renouf as I borrowed some of his PCLI code snippets :) 8 | # 9 | # Changelog 10 | # 11/22/16 11 | # * Automatically handle Nested ESXi on vSAN 12 | # 01/20/17 13 | # * Resolved "Another task in progress" thanks to Jason M 14 | # 02/12/17 15 | # * Support for deploying to VC Target 16 | # * Support for enabling SSH on VCSA 17 | # * Added option to auto-create vApp Container for VMs 18 | # * Added pre-check for required files 19 | # 02/17/17 20 | # * Added missing dvFilter param to eth1 (missing in Nested ESXi OVA) 21 | # 02/21/17 22 | # * Support for deploying NSX 6.3 & registering with vCenter Server 23 | # * Support for updating Nested ESXi VM to ESXi 6.5a (required for NSX 6.3) 24 | # * Support for VDS + VXLAN VMkernel configuration (required for NSX 6.3) 25 | # * Support for "Private" Portgroup on eth1 for Nested ESXi VM used for VXLAN traffic (required for NSX 6.3) 26 | # * Support for both Virtual & Distributed Portgroup on $VMNetwork 27 | # * Support for adding ESXi hosts into VC using DNS name (disabled by default) 28 | # * Added CPU/MEM/Storage resource requirements in confirmation screen 29 | # 05/08/17 30 | # * Support for patching ESXi using VMware Online repo thanks to Matt Lichstein for contribution 31 | # * Added fix to test ESXi endpoint before trying to patch 32 | # 04/18/18 33 | # * Added support for vCenter Server 6.7, some of the JSON params have changed for consistency purposes which needed to be updated 34 | # * Added support for new Nested ESXi 6.7 Virtual Appliance (will need to download that first) 35 | # * vMotion is now enabled by default on vmk0 for all Nested ESXi hosts 36 | # 02/10/2020 37 | # * Added support for deploying basic vSphere environment (ESXi VM + VCSA) into VMware Cloud on AWS (Nested vSAN not supported) 38 | 39 | # Physical ESXi host or vCenter Server to deploy vSphere 6.7 lab 40 | $VIServer = "vcenter.sddc-a-b-c-d.vmwarevmc.com" 41 | $VIUsername = 'cloudadmin@vmc.local' 42 | $VIPassword = 'FILL-ME-IN' 43 | 44 | # Specifies whether deployment is to an ESXi host or vCenter Server 45 | # Use either ESXI or VCENTER or VMC 46 | $DeploymentTarget = "VMC" 47 | 48 | # Full Path to both the Nested ESXi 6.7 VA + extracted VCSA 6.7 ISO 49 | $NestedESXiApplianceOVA = 'C:\Users\Administrator\Desktop\VMC-Customer0\Nested_ESXi6.7u3_Appliance_Template_v1.ova' 50 | $VCSAInstallerPath = 'C:\Users\Administrator\Desktop\VMC-Customer0\VMware-VCSA-all-6.7.0-15132721' 51 | $NSXOVA = 'C:\Users\Administrator\Desktop\VMC-Customer0\VMware-NSX-Manager-6.3.0-5007049.ova' 52 | $ESXi65OfflineBundle = 'C:\Users\Administrator\Desktop\VMC-Customer0\ESXi650-201701001\vmw-ESXi-6.5.0-metadata.zip' # Used for offline upgrade only 53 | $ESXiProfileName = 'ESXi-6.5.0-20170404001-standard' # Used for online upgrade only 54 | 55 | # Nested ESXi VMs to deploy 56 | $NestedESXiHostnameToIPs = @{ 57 | "vesxi67-1" = "192.168.1.51" 58 | "vesxi67-2" = "192.168.1.52" 59 | "vesxi67-3" = "192.168.1.53" 60 | } 61 | 62 | # Nested ESXi VM Resources 63 | $NestedESXivCPU = "2" 64 | $NestedESXivMEM = "6" #GB 65 | $NestedESXiCachingvDisk = "4" #GB 66 | $NestedESXiCapacityvDisk = "8" #GB 67 | 68 | # VCSA Deployment Configuration 69 | $VCSADeploymentSize = "tiny" 70 | $VCSADisplayName = "vcenter67-1" 71 | $VCSAIPAddress = "192.168.1.50" 72 | $VCSAHostname = "vcenter67-1.vmware.corp" #Change to IP if you don't have valid DNS 73 | $VCSAPrefix = "24" 74 | $VCSASSODomainName = "vsphere.local" 75 | $VCSASSOPassword = "VMware1!" 76 | $VCSARootPassword = "VMware1!" 77 | $VCSASSHEnable = "true" 78 | 79 | # General Deployment Configuration for Nested ESXi, VCSA & NSX VMs 80 | $VirtualSwitchType = "VDS" # VSS or VDS 81 | $VMNetwork = "sddc-cgw-network-1" 82 | $VMDatastore = "WorkloadDatastore" 83 | $VMNetmask = "255.255.255.0" 84 | $VMGateway = "192.168.1.1" 85 | $VMDNS = "192.168.1.100" 86 | $VMNTP = "pool.ntp.org" 87 | $VMPassword = "VMware1!" 88 | $VMDomain = "vmware.corp" 89 | $VMSyslog = "192.168.1.200" 90 | # Applicable to Nested ESXi only 91 | $VMSSH = "true" 92 | $VMVMFS = "false" 93 | # Applicable to VC Deployment Target only 94 | $VMCluster = "Cluster-1" 95 | # Defaults for VMC 96 | $VMDatacenter = "SDDC-Datacenter" 97 | $VMFolder = "Workloads" 98 | $VMResourcePool = "Compute-ResourcePool" 99 | 100 | # Name of new vSphere Datacenter/Cluster when VCSA is deployed 101 | $NewVCDatacenterName = "Datacenter" 102 | $NewVCVSANClusterName = "vSphere-Cluster" 103 | 104 | # NSX Manager Configuration 105 | $DeployNSX = 0 106 | $NSXvCPU = "2" # Reconfigure NSX vCPU 107 | $NSXvMEM = "8" # Reconfigure NSX vMEM (GB) 108 | $NSXDisplayName = "nsx63-1" 109 | $NSXHostname = "nsx63-1.primp-industries.com" 110 | $NSXIPAddress = "172.30.0.250" 111 | $NSXNetmask = "255.255.255.0" 112 | $NSXGateway = "172.30.0.1" 113 | $NSXSSHEnable = "true" 114 | $NSXCEIPEnable = "false" 115 | $NSXUIPassword = "VMw@re123!" 116 | $NSXCLIPassword = "VMw@re123!" 117 | 118 | # VDS / VXLAN Configurations 119 | $PrivateVXLANVMNetwork = "dv-private-network" # Existing Portgroup 120 | $VDSName = "VDS-6.7" 121 | $VXLANDVPortgroup = "VXLAN" 122 | $VXLANSubnet = "172.16.66." 123 | $VXLANNetmask = "255.255.255.0" 124 | 125 | # Advanced Configurations 126 | # Set to 1 only if you have DNS (forward/reverse) for ESXi hostnames 127 | $addHostByDnsName = 1 128 | # Upgrade vESXi hosts (defaults to pulling upgrade from VMware using profile specified in $ESXiProfileName) 129 | $upgradeESXi = 0 130 | # Set to 1 only if you want to upgrade using local bundle specified in $ESXi65OfflineBundle 131 | $offlineUpgrade = 0 132 | # Enable verbose output to a new PowerShell Console. Thanks to suggestion by Christian Mohn 133 | $enableVerboseLoggingToNewShell = 0 134 | 135 | #### DO NOT EDIT BEYOND HERE #### 136 | 137 | $verboseLogFile = "vsphere67-lab-deployment.log" 138 | $vSphereVersion = "6.7" 139 | $deploymentType = "Standard" 140 | $random_string = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_}) 141 | $VAppName = "Nested-vSphere-Lab-$vSphereVersion-$random_string" 142 | $depotServer = "https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml" 143 | 144 | 145 | #default bin for windows 146 | $vcsaInstallBin = "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe" 147 | $pwshBin = "powershell.exe" 148 | $vcsaEsxJson = "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_ESXi.json" 149 | $vcsaVcJson = "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_VC.json" 150 | 151 | #test if system is linux and set linux path 152 | if ($IsLinux) { 153 | $vcsaInstallBin = "$($VCSAInstallerPath)/vcsa-cli-installer/lin64/vcsa-deploy" 154 | $pwshBin = "pwsh" 155 | $vcsaEsxJson = "$($VCSAInstallerPath)/vcsa-cli-installer/templates/install/embedded_vCSA_on_ESXi.json" 156 | $vcsaVcJson = "$($VCSAInstallerPath)/vcsa-cli-installer/templates/install/embedded_vCSA_on_VC.json" 157 | } 158 | 159 | #test if system is mac and set linux path 160 | if ($IsMacOS) { 161 | $vcsaInstallBin = "$($VCSAInstallerPath)/vcsa-cli-installer/mac/vcsa-deploy" 162 | $pwshBin = "pwsh" 163 | $vcsaEsxJson = "$($VCSAInstallerPath)/vcsa-cli-installer/templates/install/embedded_vCSA_on_ESXi.json" 164 | $vcsaVcJson = "$($VCSAInstallerPath)/vcsa-cli-installer/templates/install/embedded_vCSA_on_VC.json" 165 | } 166 | 167 | 168 | $vcsaSize2MemoryStorageMap = @{ 169 | "tiny"=@{"cpu"="2";"mem"="10";"disk"="250"}; 170 | "small"=@{"cpu"="4";"mem"="16";"disk"="290"}; 171 | "medium"=@{"cpu"="8";"mem"="24";"disk"="425"}; 172 | "large"=@{"cpu"="16";"mem"="32";"disk"="640"}; 173 | "xlarge"=@{"cpu"="24";"mem"="48";"disk"="980"} 174 | } 175 | 176 | $esxiTotalCPU = 0 177 | $vcsaTotalCPU = 0 178 | $nsxTotalCPU = 0 179 | $esxiTotalMemory = 0 180 | $vcsaTotalMemory = 0 181 | $nsxTotalMemory = 0 182 | $esxiTotStorage = 0 183 | $vcsaTotalStorage = 0 184 | $nsxTotalStorage = 0 185 | 186 | $preCheck = 1 187 | $confirmDeployment = 1 188 | $deployNestedESXiVMs = 1 189 | $deployVCSA = 1 190 | $setupNewVC = 1 191 | $addESXiHostsToVC = 1 192 | $configureVSANDiskGroups = 0 193 | $clearVSANHealthCheckAlarm = 0 194 | $configurevMotion = 1 195 | $setupVXLAN = 0 196 | $configureNSX = 0 197 | $moveVMsIntovApp = 1 198 | 199 | $StartTime = Get-Date 200 | 201 | Function My-Logger { 202 | param( 203 | [Parameter(Mandatory=$true)] 204 | [String]$message 205 | ) 206 | 207 | $timeStamp = Get-Date -Format "MM-dd-yyyy_hh:mm:ss" 208 | 209 | Write-Host -NoNewline -ForegroundColor White "[$timestamp]" 210 | Write-Host -ForegroundColor Green " $message" 211 | $logMessage = "[$timeStamp] $message" 212 | $logMessage | Out-File -Append -LiteralPath $verboseLogFile 213 | } 214 | 215 | Function URL-Check([string] $url) { 216 | $isWorking = $true 217 | 218 | try { 219 | $request = [System.Net.WebRequest]::Create($url) 220 | $request.Method = "HEAD" 221 | $request.UseDefaultCredentials = $true 222 | 223 | $response = $request.GetResponse() 224 | $httpStatus = $response.StatusCode 225 | 226 | $isWorking = ($httpStatus -eq "OK") 227 | } 228 | catch { 229 | $isWorking = $false 230 | } 231 | return $isWorking 232 | } 233 | 234 | if($preCheck -eq 1) { 235 | if(!(Test-Path $NestedESXiApplianceOVA)) { 236 | Write-Host -ForegroundColor Red "`nUnable to find $NestedESXiApplianceOVA ...`nexiting" 237 | exit 238 | } 239 | 240 | if(!(Test-Path $VCSAInstallerPath)) { 241 | Write-Host -ForegroundColor Red "`nUnable to find $VCSAInstallerPath ...`nexiting" 242 | exit 243 | } 244 | 245 | if($DeployNSX -eq 1) { 246 | if(!(Test-Path $NSXOVA)) { 247 | Write-Host -ForegroundColor Red "`nUnable to find $NSXOVA ...`nexiting" 248 | exit 249 | } 250 | 251 | if(-not (Get-Module -Name "PowerNSX")) { 252 | Write-Host -ForegroundColor Red "`nPowerNSX Module is not loaded, please install and load PowerNSX before running script ...`nexiting" 253 | exit 254 | } 255 | $upgradeESXi = 1 256 | } 257 | 258 | if($upgradeESXi -eq 1) { 259 | if($offlineUpgrade -eq 1) { 260 | if(!(Test-Path $ESXi65OfflineBundle)) { 261 | Write-Host -ForegroundColor Red "`nUnable to find $ESXi65OfflineBundle ...`nexiting" 262 | exit 263 | } 264 | else { 265 | if(!(URL-Check($depotServer))) { 266 | Write-Host -ForegroundColor Red "`nVMware depot server is unavailable ...`nexiting" 267 | exit 268 | } 269 | } 270 | } 271 | } 272 | } 273 | 274 | if($confirmDeployment -eq 1) { 275 | Write-Host -ForegroundColor Magenta "`nPlease confirm the following configuration will be deployed:`n" 276 | 277 | Write-Host -ForegroundColor Yellow "---- vSphere Automated Lab Deployment Configuration ---- " 278 | Write-Host -NoNewline -ForegroundColor Green "Deployment Target: " 279 | Write-Host -ForegroundColor White $DeploymentTarget 280 | Write-Host -NoNewline -ForegroundColor Green "Deployment Type: " 281 | Write-Host -ForegroundColor White $deploymentType 282 | Write-Host -NoNewline -ForegroundColor Green "vSphere Version: " 283 | Write-Host -ForegroundColor White "vSphere $vSphereVersion" 284 | Write-Host -NoNewline -ForegroundColor Green "Nested ESXi Image Path: " 285 | Write-Host -ForegroundColor White $NestedESXiApplianceOVA 286 | Write-Host -NoNewline -ForegroundColor Green "VCSA Image Path: " 287 | Write-Host -ForegroundColor White $VCSAInstallerPath 288 | 289 | if($DeployNSX -eq 1) { 290 | Write-Host -NoNewline -ForegroundColor Green "NSX Image Path: " 291 | Write-Host -ForegroundColor White $NSXOVA 292 | } 293 | 294 | if($DeploymentTarget -eq "ESXI") { 295 | Write-Host -ForegroundColor Yellow "`n---- Physical ESXi Deployment Target Configuration ----" 296 | Write-Host -NoNewline -ForegroundColor Green "ESXi Address: " 297 | } else { 298 | Write-Host -ForegroundColor Yellow "`n---- vCenter Server Deployment Target Configuration ----" 299 | Write-Host -NoNewline -ForegroundColor Green "vCenter Server Address: " 300 | } 301 | 302 | Write-Host -ForegroundColor White $VIServer 303 | Write-Host -NoNewline -ForegroundColor Green "Username: " 304 | Write-Host -ForegroundColor White $VIUsername 305 | Write-Host -NoNewline -ForegroundColor Green "VM Network: " 306 | Write-Host -ForegroundColor White $VMNetwork 307 | 308 | if($DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 309 | Write-Host -NoNewline -ForegroundColor Green "Private VXLAN VM Network: " 310 | Write-Host -ForegroundColor White $PrivateVXLANVMNetwork 311 | } 312 | 313 | Write-Host -NoNewline -ForegroundColor Green "VM Storage: " 314 | Write-Host -ForegroundColor White $VMDatastore 315 | 316 | if($DeploymentTarget -eq "VCENTER") { 317 | Write-Host -NoNewline -ForegroundColor Green "VM Cluster: " 318 | Write-Host -ForegroundColor White $VMCluster 319 | Write-Host -NoNewline -ForegroundColor Green "VM vApp: " 320 | Write-Host -ForegroundColor White $VAppName 321 | } 322 | 323 | if($DeploymentTarget -eq "VMC") { 324 | Write-Host -NoNewline -ForegroundColor Green "VM Folder: " 325 | Write-Host -ForegroundColor White $VMFolder 326 | Write-Host -NoNewline -ForegroundColor Green "VM Resource Pool: " 327 | Write-Host -ForegroundColor White $VMResourcePool 328 | Write-Host -NoNewline -ForegroundColor Green "VM vApp: " 329 | Write-Host -ForegroundColor White $VAppName 330 | } 331 | 332 | Write-Host -ForegroundColor Yellow "`n---- vESXi Configuration ----" 333 | Write-Host -NoNewline -ForegroundColor Green "# of Nested ESXi VMs: " 334 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.count 335 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 336 | Write-Host -ForegroundColor White $NestedESXivCPU 337 | Write-Host -NoNewline -ForegroundColor Green "vMEM: " 338 | Write-Host -ForegroundColor White "$NestedESXivMEM GB" 339 | Write-Host -NoNewline -ForegroundColor Green "Caching VMDK: " 340 | Write-Host -ForegroundColor White "$NestedESXiCachingvDisk GB" 341 | Write-Host -NoNewline -ForegroundColor Green "Capacity VMDK: " 342 | Write-Host -ForegroundColor White "$NestedESXiCapacityvDisk GB" 343 | Write-Host -NoNewline -ForegroundColor Green "IP Address(s): " 344 | Write-Host -ForegroundColor White $NestedESXiHostnameToIPs.Values 345 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 346 | Write-Host -ForegroundColor White $VMNetmask 347 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 348 | Write-Host -ForegroundColor White $VMGateway 349 | Write-Host -NoNewline -ForegroundColor Green "DNS: " 350 | Write-Host -ForegroundColor White $VMDNS 351 | Write-Host -NoNewline -ForegroundColor Green "NTP: " 352 | Write-Host -ForegroundColor White $VMNTP 353 | Write-Host -NoNewline -ForegroundColor Green "Syslog: " 354 | Write-Host -ForegroundColor White $VMSyslog 355 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 356 | Write-Host -ForegroundColor White $VMSSH 357 | Write-Host -NoNewline -ForegroundColor Green "Create VMFS Volume: " 358 | Write-Host -ForegroundColor White $VMVMFS 359 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 360 | Write-Host -ForegroundColor White $VMPassword 361 | 362 | Write-Host -ForegroundColor Yellow "`n---- VCSA Configuration ----" 363 | Write-Host -NoNewline -ForegroundColor Green "Deployment Size: " 364 | Write-Host -ForegroundColor White $VCSADeploymentSize 365 | Write-Host -NoNewline -ForegroundColor Green "SSO Domain: " 366 | Write-Host -ForegroundColor White $VCSASSODomainName 367 | Write-Host -NoNewline -ForegroundColor Green "SSO Password: " 368 | Write-Host -ForegroundColor White $VCSASSOPassword 369 | Write-Host -NoNewline -ForegroundColor Green "Root Password: " 370 | Write-Host -ForegroundColor White $VCSARootPassword 371 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 372 | Write-Host -ForegroundColor White $VCSASSHEnable 373 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 374 | Write-Host -ForegroundColor White $VCSAHostname 375 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 376 | Write-Host -ForegroundColor White $VCSAIPAddress 377 | Write-Host -NoNewline -ForegroundColor Green "Netmask " 378 | Write-Host -ForegroundColor White $VMNetmask 379 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 380 | Write-Host -ForegroundColor White $VMGateway 381 | 382 | if($DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 383 | Write-Host -NoNewline -ForegroundColor Green "VDS Name: " 384 | Write-Host -ForegroundColor White $VDSName 385 | Write-Host -NoNewline -ForegroundColor Green "VXLAN Portgroup Name: " 386 | Write-Host -ForegroundColor White $VXLANDVPortgroup 387 | Write-Host -NoNewline -ForegroundColor Green "VXLAN Subnet: " 388 | Write-Host -ForegroundColor White $VXLANSubnet 389 | Write-Host -NoNewline -ForegroundColor Green "VXLAN Netmask: " 390 | Write-Host -ForegroundColor White $VXLANNetmask 391 | } 392 | 393 | if($DeployNSX -eq 1) { 394 | Write-Host -ForegroundColor Yellow "`n---- NSX Configuration ----" 395 | Write-Host -NoNewline -ForegroundColor Green "vCPU: " 396 | Write-Host -ForegroundColor White $NSXvCPU 397 | Write-Host -NoNewline -ForegroundColor Green "Memory (GB): " 398 | Write-Host -ForegroundColor White $NSXvMEM 399 | Write-Host -NoNewline -ForegroundColor Green "Hostname: " 400 | Write-Host -ForegroundColor White $NSXHostname 401 | Write-Host -NoNewline -ForegroundColor Green "IP Address: " 402 | Write-Host -ForegroundColor White $NSXIPAddress 403 | Write-Host -NoNewline -ForegroundColor Green "Netmask: " 404 | Write-Host -ForegroundColor White $NSXNetmask 405 | Write-Host -NoNewline -ForegroundColor Green "Gateway: " 406 | Write-Host -ForegroundColor White $NSXGateway 407 | Write-Host -NoNewline -ForegroundColor Green "Enable SSH: " 408 | Write-Host -ForegroundColor White $NSXSSHEnable 409 | Write-Host -NoNewline -ForegroundColor Green "Enable CEIP: " 410 | Write-Host -ForegroundColor White $NSXCEIPEnable 411 | Write-Host -NoNewline -ForegroundColor Green "UI Password: " 412 | Write-Host -ForegroundColor White $NSXUIPassword 413 | Write-Host -NoNewline -ForegroundColor Green "CLI Password: " 414 | Write-Host -ForegroundColor White $NSXCLIPassword 415 | } 416 | 417 | $esxiTotalCPU = $NestedESXiHostnameToIPs.count * [int]$NestedESXivCPU 418 | $esxiTotalMemory = $NestedESXiHostnameToIPs.count * [int]$NestedESXivMEM 419 | $esxiTotalStorage = ($NestedESXiHostnameToIPs.count * [int]$NestedESXiCachingvDisk) + ($NestedESXiHostnameToIPs.count * [int]$NestedESXiCapacityvDisk) 420 | $vcsaTotalCPU = $vcsaSize2MemoryStorageMap.$VCSADeploymentSize.cpu 421 | $vcsaTotalMemory = $vcsaSize2MemoryStorageMap.$VCSADeploymentSize.mem 422 | $vcsaTotalStorage = $vcsaSize2MemoryStorageMap.$VCSADeploymentSize.disk 423 | 424 | Write-Host -ForegroundColor Yellow "`n---- Resource Requirements ----" 425 | Write-Host -NoNewline -ForegroundColor Green "ESXi VM CPU: " 426 | Write-Host -NoNewline -ForegroundColor White $esxiTotalCPU 427 | Write-Host -NoNewline -ForegroundColor Green " ESXi VM Memory: " 428 | Write-Host -NoNewline -ForegroundColor White $esxiTotalMemory "GB " 429 | Write-Host -NoNewline -ForegroundColor Green "ESXi VM Storage: " 430 | Write-Host -ForegroundColor White $esxiTotalStorage "GB" 431 | Write-Host -NoNewline -ForegroundColor Green "VCSA VM CPU: " 432 | Write-Host -NoNewline -ForegroundColor White $vcsaTotalCPU 433 | Write-Host -NoNewline -ForegroundColor Green " VCSA VM Memory: " 434 | Write-Host -NoNewline -ForegroundColor White $vcsaTotalMemory "GB " 435 | Write-Host -NoNewline -ForegroundColor Green "VCSA VM Storage: " 436 | Write-Host -ForegroundColor White $vcsaTotalStorage "GB" 437 | 438 | if($DeployNSX -eq 1) { 439 | $nsxTotalCPU = [int]$NSXvCPU 440 | $nsxTotalMemory = [int]$NSXvMEM 441 | $nsxTotalStorage = 60 442 | Write-Host -NoNewline -ForegroundColor Green "NSX VM CPU: " 443 | Write-Host -NoNewline -ForegroundColor White $nsxTotalCPU 444 | Write-Host -NoNewline -ForegroundColor Green " NSX VM Memory: " 445 | Write-Host -NoNewline -ForegroundColor White $nsxTotalMemory "GB " 446 | Write-Host -NoNewline -ForegroundColor Green " NSX VM Storage: " 447 | Write-Host -ForegroundColor White $nsxTotalStorage "GB" 448 | } 449 | 450 | Write-Host -ForegroundColor White "---------------------------------------------" 451 | Write-Host -NoNewline -ForegroundColor Green "Total CPU: " 452 | Write-Host -ForegroundColor White ($esxiTotalCPU + $vcsaTotalCPU + $nsxTotalCPU) 453 | Write-Host -NoNewline -ForegroundColor Green "Total Memory: " 454 | Write-Host -ForegroundColor White ($esxiTotalMemory + $vcsaTotalMemory + $nsxTotalMemory) "GB" 455 | Write-Host -NoNewline -ForegroundColor Green "Total Storage: " 456 | Write-Host -ForegroundColor White ($esxiTotalStorage + $vcsaTotalStorage + $nsxTotalStorage) "GB" 457 | 458 | Write-Host -ForegroundColor Magenta "`nWould you like to proceed with this deployment?`n" 459 | $answer = Read-Host -Prompt "Do you accept (Y or N)" 460 | if($answer -ne "Y" -or $answer -ne "y") { 461 | exit 462 | } 463 | Clear-Host 464 | } 465 | 466 | My-Logger "Connecting to $VIServer ..." 467 | $viConnection = Connect-VIServer $VIServer -User $VIUsername -Password $VIPassword -WarningAction SilentlyContinue 468 | 469 | if($DeploymentTarget -eq "ESXI") { 470 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore 471 | if($VirtualSwitchType -eq "VSS") { 472 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork 473 | if($DeployNSX -eq 1) { 474 | $privateNetwork = Get-VirtualPortGroup -Server $viConnection -Name $PrivateVXLANVMNetwork 475 | } 476 | } else { 477 | $network = Get-VDPortgroup -Server $viConnection -Name $VMNetwork 478 | if($DeployNSX -eq 1) { 479 | $privateNetwork = Get-VDPortgroup -Server $viConnection -Name $PrivateVXLANVMNetwork 480 | } 481 | } 482 | $vmhost = Get-VMHost -Server $viConnection 483 | 484 | if($datastore.Type -eq "vsan") { 485 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 486 | Get-AdvancedSetting -Entity $vmhost -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 487 | } 488 | } else { 489 | $datastore = Get-Datastore -Server $viConnection -Name $VMDatastore | Select -First 1 490 | if($DeploymentTarget -eq "VMC") { 491 | $network = Get-VirtualNetwork -Server $viConnection -Name $VMNetwork | Select -First 1 492 | } else { 493 | if($VirtualSwitchType -eq "VSS") { 494 | $network = Get-VirtualPortGroup -Server $viConnection -Name $VMNetwork | Select -First 1 495 | if($DeployNSX -eq 1) { 496 | $privateNetwork = Get-VirtualPortGroup -Server $viConnection -Name $PrivateVXLANVMNetwork | Select -First 1 497 | } 498 | } else { 499 | $network = Get-VDPortgroup -Server $viConnection -Name $VMNetwork | Select -First 1 500 | if($DeployNSX -eq 1) { 501 | $privateNetwork = Get-VDPortgroup -Server $viConnection -Name $PrivateVXLANVMNetwork | Select -First 1 502 | } 503 | } 504 | } 505 | 506 | if($DeploymentTarget -eq "VMC") { 507 | $datacenter = Get-Datacenter -Name $VMDatacenter 508 | $resourcePool = Get-ResourcePool -Server $viConnection -Name $VMResourcePool 509 | $folder = Get-Folder -Server $viConnection -Name $VMFolder 510 | $vmhost = (Get-Cluster -Server $viConnection -Name "Cluster-1") | Get-VMHost | Select -First 1 511 | } else { 512 | $cluster = Get-Cluster -Server $viConnection -Name $VMCluster 513 | $datacenter = $cluster | Get-Datacenter 514 | $vmhost = $cluster | Get-VMHost | Select -First 1 515 | $vmhostfullcluster = $cluster | Get-VMHost 516 | } 517 | 518 | if($datastore.Type -eq "vsan" -and $DeploymentTarget -ne "VMC") { 519 | My-Logger "VSAN Datastore detected, enabling Fake SCSI Reservations ..." 520 | Get-AdvancedSetting -Entity $vmhostfullcluster -Name "VSAN.FakeSCSIReservations" | Set-AdvancedSetting -Value 1 -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 521 | } 522 | } 523 | 524 | if($deployNestedESXiVMs -eq 1) { 525 | if($DeploymentTarget -eq "ESXI") { 526 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 527 | $VMName = $_.Key 528 | $VMIPAddress = $_.Value 529 | 530 | My-Logger "Deploying Nested ESXi VM $VMName ..." 531 | $vm = Import-VApp -Server $viConnection -Source $NestedESXiApplianceOVA -Name $VMName -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 532 | 533 | My-Logger "Updating VM Network ..." 534 | $vm | Get-NetworkAdapter -Name "Network adapter 1" | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 535 | sleep 5 536 | 537 | if($DeployNSX -eq 1) { 538 | $vm | Get-NetworkAdapter -Name "Network adapter 2" | Set-NetworkAdapter -Portgroup $privateNetwork -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 539 | } else { 540 | $vm | Get-NetworkAdapter -Name "Network adapter 2" | Set-NetworkAdapter -Portgroup $network -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 541 | } 542 | 543 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 544 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 545 | 546 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 547 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 548 | 549 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 550 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 551 | 552 | $orignalExtraConfig = $vm.ExtensionData.Config.ExtraConfig 553 | $a = New-Object VMware.Vim.OptionValue 554 | $a.key = "guestinfo.hostname" 555 | $a.value = $VMName 556 | $b = New-Object VMware.Vim.OptionValue 557 | $b.key = "guestinfo.ipaddress" 558 | $b.value = $VMIPAddress 559 | $c = New-Object VMware.Vim.OptionValue 560 | $c.key = "guestinfo.netmask" 561 | $c.value = $VMNetmask 562 | $d = New-Object VMware.Vim.OptionValue 563 | $d.key = "guestinfo.gateway" 564 | $d.value = $VMGateway 565 | $e = New-Object VMware.Vim.OptionValue 566 | $e.key = "guestinfo.dns" 567 | $e.value = $VMDNS 568 | $f = New-Object VMware.Vim.OptionValue 569 | $f.key = "guestinfo.domain" 570 | $f.value = $VMDomain 571 | $g = New-Object VMware.Vim.OptionValue 572 | $g.key = "guestinfo.ntp" 573 | $g.value = $VMNTP 574 | $h = New-Object VMware.Vim.OptionValue 575 | $h.key = "guestinfo.syslog" 576 | $h.value = $VMSyslog 577 | $i = New-Object VMware.Vim.OptionValue 578 | $i.key = "guestinfo.password" 579 | $i.value = $VMPassword 580 | $j = New-Object VMware.Vim.OptionValue 581 | $j.key = "guestinfo.ssh" 582 | $j.value = $VMSSH 583 | $k = New-Object VMware.Vim.OptionValue 584 | $k.key = "guestinfo.createvmfs" 585 | $k.value = $VMVMFS 586 | $l = New-Object VMware.Vim.OptionValue 587 | $l.key = "ethernet1.filter4.name" 588 | $l.value = "dvfilter-maclearn" 589 | $m = New-Object VMware.Vim.OptionValue 590 | $m.key = "ethernet1.filter4.onFailure" 591 | $m.value = "failOpen" 592 | $orignalExtraConfig+=$a 593 | $orignalExtraConfig+=$b 594 | $orignalExtraConfig+=$c 595 | $orignalExtraConfig+=$d 596 | $orignalExtraConfig+=$e 597 | $orignalExtraConfig+=$f 598 | $orignalExtraConfig+=$g 599 | $orignalExtraConfig+=$h 600 | $orignalExtraConfig+=$i 601 | $orignalExtraConfig+=$j 602 | $orignalExtraConfig+=$k 603 | $orignalExtraConfig+=$l 604 | $orignalExtraConfig+=$m 605 | 606 | $spec = New-Object VMware.Vim.VirtualMachineConfigSpec 607 | $spec.ExtraConfig = $orignalExtraConfig 608 | 609 | My-Logger "Adding guestinfo customization properties to $vmname ..." 610 | $task = $vm.ExtensionData.ReconfigVM_Task($spec) 611 | $task1 = Get-Task -Id ("Task-$($task.value)") 612 | $task1 | Wait-Task | Out-Null 613 | 614 | My-Logger "Powering On $vmname ..." 615 | Start-VM -Server $viConnection -VM $vm -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 616 | } 617 | } else { 618 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 619 | $VMName = $_.Key 620 | $VMIPAddress = $_.Value 621 | 622 | $ovfconfig = Get-OvfConfiguration $NestedESXiApplianceOVA 623 | $networkMapLabel = ($ovfconfig.ToHashTable().keys | where {$_ -Match "NetworkMapping"}).replace("NetworkMapping.","").replace("-","_").replace(" ","_") 624 | $ovfconfig.NetworkMapping.$networkMapLabel.value = $VMNetwork 625 | 626 | $ovfconfig.common.guestinfo.hostname.value = $VMName 627 | $ovfconfig.common.guestinfo.ipaddress.value = $VMIPAddress 628 | $ovfconfig.common.guestinfo.netmask.value = $VMNetmask 629 | $ovfconfig.common.guestinfo.gateway.value = $VMGateway 630 | $ovfconfig.common.guestinfo.dns.value = $VMDNS 631 | $ovfconfig.common.guestinfo.domain.value = $VMDomain 632 | $ovfconfig.common.guestinfo.ntp.value = $VMNTP 633 | $ovfconfig.common.guestinfo.syslog.value = $VMSyslog 634 | $ovfconfig.common.guestinfo.password.value = $VMPassword 635 | if($VMSSH -eq "true") { 636 | $VMSSHVar = $true 637 | } else { 638 | $VMSSHVar = $false 639 | } 640 | $ovfconfig.common.guestinfo.ssh.value = $VMSSHVar 641 | 642 | My-Logger "Deploying Nested ESXi VM $VMName ..." 643 | if($DeploymentTarget -eq "VMC") { 644 | $vm = Import-VApp -Source $NestedESXiApplianceOVA -OvfConfiguration $ovfconfig -Name $VMName -Location $resourcePool -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin -InventoryLocation $folder 645 | } else { 646 | $vm = Import-VApp -Source $NestedESXiApplianceOVA -OvfConfiguration $ovfconfig -Name $VMName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 647 | } 648 | 649 | if($DeployNSX -eq 1) { 650 | My-Logger "Connecting Eth1 to $privateNetwork ..." 651 | $vm | Get-NetworkAdapter -Name "Network adapter 2" | Set-NetworkAdapter -Portgroup $privateNetwork -confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 652 | } 653 | 654 | My-Logger "Updating vCPU Count to $NestedESXivCPU & vMEM to $NestedESXivMEM GB ..." 655 | Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 656 | 657 | My-Logger "Updating vSAN Caching VMDK size to $NestedESXiCachingvDisk GB ..." 658 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 659 | 660 | My-Logger "Updating vSAN Capacity VMDK size to $NestedESXiCapacityvDisk GB ..." 661 | Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 662 | 663 | My-Logger "Powering On $vmname ..." 664 | $vm | Start-Vm -RunAsync | Out-Null 665 | } 666 | } 667 | } 668 | 669 | if($DeployNSX -eq 1) { 670 | if($DeploymentTarget -eq "VCENTER" -or $DeploymentTarget -eq "VMC") { 671 | $ovfconfig = Get-OvfConfiguration $NSXOVA 672 | $ovfconfig.NetworkMapping.VSMgmt.value = $VMNetwork 673 | 674 | $ovfconfig.common.vsm_hostname.value = $NSXHostname 675 | $ovfconfig.common.vsm_ip_0.value = $NSXIPAddress 676 | $ovfconfig.common.vsm_netmask_0.value = $NSXNetmask 677 | $ovfconfig.common.vsm_gateway_0.value = $NSXGateway 678 | $ovfconfig.common.vsm_dns1_0.value = $VMDNS 679 | $ovfconfig.common.vsm_domain_0.value = $VMDomain 680 | $ovfconfig.common.vsm_ntp_0 = $VMNTP 681 | if($NSXSSHEnable -eq "true") { 682 | $NSXSSHEnableVar = $true 683 | } else { 684 | $NSXSSHEnableVar = $false 685 | } 686 | $ovfconfig.common.vsm_isSSHEnabled.value = $NSXSSHEnableVar 687 | if($NSXCEIPEnable -eq "true") { 688 | $NSXCEIPEnableVar = $true 689 | } else { 690 | $NSXCEIPEnableVar = $false 691 | } 692 | $ovfconfig.common.vsm_isCEIPEnabled.value = $NSXCEIPEnableVar 693 | $ovfconfig.common.vsm_cli_passwd_0.value = $NSXUIPassword 694 | $ovfconfig.common.vsm_cli_en_passwd_0.value = $NSXCLIPassword 695 | 696 | My-Logger "Deploying NSX VM $NSXDisplayName ..." 697 | if($DeploymentTarget -eq "VMC") { 698 | $vm = Import-VApp -Source $NSXOVA -OvfConfiguration $ovfconfig -Name $NSXDisplayName -Location $resourcePool -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin -InventoryLocation $folder 699 | } else { 700 | $vm = Import-VApp -Source $NSXOVA -OvfConfiguration $ovfconfig -Name $NSXDisplayName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin 701 | } 702 | 703 | My-Logger "Updating vCPU Count to $NSXvCPU & vMEM to $NSXvMEM GB ..." 704 | Set-VM -Server $viConnection -VM $vm -NumCpu $NSXvCPU -MemoryGB $NSXvMEM -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 705 | 706 | My-Logger "Powering On $NSXDisplayName ..." 707 | $vm | Start-Vm -RunAsync | Out-Null 708 | } 709 | } 710 | 711 | if($upgradeESXi -eq 1) { 712 | sleep 60 713 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 714 | $VMName = $_.Key 715 | $VMIPAddress = $_.Value 716 | 717 | My-Logger "Connecting directly to $VMName for ESXi upgrade ..." 718 | while(1) { 719 | try { 720 | $results = Invoke-WebRequest -Uri https://$VMIPAddress/ui -Method GET 721 | if($results.StatusCode -eq 200) { 722 | break 723 | } 724 | } 725 | catch { 726 | My-Logger "$VMName is not ready yet, sleeping 30seconds ..." 727 | sleep 30 728 | } 729 | } 730 | # This is apparently needed due to patching using online image profile taking longer 731 | Set-PowerCLIConfiguration -WebOperationTimeoutSeconds 900 -Scope Session -Confirm:$false | Out-Null 732 | 733 | $vESXi = Connect-VIServer -Server $VMIPAddress -User root -Password $VMPassword -WarningAction SilentlyContinue 734 | 735 | My-Logger "Entering Maintenance Mode ..." 736 | Set-VMHost -VMhost $VMIPAddress -State Maintenance -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 737 | 738 | if($offlineUpgrade -eq 1) { 739 | My-Logger "Upgrading $VMname using offline bundle $ESXi65OfflineBundle ..." 740 | Install-VMHostPatch -VMHost $VMIPAddress -LocalPath $ESXi65OfflineBundle -HostUsername root -HostPassword $VMPassword -WarningAction SilentlyContinue -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 741 | } 742 | else { 743 | My-Logger "Upgrading $VMName using Image Profile $ESXiProfileName ..." 744 | $esxcli = Get-EsxCli -VMHost $VMIPAddress -V2 745 | $esxcli.network.firewall.ruleset.set.Invoke(@{enabled = 'true' ; rulesetid = 'httpClient'}) | Out-Null 746 | $esxcli.software.profile.update.Invoke(@{profile = $ESXiProfileName; depot = $depotServer}) | Out-File -Append -LiteralPath $verboseLogFile 747 | } 748 | 749 | My-Logger "Rebooting $VMName ..." 750 | Restart-VMHost $VMIPAddress -RunAsync -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 751 | 752 | My-Logger "Disconnecting from new ESXi host ..." 753 | Disconnect-VIServer $vESXi -Confirm:$false 754 | } 755 | } 756 | 757 | if($deployVCSA -eq 1) { 758 | if($DeploymentTarget -eq "ESXI") { 759 | # Deploy using the VCSA CLI Installer 760 | $config = (Get-Content -Raw "$($vcsaEsxJson)") | convertfrom-json 761 | $config.new_vcsa.esxi.hostname = $VIServer 762 | $config.new_vcsa.esxi.username = $VIUsername 763 | $config.new_vcsa.esxi.password = $VIPassword 764 | $config.new_vcsa.esxi.deployment_network = $VMNetwork 765 | $config.new_vcsa.esxi.datastore = $datastore 766 | $config.new_vcsa.appliance.thin_disk_mode = $true 767 | $config.new_vcsa.appliance.deployment_option = $VCSADeploymentSize 768 | $config.new_vcsa.appliance.name = $VCSADisplayName 769 | $config.new_vcsa.network.ip_family = "ipv4" 770 | $config.new_vcsa.network.mode = "static" 771 | $config.new_vcsa.network.ip = $VCSAIPAddress 772 | $config.new_vcsa.network.dns_servers[0] = $VMDNS 773 | $config.new_vcsa.network.prefix = $VCSAPrefix 774 | $config.new_vcsa.network.gateway = $VMGateway 775 | $config.new_vcsa.network.system_name = $VCSAHostname 776 | $config.new_vcsa.os.password = $VCSARootPassword 777 | if($VCSASSHEnable -eq "true") { 778 | $VCSASSHEnableVar = $true 779 | } else { 780 | $VCSASSHEnableVar = $false 781 | } 782 | $config.new_vcsa.os.ntp_servers = $VMNTP 783 | $config.new_vcsa.os.ssh_enable = $VCSASSHEnableVar 784 | $config.new_vcsa.sso.password = $VCSASSOPassword 785 | $config.new_vcsa.sso.domain_name = $VCSASSODomainName 786 | 787 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 788 | $config | ConvertTo-Json | Set-Content -Path "$([System.IO.Path]::GetTempPath())jsontemplate.json" 789 | 790 | if($enableVerboseLoggingToNewShell -eq 1) { 791 | My-Logger "Spawning new PowerShell Console for detailed verbose output ..." 792 | #Start-process powershell.exe -argument "-nologo -noprofile -executionpolicy bypass -command Get-Content $verboseLogFile -Tail 2 -Wait" 793 | Start-process $pwshBin -argument "-nologo -noprofile -executionpolicy bypass -command Get-Content $verboseLogFile -Tail 2 -Wait" 794 | } 795 | 796 | My-Logger "Deploying VCSA ..." 797 | #Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-ssl-certificate-verification --accept-eula --acknowledge-ceip $([System.IO.Path]::GetTempPath())jsontemplate.json"| Out-File -Append -LiteralPath $verboseLogFile 798 | Invoke-Expression "$($vcsaInstallBin) install --no-ssl-certificate-verification --accept-eula --acknowledge-ceip $([System.IO.Path]::GetTempPath())jsontemplate.json"| Out-File -Append -LiteralPath $verboseLogFile 799 | 800 | } else { 801 | # Deploy using the VCSA CLI Installer 802 | $config = (Get-Content -Raw "$($vcsaVcJson)") | convertfrom-json 803 | $config.new_vcsa.vc.hostname = $VIServer 804 | $config.new_vcsa.vc.username = $VIUsername 805 | $config.new_vcsa.vc.password = $VIPassword 806 | $config.new_vcsa.vc.deployment_network = $VMNetwork 807 | $config.new_vcsa.vc.datastore = $datastore 808 | $config.new_vcsa.vc.datacenter = $datacenter.name 809 | 810 | if($DeploymentTarget -eq "VMC") { 811 | #$VMCResourcePool = @("Cluster-1","Resources","Compute-ResourcePool") 812 | $config.new_vcsa.vc.target = "VMC_REPLACE" 813 | } else { 814 | $config.new_vcsa.vc.target = $VMCluster 815 | } 816 | 817 | $config.new_vcsa.appliance.thin_disk_mode = $true 818 | $config.new_vcsa.appliance.deployment_option = $VCSADeploymentSize 819 | $config.new_vcsa.appliance.name = $VCSADisplayName 820 | $config.new_vcsa.network.ip_family = "ipv4" 821 | $config.new_vcsa.network.mode = "static" 822 | $config.new_vcsa.network.ip = $VCSAIPAddress 823 | $config.new_vcsa.network.dns_servers[0] = $VMDNS 824 | $config.new_vcsa.network.prefix = $VCSAPrefix 825 | $config.new_vcsa.network.gateway = $VMGateway 826 | $config.new_vcsa.network.system_name = $VCSAHostname 827 | $config.new_vcsa.os.password = $VCSARootPassword 828 | if($VCSASSHEnable -eq "true") { 829 | $VCSASSHEnableVar = $true 830 | } else { 831 | $VCSASSHEnableVar = $false 832 | } 833 | $config.new_vcsa.os.ntp_servers = $VMNTP 834 | $config.new_vcsa.os.ssh_enable = $VCSASSHEnableVar 835 | $config.new_vcsa.sso.password = $VCSASSOPassword 836 | $config.new_vcsa.sso.domain_name = $VCSASSODomainName 837 | 838 | if($DeploymentTarget -eq "VMC") { 839 | $config.new_vcsa.vc | Add-Member -Type NoteProperty -Name 'vm_folder' -Value $VMCVMFolder 840 | } 841 | 842 | My-Logger "Creating VCSA JSON Configuration file for deployment ..." 843 | $config | ConvertTo-Json | Set-Content -Path "$([System.IO.Path]::GetTempPath())jsontemplate.json" 844 | 845 | if($DeploymentTarget -eq "VMC") { 846 | (Get-Content -Path "$([System.IO.Path]::GetTempPath())jsontemplate.json" -Raw) -replace '"VMC_REPLACE"',"[`"$VMCluster`",`"Resources`",`"$VMResourcePool`"]" | Set-Content -Path "$([System.IO.Path]::GetTempPath())jsontemplate.json" 847 | } 848 | 849 | if($enableVerboseLoggingToNewShell -eq 1) { 850 | My-Logger "Spawning new PowerShell Console for detailed verbose output ..." 851 | #Start-process powershell.exe -argument "-nologo -noprofile -executionpolicy bypass -command Get-Content $verboseLogFile -Tail 2 -Wait" 852 | Start-process $pwshBin -argument "-nologo -noprofile -executionpolicy bypass -command Get-Content $verboseLogFile -Tail 2 -Wait" 853 | } 854 | 855 | My-Logger "Deploying the VCSA ..." 856 | #Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-ssl-certificate-verification --accept-eula --acknowledge-ceip $([System.IO.Path]::GetTempPath())jsontemplate.json"| Out-File -Append -LiteralPath $verboseLogFile 857 | Invoke-Expression "$($vcsaInstallBin) install --no-ssl-certificate-verification --accept-eula --acknowledge-ceip $([System.IO.Path]::GetTempPath())jsontemplate.json"| Out-File -Append -LiteralPath $verboseLogFile 858 | } 859 | } 860 | 861 | if($moveVMsIntovApp -eq 1 -and ($DeploymentTarget -eq "VCENTER" -or $DeploymentTarget -eq "VMC")) { 862 | # Check whether DRS is enabled as that is required to create vApp 863 | if((Get-Cluster -Server $viConnection $cluster).DrsEnabled) { 864 | My-Logger "Creating vApp $VAppName ..." 865 | if($DeploymentTarget -eq "VMC") { 866 | $VApp = New-VApp -Name $VAppName -Server $viConnection -Location (Get-ResourcePool $VMResourcePool) 867 | } else { 868 | $VApp = New-VApp -Name $VAppName -Server $viConnection -Location $cluster 869 | } 870 | 871 | if($deployNestedESXiVMs -eq 1) { 872 | My-Logger "Moving Nested ESXi VMs into $VAppName vApp ..." 873 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 874 | $vm = Get-VM -Name $_.Key -Server $viConnection 875 | Move-VM -VM $vm -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 876 | } 877 | } 878 | 879 | if($deployVCSA -eq 1) { 880 | $vcsaVM = Get-VM -Name $VCSADisplayName -Server $viConnection 881 | My-Logger "Moving $VCSADisplayName into $VAppName vApp ..." 882 | Move-VM -VM $vcsaVM -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 883 | } 884 | 885 | if($DeployNSX -eq 1) { 886 | $nsxVM = Get-VM -Name $NSXDisplayName -Server $viConnection 887 | My-Logger "Moving $NSXDisplayName into $VAppName vApp ..." 888 | Move-VM -VM $nsxVM -Server $viConnection -Destination $VApp -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 889 | } 890 | } else { 891 | My-Logger "vApp $VAppName will NOT be created as DRS is NOT enabled on vSphere Cluster ${cluster} ..." 892 | } 893 | } 894 | 895 | My-Logger "Disconnecting from $VIServer ..." 896 | Disconnect-VIServer $viConnection -Confirm:$false 897 | 898 | 899 | if($setupNewVC -eq 1) { 900 | My-Logger "Connecting to the new VCSA ..." 901 | $vc = Connect-VIServer $VCSAIPAddress -User "administrator@$VCSASSODomainName" -Password $VCSASSOPassword -WarningAction SilentlyContinue 902 | 903 | My-Logger "Creating Datacenter $NewVCDatacenterName ..." 904 | New-Datacenter -Server $vc -Name $NewVCDatacenterName -Location (Get-Folder -Type Datacenter -Server $vc) | Out-File -Append -LiteralPath $verboseLogFile 905 | 906 | if($DeploymentTarget -eq "VMC") { 907 | My-Logger "Creating vSphere Cluster $NewVCVSANClusterName ..." 908 | New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled | Out-File -Append -LiteralPath $verboseLogFile 909 | } else { 910 | My-Logger "Creating VSAN Cluster $NewVCVSANClusterName ..." 911 | New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -VsanEnabled -VsanDiskClaimMode 'Manual' | Out-File -Append -LiteralPath $verboseLogFile 912 | } 913 | 914 | if($addESXiHostsToVC -eq 1) { 915 | $NestedESXiHostnameToIPs.GetEnumerator() | Sort-Object -Property Value | Foreach-Object { 916 | $VMName = $_.Key 917 | $VMIPAddress = $_.Value 918 | 919 | $targetVMHost = $VMIPAddress 920 | if($addHostByDnsName -eq 1) { 921 | $targetVMHost = $VMName 922 | } 923 | My-Logger "Adding ESXi host $targetVMHost to Cluster ..." 924 | Add-VMHost -Server $vc -Location (Get-Cluster -Name $NewVCVSANClusterName) -User "root" -Password $VMPassword -Name $targetVMHost -Force | Out-File -Append -LiteralPath $verboseLogFile 925 | } 926 | } 927 | 928 | if($DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 929 | My-Logger "Creating VDS $VDSName ..." 930 | $vds = New-VDSwitch -Server $vc -Name $VDSName -Location (Get-Datacenter -Name $NewVCDatacenterName) 931 | 932 | My-Logger "Creating new VXLAN DVPortgroup $VXLANDVPortgroup ..." 933 | $vxlanDVPG = New-VDPortgroup -Server $vc -Name $VXLANDVPortgroup -Vds $vds 934 | 935 | $vmhosts = Get-Cluster -Server $vc -Name $NewVCVSANClusterName | Get-VMHost 936 | foreach ($vmhost in $vmhosts) { 937 | $vmhostname = $vmhost.name 938 | 939 | My-Logger "Adding $vmhostname to VDS ..." 940 | Add-VDSwitchVMHost -Server $vc -VDSwitch $vds -VMHost $vmhost | Out-File -Append -LiteralPath $verboseLogFile 941 | 942 | My-Logger "Adding vmmnic1 to VDS ..." 943 | $vmnic = $vmhost | Get-VMHostNetworkAdapter -Physical -Name vmnic1 944 | Add-VDSwitchPhysicalNetworkAdapter -Server $vc -DistributedSwitch $vds -VMHostPhysicalNic $vmnic -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 945 | 946 | $vmk0 = Get-VMHostNetworkAdapter -Server $vc -Name vmk0 -VMHost $vmhost 947 | $lastNetworkOcet = $vmk0.ip.Split('.')[-1] 948 | $vxlanVmkIP = $VXLANSubnet + $lastNetworkOcet 949 | 950 | My-Logger "Adding VXLAN VMKernel $vxlanVmkIP to VDS ..." 951 | New-VMHostNetworkAdapter -VMHost $vmhost -PortGroup $VXLANDVPortgroup -VirtualSwitch $vds -IP $vxlanVmkIP -SubnetMask $VXLANNetmask -Mtu 1600 | Out-File -Append -LiteralPath $verboseLogFile 952 | } 953 | } 954 | 955 | if($configureVSANDiskGroups -eq 1 -and $DeploymentTarget -ne "VMC") { 956 | My-Logger "Enabling VSAN Space Efficiency/De-Dupe & disabling VSAN Health Check ..." 957 | Get-VsanClusterConfiguration -Server $vc -Cluster $NewVCVSANClusterName | Set-VsanClusterConfiguration -SpaceEfficiencyEnabled $true -HealthCheckIntervalMinutes 0 | Out-File -Append -LiteralPath $verboseLogFile 958 | 959 | 960 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 961 | $luns = $vmhost | Get-ScsiLun | select CanonicalName, CapacityGB 962 | 963 | My-Logger "Querying ESXi host disks to create VSAN Diskgroups ..." 964 | foreach ($lun in $luns) { 965 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { 966 | $vsanCacheDisk = $lun.CanonicalName 967 | } 968 | if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { 969 | $vsanCapacityDisk = $lun.CanonicalName 970 | } 971 | } 972 | My-Logger "Creating VSAN DiskGroup for $vmhost ..." 973 | New-VsanDiskGroup -Server $vc -VMHost $vmhost -SsdCanonicalName $vsanCacheDisk -DataDiskCanonicalName $vsanCapacityDisk | Out-File -Append -LiteralPath $verboseLogFile 974 | } 975 | } 976 | 977 | if($clearVSANHealthCheckAlarm -eq 1 -and $DeploymentTarget -ne "VMC") { 978 | My-Logger "Clearing default VSAN Health Check Alarms, not applicable in Nested ESXi env ..." 979 | $alarmMgr = Get-View AlarmManager -Server $vc 980 | Get-Cluster -Server $vc | where {$_.ExtensionData.TriggeredAlarmState} | %{ 981 | $cluster = $_ 982 | $Cluster.ExtensionData.TriggeredAlarmState | %{ 983 | $alarmMgr.AcknowledgeAlarm($_.Alarm,$cluster.ExtensionData.MoRef) 984 | } 985 | } 986 | } 987 | 988 | if($configurevMotion -eq 1) { 989 | My-Logger "Enabling vMotion on ESXi hosts ..." 990 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 991 | $vmhost | Get-VMHostNetworkAdapter -VMKernel | Set-VMHostNetworkAdapter -VMotionEnabled $true -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 992 | } 993 | } 994 | 995 | # Exit maintanence mode in case patching was done earlier 996 | foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { 997 | if($vmhost.ConnectionState -eq "Maintenance") { 998 | Set-VMHost -VMhost $vmhost -State Connected -RunAsync -Confirm:$false | Out-File -Append -LiteralPath $verboseLogFile 999 | } 1000 | } 1001 | 1002 | My-Logger "Disconnecting from new VCSA ..." 1003 | Disconnect-VIServer $vc -Confirm:$false 1004 | } 1005 | 1006 | if($configureNSX -eq 1 -and $DeployNSX -eq 1 -and $setupVXLAN -eq 1) { 1007 | if(!(Connect-NSXServer -Server $NSXHostname -Username admin -Password $NSXUIPassword -DisableVIAutoConnect -WarningAction SilentlyContinue)) { 1008 | Write-Host -ForegroundColor Red "Unable to connect to NSX Manager, please check the deployment" 1009 | exit 1010 | } else { 1011 | My-Logger "Successfully logged into NSX Manager $NSXHostname ..." 1012 | } 1013 | 1014 | $ssoUsername = "administrator@$VCSASSODomainName" 1015 | My-Logger "Registering NSX Manager with vCenter Server $VCSAHostname ..." 1016 | $vcConfig = Set-NsxManager -vCenterServer $VCSAHostname -vCenterUserName $ssoUsername -vCenterPassword $VCSASSOPassword 1017 | 1018 | My-Logger "Registering NSX Manager with vCenter SSO $VCSAHostname ..." 1019 | $ssoConfig = Set-NsxManager -SsoServer $VCSAHostname -SsoUserName $ssoUsername -SsoPassword $VCSASSOPassword -AcceptAnyThumbprint 1020 | 1021 | My-Logger "Disconnecting from NSX Manager ..." 1022 | Disconnect-NsxServer 1023 | } 1024 | 1025 | $EndTime = Get-Date 1026 | $duration = [math]::Round((New-TimeSpan -Start $StartTime -End $EndTime).TotalMinutes,2) 1027 | 1028 | My-Logger "vSphere $vSphereVersion Lab Deployment Complete!" 1029 | My-Logger "StartTime: $StartTime" 1030 | My-Logger " EndTime: $EndTime" 1031 | My-Logger " Duration: $duration minutes" 1032 | --------------------------------------------------------------------------------