search
Categories
Sponsors
VirtualMetric Hyper-V Monitoring, Hyper-V Reporting
Archive
Blogroll

Badges
MCSE
Community

Cozumpark Bilisim Portali
Posted in Virtual Machine Manager, Windows Powershell, Windows Server | No Comment | 1,934 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"
			}
		}
	}
}

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.