search
Categories
Archive
Blogroll

Badges

Microsoft PowerShell MVP
MCSE
Sponsors

VirtualMetric
Cozumpark Bilisim Portali
Posted in Windows Powershell | No Comment | 17 views | 31/10/2014 17:39

If you create a secure password on PowerShell and output it into a txt file, you can decrypt it on another Windows machine. So we use a predefined user key to create our secure passwords:

There was a question about this post. So how you can create your own key?

So what you need to do is:

1
2
3
4
$SecureKey = New-Object byte[](16)
$RNGCryptoServiceProvider = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create()
$RNGCryptoServiceProvider.GetBytes($SecureKey)
$SecureKey

That will create a random key for you. So you can replace it with predefined key.


Posted in Windows Powershell, Windows Server | No Comment | 310 views | 23/09/2014 04:25

This is an example script to show how you can monitor Supermicro servers via PowerShell:

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
# Test Supermicro CLI Path
$TestSupermicroCLIPath = Test-Path -Path "C:\Program Files\Supermicro\SuperDoctor5\sdc.bat"
 
if ($TestSupermicroCLIPath -eq $True)
{				
	# Test Supermicro CLI Output
	$SensorInfo = Invoke-Command -ScriptBlock {
		&'C:\Program Files\Supermicro\SuperDoctor5\sdc.bat' "-d"
	}
}
 
# Create Supermicro Sensors Function
function Get-SupermicroSensor
{
	param ($SensorSource)
 
	if ($SensorSource)
	{
		# Get Supermicro Sensors
		$SupermicroSensors = $SensorSource | Select-String "2.1.1.1.1.2."
 
		# Parse Supermicro Output
		foreach ($SupermicroSensor in $SupermicroSensors)
		{
			# Clear Values
			$SupermicroSensorCurrentReading = $Null;
			$SupermicroSensorHighLimit = $Null;
			$SupermicroSensorLowLimit = $Null;
			$SupermicroSensorMetric = $Null;
 
			# Get Sensor Information
			$SupermicroSensorValues = $SupermicroSensor.ToString().Split(",")
			$SupermicroSensorID = ($SupermicroSensorValues[0]).Split(".")[-1]
			$SupermicroSensorName = $SupermicroSensorValues[-1]
 
			# Get Sensor Results
			$SupermicroSensorCurrentReading = $SensorSource | Select-String "2.1.1.1.1.4.$SupermicroSensorID\b"
			$SupermicroSensorHighLimit = $SensorSource | Select-String "2.1.1.1.1.5.$SupermicroSensorID\b"
			$SupermicroSensorLowLimit = $SensorSource | Select-String "2.1.1.1.1.6.$SupermicroSensorID\b"
			$SupermicroSensorMetric = $SensorSource | Select-String "2.1.1.1.1.11.$SupermicroSensorID\b"
 
			# Parameter Validation
			if (!$SupermicroSensorCurrentReading) { [string]$SupermicroSensorCurrentReading = "Unknown" } else { [string]$SupermicroSensorCurrentReading = $SupermicroSensorCurrentReading.ToString().Split(",")[-1] }
			if (!$SupermicroSensorHighLimit) { [string]$SupermicroSensorHighLimit = "Unknown" } else { [string]$SupermicroSensorHighLimit = $SupermicroSensorHighLimit.ToString().Split(",")[-1] }
			if (!$SupermicroSensorLowLimit) { [string]$SupermicroSensorLowLimit = "Unknown" } else { [string]$SupermicroSensorLowLimit = $SupermicroSensorLowLimit.ToString().Split(",")[-1] }
			if (!$SupermicroSensorMetric) { [string]$SupermicroSensorMetric = "Unknown" } else { [string]$SupermicroSensorMetric = $SupermicroSensorMetric.ToString().Split(",")[-1] }
 
			$Properties = New-Object Psobject
			$Properties | Add-Member Noteproperty ID $SupermicroSensorID
			$Properties | Add-Member Noteproperty Name $SupermicroSensorName
			$Properties | Add-Member Noteproperty CurrentReading $SupermicroSensorCurrentReading
			$Properties | Add-Member Noteproperty Metric $SupermicroSensorMetric
			$Properties | Add-Member Noteproperty HighLimit $SupermicroSensorHighLimit
			$Properties | Add-Member Noteproperty LowLimit $SupermicroSensorLowLimit
			Write-Output $Properties
		}
	}
}
 
# Get Supermicro Sensor Results
$SupermicroSensorResults = Get-SupermicroSensor -SensorSource $SensorInfo

You need to install Super Doctor 5 on your Supermicro server before using this script.


Posted in Windows Powershell, Windows Server | No Comment | 378 views | 05/08/2014 15:21

