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

Badges
MCSE
Community

Cozumpark Bilisim Portali
Posted in Windows Server | No Comment | 965 views | 13/06/2014 22:13

This is an example script to check DNS servers on remote servers. If DNS count is not equal to 4, that will add server name into output.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# DNS Server Control
$ServerList = Get-Content VMs.txt
 
foreach ($Server in $ServerList)
{	
	Write-Host $Server
 
	$DNSServers = $Null
	$DNSServers = (Get-WmiObject -ComputerName $Server -Class Win32_NetworkAdapterConfiguration | where {$_.DNSServerSearchOrder -ne $Null}).DNSServerSearchOrder
 
	if ($DNSServers.Count -ne "4")
	{
		Add-Content -Value $Server -Path DNSProblem.txt
	}
 
	Write-Host $DNSServers
	Write-Host " "
	Write-Host " "
}

You should check DNSProblem.txt file to see which servers don’t have 4 DNS entries.


Posted in Linux Server, Windows Powershell, Windows Server | No Comment | 2,327 views | 12/06/2014 22:44

This is an example for nxService of PowerShell DSC.

You will able to stop a service like postfix on Linux by using PowerShell DSC.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$cred=Get-Credential -UserName:"root" -Message:"Root User?"
$opt = New-CimSessionOption -UseSsl:$true -SkipCACheck:$true -SkipCNCheck:$true -SkipRevocationCheck:$true
$linuxcomp=New-CimSession -Credential:$cred -ComputerName:linuxdsc.cloudapp.net -Port:5986 -Authentication:basic -SessionOption:$opt
 
Configuration StopService
{
   Import-DSCResource -Module nx
   Node "linuxdsc.cloudapp.net"{    
        nxService StopService
        {
			Name = "postfix"
			Controller = "init"
			State = "Stopped"
        }
    }
}
 
StopService -OutputPath:"C:\temp"
Start-DscConfiguration -CimSession:$linuxcomp -Path:"C:\temp" -Verbose -Wait

After you run DSC, postfix service will be stopped on destination Linux Server.


Posted in Virtual Machine Manager, Windows Server | No Comment | 1,968 views | 09/06/2014 17:54

This is my notes and scripts for a Hyper-V Disaster Recovery with Storage Replication.

First script on Main Site, creates Volume identifiers under CSV Volumes. So after a Volume restore, we can restore Volume names with that index. Also scripts exports all virtual machine configs. That will make it easier to restore all Virtual Machines on Hyper-V.

On Main Site:

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
##################################################
# START ON MAIN SITE
##################################################
 
# Clear VM Config
$TestVMConfigPath = Test-Path -Path "C:\ClusterStorage\Volume1\VMExport.Config"
 
if ($TestVMConfigPath)
{
	Clear-Content -Path "C:\ClusterStorage\Volume1\VMExport.Config"
}
 
# Export VM Config
$ClusterNodes = Get-Cluster | Get-ClusterNode
 
foreach ($ClusterNode in $ClusterNodes)
{
	# Get Virtual Machines
	$VMs = Get-VM -ComputerName $ClusterNode
 
	# Export VM Config
	foreach ($VM in $VMs)
	{
		# Get Virtual Machines
		$VMConfigPath = $VM.ConfigurationLocation + "\Virtual Machines\" + $VM.Id + ".xml"
 
		# Export to Config File
		Add-Content -Value $VMConfigPath -Path "C:\ClusterStorage\Volume1\VMExport.Config"
	}
}
 
# Read All CSV Directories
$CSVVolumes = Get-ChildItem "C:\ClusterStorage"
 
foreach ($CSVVolume in $CSVVolumes)
{
	# Get CSV Volume Name
	$CSVVolumeName = $CSVVolume.Name
 
	# Get CSV Identifier Name
	$CSVIdentifierName = $CSVVolumeName + ".CSV"
 
	# Get CSV Path
	$CSVPath = $CSVVolume.FullName
 
	# Get CSV Identifier Path
	$CSVIdentifierPath = $CSVPath + "\" + $CSVIdentifierName
 
	# Test CSV Identifier Path
	$TestCSVIdentifierPath = Test-Path $CSVIdentifierPath
 
	if (!$TestCSVIdentifierPath)
	{
		# Create CSV Identifier
		New-Item -Path "$CSVPath" -Name "$CSVIdentifierName" -ItemType File
	}
}

