Archive for June, 2009

Exchange 2007 DAS or SAN? Discussion goes on…

I have read about it in many places and my friend Rob actually posted once here about it. Should I use SAN for my Exchange 2007? Will DAS save me money? What about performance? How do I manage storage silos? Troubleshooting complexities in SAN deployments… many questions and many views, but rarely an answer.

There is a reason for it. One cannot definitively answer this question. There are collaterals published by both Microsoft and Storage vendors. Each for obvious reasons promoting different solution.

Microsoft IT published a whitepaper that discussed how Exchange 2007 storage solution was designed and what went into the decision process. Everyone has been reading into the cost savings not realizing that’s not the only takeaway from that whitepaper. To summarize, the following factors played key role:

  • Previous SAN failure and it’s impact on availability
  • Dependency on another group for managing and troubleshooting storage related issues
  • Scaling to higher capacity for each mailbox while controlling costs associated with storage

And these were not the only factors so don’t respond to me with list of other factors that I did not list here.

Microsoft IT deployed DAS based solution and shared their challenges, decision process and outcome along with benefits they reap from the solution implemented.

At the end of the day, the decision is going to be made based on lot of factors including business reasons. Business reasons playing a key role in decisions that will decide if you will implement SAN or DAS. Few I will list here:

  • Existing investment in SAN solutions
  • Existing knowledge and expertise in SAN solutions
  • Management of storage (who is responsible? Application group or Storage group)
  • Cost to implement DAS solution (learning curve, procedures, staff training, support)
  • Operational framework and responsibilities (who should manage storage)
  • Willingness of Storage group to dedicate storage and guarantee performance (dedicated disks on shared array vs. shared disks on shared array)
  • SLAs, Tolerances, Dependencies, Time to recover… the list goes on

As you can see, the factors I listed above are not all technical. Business decisions are made by asking these questions along with facts that answer technical questions related to performance, MTBF, complexity to implement and manage/troubleshoot and so on.

In the end, I am not writing this post to tell you what is the best answer to DAS vs SAN debate. I am writing this to give you some questions that can help you decide for yourself what is best for your environment.

 

“We are our best friend or worst enemies.”

 

Some references to aggregate:

How Microsoft IT Exceeds High-Availability Targets with Large Mailboxes at Low Costs Based on New Storage Designs

Some more thoughts on SAN v DAS. Is it actually time to consider DAS? – Doug Owans

Brian Henderson – Microsoft Exchange Server 2007 Storage Considerations: DAS or SAN

Share

Tags: , , ,

Exctrlst.exe – The case of missing Performance Coutners

Recently I wrote about how to fix Corrupt of Missing Performance Coutners on a Windows Server. If you read the KB Article mentioned, it may sound complicated. One of the steps is to go through registry and find all services that have performance subkey. This could be very time consuming and tedious.

Also, if you missed, the article does mention you have to make sure you rebuild counters from other programs such as Exchange Server and SQL server among others. It’s not part of rebuild process outlined in the KB.

So, I went digging for gold and found Exctrlst.exe. If you run the exe, it will bring up the UI and displays all registry-based performance counters installed on the system. There is a neat option in the UI. The check box “Performance Counter Enabled” allows you to see if you have any performance counters that are not loaded. The UI is not very helpful in making user aware that you can just click the checkbox if the counters are not loaded and it will load it for you. There are no “OK” or “Apply” buttons and change is instant.

There may be services that does not immediately reflect this and you may have to unload/reload counters but I will let you figure out how to do that. Most of the counters should load immediately and you should be able to report on them using Performance Monitor.

For those who need to see the gold I dug up, follow me.

P.S.: I have read some posts which confirms this will also work with Windows Server 2008. Don’t take it as my word, but you have one more reason to experiment.

Share

Tags:

Get-Service StartupType

If you want to find out startup type of a service using Get-Service cmdlet, you are out of luck. Get-Service cmdlet does not have StartupType property. Set-Service however does. So how can you find out the startup type of a service using powershell?

You can use Get-WmiObject.

(Get-WmiObject Win32_Service -filter "Name='W32Time'").StartMode

Once you determine the startup type of desired service, you can change it using Set-Service cmdlet:

Set-Service W32Time - StartupType Manual
Share

Tags:

Measure script run time

When I am writing PowerShell scripts, one thing that is always in my mind: How long will it take to run this script and what can I do to reduce the run time.

While optimizing the code itself is not the scope of this article, what I am going to write may help you determine how long your script, function or code sections takes to run.

Insert the following at start of the section of code you want to check:

# Get Start Time
$startDTM = (Get-Date)

Insert the following at the end of the section of code you want to check:

# Get End Time
$endDTM = (Get-Date)
 
# Echo Time elapsed
"Elapsed Time: $(($endDTM-$startDTM).totalseconds) seconds"

Here is an example of my code optimization:

BEFORE (Run Time 40.4 seconds):

filter GetMailboxCount{
$Server = $_
 
$strFilter = "(&(&(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(msExchHomeServerName=$Server)) ))))"
 
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
 
$colResults = $objSearcher.FindAll()
$colCount = ($colResults | Measure-Object | %{$_.Count})
"$Server,$colCount"
 
}

AFTER (Run Time 4.53 seconds):

filter GetMailboxCount{
$Server = $_
 
$strFilter = "(&(&(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(msExchHomeServerName=$Server)) ))))"
 
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
 
$colProplist = "name"
$retval = $colProplist | foreach {$objSearcher.PropertiesToLoad.Add($_)}
 
$colResults = $objSearcher.FindAll()
$colCount = ($colResults | Measure-Object | %{$_.Count})
"$Server,$colCount"
 
}

As you will see the “name” property is irrelevant to my code but by querying on indexed attribute and limiting scope of the query, I was able to improve run time ten folds. Now that is huge time savings when you have to run this code in a loop across all of your servers!

Share

Tags:

How do I check Rollup Update version on Exchange 2007 server?

This is one question that gets asked around many times! The article “Exchange Server 2007: Platforms, Editions and Versions” gives important information to identify the build numbers for each Rollup Updates, however, it is unclear where to look for this information.

To solve that problem, I have come up with a script which looks at Exsetup.exe version and registry entries for each Rollup Update installed…

Uh, what happened to the rest of this post?

Well, since I wrote a better script that handles both Exchange 2010 and Exchange 2007, I have removed this script. You can find new version here.

Share

Tags: ,

Corrupt or Missing Performance Counters

One of the functions in the code I posted in “Check Exchange 2003 vitals with PowerShell” is to check performance counters. When running the script, you may encounter an error:

Get-WmiObject : Invalid Class

 

This could happen for 2 reasons:

1: You have a typo in Perf Counter object.

2: The performance counter is missing on the host you are checking.

 

When this happened to me, I checked and verified this by loading performance monitor on affected server and trying to load Memory counters which the code was checking for. To no surprise, I found that the server did not have Memory object.

There are many reasons why the performance object could go missing from the OS. The KB article “How to manually rebuild Performance Counter Library values” explains how you can resolve this problem and bring the missing performance counter objects back.

Share

Tags: , ,

Check Exchange 2003 vitals with PowerShell – Part II

In continuation to my previous post “Check Exchange 2003 vitals with PowerShell”, I also have a code block that you can replace if you want to query all exchange servers in your environment dynamically with script instead of using text file as in the code I posted earlier.

In the code I posted earlier, the following lines read the file servers.txt.

1
2
3
# Read file and store server names in variable
 
$Servers = (Get-Content .\servers.txt)

Replace it with the following, which queries Active Directory for objectclass msExchExchangeServer and returns all servers found.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Get Exchange Servers from Active Directory
 
