Archive for the ‘Windows Server’ Category

Powershell-Generate Automated CSVFreespace and Memory Report

December 4, 2014

This script relies the Hyper-V clusters are been managed by VMM but if you do not use VMM you can also modify based on your environment. It should just give you an idea how to collect data and use sentmail function to get a daily report of your resource status.

Note: script version 1.3 is targeted to be run as a task so no console outputs are considered, just a logfile is written into same folder where is script is located

as no user interaction is possible because we want to use this as a task following variables has to be updated in the script

$smtpServer = "YOURSMTP"
$smtpFrom = ""
$SMTPPort = "25"
$Username = ""
$Password = ‘YOURPASSWORD’
$smtpTo =

#Creator: Ramazan Can
#V1.2 	- dumping into log and generating mail with function "SentReportviaMail"
#		- mail sender, recipient, account for authentification can be modified in function "SentReportviaMail"
# 				$smtpFrom - $Username - $smtpTo 
#V1.3	- task scheduler version

#Write-Host " "
import-module virtualmachinemanager
import-module failoverclusters
$VMMClusters=(Get-SCVMHostCluster -vmmserver $VMMServer).Name
$timestamp=(get-date -Format d).Replace("/","_")
Get-item ".\CSVandMemory_Report_$timestamp.txt" -ea 0 | Remove-Item -ea 0

"This Report was run at $date " | out-file -filepath $logfile -append
" " | out-file -filepath $logfile -append