Second Script on DR site, clears all old objects on Hyper-V and Failover Cluster. Restores volume names according to Volume Identifiers. After that imports all virtual machines by using our virtual machine exports.

On DR Site:

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
##################################################
# START ON DR SITE
##################################################
 
# Clear Failover Cluster Objects
$ClusterGroup = Get-ClusterGroup | Where GroupType -eq "VirtualMachine" | Remove-ClusterGroup -RemoveResources -Force
 
# Get All Cluster Nodes
$ClusterNodes = Get-Cluster | Get-ClusterNode
 
if ($ClusterNode in $ClusterNodes)
{
	Invoke-Command -ComputerName $ClusterNode -ScriptBlock {
 
		# Stop Hyper-V Management Service
		Set-Service "vmms" -StartupType Disabled
		Stop-Service "vmms"
 
		# Clear Hyper-V Database
		Get-ChildItem -Path "C:\ProgramData\Microsoft\Windows\Hyper-V\Virtual Machines" | Remove-Item
	}
}
 
# Read All CSV Directories
$CSVVolumes = Get-ChildItem "C:\ClusterStorage"
 
# Clear Iteration
$i = 1;
 
foreach ($CSVVolume in $CSVVolumes)
{	
	# Create Time Guid
	$TimeGuid = (Get-Date).ToString("ddMMyyyyhhmmss")
 
	# Change CSV Volume Name
	$CSVVolume | Rename-Item -NewName "CSVolume$TimeGuid$i"
 
	# Update Iteration
	$i++
}
 
# Read Updated CSV Directories
$CSVVolumes = Get-ChildItem "C:\ClusterStorage"
 
foreach ($CSVVolume in $CSVVolumes)
{
	# Get CSV Volume Name
	$CSVVolumeName = $CSVVolume.Name
 
	# Get CSV Volume Filter
	$CSVVolumeFilter = "*.CSV"
 
	# Get CSV Path
	$CSVPath = $CSVVolume.FullName
 
	# Find CSV Identifier
	$CSVIdentifier = $Null;
	$CSVIdentifier = (Get-ChildItem "$CSVPath" -Filter "$CSVVolumeFilter" -Recurse).Name
	$CSVIdentifier = $CSVIdentifier.Split(".")[0]
 
	if ($CSVIdentifier)
	{
		# CSV Volume ID
		$NewCSVVolumeName = "Volume" + $CSVIdentifier.Substring("0,6")
 
		# Change CSV Volume Name
		$CSVVolume | Rename-Item -NewName "$NewCSVVolumeName"
	}
	else
	{
		Write-Host "Error: Could not find CSV Identifier for $CSVVolume"
	}
}
 
# Get All Cluster Nodes
$ClusterNodes = Get-Cluster | Get-ClusterNode
 
if ($ClusterNode in $ClusterNodes)
{
	Invoke-Command -ComputerName $ClusterNode -ScriptBlock {
 
		# Start Hyper-V Management Service
		Set-Service "vmms" -StartupType Automatic
		Start-Service "vmms"
	}
}
 
# Get VM Import Config
$VMImportConfig = Get-Content "C:\ClusterStorage\Volume1\VMExport.Config"
 
foreach ($VM in $VMImportConfig)
{
	# Import Virtual Machine
	$ImportVM = Import-VM $VM
 
	# Get Virtual Machine Name
	$VMName = $ImportVM.Name
 
	# Add VM to Failover Cluster
	Add-VMToCluster $VMName
}

After that, you will be able to start your virtual machines.


Posted in Virtual Machine Manager, Windows Powershell, Windows Server | 3 Comments | 3,062 views | 09/06/2014 01:19

Sometimes, you may need to empty your CSV volume for a maintenance operation or due to a volume corruption.
So you can use this script if you need to drain all virtual machines and virtual disks from a CSV.

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
# Target Volume
$TargetVolume = "Volume8"
 
# Get Cluster Nodes
$ClusterNodes = Get-Cluster | Get-ClusterNode
 
