-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHyperHobo.ps1
More file actions
executable file
·170 lines (149 loc) · 6.11 KB
/
Copy pathHyperHobo.ps1
File metadata and controls
executable file
·170 lines (149 loc) · 6.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<#
.SYNOPSIS
"A hobo is a migrant worker or homeless vagrant, especially one who is impoverished."
HyperHobo is a bit of automation around Windows Hyper-V.
.EXAMPLE
hh.bat apply "example"
#>
param(
[Parameter(Position = 0, Mandatory = 1)][string]
$verb,
# Collect remaining arguments as per https://stackoverflow.com/a/7418440/98903
[Parameter(Position = 1, Mandatory = 0, ValueFromRemainingArguments = $true)]
$remaining
)
# Thank you, aggieNick02 for https://stackoverflow.com/a/44810914/98903
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
function ThrowOnNativeFailure {
if (-not $?) {
throw 'Native Failure'
}
}
# Configuration; some of these could be overriden by $configFile
$dependenciesFolder = "dependencies"
$carbonVersion = "2.10.2"
$hostsFileComment = "Set by HyperHobo"
function Assert-Folder {
param(
[Parameter(Position = 0, Mandatory = 1)][string]
$folder
)
$result = $true
if (-not (Test-Path -Path $folder -PathType Container)) {
New-Item -Path $folder -ItemType Directory | Out-Null
$result = $false
}
return $result
}
function Assert-CarbonModule {
# https://github.com/webmd-health-services/Carbon/releases/download/2.10.2/Carbon-2.10.2.zip
Assert-Folder $dependenciesFolder | Out-Null
$carbonFolder = Join-Path -Path $dependenciesFolder -ChildPath "Carbon-${carbonVersion}"
if (-not (Assert-Folder $carbonFolder)) {
$carbonFile = Join-Path -Path $dependenciesFolder -ChildPath "Carbon-${carbonVersion}.zip"
$url = "https://github.com/webmd-health-services/Carbon/releases/download/${carbonVersion}/Carbon-${carbonVersion}.zip"
Invoke-WebRequest -Uri $url -OutFile $carbonFile
Expand-Archive -Path $carbonFile -DestinationPath $carbonFolder
Remove-Item -Path $carbonFile
}
. ".\${carbonFolder}\Carbon\Import-Carbon.ps1"
}
function Set-HostsFilePair {
param(
[Parameter(Position = 0, Mandatory = 1)][string]
$hostsFile,
[Parameter(Position = 1, Mandatory = 1)][Net.IPAddress]
$ipAddress,
[Parameter(Position = 2, Mandatory = 1)][string[]]
$hostNames
)
Assert-CarbonModule
Write-Host "Setting ${hostNames} -> ${ipAddress}..."
Set-CHostsEntry -IPAddress $ipAddress -HostName "${hostNames}" -Description $hostsFileComment -Path $hostsFile
}
function Apply {
[CmdletBinding()]
param(
[Parameter(Position = 0, Mandatory = 1)][string]$checkpointName
)
# See if the requested VM & checkpoint exist before going further...
Get-VMSnapshot -VMName $vmName -Name $checkpointName | Out-Null
Write-Host "Turning off '${vmName}'..."
Stop-VM -Name $vmName -TurnOff
Write-Host "Restoring '${vmName}' to '${checkpointName}'..."
Restore-VMCheckpoint -VMName $vmName -Name $checkpointName -Confirm:$false
Write-Host "Turning on '${vmName}'..."
Start-VM -Name $vmName
Update-HostsFile
}
function Update-HostsFile {
Write-Host "Waiting for '${vmName}'..."
# Inspired by https://johntaurins.wordpress.com/2014/08/22/hyper-v-start-vms-in-order-wait-for-vm-heartbeat/
Do {
Start-Sleep -milliseconds 100
}
Until ((Get-VMIntegrationService -VMName $vmName |`
Where-Object { $_.name -eq "Heartbeat" }).PrimaryStatusDescription -eq "OK")
if ($null -ne $hostName) {
Write-Host "Waiting for an IPv4 address..."
# TODO: there could be more than one network adapter, and there's both IPv4 & IPv6
$addresses = (Get-VMNetworkAdapter -VMName $vmName).IPAddresses
if ($addresses) {
# if it looks like a single IPv6 address, keep looking
while ($addresses[0].Contains(":")) {
Start-Sleep -milliseconds 100
$addresses = (Get-VMNetworkAdapter -VMName $vmName).IPAddresses
}
$ipv4Address = $addresses[0]
Assert-CarbonModule
$hostsFile = (Get-CPathToHostsFile)
Set-HostsFilePair -hostsFile $hostsFile -ipAddress $ipv4Address -hostNames $hostName
}
else {
Write-Host "WARNING: Unable to determine IP address(es)!"
Write-Host "Running a non-Windows OS? You might need to install an 'Integration Service'."
Write-Host "See https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/supported-linux-and-freebsd-virtual-machines-for-hyper-v-on-windows"
Write-Host "Short version:"
Write-Host " - Ubuntu: sudo apt-get install `"linux-cloud-tools-`$(uname -r)`""
Write-Host " - CentOS: sudo yum install hyperv-daemons"
Write-Host ""
Write-Host "...once you've installed, reboot."
Write-Host "Confirm you can see IP Addresses and create a new CheckPoint."
}
}
}
if (-not (Get-Variable -Name "vmName" -ErrorAction SilentlyContinue)) {
$configFile = "HyperHoboConfig.ps1";
if (-not (Test-Path -Path $configFile -PathType Leaf)) {
throw "ERROR: Could not find ${configFile}!"
}
. ".\${configFile}"
}
switch ($verb) {
"Apply" {
Apply @remaining
}
"Assert-CarbonModule" {
# Runs a test of the Carbon module download & import in isolation
Assert-CarbonModule
Write-Host (Get-CPathToHostsFile)
}
"Set-HostsFilePair" {
# Runs some tests of the Set-HostsFilePair method
Write-Host "---"
Set-HostsFilePair -hostsFile "one.txt" "192.0.2.1" "one.example"
Write-Host "---"
# TODO: there's a defect in Set-CHostsEntry whereby a line with aliases will be duplicated on subsequent runs
Set-HostsFilePair -hostsFile "one-to-many.txt" "192.0.2.1" ("one.example", "one-to-many.example")
Write-Host "---"
}
"Update-HostsFile" {
Update-HostsFile
}
# TODO: add more verbs
default {
throw "ERROR: The verb ${verb} is not recognized!"
}
}