Tuesday, 7 April 2009

Putting Shay's Powershell Registry Functions To Use

Recently I needed to check some registry key values on a bunch of servers. There were far too many servers to make this a manual task and in addition if they weren't what I was expecting then I needed to change them.

Shay Levy has very helpfully published a Stand Alone Registry Functions Library which I made use of. It allows you to query and set registry values for things such as DWords, Strings, Binary Values on remote machines very easily. In my case I was particularly interested in some configuration settings for the ICA protocol, HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\ICA-tcp, all of them DWords.

First of all we use Shay's Get-RegDWord function at the top of the script which contains some .NET code to query a remote registry


function Get-RegDWord{
param(
[
string]$server = ".",
[
string]$hive,
[
string]$keyName,
[
string]$valueName,
[
object]$defaultValue="Your default value"
)

$hives = [enum]::getnames([Microsoft.Win32.RegistryHive])

if($hives -notcontains $hive){
write-error "Invalid hive value";
return;
}
$regHive = [Microsoft.Win32.RegistryHive]$hive;
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($regHive,$server);
$subKey = $regKey.OpenSubKey($keyName);

if(!$subKey){
write-error "The specified registry key does not exist.";
return;
}
$subKey.GetValue($valueName,$defaultValue);
}
Then we specify the list of servers to query. You could either use something like:

$servers = Get-Content servers.txt
or in my case they were all virtual servers in VMware so I used a couple of VI Toolkit commands to specify the list

# Connect to Virtual Center
Connect-VIServer vc

# Get a list of all the powered on APP servers
$servers = Get-Folder 'Servers' | Get-VM | Where-Object {$_.Powerstate -eq 'PoweredOn'}

Then we loop through each server, call Shay's Get-RegDWord function for each of the DWords we are interested in and store the results in the $myCOl variable. At the end we export the $myCol variable into a CSV file for handy viewing.

# Create an empty array to store the results in
$myCol = @()

foreach ($server in $servers){

$hive = 'LocalMachine'
$keyname = 'System\CurrentControlSet\Control\Terminal Server\WinStations\ICA-tcp'

# Find MaxIdleTime
$valuename = 'MaxIdleTime'
$MaxIdleTime = Get-RegDWord $server $hive $keyName $valueName

# Find fInheritMaxIdleTime
$valueName = 'fInheritMaxIdleTime'
$fInheritMaxIdleTime = Get-RegDWord $server $hive $keyName $valueName

# Find MaxDisconnectionTime
$valueName = 'MaxDisconnectionTime'
$MaxDisconnectionTime = Get-RegDWord $server $hive $keyName $valueName

# Find fInheritMaxDisconnectionTime
$valueName = 'fInheritMaxDisconnectionTime'
$fInheritMaxDisconnectionTime = Get-RegDWord $server $hive $keyName $valueName

# Add the results to the $MYInfo variable, then $myCol
$MYInfo = "" | select-Object Name,MaxIdleTime,fInheritMaxIdleTime,MaxDisconnectionTime,fInheritMaxDisconnectionTime
$MYInfo.Name = $server
$MYInfo.MaxIdleTime = $MaxIdleTime
$MYInfo.fInheritMaxIdleTime = $fInheritMaxIdleTime
$MYInfo.MaxDisconnectionTime = $MaxDisconnectionTime
$MYInfo.fInheritMaxDisconnectionTime = $fInheritMaxDisconnectionTime
$myCol += $MYInfo

}

# Export the results to a csv file
$myCol | Export-Csv citrixservers.csv -NoTypeInformation

Now that we can view the results I was able to see that I needed to set a lot of these values to something new. Using Shay's Set-RegDWord function it is a pretty straightfoward task to extend the above to do that. First of all add the function to the top of the script.


function Set-RegDWord{
param(
[
string]$server = ".",
[
string]$hive,
[
string]$keyName,
[
string]$valueName,
[
double]$value
)

$hives = [enum]::getnames([Microsoft.Win32.RegistryHive])

if($hives -notcontains $hive){
write-error "Invalid hive value";
return;
}
$regHive = [Microsoft.Win32.RegistryHive]$hive;
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($regHive,$server);
$subKey = $regKey.OpenSubKey($keyName,$true);

if(!$subKey){
write-error "The specified registry key does not exist.";
return;
}
$subKey.SetValue($valueName, $value,[Microsoft.Win32.RegistryValueKind]::DWord);
if($?) {$true} else {$false}
}

Then for each of the values you want to change use an if statement to check whether it needs changing and if so call Shay's Set-RegDword to make the necessary changes.



    # Find fInheritMaxIdleTime
$valueName = 'fInheritMaxIdleTime'
$fInheritMaxIdleTime = Get-RegDWord $server $hive $keyName $valueName

# Check the value and change if necessary
if ($fInheritMaxIdleTime -eq 1){

$value = '0'
Set-RegDWord $server $hive $keyName $valueName $value

}

Thanks again to Shay for publishing these functions, it made this particular task very easy to complete and I'm sure I'll be using them again in the future.

2 comments:

Anonymous said...

Hi Jonathan.

I've referenced your page for serveral helpful things, but I'm currrently stuck.

The value I need to query in the registry is the (default) value of a key, yet I cannot get a return.

the GetValueNames displays only a carriage return.

Anyhelp would be excellent!

Jonathan Medd said...

Have you tried the Get-RegDefault function over on Shay's blog?

http://blogs.microsoft.co.il/blogs/scriptfanatic/archive/2007/10/30/stand-alone-registry-functions-library.aspx