Categories
Sponsors
Archive
Blogroll
Badges
Community
|
Posted in Virtual Machine Manager, Windows Powershell, Windows Server | No Comment | 1,946 views | 08/06/2014 21:56
Your Hyper-V storage environment crashed and you restored it from a backup or volume snapshot or you want to restore all virtual machines to the Disaster Center via Storage Replication. You added new storage luns into Failover Cluster but CSV names are changed. In that case you may not be able to import Virtual Machines into Hyper-V quickly due to incorrect virtual disk paths.
This script will check all Virtual Machine configs and shows you which configuration is not correct.
Then you can fix it manually or you can fix it via this script.
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
| function Repair-VMConfig {
<#
.SYNOPSIS
Function to repair Virtual Machine config after CSV volume path changes.
You should put a volume identifier into CSV volumes to be able to use this script.
Simply put a Volume1.CSV into Volume1 as a volume identifier.
.DESCRIPTION
In some cases, CSV volume names could be changed. So you may not start your virtual machines due to incorrect virtual disk paths.
This function is written to fix this issue. It finds all Virtual Machines configuration problems and shows you as a output.
If you use ApplyChanges switch, it stops all Hyper-V Management Services in all Cluster Nodes, backups VM configs and fix incorrect VM virtual disk paths. Restarts Hyper-V Management Services after changes.
You should put a volume identifier into CSV volumes to be able to use this script. Simply put a Volume1.CSV into Volume1 as a volume identifier.
.PARAMETER WhatIf
Display what would happen if you would run the function with given parameters.
.PARAMETER Confirm
Prompts for confirmation for each operation. Allow user to specify Yes/No to all option to stop prompting.
.EXAMPLE
Repair-VMConfig
Just shows VM configuration problems and do not take any action unless you add -ApplyChanges switch.
.EXAMPLE
Repair-VMConfig -ApplyChanges
Stops all Hyper-V Management Services in all Cluster Nodes, backups VM configs and fix incorrect VM virtual disk paths. Restarts Hyper-V Management Services after changes.
.INPUTS
ApplyChanges switch to apply changes on Virtual Machines.
.OUTPUTS
None
.NOTES
Author: Yusuf Ozturk
Website: http://www.yusufozturk.info
Email: ysfozy@gmail.com
Date created: 07-June-2014
Last modified: 08-June-2014
Version: 1.2
.LINK
http://www.yusufozturk.info
http://twitter.com/yusufozturk
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param (
# Do you confirm changes on Virtual Machines?
[Parameter(
Mandatory = $false,
HelpMessage = 'Do you confirm changes on Virtual Machines?')]
[switch]$ApplyChanges = $false,
# Debug Mode
[Parameter(
Mandatory = $false,
HelpMessage = 'Debug Mode')]
[switch]$DebugMode = $false
)
if ($ApplyChanges -eq $True)
{
# Get Cluster Node List
$ClusterNodes = Get-Cluster | Get-ClusterNode
foreach ($ClusterNode in $ClusterNodes)
{
# Stop Hyper-V Management Service
Invoke-Command -ComputerName $ClusterNode -ScriptBlock {
Set-Service "vmms" -StartupType Disabled
Stop-Service "vmms"
}
}
}
# Read All CSV Directories
$CSVVolumes = Get-ChildItem "C:\ClusterStorage"
foreach ($CSVVolume in $CSVVolumes)
{
# Informational Output
Write-Host " "
Write-Host " "
Write-Host "Working on $CSVVolume .." -ForegroundColor Cyan
Write-Host " "
# CSV Volume Name
$CSVVolumeName = $CSVVolume.Name
# Read All VM Config Files
$VMConfigs = Get-ChildItem "C:\ClusterStorage\$CSVVolumeName" -Filter "*.xml" -Recurse
foreach ($VMConfig in $VMConfigs)
{
# Set Replace VM Config Identifier
$ReplaceVMConfig = "0"
# Get VM Config Full Path
$VMConfigPath = $VMConfig.FullName
if ($ApplyChanges -eq $True)
{
# VM Config Backup Name
$VMConfigBackupPath = $VMConfigPath + ".backup"
# Backup Old VM Config
$BackupVMConfig = Copy-Item -Path $VMConfigPath -Destination $VMConfigBackupPath
}
# Informational Output
Write-Host " "
Write-Host "Working on $VMConfigPath .." -ForegroundColor Yellow
# CSV Volume Regex Pattern
$Pattern = '<pathname type="string">(.*?)</pathname>'
# Get VM Config Content
$VMConfigContent = Get-Content "$VMConfigPath"
# Get CSV Volume Name
$RegexResults = $VMConfigContent -match $Pattern
foreach ($RegexResult in $RegexResults)
{
# Search for Virtual Disks
$RegexSearch = [string]$RegexResult -match $Pattern
# Get Virtual Disk Path
$VHDPath = $Null;
$VHDPath = $Matches[1]
if ($VHDPath)
{
# Check VHD Path
$TestVHDPath = $Null;
$TestVHDPath = Test-Path "$VHDPath"
if (!$TestVHDPath)
{
Write-Host "Error: $VHDPath" -ForegroundColor Red
# CSV Volume Pattern
$CSVPattern = "volume\d{1,2}"
# Search for CSV Volume Name
$RegexSearch = [string]$RegexResult -match $CSVPattern
# Get CSV Volume Name
$CSVName = $Null;
$CSVName = $Matches[0]
if ($CSVName -like "Volume*")
{
# Get CSV Volume Filter
$CSVVolumeFilter = "*" + $CSVName + ".CSV"
# Find CSV Directory
$GetCSVDirectory = $Null;
$GetCSVDirectory = (Get-ChildItem "C:\ClusterStorage" -Filter "$CSVVolumeFilter" -Recurse).Directory.FullName
if ($GetCSVDirectory -ne $Null)
{
# Get Config Content
$ConfigContent = Get-Content -Path "$VMConfigPath"
# Get New CSV Volume
$NewCSVVolume = $GetCSVDirectory.Split("\")[-1]
# Check CSV Volume
if ($NewCSVVolume -like "Volume*")
{
$NewCSVVolume = "TEMPORARY_VOLUME" + $NewCSVVolume.Substring("0,6")
if ($ApplyChanges -eq $True)
{
# Replace CSV Volume
$Regex = New-Object Text.RegularExpressions.Regex $CSVName, "None"
$NewConfigContent = $Regex.Replace($ConfigContent, $NewCSVVolume)
# Save Changes on Config
Set-Content -Value "$NewConfigContent" -Path "$VMConfigPath" -Encoding "BigEndianUnicode"
# Set Replace VM Config Identifier
$ReplaceVMConfig = "1"
}
}
else
{
Write-Host "Error: Could not get volume name of $VHDPath" -ForegroundColor Red
}
}
else
{
Write-Host "Error: Could not find any volume identifier for $CSVName" -ForegroundColor Red
}
}
else
{
Write-Host "Error: $VHDPath is not on a CSV Volume" -ForegroundColor Red
}
}
else
{
Write-Host "OK: $VHDPath" -ForegroundColor Green
}
}
}
if ($ApplyChanges -eq $True)
{
if ($ReplaceVMConfig -eq "1")
{
# Get Config Content
$ConfigContent = Get-Content -Path "$VMConfigPath"
# CSV Volume Prefix
$CSVVolumePrefix = "Volume"
# Replace CSV Volume
$Regex = New-Object Text.RegularExpressions.Regex "TEMPORARY_VOLUME", "None"
$NewConfigContent = $Regex.Replace($ConfigContent, $CSVVolumePrefix)
# Save Changes on Config
Set-Content -Value "$NewConfigContent" -Path "$VMConfigPath" -Encoding "BigEndianUnicode"
}
}
}
}
if ($ApplyChanges -eq $True)
{
foreach ($ClusterNode in $ClusterNodes)
{
# Start Hyper-V Management Service
Invoke-Command -ComputerName $ClusterNode -ScriptBlock {
Set-Service "vmms" -StartupType Automatic
Start-Service "vmms"
}
}
}
} |
function Repair-VMConfig {
<#
.SYNOPSIS
Function to repair Virtual Machine config after CSV volume path changes.
You should put a volume identifier into CSV volumes to be able to use this script.
Simply put a Volume1.CSV into Volume1 as a volume identifier.
.DESCRIPTION
In some cases, CSV volume names could be changed. So you may not start your virtual machines due to incorrect virtual disk paths.
This function is written to fix this issue. It finds all Virtual Machines configuration problems and shows you as a output.
If you use ApplyChanges switch, it stops all Hyper-V Management Services in all Cluster Nodes, backups VM configs and fix incorrect VM virtual disk paths. Restarts Hyper-V Management Services after changes.
You should put a volume identifier into CSV volumes to be able to use this script. Simply put a Volume1.CSV into Volume1 as a volume identifier.
.PARAMETER WhatIf
Display what would happen if you would run the function with given parameters.
.PARAMETER Confirm
Prompts for confirmation for each operation. Allow user to specify Yes/No to all option to stop prompting.
.EXAMPLE
Repair-VMConfig
Just shows VM configuration problems and do not take any action unless you add -ApplyChanges switch.
.EXAMPLE
Repair-VMConfig -ApplyChanges
Stops all Hyper-V Management Services in all Cluster Nodes, backups VM configs and fix incorrect VM virtual disk paths. Restarts Hyper-V Management Services after changes.
.INPUTS
ApplyChanges switch to apply changes on Virtual Machines.
.OUTPUTS
None
.NOTES
Author: Yusuf Ozturk
Website: http://www.yusufozturk.info
Email: ysfozy@gmail.com
Date created: 07-June-2014
Last modified: 08-June-2014
Version: 1.2
.LINK
http://www.yusufozturk.info
http://twitter.com/yusufozturk
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param (
# Do you confirm changes on Virtual Machines?
[Parameter(
Mandatory = $false,
HelpMessage = 'Do you confirm changes on Virtual Machines?')]
[switch]$ApplyChanges = $false,
# Debug Mode
[Parameter(
Mandatory = $false,
HelpMessage = 'Debug Mode')]
[switch]$DebugMode = $false
)
if ($ApplyChanges -eq $True)
{
# Get Cluster Node List
$ClusterNodes = Get-Cluster | Get-ClusterNode
foreach ($ClusterNode in $ClusterNodes)
{
# Stop Hyper-V Management Service
Invoke-Command -ComputerName $ClusterNode -ScriptBlock {
Set-Service "vmms" -StartupType Disabled
Stop-Service "vmms"
}
}
}
# Read All CSV Directories
$CSVVolumes = Get-ChildItem "C:\ClusterStorage"
foreach ($CSVVolume in $CSVVolumes)
{
# Informational Output
Write-Host " "
Write-Host " "
Write-Host "Working on $CSVVolume .." -ForegroundColor Cyan
Write-Host " "
# CSV Volume Name
$CSVVolumeName = $CSVVolume.Name
# Read All VM Config Files
$VMConfigs = Get-ChildItem "C:\ClusterStorage\$CSVVolumeName" -Filter "*.xml" -Recurse
foreach ($VMConfig in $VMConfigs)
{
# Set Replace VM Config Identifier
$ReplaceVMConfig = "0"
# Get VM Config Full Path
$VMConfigPath = $VMConfig.FullName
if ($ApplyChanges -eq $True)
{
# VM Config Backup Name
$VMConfigBackupPath = $VMConfigPath + ".backup"
# Backup Old VM Config
$BackupVMConfig = Copy-Item -Path $VMConfigPath -Destination $VMConfigBackupPath
}
# Informational Output
Write-Host " "
Write-Host "Working on $VMConfigPath .." -ForegroundColor Yellow
# CSV Volume Regex Pattern
$Pattern = '<pathname type="string">(.*?)</pathname>'
# Get VM Config Content
$VMConfigContent = Get-Content "$VMConfigPath"
# Get CSV Volume Name
$RegexResults = $VMConfigContent -match $Pattern
foreach ($RegexResult in $RegexResults)
{
# Search for Virtual Disks
$RegexSearch = [string]$RegexResult -match $Pattern
# Get Virtual Disk Path
$VHDPath = $Null;
$VHDPath = $Matches[1]
if ($VHDPath)
{
# Check VHD Path
$TestVHDPath = $Null;
$TestVHDPath = Test-Path "$VHDPath"
if (!$TestVHDPath)
{
Write-Host "Error: $VHDPath" -ForegroundColor Red
# CSV Volume Pattern
$CSVPattern = "volume\d{1,2}"
# Search for CSV Volume Name
$RegexSearch = [string]$RegexResult -match $CSVPattern
# Get CSV Volume Name
$CSVName = $Null;
$CSVName = $Matches[0]
if ($CSVName -like "Volume*")
{
# Get CSV Volume Filter
$CSVVolumeFilter = "*" + $CSVName + ".CSV"
# Find CSV Directory
$GetCSVDirectory = $Null;
$GetCSVDirectory = (Get-ChildItem "C:\ClusterStorage" -Filter "$CSVVolumeFilter" -Recurse).Directory.FullName
if ($GetCSVDirectory -ne $Null)
{
# Get Config Content
$ConfigContent = Get-Content -Path "$VMConfigPath"
# Get New CSV Volume
$NewCSVVolume = $GetCSVDirectory.Split("\")[-1]
# Check CSV Volume
if ($NewCSVVolume -like "Volume*")
{
$NewCSVVolume = "TEMPORARY_VOLUME" + $NewCSVVolume.Substring("0,6")
if ($ApplyChanges -eq $True)
{
# Replace CSV Volume
$Regex = New-Object Text.RegularExpressions.Regex $CSVName, "None"
$NewConfigContent = $Regex.Replace($ConfigContent, $NewCSVVolume)
# Save Changes on Config
Set-Content -Value "$NewConfigContent" -Path "$VMConfigPath" -Encoding "BigEndianUnicode"
# Set Replace VM Config Identifier
$ReplaceVMConfig = "1"
}
}
else
{
Write-Host "Error: Could not get volume name of $VHDPath" -ForegroundColor Red
}
}
else
{
Write-Host "Error: Could not find any volume identifier for $CSVName" -ForegroundColor Red
}
}
else
{
Write-Host "Error: $VHDPath is not on a CSV Volume" -ForegroundColor Red
}
}
else
{
Write-Host "OK: $VHDPath" -ForegroundColor Green
}
}
}
if ($ApplyChanges -eq $True)
{
if ($ReplaceVMConfig -eq "1")
{
# Get Config Content
$ConfigContent = Get-Content -Path "$VMConfigPath"
# CSV Volume Prefix
$CSVVolumePrefix = "Volume"
# Replace CSV Volume
$Regex = New-Object Text.RegularExpressions.Regex "TEMPORARY_VOLUME", "None"
$NewConfigContent = $Regex.Replace($ConfigContent, $CSVVolumePrefix)
# Save Changes on Config
Set-Content -Value "$NewConfigContent" -Path "$VMConfigPath" -Encoding "BigEndianUnicode"
}
}
}
}
if ($ApplyChanges -eq $True)
{
foreach ($ClusterNode in $ClusterNodes)
{
# Start Hyper-V Management Service
Invoke-Command -ComputerName $ClusterNode -ScriptBlock {
Set-Service "vmms" -StartupType Automatic
Start-Service "vmms"
}
}
}
}
You should add -ApplyChanges switch in order to confirm changes on virtual machine configs. That will backup all VM configs before modification. Also that will stop and start all Hyper-V Management Services in all cluster nodes due to changes on VM configs.
|