You can use following script to get passthrough disk reports from Hyper-V Clusters:

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
# Get Clusters
$Clusters = Get-Content Clusters.txt
 
foreach ($Cluster in $Clusters)
{
	# Get Cluster Nodes
	$ClusterNodes = Get-Cluster $Cluster | Get-ClusterNode
 
	foreach ($ClusterNode in $ClusterNodes)
	{
		Write-Host Working on $ClusterNode
 
		# Clear PT Values
		$PTDisks = $Null;
		$DiskNumber = $Null;
 
		# Get Passthrough Disks
		$PTDisks = Get-VM -ComputerName $ClusterNode | Get-VMHardDiskDrive | Where Path -like Disk*
 
		foreach ($PTDisk in $PTDisks)
		{
			# Get VM Name
			$VMName = $PTDisk.VMName
 
			Write-Host Working on $VMName
 
			# Get Passthrough Disk Info
			$PTInfo = $PTDisk.Path
			$DiskNumber = $PTDisk.DiskNumber
			$ControllerNumber = $PTDisk.ControllerNumber
			$ControllerLocation = $PTDisk.ControllerLocation
			$ControllerType = $PTDisk.ControllerType
			Write-Host Working on Disk $DiskNumber
 
			if (!$DiskNumber)
			{
				$DiskNumber = $PTInfo.Split(" ")[1]
			}
 
			# Get Disk Info
			$DiskInfo = Get-WmiObject Win32_DiskDrive -ComputerName $ClusterNode | Where Index -eq $DiskNumber
			$Model = $DiskInfo.Model
			$Caption = $DiskInfo.Caption
			$Signature = $DiskInfo.Signature
			$Size = [math]::round($DiskInfo.Size / 1GB,0)
 
			# Set Output
			$Value = $VMName + ";" + $ClusterNode + ";" + $ControllerType + ";" + $ControllerNumber + ";" + $ControllerLocation + ";" + $DiskNumber + ";" + $Model + ";" + $Signature + ";" + $Size
 
			# Informational Output
			Add-Content -Value $Value -Path Output.txt
		}
	}
}

You need to add your clusters into Clusters.txt file.


Posted in Windows Powershell, Windows Server | No Comment | 1,405 views | 05/08/2014 14:28

You can get operating system report of your remote servers via PowerShell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Get-Content C:\Servers.txt
foreach ($Server in $Servers)
{
	try
	{
		$OS = Get-WmiObject -ComputerName $Server -Class Win32_OperatingSystem -EA Stop
		$OSName = $OS.Caption
		$SPV = $OS.CSDVersion
 
		$Value = $Server + ";" + $OSName + ";" + $SPV
		Write-Host $Value
	}
	catch
	{
		Write-Host $_
	}
}

That will give you OS Name and Service Pack version.


Posted in Windows Powershell, Windows Server | No Comment | 377 views | 31/07/2014 11:30

You can get host reports with following 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
$Servers = "Server01","Server02"
 
foreach ($Server in $Servers)
{
	# Get Local Disks
	$Disks = (Get-WmiObject -ComputerName $Server -Class Win32_LogicalDisk)
 
	# Clear Variables
	$TotalSize = 0;
	$TotalUsedSize = 0;
 
	foreach ($Disk in $Disks)
	{
		# Get Disk Space
		$Size = $Disk.Size
		$FreeSpace = $Disk.FreeSpace
 
		# Calculate Used Size
		[int64]$UsedSize = [int64]$Size - [int64]$FreeSpace
 
		# Calculate Total Size
		$TotalSize = $TotalSize + $Size;
		$TotalUsedSize = $TotalUsedSize + $UsedSize;
	}
 
	# Convert Total Size to MB
	[int64]$TotalUsedSize = [math]::round(($TotalUsedSize / 1MB), 0)
	[int64]$TotalSize = [math]::round(($TotalSize / 1MB), 0)
	[int64]$TotalFreeSpace = $TotalSize-$TotalUsedSize
 
	# Get OS and CPU Info
	$OSInformation = Get-WmiObject -ComputerName $Server -Class "Win32_OperatingSystem"
	$CPUInformation = (Get-WmiObject -ComputerName $Server -Class "Win32_Processor").Count
 
	# Calculate Memory
	$HostTotalMemory = ([math]::round(($OSInformation.TotalVisibleMemorySize / 1MB), 0)) * 1024
	$HostFreeMemory = ([math]::round(($OSInformation.FreePhysicalMemory / 1MB), 0)) * 1024
	$HostUsedMemory = $HostTotalMemory-$HostFreeMemory
 
	# Output Results
	$Value = $Server + ";" + $CPUInformation + ";" + $HostTotalMemory + ";" + $HostUsedMemory + ";" + $HostFreeMemory + ";" + $TotalSize + ";" + $TotalUsedSize + ";" + $TotalFreeSpace
	$Value
}