function GetCSVFreeSpace {
#incorporated and modified from
$objs = @()

$csvs = Get-ClusterSharedVolume -Cluster $Cluster
foreach ( $csv in $csvs )
   $csvinfos = $csv | select -Property Name -ExpandProperty SharedVolumeInfo
   foreach ( $csvinfo in $csvinfos )
      $obj = New-Object PSObject -Property @{
         Name        = $csv.Name
         Path        = $csvinfo.FriendlyVolumeName
         Size        = $csvinfo.Partition.Size
         FreeSpace   = $csvinfo.Partition.FreeSpace
         UsedSpace   = $csvinfo.Partition.UsedSpace
         PercentFree = $csvinfo.Partition.PercentFree
      $objs += $obj

$objs | ft -auto Name,Path,@{ Label = "Size(GB)" ; Expression = { "{0:N2}" -f ($_.Size/1024/1024/1024) } },@{ Label = "FreeSpace(GB)" ; Expression = { "{0:N2}" -f ($_.FreeSpace/1024/1024/1024) } },@{ Label = "UsedSpace(GB)" ; Expression = { "{0:N2}" -f ($_.UsedSpace/1024/1024/1024) } },@{ Label = "PercentFree" ; Expression = { "{0:N2}" -f ($_.PercentFree) }}

function SentReportviaMail {
$logfile=(Get-item ".\CSVandMemory_Report*" -ea 0).Name
$Logs=Get-Content $logfile
$smtpServer = "YOURSMTP"
$smtpFrom = ""
$SMTPPort = "25"
$Username = ""
$Password = 'YOURPASSWORD'
$smtpTo = ""
$messageSubject = "$VMMServer - Automated CSV FreeSpace and Total Memory Report"

[string]$messagebody = ""

foreach ($log in $logs )
	$messagebody = $messagebody + $log + "`r`n"
#Write-Host " "
#Write-Host "Starting to sent mail to $smtpTo via $smtpServer ...." -ForegroundColor green
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
#Write-Host "mail sent completed " -ForegroundColor green
#Write-Host " "

foreach ($Cluster in $VMMClusters)
	#Write-Host "Starting to collect memory and CSV free space data in $Cluster ....." -foregroundcolor green
	[int]$TotalFreeMemory = 0;
	[int]$TotalMemory = 0;
	$ClusterNodes = Get-Cluster $Cluster | Get-ClusterNode
	foreach ($ClusterNode in $ClusterNodes)
		[int]$FreeMemory = [math]::round(((Get-WmiObject -ComputerName $ClusterNode -Class Win32_OperatingSystem).FreePhysicalMemory / 1MB), 0)
		[int]$TotalFreeMemory = [int]$TotalFreeMemory + [int]$FreeMemory
		[int]$NodeMemory = [math]::round(((Get-WmiObject -ComputerName $ClusterNode -Class Win32_OperatingSystem).TotalVisibleMemorySize / 1MB), 0)
		[int]$TotalMemory = [int]$TotalMemory + [int]$NodeMemory


	$TotalAvailableMemory = $TotalFreeMemory - $NodeMemory
	"Cluster: $Cluster" | out-file -filepath $logfile -append
	"Total Memory: $TotalMemory" | out-file -filepath $logfile -append
	"Total Free Memory: $TotalFreeMemory" | out-file -filepath $logfile -append
	"Total Available Memory: $TotalAvailableMemory" | out-file -filepath $logfile -append
	" " | out-file -filepath $logfile -append
	"CSV Freespace : " | out-file -filepath $logfile -append
	GetCSVFreeSpace | out-file -filepath $logfile -append
	" " | out-file -filepath $logfile -append

example output mail:


Disclaimer: Please read, understand and test script before you run put in production! This should just give you an idea around the power of powershell and automation



Powershell–How to monitor HP Smartarray disk status?

July 4, 2014

really a quick one and straight forward but sometimes very useful. here is a quick example how you can monitor your smartarray controller disk status and in case of “Failed” drive detected sent a mail out to you with the summary.

Of course, SCOM has also automated capabilities to monitor HP hardware components in a much more efficient way but that’s a another story

Prerequisites are:

– depends on your SA version – you need the “HP ProLiant Array Configuration Utility (CLI) for Windows” and can be found here, the user guide here

– if required, modify program path to hp array utility command line tool "C:\Program Files\HP\hpssacli\bin\hpssacli.exe"

– modify smtp settings $smtpServer, $smtpFrom, $SMTPPort, $Username, $Password and $smtpTo

– modify $localhost

– check if your controller is 0 “controller slot=0”

###Code Snippet###

Get-item ".\log.txt" -ea 0 | Remove-Item -ea 0

function CheckSmartArray {
Write-Host " "
Write-Host "Checking SmartArray on system"$localhost"" -foregroundcolor green
C:\Windows\System32\cmd.exe /c "C:\Program Files\HP\hpssacli\bin\hpssacli.exe" controller slot=0 physicaldrive all show

CheckSmartArray | out-file -filepath $logfile -append

function SentDiskDrivefailedviaMail {
$Logs=Get-Content $logfile
$smtpServer = ""
$smtpFrom = ""
$SMTPPort = "25"
$Username = ""
$Password = "passwordhere"
$smtpTo = ""
$messageSubject = "Disk Drive failed at $localhost"

[string]$messagebody = ""

foreach ($log in $logs )
    $messagebody = $messagebody + $log + "`r`n"
Write-Host "failed disk detected – starting to sent mail to $smtpTo via $smtpServer …." -ForegroundColor red
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
Write-Host "mail sent completed " -ForegroundColor green
Write-Host " "

#Check logfile if a "Failed" status can be found, if true send a mail with "SentDiskDrivefailedviaMail" function
[array]$logcontent=gc $logfile
foreach ($line in $logcontent) {
    if ($line -match "Failed") {
    Write-Host " "
    write-host "failed disk found at $localhost " -foregroundcolor red
    write-host "detailed logs can be found $logfile " -foregroundcolor red
    Write-Host " "

###Code Snippet###

Sample Output from smart array CLI utility “controller slot=0 physicaldrive all show”


Disclaimer: Please read and test script before you run in your production!

Powershell-How to easily verify patch level between computers

July 4, 2014

Compare patches between computers? Here is a quick and easy way how you can verify this with Powershell

$node1 = Get-HotFix -ComputerName SERVER1
$node2 = Get-HotFix -ComputerName SERVER2
Compare-Object -ReferenceObject $node1 -DifferenceObject $node2 -Property HotFixID

Example Output:

HotFixID                                                    SideIndicator
——–                                                    ————-
KB2862152                                                   =>
KB2876331                                                   =>
KB2884846                                                   <=
KB2892074                                                   <=
KB2894029                                                   =>

The Compare-Object cmdlet compares two sets of objects. One set of objects is the "reference set," and the other set is the "difference set."

The result of the comparison indicates whether a property value appeared only in the object from the reference set (indicated by the <= symbol), only in the object from the difference set (indicated by the => symbol) or, if the IncludeEqual parameter is specified, in both objects (indicated by the == symbol).

Compare-Object is really powerful, check it out

Powershell – How to get total VM memory overview (dynamic, static and startup memory) per node in a cluster?

June 16, 2014

Host Memory Pressure – I think this is one of the keys (in addition to storage, network, CPU) in performance when running virtualization with dynamic memory and should be monitored. An balance between high density of running VMs on a host and memory calculation/demand is something to consider when managing self service clouds and/or running memory intensive workloads.

Write-host " "
Write-Host " "
$Cluster = Read-Host "Cluster Name "
Write-Host " "
Write-Host "Starting to check VM Memory pressure on $Cluster nodes " -ForegroundColor green
Write-Host " "
Write-Host "Collecting data like nodes, VMs Memory….please be patient" -ForegroundColor green
Write-Host " "
Write-Host " "
$Hostnames=(Get-Cluster $Cluster | Get-ClusterNode).Name

foreach ($Host1 in $Hostnames) {
[int]$hostmem=@{} | Out-Null
[int]$totalstartupmem=@{} | Out-Null
[int]$totalmaxmem=@{} | Out-Null
[int]$staticmemory=@{} | Out-Null
[int]$overcommited=@{} | Out-Null
[int]$totalramrequired=@{} | Out-Null

$AllVMs=(get-vm -ComputerName $Host1).Name
$Hostmem=(Get-VMhost -ComputerName $Host1).MemoryCapacity / 1024 / 1024 / 1024

foreach ($VM in $AllVMs) {
$CurrentVM=(get-VM $VM -ComputerName "$Host1" | fl *)
if ((Get-VMMemory -vmname $VM -ComputerName "$Host1").DynamicMemoryEnabled -eq "True") {
$memorystartup=(get-vm $VM -ComputerName "$Host1" | select-object MemoryStartup).MemoryStartup /1024 / 1024 / 1024
$MemoryMaximum=(get-vm $VM -ComputerName "$Host1" | select-object MemoryMaximum).memorymaximum /1024 / 1024 / 1024
$totalstartupmem += $memorystartup
$totalmaxmem += $MemoryMaximum
else {
$static=(get-vm $VM -ComputerName "$Host1" | select-object MemoryStartup).MemoryStartup /1024 / 1024 / 1024
$staticmemory += $static
$totalramrequired=$totalstartupmem + $staticmemory

write-host "Summary Report for Host $Host1" -foregroundcolor green
write-host "Total Startupmem for Dynamic VMs $totalstartupmem GB " -foregroundcolor green
write-host "Total Staticmem for Static VMs $staticmemory GB " -foregroundcolor green
write-host "Total minimum RAM (Startup+Static) required $totalramrequired GB " -foregroundcolor yellow
write-host "Total Maxmem for Dynamic VMs $totalmaxmem GB " -foregroundcolor yellow
write-host "Total available memory $Hostmem GB " -foregroundcolor green
if ($totalmaxmem -gt $Hostmem) {Write-Host "$Host1 is overcomitted " -foregroundcolor red}
write-host " "
write-host " "


This is just one way to get a total summary per node in your Hyper-V cluster and their configured memory demand. It provides a quick view on memory utilization of your Hyper-V nodes. Be creative and modify based on your needs.

Disclaimer: Please read and test script before you run in your production!

Dynamic Memory Pressure Monitoring:

…a “bad” configuration can result in “bad” performance 🙂

Stay tuned…

How to configure Preferred Owners and AutoFailback with Powershell in Failover Cluster?

April 7, 2014

Consider scenario, you “balanced” your VMs across your nodes and you come back in the morning and they are migrated “for whatever reason” to different nodes. But as a typical administrator 😉 you know your workload best and you want to keep them preferred on a targeted node. In case of an unexpected reboot the VMs will get migrated to next available node in your Failover Cluster and goal is as soon as the node is back the VM should automatically fail back = PreferredOwners. 

Here is a quick example where you configure all clustered VM roles in a targeted cluster for preferred owners based on the current owner node. this should only give you an idea how things can be automated very easily with Powershell:

$Cluster = Read-Host "Cluster Name "
$Praefix = Read-Host "Please provide präfix for your clustered VM role names (a.e.SCVMM) "
Write-Host " "
Write-Host "Getting all clustered VM roles and configure Preferred Owners in cluster $Cluster" -ForegroundColor yellow
Write-Host " "
Write-Host " "
$AllClusterGroup = Get-ClusterGroup -Cluster $Cluster -Name $Praefix*

Write-Host "….running loop for all Clustered VMs"
Write-Host " "
Write-Host " "
foreach ($ClusterGroup in $AllClusterGroup)
    $ClusterGroupDetails = Get-ClusterGroup -Name "$ClusterGroup"
    Write-Host "Getting current Owner for $ClusterGroup…." -ForegroundColor yellow
    $CurrentOwner = $ClusterGroupDetails.OwnerNode.Name

    Set-ClusterOwnerNode -Group $ClusterGroup $CurrentOwner
    Write-Host "Current owner for VM $ClusterGroup is $CurrentOwner, configure Preferred Owner…done" -ForegroundColor yellow
    #Enable Autofailback
    (Get-ClusterGroup -Name "$ClusterGroup").AutoFailbackType=1
    Write-Host "Enabling Autofailback VM $ClusterGroup…done" -ForegroundColor yellow
    Write-Host " "

Disclaimer: Please read and test script before you run in your production, this reconfigures the preferred owner property at all your clustered VM roles in your cluster !!

There are more options how you can control clustered roles, like “AntiAffinityClass” – when a group is moved during failover, anti-affinity affects the algorithm used to determine the destination node. a.e. never run together at same node…

Here are just a few more good resources around failover options in a Failover Cluster:

Preferred Owners in a Cluster

Failover behavior on clusters of three or more nodes

Understanding Hyper-V Virtual Machine (VM) Failover Policies

Modify the Failover Settings for a Clustered Service or Application

Configure Failover and Failback Settings for a Clustered Service or Application


Using Guest Clustering for High Availability

Its all about IOPS

September 16, 2013

Sharing some personal experience from previous benchmarks. Here are some general guidelines for determining the number of hard disk drives required for a given I/O load.

Generally, a single disk drive can do this many "physical" IOPS per disk:
15k rpm: 180-210 IOPS
10k rpm: 130-150 IOPS
7200 rpm: 80-100 IOPS
5400 rpm: 50-80 IOPS

In a mirrored configuration:
Disk IOPS = Read IOPS + (2 * Write IOPS)
In a parity (RAID5) configuration:
Disk IOPS = Read IOPS + (4 * Write IOPS)
Summary of the number of operations per RAID type:
RAID 1 and 1/0 require that two disks to be written for each host initiated write.
Total IO = host reads + 2 x host writes
RAID5 (4+1) requires 4 operations per host write = a RAID5 write requires 2 reads and 2 writes
Total IO = host reads + 4 x host writes

Personal Note on RAID5: as you can see here, RAID5 does need more writes compared to other RAID level. my personal opinion on RAID5 is, when you know your IO pattern from your application you can also go with RAID5 to get efficiency and same time a "good performance" when the majority of IO operations are reads and not writes. a typical scenario for RAID5 would be a.e. "Streaming Services" where mainly 100% large sequential reads does happen.

if you are interested more on characterization of IO pattern, the SQL Team has released an really good Whitepaper on this ->…

Storage Top 10 Best Practices

SQL Server Best Practices Article

NT Server and Disk Subsystem Performance


VHD Performance…

SCVMM 2008 R2–Error 2912 – An internal error has occurred trying to contact an agent

March 20, 2013

I love the “unknown” error things but as all of us know you can NOT handle all error conditions within application coding. Therefore I would like to provide here an possible resolution which you need to confirm if it applies to your environment.

I faced this error and did some research and found out that this could also be related to BITS (Background Intelligent Transfer Service). BITS is being used excessively by VMM for file transfers.

Error (2912)
An internal error has occurred trying to contact an agent on the server.
(Unknown error (0x80041001))

Recommended Action
Ensure the agent is installed and running. Ensure the WS-Management service is installed and running, then restart the agent.

Possible fix:

import-module BitsTransfer
Get-BitsTransfer -AllUsers

Check for the output if you see any BITS jobs which are not owned by "NT AUTHORITY\SYSTEM" and have status "Suspended".

To delete the failed/corrupt BITS job you need to run:
import-module BitsTransfer
$AllJobs = Get-BitsTransfer -AllUsers
Remove-BitsTransfer -BitsJob $AllJobs

You will receive an "Access Denied" but this is ok as SYSTEM owned jobs cannot be deleted:

Remove-BitsTransfer : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))


List of known issues for Background Intelligent Transfer Service (BITS)

How to generate and correctly interpret Failover Cluster Log

July 2, 2011

Very often it is required to generate cluster log if the eventlog information’s are not enough to nail down your root cause and for getting a better understanding what is happening under the hood of your failover cluster.

Hereby are some useful articles and techniques for how to generate cluster logs and of course how to correctly read and interpret them:

Anatomy of a Cluster Log Entry

Techniques for Tracking the Source of a Problem

Interpreting the Cluster Log

Cluster Log Basics

Understanding the Cluster Debug Log in 2008

Windows Server 2008 and R2 Cluster Log Appears to Be Missing Gaps of Data

View Events and Logs for a Failover Cluster

TechNet Webcast: Failover Cluster Validation and Troubleshooting with Windows Server 2008 (Level 300)

Failover Clustering: Pro Troubleshooting in Windows Server 2008 (PPT)

How to create the cluster.log in Windows Server 2008 Failover Clustering

DBA 101: Collecting and Interpreting Failover Cluster Logs

Introduction to Cluster Diagnostics and Verification Tool for Exchange Administrators

How to turn on cluster logging in Microsoft Cluster Server (W2K3)

The meaning of state codes in the Cluster log

Failover Cluster Troubleshooting

Troubleshooting Cluster Logs 101 – Why did the resources failover to the other node?

Hope this helps to understand more what is going on under the hood of your failover cluster, especially in root cause analyses (RCA), test and/or proof-of-concept scenarios it is really helpful to be able to read and interpret the cluster logs.

Stay tuned Winking smile

Best Regards


Step-by-Step and Capacity Planning Guides for Remote Desktop Services–SP1 updated

June 14, 2011

Microsoft has released updated documents for host and capacity planning as well step-by-step documentation for their great and really powerfully new terminal service roles like Session Host, RD Web Access, RD Gateway (my favourite), RD Virtualization host…..with updated functionalities like RemoteFX for VDI scenarios based on Windows 2008 R2 SP1.

Here are consolidated links of some of those documents for download purposes:

Stay tuned…. Winking smile



Every 20 min an Event 1069 and 1558?

May 15, 2011

DISCLAIMER: Event 1069 is an generic event therefore you should check and decide by your own if this blog post is an possible solution for your scenario and environment. This can be verified in the cluster logs when you identify "‘Failed to create cluster directory on witness”! which is generated by Quorum Agent.


In a customer scenario we had identified every 20 min the events 1069 and 1558. They had pointed to quorum disk issues which we could not confirm in the 1st step as the disk was online and could be failed over to other nodes without any issues.

Event ID 1069 — Clustered Service or Application Availability

Event ID 1558 — Cluster Witness Functionality

After digging deeper and doing an cluster log analyses I had found an very interesting pointer there:

ERR mscs::QuorumAgent::PostOnline: ERROR_PATH_NOT_FOUND(3)’ because of ‘Failed to create cluster directory on witness, path \\?\Volume{5c65f7b0-15e4-11e0-b316-002655db949a}\Cluster

This tells me, that the cluster services has issues when trying to access the quorum disk when “he” want to write his cluster hive (=configuration) to the quorum disk.

As the cluster hive is “redundantly” available on each in the cluster and can also be manually created anytime when changing the cluster quorum configuration in your cluster, I used this scenario for troubleshooting my issue here.


1. Changing the Quorum Modell temporary to “Node Majority” so that I can remove the Quorum Disk “Q:” from the cluster (Note: When changing quorum model, be aware of the available “votes” (keep majority) in your cluster)



2. Remove Quorum Disk from Cluster , Re-Format with NTFS and back to Cluster

3. Restore Quorum model – in my case “Node und Disk Majority” and point to new-formatted Quorum disk Q:


Result:: Die Cluster Hive is newly created on Quorum Disk Q:\


After the cluster hive is successfully created from cluster service, all entries in cluster logs and also events 1069 and 1558 are gone Winking smile


General Information’s around Cluster Logs can be found here:

How to create the cluster.log in Windows Server 2008 Failover Clustering

Troubleshooting Cluster Logs 101 – Why did the resources failover to the other node?

Introduction to Cluster Diagnostics and Verification Tool for Exchange Administrators

….wish you good luck with “troubleshooting” clip_image010

Best Regards