├── LICENSE ├── README.md └── esxi_macos_vm_creation.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 rtrouton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This script is designed to create and configure virtual machines running Apple operating systems, hosted on a VMware ESXi server running on Apple hardware. The script assumes that the virtual machines are built using copied VMDK disk files. 2 | 3 | Script is designed to be stored on an ESXi datastore and run from the ESXi server's command line interface. 4 | 5 | Usage: `/path/to/esxi_macos_vm_creation.sh -n -d -c -h -i -o -r -s -v -p` 6 | 7 | Options: 8 | 9 | * **-n**: Name of VM (required) 10 | * **-d**: Location of a VMDK disk file (required). Location must be in this format - `/vmfs/volumes/datastore_number_here/path/to/vmdk_file.vmdk` 11 | * **-c**: Number of virtual CPUs 12 | * **-h**: VMware Hardware Version 13 | * **-i**: Location of an ISO image. Location must be in this format - `/vmfs/volumes/datastore_number_here/path/to/iso_file.iso` 14 | * **-o**: Apple OS version 15 | * **-r**: RAM size in MB 16 | * **-s**: Disk size in GB 17 | * **-v**: VNC port between 5900 and 5909 18 | * **-p**: VNC password. Maximum password length is eight characters. 19 | 20 | **Examples:** 21 | 22 | To set up a VM specifying only the VM name and VMDK location: 23 | 24 | `/path/to/esxi_macos_vm_creation.sh -n VM_Name_Goes_Here -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk` 25 | 26 | To set up a VM using a name with spaces and/or special characters, add quotation marks to the VM name: 27 | 28 | `/path/to/esxi_macos_vm_creation.sh -n "VM's Name Goes Here!" -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk` 29 | 30 | 31 | Other flags can be added as needed: 32 | 33 | To set up a VM and add more CPUs: 34 | 35 | `/path/to/esxi_macos_vm_creation.sh -n VM_Name_Goes_Here -c 4 -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk` 36 | 37 | To set up a VM and enable VNC on port 5901 with the password set to the word `password`: 38 | 39 | `/path/to/esxi_macos_vm_creation.sh -n VM_Name_Goes_Here -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk -v 5901 -p password` 40 | 41 | To set up a VM named `MacOS VM 10.12` using a VDMK stored on `/vmfs/volumes/datastore1/template` and named `macos-vm.vmdk` with 4 CPUs, 8 GBs of RAM, a 52 GB hard drive, set to HW Version 13, guest OS set to macOS Sierra and VNC enabled on port 5902 with the VNC password set to the word `password`: 42 | 43 | `/path/to/esxi_macos_vm_creation.sh -n "MacOS VM 10.12" -d /vmfs/volumes/datastore1/template/macos-vm.vmdk -c 4 -r 8192 -s 52 -h 13 -o darwin16-64 -v 5902 -p password` 44 | 45 | 46 | 47 | Based on [Tamas Piros](https://github.com/tpiros)'s auto-create: [https://github.com/tpiros/auto-create](https://github.com/tpiros/auto-create) 48 | 49 | Blog post: [http://www.tamas.io/automatic-virtual-machine-creation-from-command-line-in-vmwares-esxi/](http://www.tamas.io/automatic-virtual-machine-creation-from-command-line-in-vmwares-esxi/) -------------------------------------------------------------------------------- /esxi_macos_vm_creation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Parameters: 4 | # 5 | # Virtual machine name (required) 6 | # CPU (number of cores) 7 | # VMDK (location of VMDK file, required) 8 | # RAM (memory size in MB) 9 | # Hard Drive size (in GB) 10 | # Hardware Version 11 | # ISO (Location of ISO image, optional) 12 | # Apple OS version 13 | # VNC port 14 | # VNC password 15 | # 16 | # Default values: CPU: 2, RAM: 4096, Hard drive size: 40 GB, Hardware Version: 11, ISO: 'blank', OS version: darwin14-64 17 | # 18 | # Usage: 19 | # When using the script, command should look something like this: 20 | # 21 | # /vmfs/volumes/datastore_number_here/path/to/esxi_macos_vm_creation.sh -n VM_Name_Goes_Here -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk 22 | # 23 | # To set up a VM using a name with spaces and/or special characters, add quotation marks to the VM name: 24 | # 25 | # /vmfs/volumes/datastore_number_here/path/to/esxi_macos_vm_creation.sh -n "VM's Name Goes Here!" -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk 26 | # 27 | # Other flags can be added as needed: 28 | # 29 | # To set up a VM and add more CPUs: 30 | # 31 | # /vmfs/volumes/datastore_number_here/path/to/esxi_macos_vm_creation.sh -n VM_Name_Goes_Here -c 4 -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk 32 | # 33 | # To set up a VM and enable VNC on port 5901 with the password of "password": 34 | # 35 | # /vmfs/volumes/datastore_number_here/path/to/esxi_macos_vm_creation.sh -n VM_Name_Goes_Here -d /vmfs/volumes/datastore_number_here/path/to/filename_here.vmdk -v 5901 -p password 36 | # 37 | # To set up a VM named "MacOS VM 10.12" (no quotes) using a VDMK stored on /vmfs/volumes/datastore1/template and named "macos-vm.vmdk" (no quotes) with 4 CPUs 38 | # 8 GBs of RAM, a 52 GB hard drive, VMware Hardware Version set to HW Version 13, guest OS set to macOS Sierra, and VNC enabled on port 5902 with the VNC password set to the word "password" (no quotes) 39 | # 40 | # /vmfs/volumes/datastore_number_here/path/to/esxi_macos_vm_creation.sh -n "MacOS VM 10.12" -d /vmfs/volumes/datastore1/template/macos-vm.vmdk -c 4 -r 8192 -s 52 -h 13 -o darwin16-64 -v 5902 -p password 41 | 42 | phelp() { 43 | echo "" 44 | echo "Usage: ./esxi_macos_vm_creation.sh options: -n -d -c -h -i -o -r -s -v -p" 45 | echo "" 46 | echo "n: Name of VM (required). If using a name with spaces and/or special characters, add quotation marks to the VM name." 47 | echo "c: Number of virtual CPUs. Default number is two." 48 | echo "d: Location of a VMDK disk file (required). Location must be in this format - /vmfs/volumes/datastore_number_here/path/to/vmdk_file.vmdk" 49 | echo "h: VMware hardware version. ESXi 5.5 supports up to HW 10, ESXi 6.x supports up to HW 11 and ESXi 6.5 supports up to HW 13." 50 | echo "i: Location of an ISO image. Location must be in this format - /vmfs/volumes/datastore_number_here/path/to/iso_file.iso" 51 | echo "o: Mac operating system version. Default is set to darwin14, which reports the guest OS as OS X Yosemite." 52 | echo "" 53 | echo "VMware guest OS values for the following versions of OS X and macOS:" 54 | echo "" 55 | echo "Mac OS 10.7 - darwin11-64" 56 | echo "OS 10.8 - darwin12-64" 57 | echo "OS 10.9 - darwin13-64" 58 | echo "OS 10.10 - darwin14-64" 59 | echo "OS 10.11 - darwin15-64" 60 | echo "macOS 10.12 - darwin16-64" 61 | echo "" 62 | echo "r: RAM size in MB. Default number is 4096, for 4 GBs of memory." 63 | echo "s: Disk size in GB. Default size is 40 GB. You can specify if you want it to be larger." 64 | echo "v: VNC port is between 5900 and 5909 (required if also using the -p option)" 65 | echo "p: VNC password (required if also using the -v option). Maximum password length is eight characters." 66 | echo "" 67 | echo "Default script values: ESXi datastore location: /vmfs/volumes/datastore1, CPU: 2, RAM: 4096MB, Hard drive size: 40GB, Guest OS: darwin14-64, Hardware Version: 11" 68 | echo "" 69 | } 70 | 71 | # Set datastore location 72 | 73 | DATASTORE="/vmfs/volumes/datastore1" 74 | 75 | # Default variables. These values are overriden if alternate values 76 | # are enabled by the script's available options. 77 | 78 | CPU=2 79 | RAM=4096 80 | SIZE=40 81 | ISO="" 82 | OSVERS="darwin14-64" 83 | HWVERS="11" 84 | FLAG=true 85 | ERR=false 86 | 87 | # Error checking: 88 | # 89 | # The NAME has to be entered (i.e. the $NAME variable cannot be blank.) 90 | # The CPU has to be an integer and it has to be between 1 and 32. Modify the if statement if you want to give more than 32 cores to your Virtual Machine, and also email me pls :) 91 | # The VMDK has to have its location provided and we are checking for an actual .vmdk extension 92 | # RAM has to be an integer and has to be greater than 0. 93 | # The hard drive size has to be an integer and has to be greater than 0. 94 | # The hardware version has to be an integer and has to be greater than 0 95 | # If the ISO parameter is added, we are checking for an actual .iso extension 96 | # If the VNC port parameter is used, it has to be an integer and has to be between 5900 and 5909. 97 | # Note: If needed, this port limitation can be changed by editing the script. 98 | # If the VNC password parameter is used, a password must be entered. 99 | 100 | while getopts n:c:d:h:i:o:r:s:v:p: option 101 | do 102 | case $option in 103 | n) 104 | NAME=${OPTARG}; 105 | FLAG=false; 106 | if [ -z "${NAME}" ]; then 107 | ERR=true 108 | MSG="$MSG | Please make sure to enter a VM name." 109 | fi 110 | ;; 111 | c) 112 | CPU=${OPTARG} 113 | if [ `echo "${CPU}" | egrep "^-?[0-9]+$"` ]; then 114 | if [ "${CPU}" -le "0" ] || [ "${CPU}" -ge "32" ]; then 115 | ERR=true 116 | MSG="$MSG | The number of cores has to be between 1 and 32." 117 | fi 118 | else 119 | ERR=true 120 | MSG="$MSG | The CPU core number has to be an integer." 121 | fi 122 | ;; 123 | d) 124 | VMDK=${OPTARG} 125 | FLAG=false; 126 | if [ -z "${VMDK}" ]; then 127 | ERR=true 128 | MSG="$MSG | Please provide a path to a VMDK file." 129 | fi 130 | if [ ! `echo "${VMDK}" | egrep "^.*\.(vmdk)$"` ]; then 131 | ERR=true 132 | MSG="$MSG | The extension should be .vmdk" 133 | fi 134 | ;; 135 | h) 136 | HWVERS=${OPTARG} 137 | if [ `echo "${HWVERS}" | egrep "^-?[0-9]+$"` ]; then 138 | if [ "${HWVERS}" -eq "${HWVERS}" ] && [ "${HWVERS}" -lt "10" ]; then 139 | ERR=true 140 | MSG="$MSG | Please assign a value of 10 or more for the hardware version. ESXi 5.5 supports up to HW 10, ESXi 6.0.x supports up to HW 11 and ESXi 6.5 supports up to HW 13." 141 | fi 142 | else 143 | ERR=true 144 | MSG="$MSG | The hardware version has to be an integer." 145 | fi 146 | ;; 147 | i) 148 | ISO=${OPTARG} 149 | if [ ! `echo "${ISO}" | egrep "^.*\.(iso)$"` ]; then 150 | ERR=true 151 | MSG="$MSG | The extension should be .iso" 152 | fi 153 | ;; 154 | o) 155 | OSVERS=${OPTARG}; 156 | if [ -z "${OSVERS}" ]; then 157 | ERR=true 158 | MSG="$MSG | Please make sure to enter a valid OS version. darwin14-64 = OS X 10.10 Yosemite, darwin15-64 = OS X 10.11 El Capitan, and darwin16-64 = macOS 10.12 Sierra." 159 | fi 160 | ;; 161 | r) 162 | RAM=${OPTARG} 163 | if [ `echo "${RAM}" | egrep "^-?[0-9]+$"` ]; then 164 | if [ "${RAM}" -le "0" ]; then 165 | ERR=true 166 | MSG="$MSG | Please assign more than 1MB memory to the VM." 167 | fi 168 | else 169 | ERR=true 170 | MSG="$MSG | The RAM size has to be an integer." 171 | fi 172 | ;; 173 | s) 174 | SIZE=${OPTARG} 175 | if [ `echo "${SIZE}" | egrep "^-?[0-9]+$"` ]; then 176 | if [ "${SIZE}" -le "40" ]; then 177 | ERR=true 178 | MSG="$MSG | Please assign more than 40 GB for the hard drive size." 179 | fi 180 | else 181 | ERR=true 182 | MSG="$MSG | The hard drive size has to be an integer." 183 | fi 184 | ;; 185 | v) 186 | VNCPORT=${OPTARG} 187 | if [ `echo "${VNCPORT}" | egrep "^-?[0-9]+$"` ]; then 188 | if [ "${VNCPORT}" -lt "5900" ] || [ "${VNCPORT}" -gt "5909" ]; then 189 | ERR=true 190 | MSG="$MSG | Please assign a port number for VNC between 5900 and 5909." 191 | fi 192 | else 193 | ERR=true 194 | MSG="$MSG | The VNC port has to be an integer." 195 | fi 196 | ;; 197 | p) 198 | VNCPASS=${OPTARG} 199 | if [ -z "${VNCPASS}" ]; then 200 | ERR=true 201 | MSG="$MSG | Please make sure to enter a VNC pasword. Maximum password length is eight characters." 202 | fi 203 | ;; 204 | \?) echo "Unknown option: -$OPTARG" >&2; phelp; exit 1;; 205 | :) echo "Missing option argument for -$OPTARG" >&2; phelp; exit 1;; 206 | *) echo "Unimplemented option: -$OPTARG" >&2; phelp; exit 1;; 207 | esac 208 | done 209 | 210 | if [ -z "${NAME}" ]; then 211 | echo "" 212 | echo ">> PROBLEM << : Please specify the name of the machine using the -n option. Displaying script options below." 213 | echo "" 214 | phelp 215 | exit 1 216 | fi 217 | 218 | if [ -z "${VMDK}" ]; then 219 | echo "" 220 | echo ">> PROBLEM << : Please specify the location of a VMDK disk file with the -d parameter. Location must be in this format - /vmfs/volumes/datastore_number_here/path/to/vmdk_file.vmdk. Displaying script options below." 221 | echo "" 222 | phelp 223 | exit 1 224 | fi 225 | 226 | 227 | if [ "${VNCPORT}" != "" ] && [ -z "${VNCPASS}" ]; then 228 | echo "" 229 | echo ">> PROBLEM << : Please specify a password for VNC using the -p option. Displaying script options below." 230 | echo "" 231 | phelp 232 | exit 1 233 | elif [ "${VNCPASS}" != "" ] && [ -z "${VNCPORT}" ]; then 234 | echo "" 235 | echo ">> PROBLEM << : Please specify a port number for VNC using the -v option. Displaying script options below." 236 | echo "" 237 | phelp 238 | exit 1 239 | fi 240 | 241 | if [ "${VNCPORT}" != "" ] && [ "${VNCPASS}" != "" ]; then 242 | VNCSTATUS=TRUE 243 | else 244 | VNCSTATUS=FALSE 245 | fi 246 | 247 | if $ERR; then 248 | echo $MSG 249 | exit 1 250 | fi 251 | 252 | if [ -d "${DATASTORE}"/"${NAME}" ]; then 253 | echo "Directory - ${NAME} already exists, can't recreate it." 254 | exit 255 | fi 256 | 257 | #Creating the folder for the Virtual Machine 258 | mkdir -p "${DATASTORE}"/"${NAME}" 259 | 260 | #Creating VM disk from vmdk template using vmkfstools 261 | # Link: https://kb.vmware.com/kb/1027876 262 | vmkfstools -i "${VMDK}" "${DATASTORE}"/"${NAME}"/"${NAME}".vmdk -d thin 263 | 264 | # If specified size is larger than 40 GBs, resize VMDK file using vmkfstools 265 | # Link: https://kb.vmware.com/kb/1002019 266 | if [ "${SIZE}" -gt "40" ]; then 267 | vmkfstools -X "${SIZE}"g "${DATASTORE}"/"${NAME}"/"${NAME}".vmdk 268 | fi 269 | 270 | 271 | #Creating the config file 272 | touch "${DATASTORE}"/"${NAME}"/"${NAME}".vmx 273 | 274 | #writing information into the configuration file 275 | 276 | if [ "${VNCSTATUS}" = "TRUE" ]; then 277 | 278 | cat << EOF > "${DATASTORE}"/"${NAME}"/"${NAME}".vmx 279 | config.version = "8" 280 | virtualHW.version = "${HWVERS}" 281 | vmci0.present = "TRUE" 282 | displayName = "${NAME}" 283 | floppy0.present = "FALSE" 284 | numvcpus = "${CPU}" 285 | scsi0.present = "TRUE" 286 | scsi0.sharedBus = "none" 287 | scsi0.virtualDev = "lsilogic" 288 | sata0.present = "TRUE" 289 | memsize = "${RAM}" 290 | scsi0:0.present = "TRUE" 291 | scsi0:0.fileName = "${NAME}.vmdk" 292 | scsi0:0.deviceType = "scsi-hardDisk" 293 | sata0:1.present = "TRUE" 294 | sata0:1.fileName = "${ISO}" 295 | sata0:1.deviceType = "cdrom-image" 296 | pciBridge0.present = "TRUE" 297 | pciBridge4.present = "TRUE" 298 | pciBridge4.virtualDev = "pcieRootPort" 299 | pciBridge4.functions = "8" 300 | pciBridge5.present = "TRUE" 301 | pciBridge5.virtualDev = "pcieRootPort" 302 | pciBridge5.functions = "8" 303 | pciBridge6.present = "TRUE" 304 | pciBridge6.virtualDev = "pcieRootPort" 305 | pciBridge6.functions = "8" 306 | pciBridge7.present = "TRUE" 307 | pciBridge7.virtualDev = "pcieRootPort" 308 | pciBridge7.functions = "8" 309 | ethernet0.virtualDev = "e1000e" 310 | ethernet0.networkName = "VM Network" 311 | ethernet0.addressType = "generated" 312 | ethernet0.present = "TRUE" 313 | usb.present = "TRUE" 314 | guestOS = "${OSVERS}" 315 | RemoteDisplay.vnc.enabled = "${VNCSTATUS}" 316 | RemoteDisplay.vnc.port = "${VNCPORT}" 317 | RemoteDisplay.vnc.key = "${VNCPASS}" 318 | smc.present = "TRUE" 319 | EOF 320 | 321 | else 322 | 323 | cat << EOF > "${DATASTORE}"/"${NAME}"/"${NAME}".vmx 324 | config.version = "8" 325 | virtualHW.version = "${HWVERS}" 326 | vmci0.present = "TRUE" 327 | displayName = "${NAME}" 328 | floppy0.present = "FALSE" 329 | numvcpus = "${CPU}" 330 | scsi0.present = "TRUE" 331 | scsi0.sharedBus = "none" 332 | scsi0.virtualDev = "lsilogic" 333 | sata0.present = "TRUE" 334 | memsize = "${RAM}" 335 | scsi0:0.present = "TRUE" 336 | scsi0:0.fileName = "${NAME}.vmdk" 337 | scsi0:0.deviceType = "scsi-hardDisk" 338 | sata0:1.present = "TRUE" 339 | sata0:1.fileName = "${ISO}" 340 | sata0:1.deviceType = "cdrom-image" 341 | pciBridge0.present = "TRUE" 342 | pciBridge4.present = "TRUE" 343 | pciBridge4.virtualDev = "pcieRootPort" 344 | pciBridge4.functions = "8" 345 | pciBridge5.present = "TRUE" 346 | pciBridge5.virtualDev = "pcieRootPort" 347 | pciBridge5.functions = "8" 348 | pciBridge6.present = "TRUE" 349 | pciBridge6.virtualDev = "pcieRootPort" 350 | pciBridge6.functions = "8" 351 | pciBridge7.present = "TRUE" 352 | pciBridge7.virtualDev = "pcieRootPort" 353 | pciBridge7.functions = "8" 354 | ethernet0.virtualDev = "e1000e" 355 | ethernet0.networkName = "VM Network" 356 | ethernet0.addressType = "generated" 357 | ethernet0.present = "TRUE" 358 | usb.present = "TRUE" 359 | guestOS = "${OSVERS}" 360 | smc.present = "TRUE" 361 | EOF 362 | 363 | fi 364 | 365 | #Adding Virtual Machine to VM register 366 | MYVM=`vim-cmd solo/registervm "${DATASTORE}"/"${NAME}"/"${NAME}".vmx` 367 | #Powering up virtual machine: 368 | vim-cmd vmsvc/power.on "${MYVM}" 369 | 370 | echo "The Virtual Machine is now configured and the VM has been started up. The VM is set to use the following configuration:" 371 | echo "Name: ${NAME}" 372 | echo "CPU: ${CPU}" 373 | echo "RAM: ${RAM}" 374 | echo "Guest OS: ${OSVERS}" 375 | echo "Hardware Version: ${HWVERS}" 376 | echo "Hard drive size: ${SIZE}" 377 | if [ -n "${ISO}" ]; then 378 | echo "ISO: ${ISO}" 379 | else 380 | echo "No ISO added." 381 | fi 382 | if [ "$VNCSTATUS" = "TRUE" ]; then 383 | echo "VNC Port: ${VNCPORT}" 384 | echo "VNC Password: ${VNCPASS}" 385 | else 386 | echo "VNC not enabled." 387 | fi 388 | exit 389 | --------------------------------------------------------------------------------