You can export all results to Excel to parse values.


Posted in Windows Powershell, Windows Server | 1 Comment | 824 views | 20/07/2014 23:31

You may get following issues due to WMI problem:

403042

Reboot is only way to fix it but at least you can prevent future issues:

1. Go to Start -> Run and type wbemtest.exe
2. Click Connect
3. In the namespace text box type “root” (without quotes).
4. Click Connect
5. Click Enum Instances
6. In the Class Info dialog box enter Superclass Name as “__ProviderHostQuotaConfiguration” (without quotes) and press OK.
(Note: the Superclass name includes a double underscore at the front.)
7. In the Query Result window, double-click “__ProviderHostQuotaConfiguration=@”
8. In the Object Editor window, double-click HandlesPerHost
9. In the Value dialog, type in 8192
10. Click Save Property
11. Click Save Object
12. Under properties find the property “MemoryPerHost” or any other ones you need to modify and double click it
13. Change the value from 512 MB which is 536870912 to 1GB which is 1073741824
14. Click Save Property
15. Click Save Object
16. Close Wbemtest
17. Restart the computer

Thanks to Shaon Shan for sharing this solution.


Posted in Virtual Machine Manager, Windows Powershell, Windows Server | 1 Comment | 1,001 views | 20/07/2014 09:31

Lets assume that you have a 3 years old storage and you are using it to place your virtual machines on Hyper-V Cluster. Then you bought a new storage box, you created LUNs on it and assign them as a CSV volumes on your existing Hyper-V Cluster. So next achievement would be migrating your virtual machines from old storage to new one.

That migration could be a headache if you have many VMs and many storage LUNs. So in that case, you can use following script to migrate Virtual Machines per CSV Volume. Just you need to specify which CSV volume you would like to drain. So let’s assume that volume is Volume1. I will specify that volume like following:

Start-CSVMigration -TargetVolume "Volume1"

Now you need to specify other CSV Luns as well to filter them. Otherwise, you can migrate a VM to old storage again. So we are filtering them like following:

Start-CSVMigration -TargetVolume "Volume1" -FilteredVolumes "Volume2","Volume3","Volume4"

So how does it work?

We are creating an array called FilteredVolumes then adding our old storage luns to this array. You will see that I’m also adding $TargetVolume to same array. Because there is a chance to try to migrate a VM to same volume. So that will prevent that kind of issues.

So how can I get destination volume?

$FullQuery = '((Get-ClusterSharedVolume |' + $Query + ' Select -ExpandProperty SharedVolumeInfo | Select @{label="Name";expression={(($_.FriendlyVolumeName).Split("\"))[-1]}},@{label="FreeSpace";expression={($_ | Select -Expand Partition).FreeSpace}} | Sort FreeSpace -Descending)[0]).Name'

As you can notice from the code below, i’m getting all CSV volumes, filtering old storage volumes, sorting new storage CSVs by their free space and selecting the storage which has biggest available disk space.

So I’ll place VM into that volume:

Move-VMStorage -ComputerName "$ClusterNode" -VMName "$VMName" -DestinationStoragePath "C:\ClusterStorage\$Volume\$VMName"

You can also allow VMs with passthrough disks and vHBA. You just need to add -AllowPT switch.

Start-CSVMigration -TargetVolume "Volume1" -FilteredVolumes "Volume2","Volume3","Volume4" -AllowPT

This is what I use to filter VMs with vHBA:

Where {($_ | Select -expand FibreChannelHostBusAdapters) -eq $Null}

