Forked from InputObject2/Create-Unix-VM-cloud-init.ps1
Created
March 2, 2024 10:12
-
-
Save virasak/8b2f543ab6422fe669400547917c9b2d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Create Unix VM's. | |
PREREQUISITES: | |
- A VM that has been installed with an OS that supports cloud-init | |
- cloud-init is installed on the vm | |
How it works: | |
- Asks for a bunch of parameters | |
- Creates a disk from parent vhdx for speed | |
- Gets the vm name from the params and the existing vm with matching name | |
- Creates a cloud-init config for the vm (currently sets only hostname and ansible user ssh key) | |
- Sets up everything then starts the vm | |
- if you ask for more than one, it creates in sequence | |
WHAT TO DO: | |
- Replace the values for baseVMpath, parentDiskPath and sshPubKey then run the script. | |
FUTURE THINGS TO WORK ON : | |
- Adding parameters for baseVMpath, parentDiskPath and sshPubKey | |
- Adding the option to pass the other info in parameters as well so you don't have to redo it by hand | |
-> with 2 parameter sets, depending on dynamic memory or not | |
Helpful links (much thanks to the people who wrote these) : | |
- https://computingforgeeks.com/how-to-create-centos-8-kvm-image-template-for-openstack/ | |
- https://devops.ionos.com/tutorials/deploy-a-centos-server-customized-with-cloud-init/ | |
- https://cloudinit.readthedocs.io/en/latest/topics/examples.html | |
- https://github.com/MicrosoftDocs/Virtualization-Documentation/blob/master/hyperv-samples/benarm-powershell/Ubuntu-VM-Build/BaseUbuntuBuild.ps1 | |
#> | |
function Get-Info { | |
clear | |
$DynamicMemory = Read-Host "Dynamic Memory ? (y/n) " | |
Switch ($DynamicMemory) | |
{ | |
Y {Write-host -foreground green "Yes, dynamic memory!`n"; $dynMem=$true} | |
N {Write-Host -foreground yellow "No, I want to set min and max and startup memory.`n"; $dynMem=$false} | |
Default {Write-Host -foreground yellow "Default is that we're using it, because we believe in the power of Myth !`n"; $dynMem=$true} | |
} | |
if($dynMem) { | |
$maxMem = Read-Host "Maximum memory ? (GB) " | |
$minMem = Read-Host "Minimum memory ? (GB) " | |
$startMem = Read-Host "Startup memory ? (GB) " | |
} else { | |
$startMem = Read-Host "Memory ? (GB) " | |
} | |
$cores = Read-Host "vCPU's ? (Cores) " | |
$prefix = Read-Host "Prefix to use for these ? (A string) " | |
$VMObject = New-Object -TypeName psobject | |
$VMObject | Add-Member -MemberType NoteProperty -Name "UseDynamicMemory" -Value $dynMem | |
$VMObject | Add-Member -MemberType NoteProperty -Name "maxMemory" -Value $([int]$maxMem) | |
$VMObject | Add-Member -MemberType NoteProperty -Name "minMemory" -Value $([int]$minMem) | |
$VMObject | Add-Member -MemberType NoteProperty -Name "startMemory" -Value $([int]$startMem) | |
$VMObject | Add-Member -MemberType NoteProperty -Name "cores" -Value $([int]$cores) | |
$VMObject | Add-Member -MemberType NoteProperty -Name "nestedVirtualization" -Value $false | |
$VMObject | Add-Member -MemberType NoteProperty -Name "prefix" -Value $prefix | |
return $VMObject | |
} | |
function Setup-VM { | |
param($VMObject, $basepath, $parent, $sshPubKey) | |
$vmname = Get-NextVMNumber($VMObject.prefix) | |
$path = "$basepath\$vmname" | |
write-host "Starting script...`n`nThis will create a VM with name $vmname.`nLet's go!`n`n" | |
Add-VMVHD -vmname $vmname -path $path -parent $parent | |
Create-VM -VMObject $VMObject -vmname $vmname -path $path | |
Create-CloudInit -vmname $vmname -path $path -sshPubKey $sshPubKey | |
Set-VMProperties -VMObject $VMObject -vmname $vmname | |
Set-VMNetworkProperties -vmname $vmname | |
Add-VMDvdDrive -VMName $vmname | |
Set-VMDvdDrive -VMName $vmname -path "$($path)\metadata.iso" | |
Start-VM $vmname | |
} | |
function Create-VM { | |
param($VMObject, $vmname, $path) | |
Write-host "Creating new virtual machine." -NoNewline | |
New-VM -Name $vmname -MemoryStartupBytes ([int]($VMInfo.startMemory)*1GB) -BootDevice VHD -VHDPath "$path\Virtual Hard Disks\$vmname.vhdx" -Path "$path\" -Generation 2 -SwitchName (Get-VMSwitch -SwitchType External).name | out-null | |
Write-Host -ForegroundColor Green " Done." | |
} | |
function Create-CloudInit { | |
param( | |
$vmname, | |
$path, | |
$sshPubKey | |
) | |
$oscdimgPath = "C:\Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe" | |
$metaDataIso = "$($path)\metadata.iso" | |
$metadata = @" | |
instance-id: uuid-$([GUID]::NewGuid()) | |
local-hostname: $($vmname) | |
"@ | |
$userdata = @" | |
#cloud-config | |
users: | |
- name: ansible | |
gecos: ansible | |
sudo: ALL=(ALL) NOPASSWD:ALL | |
groups: users, admin | |
ssh_import_id: None | |
lock_passwd: true | |
ssh_authorized_keys: | |
- $sshPubKey | |
"@ | |
# Output meta and user data to files | |
if(-not (Test-Path "$($path)\Bits")) {New-Item -ItemType Directory "$($path)\Bits" | out-null} | |
sc "$($path)\Bits\meta-data" ([byte[]][char[]] "$metadata") -Encoding Byte | |
sc "$($path)\Bits\user-data" ([byte[]][char[]] "$userdata") -Encoding Byte | |
# Create meta data ISO image - this thing apparently outputs in stderr so it shows as red but it's not errors, it's just the progress for it. | |
& $oscdimgPath "$($path)\Bits" $metaDataIso -j2 -lcidata | Out-null | |
} | |
function Get-NextVMNumber { | |
param($prefix) | |
if((Get-VM -name "$prefix*").count -gt 0){ | |
$prefix += (([int](get-vm -name "$prefix*" | select @{ Label = 'Number' ;Expression = { $_.VMName.Substring($prefix.length,2) } } | sort number | select -Last 1).number) + 1).tostring().padleft(2,"0") | |
} else { | |
$prefix += "01" | |
} | |
return $prefix.ToUpper() | |
} | |
function Add-VMVHD { | |
param($vmname, $path, $parent) | |
if(-not (Test-Path "$path\Virtual Hard Disks\$vmname.vhdx")) { | |
if (-not (Test-Path "$path\Virtual Hard Disks")) { New-Item -Force -ItemType Directory -Path "$path\Virtual Hard Disks" | out-null } | |
Write-host "Creating new VHD from parent $parent." -NoNewline | |
New-VHD –Path "$path\Virtual Hard Disks\$vmname.vhdx" –ParentPath $parent –Differencing | Out-null | |
Write-Host -ForegroundColor Green " Done." | |
} | |
} | |
function Set-VMProperties { | |
param($VMObject, $vmname) | |
Write-host "Customizing virtual machine." -NoNewline | |
if($VMInfo.UseDynamicMemory) { Set-VMMemory -VMName $vmname -MaximumBytes ([int]($VMInfo.maxMemory)*1GB) -DynamicMemoryEnabled $true -MinimumBytes ([int]($VMInfo.minMemory)*1GB) } | |
Set-VM -VMname $vmname -ProcessorCount $VMInfo.cores -AutomaticStopAction ShutDown -AutomaticStartAction StartIfRunning -AutomaticStartDelay (Get-Random -Minimum 100 -Maximum 800) | |
Set-VMFirmware -VMName $vmname -EnableSecureBoot Off -FirstBootDevice (get-VMHardDiskDrive -VMName $vmname) | |
Get-VM -VMname $vmname | Enable-VMIntegrationService -Name * | |
if($VMInfo.nestedvirtualisation) { Set-VMProcessor -VMName $vmname -ExposeVirtualizationExtensions $true } | |
Write-Host -ForegroundColor Green " Done." | |
} | |
function Set-VMNetworkProperties { | |
param($vmname) | |
# This function sets the VLAN | |
Write-host "Customizing networking." -NoNewline | |
Set-VMNetworkAdapterVlan -VlanId 1 -VMName $vmname -Access | |
Write-Host -ForegroundColor Green " Done." | |
} | |
#===================================== | |
# The fun starts here | |
#===================================== | |
$baseVMpath = "D:\Virtual Machines\" | |
$parentDiskPath = "D:\Virtual Machines Templates\Centos8.vhdx" | |
# this is a full public key : ssh-rsa AAA[...]==" | |
$sshPubKey = "" | |
$VMInfo = Get-Info | |
$total = Read-Host "How many VM do you want ? (1-...) " | |
Write-Host "Starting timer.`n" | |
$stopwatch = [system.diagnostics.stopwatch]::StartNew() | |
For ($i=1; $i -le $total; $i++) { | |
Write-host "Creating VM $i of $total." | |
Setup-VM -VMObject $VMInfo -basepath $baseVMpath -parent $parentDiskPath -sshPubKey $sshPubKey | |
} | |
$stopwatch.Stop() | |
Write-host "Total time : $([math]::Round($stopwatch.Elapsed.TotalSeconds,0)) seconds for $many Virtual machines." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment