Throttling PowerShell command usage in Exchange 2010

Throttling PowerShell command usage in Exchange 2010



Administrative actions are based on PowerShell. Some administrative actions, like running large scripts, can be resource intensive. Throttling PowerShell can help lessen the strain on a server’s performance.


Exchange’s Web services (EWS) rely on remote shell sessions. Because of this, throttling PowerShell can help prevent a user from overloading Exchange by performing concurrent actions through multiple browsers.


Exchange Server 2010 provides several different parameters you can use to throttle PowerShell command usage. One such parameter is PowerShellMaxConcurrency. This parameter can be tricky because its function varies depending on the context.


When a user establishes a remote shell, the PowerShellMaxConcurrency parameter defines the maximum number of simultaneous remote shell sessions that a user can have open. This parameter may also be applied to EWS. In this case, the parameter controls the maximum number of cmdlets that a user can simultaneously run.


Where PowerShell throttling and throttling policy parameters differ

Unlike the PercentTimeIn parameter, PowerShell throttling parameters don’t automatically assume that you want to throttle commands based on percentages of a minute. Instead, you must explicitly define your desired throttling time period by assigning a period of time (in seconds) to the PowerShellMaxCmdletsTimePeriod parameter. After doing this, you can control the maximum number of PowerShell cmdlets that are allowed to run within the designated period by assigning a value to the PowerShellMaxCmdlets parameter.

One PowerShell throttling parameter that I recommend avoiding is PowerShellMaxCmdletQueueDepth, which controls the total number of PowerShell cmdlets that can be simultaneously queued. Using this parameter can have several side effects.


Modifying the PowerShellMaxCmdletQueueDepth parameter affects PowerShellMaxCmdlets and PowerShellMaxConcurrency settings, both of which already skew cmdlet depth. The PoweShellMaxConcurrency parameter limits the number of concurrent remote shell sessions that a user can have open, so it also limits the number of simultaneous cmdlets that can run. The parameter can also limit the number of browser sessions that a user can have open.


When you’re using the PowerShellMaxCmdletQueueDepth parameter, it has the same effect as decreasing the PowerShellMaxConcurrency setting by two. If you do decide to use this parameter, Microsoft recommends that you set its value to at least three times the value of the PowerShellMaxConcurrency parameter.


Note: Throttling the PowerShellMaxCmdletQueueDepth won’t affect the Exchange Control Panel or EWS.


DNS Zone Information CSV collector

This script takes command line arguments of a remote dns server, uses dnscmd to collect all the zones and some extended information about them and outputs to a csv file with the name of the remote server. You can input multiple remote servers. I have only tested this with windows 2003 server, if 2008 dnscmd output is the same format it should work as well. I wrote this to collect information on scavenging settings, so the output is more focused on that. You will need to know what the numeric values of the /zoneinfo results mean in order to interpret the csv file output.

Script Code (Perl)

#dns zone enumeration and detail gathering

#run the command with arguments of the dns servers hosting the zones. This script enumerates

#all zones, collects some of the extended details and outputs to CSV format. Requires dnscmd.exe and

#appropriate rights on the remote machine

foreach (@ARGV) {

my $filename = $_ . “.csv”;

open OUTFILE, “>$filename”

die “Can’t open output file\n”;

print OUTFILE “Zone Name,Type,Storage,Updates,DS Integrated,Aging On,Refresh Aging,No Refresh Aging,Scavenge Available\n”;

my $dnsserver = $_;

$output = `dnscmd $dnsserver /enumzones`;

@outputarr = split(/\n/,$output);

$beginning = 0;

foreach (@outputarr) {

if (!($beginning)) {

if ($_ =~ /Zone name/) {

$beginning = 1;

}

} else {

chomp($_);

$_ =~ s/^\s//;

my @temparr = split(/\s+/,$_);

if ($temparr[0] =~ /\./) {

#proper zone found,

#Format: Name, Type, Storage, Properties(multiple)

# properties Secure Rev Aging

my $details = getdetail($dnsserver,$temparr[0]);

my $outline = “$temparr[0],$temparr[1],$temparr[2],$details”;

print OUTFILE $outline;

}

}

} #end of all output from enumzones

close OUTFILE;

} #end foreach server’s passed as args

sub getdetail {

my ($dnsserver,$zone) = @_;

my $zoneinfo = `dnscmd $dnsserver /zoneinfo $zone`;

my @zonedetails = split(/\n/,$zoneinfo);

my ($zoneupdate, $dsintegrated, $aging, $agerefresh, $age_no_refresh, $scavenge_avail) = “”;

foreach (@zonedetails) {

my $line = $_;

if ($line =~ /update/) {

$zoneupdate = parsevalue($line);

} elsif ($line =~ /aging/) {

$aging = parsevalue($line);

} elsif ($line =~ /DS integrated/) {

$dsintegrated = parsevalue($line);

} elsif ($line =~ /refresh interval/) {

$agerefresh = parsevalue($line);

} elsif ($line =~ /no refresh/) {

$age_no_refresh = parsevalue($line);

} elsif ($line =~ /scavenge available/) {

$scavenge_avail = parsevalue($line);

}

} #end details

my $retval = “$zoneupdate,$dsintegrated,$aging,$agerefresh,$age_no_refresh,$scavenge_avail\n”;

return $retval;

}

sub parsevalue {

my $val = @_[0];

my @temparr = split(/=/, $val);

$val = $temparr[1];

$val =~ s/ //g;

chomp $val;

return $val;

}