If you get the idea, now I can share full 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
function Start-CSVMigration {
 
<#
    .SYNOPSIS
 
        Function to migrate all virtual machines placed on a CSV volume by using Hyper-V Live Storage Migration.
 
    .DESCRIPTION
 
        Lets assume that you have a 3 years old storage and you are using it to place your virtual machines on Hyper-V Cluster.
		Then you bought a new storage box, you created LUNs on it and assign them as a CSV volumes on your existing Hyper-V Cluster.
		So next achievement would be migrating your virtual machines from old storage to new one.
		This script moves virtual machines into different CSV volumes by using Hyper-V Live Storage Migration.
 
    .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
 
        Start-CSVMigration -TargetVolume "Volume1"
 
    .EXAMPLE
 
        Start-CSVMigration -TargetVolume "Volume1" -FilteredVolumes "Volume2","Volume3","Volume4"
 
    .EXAMPLE
 
        Start-CSVMigration -TargetVolume "Volume1" -FilteredVolumes "Volume2","Volume3","Volume4" -AllowPT
 
    .INPUTS
 
        None
 
    .OUTPUTS
 
        None
 
    .NOTES
 
        Author: Yusuf Ozturk
        Website: http://www.yusufozturk.info
        Email: ysfozy@gmail.com
        Date created: 05-July-2014
        Last modified: 20-July-2014
        Version: 1.4
 
    .LINK
 
        http://www.yusufozturk.info
        http://twitter.com/yusufozturk
 
#>
 
[CmdletBinding(SupportsShouldProcess = $true)]
param (
 
	# Target Volume
	[Parameter(
		Mandatory = $true,
		HelpMessage = 'The CSV Volume name that you want to drain, like: Volume1')]
	$TargetVolume,
 
	# Filtered Volumes
	[Parameter(
		Mandatory = $false,
		HelpMessage = 'The CSV Volume names that you want to filter, like: Volume2')]
	[array]$FilteredVolumes,
 
	# Allow Passthrough Disks
	[Parameter(
		Mandatory = $false,
		HelpMessage = 'Allow Passthrough Disks')]
	[switch]$AllowPT = $false,
 
	# Debug Mode
	[Parameter(
		Mandatory = $false,
		HelpMessage = 'Debug Mode')]
	[switch]$DebugMode = $false
)
	# Enable Debug Mode
	if ($DebugMode)
	{
		$DebugPreference = "Continue"
	}
	else
	{
		$ErrorActionPreference = "silentlycontinue"
	}
 
	# Filtered Volumes
	$FilteredVolumes += $TargetVolume
 
	# Clear Query
	$Query = $Null;
 
	# Create Query
	foreach ($FilteredVolume in $FilteredVolumes)
	{
		$Query = $Query + ' Where {$_.SharedVolumeInfo.FriendlyVolumeName -notlike "*' + $FilteredVolume + '"} |'
	}
 
	# Full Query
	$FullQuery = '((Get-ClusterSharedVolume |' + $Query + ' Select -ExpandProperty SharedVolumeInfo | Select @{label="Name";expression={(($_.FriendlyVolumeName).Split("\"))[-1]}},@{label="FreeSpace";expression={($_ | Select -Expand Partition).FreeSpace}} | Sort FreeSpace -Descending)[0]).Name'
 
	# Get Cluster Nodes
	$ClusterNodes = Get-Cluster | Get-ClusterNode
 
	foreach ($ClusterNode in $ClusterNodes)
	{
		# Clear Variables
		$VMs = $Null;
 
		# Create VM Array
		$VMArray = @()
 
		if ($AllowPT)
		{
			# 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
 
				# Add VM to VMArray
				$VMArray += $VMName
			}
		}
		else
		{
			# Get All Virtual Machines on Target Volume
			$VMs = Get-VM -ComputerName "$ClusterNode" | Where ConfigurationLocation -like "C:\ClusterStorage\$TargetVolume\*" | Where {($_ | Select -expand FibreChannelHostBusAdapters) -eq $Null}
 
			foreach ($VM in $VMs)
			{
				# Get VM Information
				$VMName = $VM.Name
 
				if ($VM.HardDrives.Path -like "Disk*")
				{
					# Skipping VM
				}
				else
				{
					# Add VM to VMArray
					$VMArray += $VMName
				}
			}
		}
 
		foreach ($VMName in $VMArray)
		{ 
			Write-Host " "
			Write-Host "Working on $VMName .."
			Write-Host "Hyper-V Host: $ClusterNode"
 
			# Get Volume Information
			$Volume = Invoke-Expression $FullQuery
 
			# Move Virtual Machine
			Move-VMStorage -ComputerName "$ClusterNode" -VMName "$VMName" -DestinationStoragePath "C:\ClusterStorage\$Volume\$VMName"
 
			Write-Host "Done."
		}
	}
}

It’s enough to run this script on one of the Cluster Node, so that will start migrating virtual machines. That will also give an output, so you will be able to see which VM you are migrating.

This is also an example how you can automate storage migrations:

1
2
3
4
5
6
7
8
9
10
11
$Volumes = @()
$Volumes += "Volume1"
$Volumes += "Volume2"
$Volumes += "Volume3"
$Volumes += "Volume4"
$Volumes += "Volume5"
 
foreach ($Volume in $Volumes)
{
	Start-CSVMigration -TargetVolume "$Volume" -FilteredVolumes "Volume1","Volume2","Volume3","Volume4","Volume5","Volume6","Volume7","Volume8","Volume9","Volume10","Volume11","Volume12","Volume13","Volume14","Volume15"
}

I hope you will find it useful. See you!