At some point in building our infrastructure, you need to automate the delivery of environments to complete new projects. It is good to create standards for creating virtual machines and prepare templates for creating virtual machines.
In this post, I will present a script that will allow you to quickly create a virtual machine based on a previously created machine by connecting its virtual disk.
Before running the script, I created a VM with Ubuntu Server 20.10 which I preconfigured:
- created user with access to sudo command
- installed hyperv-daemons package which can give as information about virtual machine IP address, needed to establish SSH session
[string] $VMName = Read-Host "Enter VM name: "
[int32] $VMGeneration = Read-Host "VM generation: (enter 1 or 2)"
[int64] $VMMemory = Read-Host "Memory: (ex. 1024) "
$VMMemory = 1MB * $VMMemory
[int32] $VMCpu = Read-Host "Processor number: "
[string] $VMPath = Read-Host "VM Directory: (D:\Hyper-V)"
# Create new Hyper-V VM
New-VM -Name $VMName -Generation $VMGeneration -MemoryStartupBytes $VMMemory -Path $VMPath
#Start-Sleep 5
# Connect virtual network card to virtual switch
$VMSwitch = Get-VMSwitch | Select-Object Name
Connect-VMNetworkAdapter -SwitchName $VMSwitch.Name -VMName $VMName
# Assign CPU cores to VM
Set-VMProcessor -VMName $VMName -count $VMCpu
# Create VM files directory
$VMPath = $VMPath + [string]'\' + $VMName
# Create directory for VM hard disk
New-Item -Path $VMPath -Name 'Virtual Hard Disks' -ItemType "Directory"
$VMDiskPath = $VMPath + [string]'\Virtual Hard Disks\'
# Copy disk VM template
Copy-Item 'D:\Export\ubuntu-server-20.10\Virtual Hard Disks\ubuntu-server-20.10.vhdx' -Destination $VMDiskPath
$VMDiskName = $VMName + [string]'.vhdx'
# Rename disk name
Rename-Item -NewName $VMDiskName -Path ($VMDiskPath + [string]'ubuntu-server-20.10.vhdx')
# Attach copied vhdx file to VM
Add-VMHardDiskDrive -VMName $VMName -Path ($VMDiskPath + $VMName + [string]'.vhdx') -ControllerType SCSI -ControllerNumber 0 -ControllerLocation 1
# Disable secure boot and set first boot device
Set-VMFirmware -VMName $VMName -EnableSecureBoot Off -FirstBootDevice $(Get-VMHardDiskDrive -VMName $VMName)
Start-VM $VMName
Example of running script DeployVM.ps1
PS C:\Script> .\DeployVM.ps1
Enter VM name: : BNRS_test
VM generation: (enter 1 or 2): 2
Memory: (ex. 1024) : 2048
Processor number: : 2
VM Directory: (D:\Hyper-V): D:\Hyper-V
Virtual machine was created and started up. Then we can run another script that will send a command to VM named BNRS_test and change its hostname for the same as created VM. Below script code RemoteCommand.ps1
$User = "bnrsadm"
$Password = "P@$$w0rd"
[string] $VMName = Read-Host "Enter VM name: "
# Find VM IP Address
$VMIPAddresses = Get-VMNetworkAdapter -VMName $VMName | Select-Object IPAddresses
$VMIPv4Address = $VMIPAddresses.IPAddresses[0]
# Credentials to connect SSH session
$secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential($User, $secpasswd)
# Create SSH session
New-SSHSession -ComputerName $VMIPv4Address -Credential $Credentials
# Invoke command over SSH
$Command = 'sudo hostnamectl set-hostname ' + $VMName
Invoke-SSHCommand -ComputerName $VMIPv4Address -Command $Command
# Disconnect SSH session
Remove-SshSession -ComputerName $VMIPv4Address
Example of running script RemoteCommand.ps1
PS C:\Script> .\RemoteCommand.ps1
Enter VM name: : BNRS_test
[192.168.2.111]
ComputerName Result Error
------------ ------ -----
192.168.2.111 False
Indeed script change hostname of BNRS_test. Below we can see that sign “_” have been missed but command changed hostname in virtual machine operating system.
The above method works, but in my opinion it should not be used as a target. Rather, it should be used as an initial system configuration that would prepare the machine for the use of configuration management software like e.g. Ansible.