function GetExchangeServers()
{
	# Set variables to connect to Active Directory, searching Configuration Naming Context
	$root= New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
	$configpartition = [adsi]("LDAP://CN=Microsoft Exchange,CN=Services," + $root.configurationNamingContext)
 
	# Set variables for search criteria
	$search = New-Object System.DirectoryServices.DirectorySearcher($configpartition)
	$search.filter = '(objectclass=msExchExchangeServer)'
 
	# Perform Serach, this will return all Exchange Server objects
	$ExchServer = $search.FindAll()
 
	# Output Name property of each server object stored in ExchServer array
	$ExchServer | foreach {$_.properties.name}
 
	# Comment the line above and uncomment the line below if you want to search specific Exchange servers by name
	# The example filter below will only output servers that have MBX in their name (i.e. MBX01, SRVMBX45 etc.)
	#$ExchServer | foreach {$_.properties.legacyexchangedn -match "MBX"}
}

You will also have to replace the lines:

1
2
# Get vitals for each server stored in $Servers array
$Servers | %{getVitals}

with the following:

1
2
# Get vitals for each server stored in $Servers array
GetExchangeServers | %{getVitals}


Comments welcome.

Share

Tags: ,

Check Exchange 2003 vitals with PowerShell

I have written recently about Free System PTEs and /PAE usage in Exchange 2003 mailbox servers.

I set out to write a PowerShell script that will run against given list of servers and report back certain vitals including boot.ini settings, SystemPages registry setting and current performance data for Free Sytem PTEs and Pool Non-Paged Bytes.

 

The output csv can be used as a checkpoint for server health and can be used for reporting matrix. The script can easily be modified to add more performance counters and registry checks as necessary.

 

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
# Read file and store server names in variable
 
$Servers = (Get-Content .\servers.txt)
 
# Write header in output file
 
# Store header in variable
$headerLine =
@"
 
Server Name,Boot String,3GB,PAE,UserVA,Basevideo,SystemPages,Free System PTEs, Pool Non-Paged Bytes
"@
 
# Write header to file
$headerLine | Out-File .\results.csv -Encoding ASCII -Append
 
function getVitals()
 
{
	# Set server to connect to
	$Server = "$_"
 
# Read SystemPages from servers
 
	# Set Registry Key variables
	$REG_KEY = "System\\CurrentControlSet\\Control\\Session Manager\\Memory Management"
	$VALUE = "SystemPages"
 
	# Open remote registry
	$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Server)
 
	# Open the targeted remote registry key/subkey
	$regKey= $reg.OpenSubKey($REG_KEY)
 
	# Read and Store SystemPages value in variable
	$SystemPages = $regkey.getvalue($VALUE)
 
	# Close the Reg Key
	$regKey.Close()
 
# Read Boot.ini from Servers
 
	# Store Boot.ini contents in variable
	$iniContent = Get-Content "\\$Server\c$\boot.ini"
 
	# Store Boot string and values in variables
	$bootString = $iniContent[4] -replace ","," "
	$userva = ($bootString -split " " | foreach {if ($_ -match "userva") {$_}} | foreach {$_ -replace "/userva=",""})
 
	if ($iniContent[4] -match "3gb") {$3gb="Present"} else {$3gb="Missing"}
	if ($iniContent[4] -match "PAE") {$pae="Present"} else {$pae="Missing"}
	if ($iniContent[4] -match "basevideo") {$basevideo="Present"} else {$userva="Missing"}
 
# Read System Pages and NPP values from Performance Counters
 
	# Read performance counters
	$freeSPTEs = (Get-WmiObject Win32_PerfFormattedData_PerfOS_Memory -ComputerName $Server).FreeSystemPageTableEntries
	$poolNPBytes = (Get-WmiObject Win32_PerfFormattedData_PerfOS_Memory -ComputerName $Server).PoolNonPagedBytes
 
# Write data to file
 
	# Store result string in a variable
	$result = "$Server,$bootString,$3gb,$pae,$userva,$basevideo,$SystemPages,$freeSPTEs,$poolNPBytes"
 
	# Write results to file
	$result | Out-File .\results.csv -Encoding ASCII -Append
 
}
 
 
# Get vitals for each server stored in $Servers array
$Servers | %{getVitals}
Share

Tags: ,