foreach ($ClusterNode in $ClusterNodes)
{
	# Clear Variables
	$VMs = $Null;
 
	# Get All Virtual Machines on Target Volume
	$VMs = Get-VM -ComputerName "$ClusterNode" | Where ConfigurationLocation -like "C:\ClusterStorage\$TargetVolume*"
 
	foreach ($VM in $VMs)
	{
		# Get VM Information
		$VMName = $VM.Name
 
		Write-Host " "
		Write-Host "Working on $VMName .."
		Write-Host "Hyper-V Host: $ClusterNode"
 
		# Get Volume Information
		$Volume = ((Get-ClusterSharedVolume | Where {$_.SharedVolumeInfo.FriendlyVolumeName -notlike "*$TargetVolume*"} | Select -ExpandProperty SharedVolumeInfo | Select @{label="Name";expression={(($_.FriendlyVolumeName).Split("\"))[-1]}},@{label="FreeSpace";expression={($_ | Select -Expand Partition).FreeSpace}} | Sort FreeSpace -Descending)[0]).Name
 
		# Move Virtual Machine
		Move-VMStorage -ComputerName "$ClusterNode" -VMName "$VMName" -DestinationStoragePath "C:\ClusterStorage\$Volume\$VMName"
 
		Write-Host "Done."
	}
}

That will move all virtual machines via Storage Live Migration into best available CSV volume.


Posted in Virtual Machine Manager, Windows Powershell, Windows Server | No Comment | 1,947 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.


Posted in Virtual Machine Manager, Windows Powershell, Windows Server | No Comment | 1,907 views | 06/06/2014 08:39

You can migrate selected Virtual Machines in a Hyper-V Cluster with following script.
That will migrate all virtual machines into target volume.
If target volume is not specified, it will look for best available CSV volume, and migrate virtual machine into that.

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
# Target Volume
$TargetVolume = "Volume1"
 
# Create VM Array
$VMArray = New-Object System.Collections.ArrayList
$VMArray.Clear();
 
$AddArray = $VMArray.Add("VM01")
$AddArray = $VMArray.Add("VM02")
$AddArray = $VMArray.Add("VM03")
 
# Get Cluster Nodes
$ClusterNodes = Get-Cluster | Get-ClusterNode
 
foreach ($ClusterNode in $ClusterNodes)
{
	# Get All Virtual Machines
	$VMs = Get-VM -ComputerName "$ClusterNode"
 
	foreach ($VM in $VMs)
	{
		# Get VM Information
		$VMName = $VM.Name
 
		if ($VMArray.Contains($VMName) -eq $True)
		{ 
			Write-Host " "
			Write-Host "Working on $VMName .."
			Write-Host "Hyper-V Host: $ClusterNode"
 
			if (!$TargetVolume)
			{
				# Get Volume Information
				$Volume = ((Get-ClusterSharedVolume | Select -ExpandProperty SharedVolumeInfo | Select @{label="Name";expression={(($_.FriendlyVolumeName).Split("\"))[-1]}},@{label="FreeSpace";expression={($_ | Select -Expand Partition).FreeSpace}} | Sort FreeSpace -Descending)[0]).Name
			}
			else
			{
				$Volume = $TargetVolume
			}
 
			# Move Virtual Machine
			Move-VMStorage -ComputerName "$ClusterNode" -VMName "$VMName" -DestinationStoragePath "C:\ClusterStorage\$Volume\$VMName"
 
			Write-Host "Done."
		}
	}
}

This script should work even if you have pass-through disks on virtual machine or virtual hba.


Posted in Virtual Machine Manager, Windows Powershell, Windows Server | No Comment | 1,154 views | 05/06/2014 15:55

If you need to get Windows OS and Version information of a list of servers, then you can use following script.

1
2
3
4
5
6
7
8
9
10
$Servers = Get-Content Servers.txt
foreach ($Server in $Servers)
{
	$OSInfo = $Null;
	$CompInfo = $Null;
	$OSInfo = Get-WmiObject -ComputerName $Server -Class "Win32_OperatingSystem"
	$CompInfo = Get-WmiObject -ComputerName $Server -Class "Win32_ComputerSystem"
	$Value = $Server + ";" + $OSInfo.Caption + ";" + $OSInfo.CSDVersion + ";" + $OSInfo.BuildNumber + ";" + $OSInfo.Version + ";" + $CompInfo.Manufacturer + ";" + $CompInfo.Model
	Add-Content -Value $Value -Path ServerOSInfo.txt
}

That will output all data into ServerOSInfo.txt file.