You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2009/06/01 19:51:52 UTC

svn commit: r780755 - in /incubator/vcl/trunk/managementnode/lib/VCL/Module/OS: Windows_mod.pm Windows_mod/Version_5.pm Windows_mod/Version_5/XP_mod.pm Windows_mod/Version_6.pm Windows_mod/Version_6/ Windows_mod/Version_6/Vista_mod.pm

Author: arkurth
Date: Mon Jun  1 17:51:52 2009
New Revision: 780755

URL: http://svn.apache.org/viewvc?rev=780755&view=rev
Log:
VCL-23
Made several minor improvements to Windows modules during testing.

Windows_mod.pm:
-Added check for 'end_state' argument in pre_capture() so child classes don't have to check for it
-Set pre_capture() to disable RDP before capture instead of enabling it for 10.x.x.x addresses in case these addresses are used for public access. Also set post_load to enable RDP on the private interface.
-Added call to post_load() to set the computer name. The script that runs during Sysprep does not always work correctly.
-Commented out disable_netbios() and disable_dynamic_dns() calls from post_load() to speed things up. These can be controlled by OS config variables some day.
-Moved grant_access() and revoke_access() within the file so they appear under the pod section for interface functions.
-Added max_depth argument and default setting to delete_files_by_pattern(). This was running very slow on Vista when searching directories with many files.
-Changed enable_pagefile() and disable_pagefile() to call reg.exe instead of importing a .reg file. The pagefile key should be a REG_MULTI_SZ. This type is difficult to configure using a .reg file.
-Changed enable_pagefile() to set the registry key to C:\pagefile.sys instead of ?:\pagefile.sys. The question mark string worked but the interface to control the pagefile did not reflect the actual setting properly.
-Changed import_registry_string() to name the temporary .reg file after the sub and line number which called it so it's easy to determine where the .reg file came from.
-Added shutdown() subroutine. This is called after newsid.exe runs.
-Changed run_newsid() to not rename the computer. This is done elsewhere.
-Added commands to disable_dynamic_dns() to disable DNS updating for each adapter.
-Added firewall_enable_rdp_private() sub which will allow RDP only on the private interface.
-Added get_node_configuration_directory() so child classes can use the variable stored in Windows_mod.pm. It is the location on the node where VCL files are stored.
-Added set_computer_name() which sets registry entries to rename the computer.

Version_5.pm:
-Added argument to SUPER::pre_capture() call to pass the args which were passed to it.

XP_mod.pm:
-Removed end_state argument check. This was moved up to Windows_mod.pm so other classes don't duplicate the code. This is only possible by passing the arguments up to the parent's subroutine.

Added Version_6.pm, Version_6 directory, and Vista_mod.pm.




Added:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6/
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6/Vista_mod.pm
Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5/XP_mod.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod.pm?rev=780755&r1=780754&r2=780755&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod.pm Mon Jun  1 17:51:52 2009
@@ -117,11 +117,19 @@
 		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
 		return;
 	}
+	
+	# Check if end_state argument was passed
+	if (defined $args->{end_state}) {
+		$self->{end_state} = $args->{end_state};
+	}
+	else {
+		$self->{end_state} = 'off';
+	}
 
 	my $computer_node_name = $self->data->get_computer_node_name();
 
-	notify($ERRORS{'OK'}, 0, "beginning Windows image capture preparation tasks on $computer_node_name, end state: $self->{end_state}");
-	
+	notify($ERRORS{'OK'}, 0, "beginning Windows image capture preparation tasks on $computer_node_name");
+
 =item 1
 
 Log off all currently logged in users
@@ -197,7 +205,6 @@
 		notify($ERRORS{'WARNING'}, 0, "unable to disable dynamic dns");
 	}
 	
-	
 =item *
 
 Disable Internet Explorer configuration page
@@ -262,7 +269,7 @@
 	
 =item *
 
-Allow users to connect remoteley
+Allow users to connect remotely
 
 =cut
 
@@ -272,12 +279,12 @@
 
 =item *
 
-Enable RDP access from private IP addresses by adding a firewall exception
+Disable RDP access from any address by adding a firewall exception
 
 =cut
 
-	if (!$self->firewall_enable_rdp('10.0.0.0/8')) {
-		notify($ERRORS{'WARNING'}, 0, "unable to enable RDP from private IP addresses");
+	if (!$self->firewall_disable_rdp()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable RDP from all addresses");
 		return 0;
 	}
 
@@ -371,7 +378,7 @@
 
 	notify($ERRORS{'OK'}, 0, "beginning Windows post-load tasks");
 
-=item *
+=item 1
 
 Log off all currently logged in users
 
@@ -380,15 +387,25 @@
 	if (!$self->logoff_users()) {
 		notify($ERRORS{'WARNING'}, 0, "failed to log off all currently logged in users");
 	}
+	
+=item *
+
+Set the computer name
+
+=cut
+
+	if (!$self->set_computer_name()) {
+		notify($ERRORS{'WARNING'}, 0, "failed to set the computer name");
+	}
 
 =item *
 
-Enable RDP access from private IP addresses by adding a firewall exception
+Enable RDP access only from private network by adding a firewall exception
 
 =cut
 
-	if (!$self->firewall_enable_rdp('10.0.0.0/8')) {
-		notify($ERRORS{'WARNING'}, 0, "unable to enable RDP from private IP addresses");
+	if (!$self->firewall_enable_rdp_private()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to enable RDP on private network");
 		return 0;
 	}
 	
@@ -422,25 +439,25 @@
 		notify($ERRORS{'WARNING'}, 0, "failed to rename My Computer");
 	}
 
-=item *
-
-Disable NetBIOS
-
-=cut
-
-	if (!$self->disable_netbios()) {
-		notify($ERRORS{'WARNING'}, 0, "failed to disable NetBIOS");
-	}
-
-=item *
-
-Disable dynamic DNS
-
-=cut
+#=item *
+#
+#Disable NetBIOS
+#
+#=cut
+#
+#	if (!$self->disable_netbios()) {
+#		notify($ERRORS{'WARNING'}, 0, "failed to disable NetBIOS");
+#	}
 
-	if (!$self->disable_dynamic_dns()) {
-		notify($ERRORS{'WARNING'}, 0, "failed to disable dynamic DNS");
-	}
+#=item *
+#
+#Disable dynamic DNS
+#
+#=cut
+#
+#	if (!$self->disable_dynamic_dns()) {
+#		notify($ERRORS{'WARNING'}, 0, "failed to disable dynamic DNS");
+#	}
 
 =item *
 
@@ -463,16 +480,6 @@
 	if (!$self->set_password('Administrator', $administrator_random_password)) {
 		notify($ERRORS{'WARNING'}, 0, "failed to set random Administrator password");
 	}
-	
-#=item *
-#
-#Create scheduled task to run script at computer startup
-#
-#=cut
-#
-#	if (!$self->create_startup_scheduled_task('System Startup Script', 'cmd.exe /c start "system_startup.cmd" /MIN cmd.exe /c "' . $NODE_CONFIGURATION_DIRECTORY . '/Scripts/system_startup.cmd  >> ' . $NODE_CONFIGURATION_DIRECTORY . '/Logs/system_startup.log 2>&1"', 'root', $root_random_password)) {
-#		notify($ERRORS{'WARNING'}, 0, "failed to create scheduled task to run system_startup.cmd at computer startup");
-#	}
 
 =item *
 
@@ -484,7 +491,7 @@
 		notify($ERRORS{'OK'}, 0, "imagemeta postoption reboot is set for image, rebooting computer");
 		if (!$self->reboot()) {
 			notify($ERRORS{'WARNING'}, 0, "failed to reboot the computer");
-			return 0;
+			return;
 		}
 	}
 
@@ -578,6 +585,107 @@
 	return 1;
 } ## end sub sanitize
 
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 grant_access
+
+ Parameters  :
+ Returns     :
+ Description :
+
+=cut
+
+sub grant_access {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+
+	my $management_node_keys = $self->data->get_management_node_keys();
+	my $computer_node_name   = $self->data->get_computer_node_name();
+	my $remote_ip            = $self->data->get_reservation_remote_ip();
+	my $multiple_users       = $self->data->get_imagemeta_usergroupmembercount();
+	my $request_forimaging   = $self->data->get_request_forimaging();
+
+	# Check to make sure remote IP is defined
+	my $remote_ip_range;
+	if (!$remote_ip) {
+		notify($ERRORS{'WARNING'}, 0, "reservation remote IP address is not set in the data structure, opening RDP to any address");
+	}
+	elsif ($multiple_users) {
+		notify($ERRORS{'OK'}, 0, "reservation has multiple users, opening RDP to any address");
+	}
+	elsif ($remote_ip !~ /^(\d{1,3}\.?){4}$/) {
+		notify($ERRORS{'WARNING'}, 0, "reservation remote IP address format is invalid: $remote_ip, opening RDP to any address");
+	}
+	else {
+		# Assemble the IP range string in CIDR notation
+		$remote_ip_range = "$remote_ip/16";
+		notify($ERRORS{'OK'}, 0, "RDP will be allowed from $remote_ip_range on $computer_node_name");
+	}
+
+	# Set the $remote_ip_range variable to the string 'all' if it isn't already set (for display purposes)
+	$remote_ip_range = 'all' if !$remote_ip_range;
+
+	# Allow RDP connections
+	if ($self->firewall_enable_rdp($remote_ip_range)) {
+		notify($ERRORS{'OK'}, 0, "firewall was configured to allow RDP access from $remote_ip_range on $computer_node_name");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "firewall could not be configured to grant RDP access from $remote_ip_range on $computer_node_name");
+		return 0;
+	}
+
+	# If this is an imaging request, make sure the Administrator account is enabled
+	if ($request_forimaging) {
+		notify($ERRORS{'DEBUG'}, 0, "imaging request, making sure Administrator account is enabled");
+		if ($self->enable_user('Administrator')) {
+			notify($ERRORS{'OK'}, 0, "Administrator account is enabled for imaging request");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "failed to enable Administrator account for imaging request");
+			return 0;
+		}
+	} ## end if ($request_forimaging)
+
+	notify($ERRORS{'OK'}, 0, "access has been granted for reservation on $computer_node_name");
+	return 1;
+} ## end sub grant_access
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 revoke_access
+
+ Parameters  :
+ Returns     :
+ Description :
+
+=cut
+
+sub revoke_access {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+
+	my $management_node_keys = $self->data->get_management_node_keys();
+	my $computer_node_name   = $self->data->get_computer_node_name();
+
+	# Disallow RDP connections
+	if ($self->firewall_disable_rdp()) {
+		notify($ERRORS{'OK'}, 0, "firewall was configured to deny RDP access on $computer_node_name");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "firewall could not be configured to deny RDP access on $computer_node_name");
+		return 0;
+	}
+
+	notify($ERRORS{'OK'}, 0, "access has been revoked to $computer_node_name");
+	return 1;
+} ## end sub revoke_access
+
 ##############################################################################
 
 =head1 AUXILIARY OBJECT METHODS
@@ -855,6 +963,7 @@
 
 	my $base_directory = shift;
 	my $pattern        = shift;
+	my $max_depth      = shift || '5';
 
 	# Make sure base directory and pattern were specified
 	if (!($base_directory && $pattern)) {
@@ -865,12 +974,12 @@
 	# Make sure base directory has trailing / or else find will fail
 	$base_directory =~ s/[\/\\]*$/\//;
 
-	notify($ERRORS{'DEBUG'}, 0, "attempting to delete files under $base_directory matching pattern $pattern");
+	notify($ERRORS{'DEBUG'}, 0, "attempting to delete files under $base_directory matching pattern $pattern, max depth: $max_depth");
 	
 	# Assemble command
 	# Use find to locate all the files under the base directory matching the pattern specified
 	# chmod 777 each file then call rm
-	my $command = "/bin/find.exe \"$base_directory\" -mindepth 1 -iregex \"$pattern\" -exec chmod 777 {} \\; -exec rm -rvf {} \\;";
+	my $command = "/bin/find.exe \"$base_directory\" -mindepth 1 -maxdepth $max_depth -iregex \"$pattern\" -exec chmod 777 {} \\; -exec rm -rvf {} \\;";
 	my ($exit_status, $output) = run_ssh_command($computer_node_name, $management_node_keys, $command, '', '', 1);
 	if (defined($exit_status)) {
 		my @deleted = grep(/removed /, @$output);
@@ -1380,14 +1489,13 @@
  Description : 
 
 =cut
-
 sub set_password {
 	my $self = shift;
 	if (ref($self) !~ /windows/i) {
 		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
 		return;
 	}
-
+	
 	my $management_node_keys = $self->data->get_management_node_keys();
 	my $computer_node_name   = $self->data->get_computer_node_name();
 
@@ -1431,7 +1539,7 @@
 
 	# Attempt to change scheduled task passwords
 	notify($ERRORS{'DEBUG'}, 0, "changing passwords for scheduled tasks");
-	my ($schtasks_query_exit_status, $schtasks_query_output) = run_ssh_command($computer_node_name, $management_node_keys, "schtasks.exe /Query /V /FO LIST");
+	my ($schtasks_query_exit_status, $schtasks_query_output) = run_ssh_command($computer_node_name, $management_node_keys, "schtasks.exe /Query /V /FO LIST", '', '', 1);
 	if (defined($schtasks_query_exit_status) && $schtasks_query_exit_status == 0) {
 		notify($ERRORS{'DEBUG'}, 0, "queried scheduled tasks on $computer_node_name");
 	}
@@ -1446,7 +1554,6 @@
 	for my $schtasks_output_line (@{$schtasks_query_output}) {
 		if ($schtasks_output_line =~ /TaskName:\s+([ \S]+)/i) {
 			$task_name = $1;
-			notify($ERRORS{'DEBUG'}, 0, "found task: " . string_to_ascii($task_name));
 		}
 		if ($schtasks_output_line =~ /Run As User.*\\$username/i) {
 			notify($ERRORS{'DEBUG'}, 0, "password needs to be updated for scheduled task: $task_name\n$schtasks_output_line");
@@ -1541,21 +1648,21 @@
 	my $management_node_keys = $self->data->get_management_node_keys();
 	my $computer_node_name   = $self->data->get_computer_node_name();
 
-	my $registry_string .= <<"EOF";
-Windows Registry Editor Version 5.00
-
-[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management]
-"PagingFiles"=""
-EOF
-
-	# Import the string into the registry
-	if ($self->import_registry_string($registry_string)) {
-		notify($ERRORS{'OK'}, 0, "set the registry key to disable the pagefile");
+	# Set the registry key to blank
+	my $memory_management_key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management';
+	my $reg_add_command = '$SYSTEMROOT/System32/reg.exe add "' . $memory_management_key . '" /v PagingFiles /d "" /t REG_MULTI_SZ /f';
+	my ($reg_add_exit_status, $reg_add_output) = run_ssh_command($computer_node_name, $management_node_keys, $reg_add_command, '', '', 1);
+	if (defined($reg_add_exit_status) && $reg_add_exit_status == 0) {
+		notify($ERRORS{'OK'}, 0, "set registry key to disable pagefile");
 	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to set the registry key to disable the pagefile");
+	elsif (defined($reg_add_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to set registry key to disable pagefile, exit status: $reg_add_exit_status, output:\n@{$reg_add_output}");
 		return 0;
 	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to set registry key to disable pagefile");
+		return;
+	}
 
 	# Attempt to reboot the computer in order to delete the pagefile
 	if ($self->reboot()) {
@@ -1594,22 +1701,22 @@
 
 	my $management_node_keys = $self->data->get_management_node_keys();
 	my $computer_node_name   = $self->data->get_computer_node_name();
-
-	my $registry_string .= <<"EOF";
-Windows Registry Editor Version 5.00
-
-[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management]
-"PagingFiles"="?:\\\\pagefile.sys"
-EOF
-
-	# Import the string into the registry
-	if ($self->import_registry_string($registry_string)) {
-		notify($ERRORS{'OK'}, 0, "set registry key to enable the pagefile");
+	
+	my $memory_management_key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management';
+	
+	my $reg_add_command = '$SYSTEMROOT/System32/reg.exe add "' . $memory_management_key . '" /v PagingFiles /d "$SYSTEMDRIVE\\pagefile.sys 0 0" /t REG_MULTI_SZ /f';
+	my ($reg_add_exit_status, $reg_add_output) = run_ssh_command($computer_node_name, $management_node_keys, $reg_add_command, '', '', 1);
+	if (defined($reg_add_exit_status) && $reg_add_exit_status == 0) {
+		notify($ERRORS{'OK'}, 0, "set registry key to enable pagefile");
 	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to set registry key to enable the pagefile");
+	elsif (defined($reg_add_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to set registry key to enable pagefile, exit status: $reg_add_exit_status, output:\n@{$reg_add_output}");
 		return 0;
 	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to set registry key to enable pagefile");
+		return;
+	}
 
 	return 1;
 } ## end sub enable_pagefile
@@ -1765,9 +1872,16 @@
 
 	# Replace regular newlines with Windows newlines
 	$registry_string =~ s/\r?\n/\r\n/gs;
+	
+	# Remove spaces from end of file
+	$registry_string =~ s/\s+$//;
 
-	# Specify where on the node the temporary registry file will reside
-	my $temp_registry_file_path = 'C:/Cygwin/tmp/vcl_import.reg';
+	# Assemble a temporary registry file path
+	# Name the file after the sub which called this so you can tell where the .reg file was generated from
+	my @caller = caller(1);
+	my ($calling_sub) = $caller[3] =~ /([^:]+)$/;
+	my $calling_line = $caller[2];
+	my $temp_registry_file_path = "C:/Cygwin/tmp/$calling_sub\_$calling_line.reg";
 
 	# Echo the registry string to a file on the node
 	my $echo_registry_command = "rm -f $temp_registry_file_path; /usr/bin/echo.exe -E \"$registry_string\" > " . $temp_registry_file_path;
@@ -2346,6 +2460,63 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 shutdown
+
+ Parameters  : 
+ Returns     : 
+ Description : 
+
+=cut
+
+sub shutdown {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+
+	my $management_node_keys = $self->data->get_management_node_keys();
+	my $computer_node_name   = $self->data->get_computer_node_name();
+
+	notify($ERRORS{'DEBUG'}, 0, "$computer_node_name will be shut down");
+
+	# Initiate the shutdown.exe command to reboot the computer
+	my $shutdown_command = "C:/Windows/system32/shutdown.exe -s -t 0 -f";
+	my ($shutdown_exit_status, $shutdown_output) = run_ssh_command($computer_node_name, $management_node_keys, $shutdown_command);
+	if (defined($shutdown_exit_status) && $shutdown_exit_status == 0) {
+		notify($ERRORS{'DEBUG'}, 0, "executed shutdown command on $computer_node_name");
+		
+		# Wait maximum of 3 minutes for the computer to become unresponsive
+		if ($self->wait_for_no_ping(3)) {
+			notify($ERRORS{'OK'}, 0, "computer has become unresponsive after shutdown command was issued");
+			return 1;
+		}
+		else {
+			# Computer never stopped responding to ping
+			notify($ERRORS{'WARNING'}, 0, "$computer_node_name never became unresponsive after shutdown command was issued, attempting power off");
+		}
+	}
+	elsif (defined($shutdown_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute shutdown command on $computer_node_name, exit status: $shutdown_exit_status, output:\n@{$shutdown_output}");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to shutdown $computer_node_name");
+	}
+	
+	# Call provisioning module's power_off() subroutine
+	if ($self->provisioner->power_off()) {
+		notify($ERRORS{'OK'}, 0, "powered off $computer_node_name");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to power off $computer_node_name");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 wait_for_ping
 
  Parameters  : Maximum number of minutes to wait (optional)
@@ -2643,21 +2814,12 @@
 	my $computer_node_name   = $self->data->get_computer_node_name();
 	my $computer_id          = $self->data->get_computer_id();
 
-	# Attempt to get the computer name from the arguments
-	# If no argument was supplied, use the name specified in the DataStructure
-	my $computer_name = shift;
-	if (!(defined($computer_name))) {
-		my $image_id            = $self->data->get_image_id();
-		my $computer_short_name = $self->data->get_computer_short_name();
-		$computer_name = "$computer_short_name-$image_id";
-	}
-
-	my $registry_string .= <<"EOF";
+	my $registry_string .= <<'EOF';
 Windows Registry Editor Version 5.00
 
 ; This registry file contains the entries to bypass the license agreement when newsid.exe is run
 
-[HKEY_CURRENT_USER\\Software\\Sysinternals\\NewSID]
+[HKEY_CURRENT_USER\Software\Sysinternals\NewSID]
 "EulaAccepted"=dword:00000001
 EOF
 
@@ -2669,22 +2831,22 @@
 		notify($ERRORS{'WARNING'}, 0, "failed to add newsid eulaaccepted registry string");
 		return 0;
 	}
-
+	
 	# Attempt to run newsid.exe
 	# newsid.exe should automatically reboot the computer
 	# It isn't done when the process exits, newsid.exe starts working and immediately returns
 	# NewSid.exe [/a[[/n]|[/d <reboot delay (in seconds)>]]][<new computer name>]
 	# /a - run without prompts
 	# /n - Don't reboot after automatic run
-	my $newsid_command               = "\"$NODE_CONFIGURATION_DIRECTORY/Utilities/newsid.exe\" /a \"$computer_name\"";
+	my $newsid_command = "\"$NODE_CONFIGURATION_DIRECTORY/Utilities/NewSID/newsid.exe\" /a";
 	my $newsid_start_processing_time = time();
 	my ($newsid_exit_status, $newsid_output) = run_ssh_command($computer_node_name, $management_node_keys, $newsid_command);
 	if (defined($newsid_exit_status) && $newsid_exit_status == 0) {
-		notify($ERRORS{'OK'}, 0, "newsid.exe has been started on $computer_node_name, new computer name: $computer_name");
+		notify($ERRORS{'OK'}, 0, "newsid.exe has been started on $computer_node_name");
 	}
 	elsif (defined($newsid_exit_status)) {
 		notify($ERRORS{'WARNING'}, 0, "failed to start newsid.exe on $computer_node_name, exit status: $newsid_exit_status, output:\n@{$newsid_output}");
-		return 0;
+		return;
 	}
 	else {
 		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to start newsid.exe on $computer_node_name");
@@ -2693,13 +2855,13 @@
 
 	my $newsid_end_processing_time = time();
 	my $newsid_processing_duration = ($newsid_end_processing_time - $newsid_start_processing_time);
-	notify($ERRORS{'OK'}, 0, "newsid.exe complete, newsid.exe took $newsid_processing_duration seconds");
-	insertloadlog($reservation_id, $computer_id, "info", "newsid.exe processing took $newsid_processing_duration seconds");
+	notify($ERRORS{'OK'}, 0, "newsid.exe execution took $newsid_processing_duration seconds");
+	insertloadlog($reservation_id, $computer_id, "info", "newsid.exe execution took $newsid_processing_duration seconds");
 
 	# After launching newsid.exe, wait for machine to become unresponsive
 	if (!$self->wait_for_no_ping(10)) {
 		notify($ERRORS{'WARNING'}, 0, "failed to run newsid.exe, $computer_node_name never rebooted after waiting 10 minutes");
-		return 0;
+		return;
 	}
 
 	my $newsid_shutdown_time = time();
@@ -2906,8 +3068,8 @@
 
 	# Attempt to delete the user account
 	my $schtasks_command = '$SYSTEMROOT/System32/schtasks.exe /Change /DISABLE /TN "' . $task_name . '"';
-	my ($schtasks_exit_status, $schtasks_output) = run_ssh_command($computer_node_name, $management_node_keys, $schtasks_command);
-	if (defined($schtasks_exit_status) && $schtasks_exit_status == 0) {
+	my ($schtasks_exit_status, $schtasks_output) = run_ssh_command($computer_node_name, $management_node_keys, $schtasks_command, '', '', 1);
+	if (defined($schtasks_output) && grep(/have been changed/, @$schtasks_output)) {
 		notify($ERRORS{'OK'}, 0, "$task_name scheduled task disabled on $computer_node_name");
 	}
 	elsif (defined($schtasks_exit_status)) {
@@ -3072,14 +3234,46 @@
 	}
 	else {
 		notify($ERRORS{'WARNING'}, 0, "failed to disable dynamic dns");
-		return 0;
+		return;
 	}
 
 	# Get the network configuration
 	my $network_configuration = $self->get_network_configuration();
 	if (!$network_configuration) {
 		notify($ERRORS{'WARNING'}, 0, "unable to retrieve network configuration");
-		return 0;
+		return;
+	}
+	
+	# Get the public and private interface names
+	my $public_interface_name = $self->get_public_interface_name();
+	my $private_interface_name = $self->get_private_interface_name();
+	
+	# Assemble netsh.exe commands to disable DNS registration
+	my $netsh_command;
+	$netsh_command .= "netsh.exe interface ip set dns";
+	$netsh_command .= " name = \"$public_interface_name\"";
+	$netsh_command .= " source = dhcp";
+	$netsh_command .= " register = none";
+	$netsh_command .= " ;";
+	
+	$netsh_command .= "netsh.exe interface ip set dns";
+	$netsh_command .= " name = \"$private_interface_name\"";
+	$netsh_command .= " source = dhcp";
+	$netsh_command .= " register = none";
+	$netsh_command .= " ;";
+	
+	# Execute the netsh.exe command
+	my ($netsh_exit_status, $netsh_output) = run_ssh_command($computer_node_name, $management_node_keys, $netsh_command);
+	if (defined($netsh_exit_status)  && $netsh_exit_status == 0) {
+		notify($ERRORS{'OK'}, 0, "disabled dynamic DNS registration on public and private adapters");
+	}
+	elsif (defined($netsh_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to disable dynamic DNS registration on public and private adapters, exit status: $netsh_exit_status, output:\n@{$netsh_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to disable dynamic DNS registration on public and private adapters");
+		return;
 	}
 
 	return 1;
@@ -3255,109 +3449,7 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 grant_access
-
- Parameters  :
- Returns     :
- Description :
-
-=cut
-
-sub grant_access {
-	my $self = shift;
-	if (ref($self) !~ /windows/i) {
-		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
-		return;
-	}
-
-	my $management_node_keys = $self->data->get_management_node_keys();
-	my $computer_node_name   = $self->data->get_computer_node_name();
-	my $remote_ip            = $self->data->get_reservation_remote_ip();
-	my $multiple_users       = $self->data->get_imagemeta_usergroupmembercount();
-	my $request_forimaging   = $self->data->get_request_forimaging();
-
-	# Check to make sure remote IP is defined
-	my $remote_ip_range;
-	if (!$remote_ip) {
-		notify($ERRORS{'WARNING'}, 0, "reservation remote IP address is not set in the data structure, opening RDP to any address");
-		$remote_ip_range = '0.0.0.0/32';
-	}
-	elsif ($multiple_users) {
-		notify($ERRORS{'OK'}, 0, "reservation has multiple users, opening RDP to any address");
-		$remote_ip_range = '0.0.0.0/32';
-	}
-	elsif ($remote_ip !~ /^(\d{1,3}\.?){4}$/) {
-		notify($ERRORS{'WARNING'}, 0, "reservation remote IP address format is invalid: $remote_ip, opening RDP to any address");
-		$remote_ip_range = '0.0.0.0/32';
-	}
-	else {
-		# Assemble the IP range string in CIDR notation
-		$remote_ip_range = "$remote_ip/16";
-		notify($ERRORS{'OK'}, 0, "RDP will be allowed from $remote_ip_range on $computer_node_name");
-	}
-
-
-	# Allow RDP connections
-	if ($self->firewall_enable_rdp($remote_ip_range)) {
-		notify($ERRORS{'OK'}, 0, "firewall was configured to allow RDP access from $remote_ip_range on $computer_node_name");
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "firewall could not be configured to grant RDP access from $remote_ip_range on $computer_node_name");
-		return 0;
-	}
-
-	# If this is an imaging request, make sure the Administrator account is enabled
-	if ($request_forimaging) {
-		notify($ERRORS{'DEBUG'}, 0, "imaging request, making sure Administrator account is enabled");
-		if ($self->enable_user('Administrator')) {
-			notify($ERRORS{'OK'}, 0, "Administrator account is enabled for imaging request");
-		}
-		else {
-			notify($ERRORS{'WARNING'}, 0, "failed to enable Administrator account for imaging request");
-			return 0;
-		}
-	} ## end if ($request_forimaging)
-
-	notify($ERRORS{'OK'}, 0, "access has been granted for reservation on $computer_node_name");
-	return 1;
-} ## end sub grant_access
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 revoke_access
-
- Parameters  :
- Returns     :
- Description :
-
-=cut
-
-sub revoke_access {
-	my $self = shift;
-	if (ref($self) !~ /windows/i) {
-		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
-		return;
-	}
-
-	my $management_node_keys = $self->data->get_management_node_keys();
-	my $computer_node_name   = $self->data->get_computer_node_name();
-
-	# Disallow RDP connections
-	if ($self->firewall_disable_rdp()) {
-		notify($ERRORS{'OK'}, 0, "firewall was configured to deny RDP access on $computer_node_name");
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "firewall could not be configured to deny RDP access on $computer_node_name");
-		return 0;
-	}
-
-	notify($ERRORS{'OK'}, 0, "access has been revoked to $computer_node_name");
-	return 1;
-} ## end sub revoke_access
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_currentimage_txt_contents
+=head2 get_currentimage_txt_contents
 
  Parameters  : 
  Returns     : array containing lines in currentimage.txt
@@ -3951,6 +4043,91 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 firewall_enable_rdp_private
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_rdp_private {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	my $netsh_command;
+	
+	# Get the public interface name
+	# Add command to disable RDP on public interface if its name is found
+	my $public_interface_name = $self->get_public_interface_name();
+	if ($public_interface_name) {
+		notify($ERRORS{'DEBUG'}, 0, "RDP will be disabled on public interface: $public_interface_name");
+		
+		$netsh_command .= "netsh.exe firewall delete portopening";
+		$netsh_command .= " protocol = TCP";
+		$netsh_command .= " port = 3389";
+		$netsh_command .= " interface = \"$public_interface_name\"";
+		$netsh_command .= ' ;';
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "RDP will not be disabled on public interface because public interface name could not be determined");
+	}
+	
+	# Get the private interface name
+	# Add command to ensable RDP on private interface if its name is found
+	my $private_interface_name = $self->get_private_interface_name();
+	if ($private_interface_name) {
+		notify($ERRORS{'DEBUG'}, 0, "RDP will be enabled on private interface: $private_interface_name");
+		
+		$netsh_command .= "netsh.exe firewall delete portopening";
+		$netsh_command .= " protocol = TCP";
+		$netsh_command .= " port = 3389";
+		$netsh_command .= " profile = ALL";
+		$netsh_command .= ' ;';
+		
+		$netsh_command .= "netsh.exe firewall set portopening";
+		$netsh_command .= " name = \"Remote Desktop\"";
+		$netsh_command .= " protocol = TCP";
+		$netsh_command .= " port = 3389";
+		$netsh_command .= " mode = ENABLE";
+		$netsh_command .= " interface = \"$private_interface_name\"";
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "private interface name could not be determined, RDP will be enabled for all profiles");
+		
+		$netsh_command .= "netsh.exe firewall set portopening";
+		$netsh_command .= " name = \"Remote Desktop\"";
+		$netsh_command .= " protocol = TCP";
+		$netsh_command .= " port = 3389";
+		$netsh_command .= " profile = ALL";
+	}
+	
+	# Execute the netsh.exe command
+	my ($netsh_exit_status, $netsh_output) = run_ssh_command($computer_node_name, $management_node_keys, $netsh_command);
+	
+	if (defined($netsh_output)  && @$netsh_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "configured firewall to allow RDP on private interface");
+	}
+	elsif (defined($netsh_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure firewall to allow RDP on private interface, exit status: $netsh_exit_status, output:\n@{$netsh_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to configure firewall to allow RDP on private interface");
+		return;
+	}
+	
+	return 1;
+} ## end sub firewall_enable_ssh_private
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 firewall_disable_rdp
 
  Parameters  : 
@@ -4457,6 +4634,12 @@
 	# Remove old scripts and utilities
 	$self->delete_files_by_pattern('C:/Cygwin/home/root', '.*\(vbs\|exe\|cmd\|bat\|log\)');
 	
+	# Remove old C:\VCL directory if it exists
+	$self->delete_file('C:/VCL');
+	
+	# Delete VCL scheduled task if it exists
+	$self->delete_scheduled_task('VCL Startup Configuration');
+	
 	## Remove VCLprepare.cmd and VCLcleanup.cmd lines from scripts.ini file
 	$self->remove_group_policy_script('logon', 'VCLprepare.cmd');
 	$self->remove_group_policy_script('logoff', 'VCLcleanup.cmd');
@@ -5298,7 +5481,7 @@
 		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to clear out setupapi.log");
 		return 0;
 	}
-
+	
 	# Run Sysprep.exe, use cygstart to lauch the .exe and return immediately
 	my $sysprep_command = '/bin/cygstart.exe cmd.exe /c "C:/Sysprep/sysprep.exe /forceshutdown /quiet /reseal /mini"';
 	my ($sysprep_status, $sysprep_output) = run_ssh_command($computer_node_name, $management_node_keys, $sysprep_command);
@@ -5461,6 +5644,7 @@
 		'$SYSTEMDRIVE/RECYCLER,.*',
 		'$TEMP,.*',
 		'$TMP,.*',
+		'$SYSTEMDRIVE/cygwin/tmp,.*',
 		'$SYSTEMDRIVE/Temp,.*',
 		'$SYSTEMROOT/Temp,.*',
 		'$SYSTEMROOT/ie7updates,.*',
@@ -5468,21 +5652,21 @@
 		'$SYSTEMROOT/SoftwareDistribution/Download,.*',
 		'$SYSTEMROOT/Minidump,.*',
 		'$ALLUSERSPROFILE/Application Data/Microsoft/Dr Watson,.*',
-		'$SYSTEMROOT,.*\\.tmp',
-		'$SYSTEMROOT,.*\\$hf_mig\\$.*',
-		'$SYSTEMROOT,.*\\$NtUninstall.*',
-		'$SYSTEMROOT,.*\\$NtServicePackUninstall.*',
-		'$SYSTEMROOT,.*\\$MSI.*Uninstall.*',
+		'$SYSTEMROOT,.*\\.tmp,1',
+		'$SYSTEMROOT,.*\\$hf_mig\\$.*,1',
+		'$SYSTEMROOT,.*\\$NtUninstall.*,1',
+		'$SYSTEMROOT,.*\\$NtServicePackUninstall.*,1',
+		'$SYSTEMROOT,.*\\$MSI.*Uninstall.*,1',
 		'$SYSTEMROOT/inf,.*INFCACHE\\.1',
 		'$SYSTEMROOT/inf,.*[\\\\\\/]oem.*\\..*',
-		'$SYSTEMROOT,.*AFSCache',
-		'$SYSTEMROOT,.*afsd_init\\.log',
-		'$SYSTEMDRIVE/Documents and Settings,.*\\.log',
-		'$SYSTEMDRIVE/Documents and Settings,.*Recent\\/.*',
-		'$SYSTEMDRIVE/Documents and Settings,.*Cookies\\/.*',
-		'$SYSTEMDRIVE/Documents and Settings,.*Temp\\/.*',
-		'$SYSTEMDRIVE/Documents and Settings,.*Temporary Internet Files\\/Content.*\\/.*',
-		'$SYSTEMDRIVE,.*pagefile\\.sys',
+		'$SYSTEMROOT,.*AFSCache,1',
+		'$SYSTEMROOT,.*afsd_init\\.log,1',
+		'$SYSTEMDRIVE/Documents and Settings,.*\\.log,10',
+		'$SYSTEMDRIVE/Documents and Settings,.*Recent\\/.*,10',
+		'$SYSTEMDRIVE/Documents and Settings,.*Cookies\\/.*,10',
+		'$SYSTEMDRIVE/Documents and Settings,.*Temp\\/.*,10',
+		'$SYSTEMDRIVE/Documents and Settings,.*Temporary Internet Files\\/Content.*\\/.*,10',
+		'$SYSTEMDRIVE,.*pagefile\\.sys,1',
 	);
 
 	# Attempt to stop the AFS service, needed to delete AFS files
@@ -5491,9 +5675,9 @@
 	# Loop through the directories to empty
 	# Don't care if they aren't emptied
 	for my $base_pattern (@patterns_to_delete) {
-		my ($base_directory, $pattern) = split(',', $base_pattern);
+		my ($base_directory, $pattern, $max_depth) = split(',', $base_pattern);
 		notify($ERRORS{'DEBUG'}, 0, "attempting to delete files under $base_directory matching pattern $pattern");
-		$self->delete_files_by_pattern($base_directory, $pattern);
+		$self->delete_files_by_pattern($base_directory, $pattern, $max_depth);
 	}
 
 	# Add the cleanmgr.exe settings to the registry
@@ -5680,8 +5864,8 @@
 		notify($ERRORS{'OK'}, 0, "service is not started: $service_name");
 	}
 	elsif (defined($output) && grep(/does not exist/i, @{$output})) {
-		notify($ERRORS{'WARNING'}, 0, "service does not exist: $service_name, exit status: $status, output:\n@{$output}");
-		return 0;
+		notify($ERRORS{'OK'}, 0, "service was not stopped because it does not exist: $service_name");
+		return;
 	}
 	elsif (defined($status)) {
 		notify($ERRORS{'WARNING'}, 0, "unable to stop service: $service_name, exit status: $status, output:\n@{$output}");
@@ -6059,7 +6243,7 @@
 		$inf_target_path =~ s/\//\\\\/g;
 		
 		my $secedit_command = "$secedit_exe /configure /cfg \"$inf_target_path\" /db $secedit_db /log $secedit_log /verbose";
-		my ($secedit_exit_status, $secedit_output) = run_ssh_command($computer_node_name, $management_node_keys, $secedit_command, '', '', 1);
+		my ($secedit_exit_status, $secedit_output) = run_ssh_command($computer_node_name, $management_node_keys, $secedit_command, '', '', 0);
 		if (defined($secedit_exit_status) && $secedit_exit_status == 0) {
 			notify($ERRORS{'OK'}, 0, "ran secedit.exe to apply $inf_file_name");
 		}
@@ -6195,100 +6379,80 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 run_newsid_new
+=head2 get_node_configuration_directory
 
- Parameters  : 
- Returns     : 1 success 0 failure
- Description : 
+ Parameters  : None
+ Returns     : String containing filesystem path
+ Description : Retrieves the $NODE_CONFIGURATION_DIRECTORY variable value the
+               OS. This is the path on the computer's hard drive where image
+					configuration files and scripts are copied.
+
+=cut
+
+sub get_node_configuration_directory {
+	return $NODE_CONFIGURATION_DIRECTORY;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 set_computer_name
+
+ Parameters  : $computer_name
+ Returns     : If successful: true
+               If failed: false
+ Description : Sets the registry keys to set the computer name. This subroutine
+               does not attempt to reboot the computer.
+               The computer name argument is optional. If not supplied, the
+               computer's short name stored in the database will be used,
+               followed by a hyphen and the image ID that is loaded.
 
 =cut
 
-sub run_newsid_new {
+sub set_computer_name {
 	my $self = shift;
 	if (ref($self) !~ /windows/i) {
 		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
 		return;
 	}
 	
-	my $reservation_id           = $self->data->get_reservation_id();
-	my $management_node_keys     = $self->data->get_management_node_keys();
-	my $computer_node_name       = $self->data->get_computer_node_name();
-	my $computer_id              = $self->data->get_computer_id();
-	
-	my $registry_string .= <<'EOF';
+	# Get the computer name
+	my $computer_name = shift;
+	if (!$computer_name) {
+		$computer_name = $self->data->get_computer_short_name();
+		if (!$computer_name) {
+			notify($ERRORS{'WARNING'}, 0, "computer name argument was not supplied and could not be retrieved from the reservation data");
+			return;
+		}
+		
+		# Append the image ID to the computer name
+		my $image_id = $self->data->get_image_id();
+		$computer_name .= "-$image_id" if $image_id;
+	}
+
+	my $management_node_keys = $self->data->get_management_node_keys();
+	my $computer_node_name   = $self->data->get_computer_node_name();
+
+	my $registry_string .= <<"EOF";
 Windows Registry Editor Version 5.00
 
-; This registry file contains the entries to bypass the license agreement when newsid.exe is run
+[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName]
+"ComputerName"="$computer_name"
 
-[HKEY_CURRENT_USER\\Software\\Sysinternals\\NewSID]
-"EulaAccepted"=dword:00000001
+[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters]
+"NV Hostname"="$computer_name"
 EOF
-	
+
 	# Import the string into the registry
 	if ($self->import_registry_string($registry_string)) {
-		notify($ERRORS{'DEBUG'}, 0, "added newsid eulaaccepted registry string");
+		notify($ERRORS{'OK'}, 0, "set registry keys to change the computer name to $computer_name");
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to add newsid eulaaccepted registry string");
-	}
-	
-	# Attempt to run newsid.exe
-	# newsid.exe should automatically reboot the computer
-	# It isn't done when the process exits, newsid.exe starts working and immediately returns
-	# NewSid.exe [/a[[/n]|[/d <reboot delay (in seconds)>]]][<new computer name>]
-	# /a - run without prompts
-	# /n - Don't reboot after automatic run
-	my $newsid_command = "\"$NODE_CONFIGURATION_DIRECTORY/Utilities/newsid.exe\" /a \"$computer_node_name\"";
-	
-	my $newsid_start_processing_time = time();
-	my ($newsid_exit_status, $newsid_output) = run_ssh_command($computer_node_name, $management_node_keys, $newsid_command);
-	my $newsid_end_processing_time = time();
-	
-	if (defined($newsid_exit_status) && $newsid_exit_status == 0) {
-		notify($ERRORS{'DEBUG'}, 0, "ran newsid.exe on $computer_node_name");
-	}
-	elsif (defined($newsid_exit_status)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to run newsid.exe on $computer_node_name, exit status: $newsid_exit_status, output:\n@{$newsid_output}");
+		notify($ERRORS{'WARNING'}, 0, "failed to set registry keys to change the computer name to $computer_name");
 		return;
 	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to run newsid.exe on $computer_node_name");
-		return;
-	}
-	my $newsid_processing_duration = ($newsid_end_processing_time - $newsid_start_processing_time);
-	notify($ERRORS{'DEBUG'}, 0, "newsid.exe finished processing, newsid.exe took $newsid_processing_duration seconds");
-	insertloadlog($reservation_id, $computer_id, "info", "newsid.exe processing took $newsid_processing_duration seconds");
-	
-	# After launching newsid.exe, wait for machine to become unresponsive
-	if (!$self->wait_for_no_ping(10)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to run newsid.exe, $computer_node_name never became unresponsive after waiting 10 minutes");
-		return;
-	}
-	my $newsid_shutdown_time = time();
-	notify($ERRORS{'DEBUG'}, 0, "newsid.exe initiated reboot, $computer_node_name is unresponsive, reboot initialization took " . ($newsid_shutdown_time - $newsid_end_processing_time) . " seconds");
-	
-	# Wait maximum of 6 minutes for the computer to come back up
-	if (!$self->wait_for_ping(6)) {
-		notify($ERRORS{'WARNING'}, 0, "$computer_node_name never responded to ping, it never came back up");
-		return;
-	}
-	
-	my $newsid_ping_respond_time = time();
-	notify($ERRORS{'DEBUG'}, 0, "reboot nearly complete on $computer_node_name after running newsid.exe, ping response took " . ($newsid_ping_respond_time - $newsid_shutdown_time) . " seconds");
-	
-	# Ping successful, try ssh
-	notify($ERRORS{'OK'}, 0, "waiting for ssh to respond on $computer_node_name");
-	if (!$self->wait_for_ssh(3)) {
-		notify($ERRORS{'WARNING'}, 0, "newsid.exe failed, $computer_node_name rebooted but ssh never became available");
-		return;
-	}
-	my $newsid_ssh_respond_time = time();
-	my $newsid_entire_duration = ($newsid_ssh_respond_time - $newsid_start_processing_time);
-	notify($ERRORS{'OK'}, 0, "newsid.exe succeeded on $computer_node_name, entire process took $newsid_entire_duration seconds");
-	insertloadlog($reservation_id, $computer_id, "info", "entire newsid.exe process took $newsid_entire_duration seconds");
-	
+
 	return 1;
-}
+} ## end sub disable_ipv6
 
 #/////////////////////////////////////////////////////////////////////////////
 

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5.pm?rev=780755&r1=780754&r2=780755&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5.pm Mon Jun  1 17:51:52 2009
@@ -80,11 +80,11 @@
 		return;
 	}
 	
-	notify($ERRORS{'OK'}, 0, "beginning Windows version 5 image capture preparation tasks, end state: $self->{end_state}");
+	notify($ERRORS{'OK'}, 0, "beginning Windows version 5 image capture preparation tasks");
 	
 	# Call parent class's pre_capture() subroutine
 	notify($ERRORS{'OK'}, 0, "calling parent class pre_capture() subroutine");
-	if ($self->SUPER::pre_capture()) {
+	if ($self->SUPER::pre_capture($args)) {
 		notify($ERRORS{'OK'}, 0, "successfully executed parent class pre_capture() subroutine");
 	}
 	else {

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5/XP_mod.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5/XP_mod.pm?rev=780755&r1=780754&r2=780755&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5/XP_mod.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_5/XP_mod.pm Mon Jun  1 17:51:52 2009
@@ -96,35 +96,23 @@
 		return;
 	}
 	
-	my $imagemeta_sysprep = $self->data->get_imagemeta_sysprep();
-	
-	# Check if end_state argument was passed
-	if (defined $args->{end_state}) {
-		$self->{end_state} = $args->{end_state};
-	}
-	else {
-		$self->{end_state} = 'off';
-	}
-	
-	notify($ERRORS{'OK'}, 0, "beginning Windows XP image capture preparation tasks, end state: $self->{end_state}");
+	notify($ERRORS{'OK'}, 0, "beginning Windows XP image capture preparation tasks");
 	
 	# Call parent class's pre_capture() subroutine
 	notify($ERRORS{'OK'}, 0, "calling parent class pre_capture() subroutine");
-	if ($self->SUPER::pre_capture()) {
+	if ($self->SUPER::pre_capture($args)) {
 		notify($ERRORS{'OK'}, 0, "successfully executed parent class pre_capture() subroutine");
 	}
 	else {
 		notify($ERRORS{'WARNING'}, 0, "failed to execute parent class pre_capture() subroutine");
-		return 0;
+		return;
 	}
 	
 	# Check if Sysprep should be used
-	if ($imagemeta_sysprep) {
-		# Copy the Sysprep files to C:\Sysprep
-		# Call this *AFTER* calling copy_capture_configuration_files
+	if ($self->data->get_imagemeta_sysprep()) {
 		if (!$self->run_sysprep()) {
 			notify($ERRORS{'WARNING'}, 0, "capture preparation failed, failed to run Sysprep");
-			return 0;
+			return;
 		}
 	}
 	

Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6.pm?rev=780755&view=auto
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6.pm (added)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6.pm Mon Jun  1 17:51:52 2009
@@ -0,0 +1,1019 @@
+#!/usr/bin/perl -w
+###############################################################################
+# $Id: Version_5.pm 774457 2009-05-13 18:12:08Z arkurth $
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+=head1 NAME
+
+VCL::Module::OS::Windows_mod::Version_6.pm - VCL module to support Windows 6.x operating systems
+
+=head1 SYNOPSIS
+
+ Needs to be written
+
+=head1 DESCRIPTION
+
+ This module provides VCL support for Windows version 6.x operating systems.
+ Version 6.x Windows OS's include Windows Vista and Windows Server 2008.
+
+=cut
+
+##############################################################################
+package VCL::Module::OS::Windows_mod::Version_6;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::OS::Windows_mod);
+
+# Specify the version of this module
+our $VERSION = '2.00';
+
+# Specify the version of Perl to use
+use 5.008000;
+
+use strict;
+use warnings;
+use diagnostics;
+
+use VCL::utils;
+use File::Basename;
+
+##############################################################################
+
+=head1 INTERFACE OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 pre_capture
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Performs steps before an image is captured which are specific to
+               Windows version 6.x.
+
+=over 3
+
+=cut
+
+sub pre_capture {
+	my $self = shift;
+	my $args = shift;
+	
+	# Check if subroutine was called as an object method
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module object method");
+		return;
+	}
+	
+	notify($ERRORS{'OK'}, 0, "beginning Windows version 6 image pre-capture tasks");
+
+=item 1
+
+Disable defrag scheduled task
+
+=cut
+
+	$self->disable_scheduled_task('\Microsoft\Windows\Defrag\ScheduledDefrag');
+
+=item *
+
+Disable system restore scheduled task
+
+=cut
+
+	$self->disable_scheduled_task('\Microsoft\Windows\SystemRestore\SR');
+
+=item *
+
+Disable customer improvement program consolidator scheduled task
+
+=cut
+
+	$self->disable_scheduled_task('\Microsoft\Windows\Customer Experience Improvement Program\Consolidator');
+
+=item *
+
+Disable customer improvement program opt-in notification scheduled task
+
+=cut
+
+	$self->disable_scheduled_task('\Microsoft\Windows\Customer Experience Improvement Program\OptinNotification');
+
+=item *
+
+Call parent class's pre_capture() subroutine
+
+=cut
+
+	notify($ERRORS{'OK'}, 0, "calling parent class pre_capture() subroutine");
+	if ($self->SUPER::pre_capture($args)) {
+		notify($ERRORS{'OK'}, 0, "successfully executed parent class pre_capture() subroutine");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute parent class pre_capture() subroutine");
+		return 0;
+	}
+
+=back
+
+=cut
+
+	notify($ERRORS{'OK'}, 0, "returning 1");
+	return 1;
+} ## end sub pre_capture
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 post_load
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Performs steps after an image is loaded which are specific to
+               Windows version 6.x.
+
+=over 3
+
+=cut
+
+sub post_load {
+	my $self = shift;
+	
+	# Check if subroutine was called as an object method
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module object method");
+		return;
+	}
+	
+	notify($ERRORS{'DEBUG'}, 0, "beginning Windows version 6 (Vista, Server 2008) post-load tasks");
+	
+=item 1
+
+Activate Windows license
+
+=cut
+
+	$self->activate_license();
+
+=item *
+
+Call parent class's post_load() subroutine
+
+=cut
+
+	notify($ERRORS{'DEBUG'}, 0, "calling parent class post_load() subroutine");
+	if ($self->SUPER::post_load()) {
+		notify($ERRORS{'OK'}, 0, "successfully executed parent class post_load() subroutine");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute parent class post_load() subroutine");
+		return;
+	}
+
+=back
+
+=cut
+
+	notify($ERRORS{'DEBUG'}, 0, "Windows version 6 (Vista, Server 2008) post-load tasks complete");
+	return 1;
+}
+
+##############################################################################
+
+=head1 AUXILIARY OBJECT METHODS
+
+=cut
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 activate_license
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Runs cscript.exe slmgr.vbs -skms to set the KMS server address
+               stored on the computer.
+               Runs cscript.exe slmgr.vbs -ato to activate licensing on the
+               computer.
+
+=cut
+
+sub activate_license {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# Get the image affiliation name
+	my $image_affiliation_name = $self->data->get_image_affiliation_name();
+	if ($image_affiliation_name) {
+		notify($ERRORS{'DEBUG'}, 0, "image affiliation name: $image_affiliation_name");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "image affiliation name could not be retrieved, using default licensing configuration");
+		$image_affiliation_name = 'default';
+	}
+	
+	# Get the Windows activation data from the windows-activation variable
+	my $activation_data = $self->data->get_variable('windows-activation');
+	if ($activation_data) {
+		notify($ERRORS{'DEBUG'}, 0, "activation data:\n" . format_data($activation_data));
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "activation data could not be retrieved");
+		return;
+	}
+	
+	# Get the activation data specific to the image affiliation
+	my $affiliation_config = $activation_data->{$image_affiliation_name};
+	if ($affiliation_config) {
+		notify($ERRORS{'DEBUG'}, 0, "$image_affiliation_name affiliation activation configuration:\n" . format_data($affiliation_config));
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "activation configuration does not exist for affiliation: $image_affiliation_name, attempting to retrieve default configuration");
+		
+		$affiliation_config = $activation_data->{'default'};
+		if ($affiliation_config) {
+			notify($ERRORS{'DEBUG'}, 0, "default activation configuration:\n" . format_data($affiliation_config));
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "default activation configuration does not exist");
+			return;
+		}
+	}
+	
+	
+	# Loop through the activation methods for the affiliation
+	for my $activation_config (@$affiliation_config) {
+		my $activation_method = $activation_config->{method};
+		
+		if ($activation_method =~ /kms/i) {
+			my $kms_address = $activation_config->{address};
+			my $kms_port = $activation_config->{port} || 1688;
+			notify($ERRORS{'DEBUG'}, 0, "attempting to set kms server: $kms_address, port: $kms_port");
+			
+			# Run slmgr.vbs -skms
+			my $kms_command = '$SYSTEMROOT/System32/cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -skms ' . "$kms_address:$kms_port";
+			my ($kms_exit_status, $kms_output) = run_ssh_command($computer_node_name, $management_node_keys, $kms_command);
+			if (defined($kms_exit_status) && $kms_exit_status == 0 && grep(/successfully/i, @$kms_output)) {
+				notify($ERRORS{'OK'}, 0, "set kms server to $kms_address:$kms_port");
+			}
+			elsif (defined($kms_exit_status)) {
+				notify($ERRORS{'WARNING'}, 0, "failed to set kms server to $kms_address:$kms_port, exit status: $kms_exit_status, output:\n@{$kms_output}");
+				next;
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to set kms server to $kms_address:$kms_port");
+				next;
+			}
+			
+			# KMS server successfully set, run slmgr.vbs -ato
+			my $activate_command = '$SYSTEMROOT/System32/cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -ato';
+			my ($activate_exit_status, $activate_output) = run_ssh_command($computer_node_name, $management_node_keys, $activate_command);
+			if (defined($activate_exit_status)  && $activate_exit_status == 0 && grep(/successfully/i, @$activate_output)) {
+				notify($ERRORS{'OK'}, 0, "license activated using kms server: $kms_address");
+				return 1;
+			}
+			elsif (defined($activate_exit_status)) {
+				notify($ERRORS{'WARNING'}, 0, "failed to activate license using kms server: $kms_address, exit status: $activate_exit_status, output:\n@{$activate_output}");
+				next;
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "failed to activate license using kms server: $kms_address");
+				next;
+			}
+		}
+		
+		elsif ($activation_method =~ /mak/i) {
+			notify($ERRORS{'WARNING'}, 0, "MAK activation method is not supported yet");
+			next;
+		}
+		
+		else  {
+			notify($ERRORS{'WARNING'}, 0, "unsupported activation method: $activation_method");
+			next;
+		}
+	}
+	
+	notify($ERRORS{'WARNING'}, 0, "failed to activate license on $computer_node_name using any configured kms servers");
+	return;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 deactivate_license
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Runs cscript.exe slmgr.vbs -ckms to clear the KMS server address
+               stored on the computer.
+               Runs cscript.exe slmgr.vbs -rearm to rearm licensing on the
+               computer.
+
+=cut
+
+sub deactivate_license {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# Run slmgr.vbs -ckms
+	my $ckms_command = '$SYSTEMROOT/System32/cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -ckms';
+	my ($ckms_exit_status, $ckms_output) = run_ssh_command($computer_node_name, $management_node_keys, $ckms_command);
+	if (defined($ckms_exit_status) && $ckms_exit_status == 0 && grep(/successfully/i, @$ckms_output)) {
+		notify($ERRORS{'OK'}, 0, "cleared kms address");
+	}
+	elsif (defined($ckms_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to clear kms address, exit status: $ckms_exit_status, output:\n@{$ckms_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to clear kms address");
+		return;
+	}
+	
+	# Run slmgr.vbs -rearm
+	my $rearm_command = '$SYSTEMROOT/System32/cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -rearm';
+	my ($rearm_exit_status, $rearm_output) = run_ssh_command($computer_node_name, $management_node_keys, $rearm_command);
+	if (defined($rearm_exit_status) && $rearm_exit_status == 0 && grep(/successfully/i, @$rearm_output)) {
+		notify($ERRORS{'OK'}, 0, "rearmed licensing");
+	}
+	elsif (defined($rearm_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to rearm licensing, exit status: $rearm_exit_status, output:\n@{$rearm_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to rearm licensing");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 set_network_location
+
+ Parameters  :
+ Returns     :
+ Description : 
+
+=cut
+
+sub set_network_location {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	#Category key: Home/Work=00000000, Public=00000001
+	
+	my $registry_string .= <<"EOF";
+Windows Registry Editor Version 5.00
+
+[HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\FirstNetwork]
+"Category"=dword:00000001
+EOF
+	
+	# Import the string into the registry
+	if ($self->import_registry_string($registry_string)) {
+		notify($ERRORS{'DEBUG'}, 0, "set network location");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to set network location");
+		return 0;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_ping
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_ping {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $add_rule_command;
+	$add_rule_command .= 'netsh.exe advfirewall firewall delete rule';
+	$add_rule_command .= ' name=all';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' protocol=icmpv4:8,any';
+	$add_rule_command .= ' ;';
+	
+	$add_rule_command .= ' netsh.exe advfirewall firewall add rule';
+	$add_rule_command .= ' name="VCL: allow ping from any address"';
+	$add_rule_command .= ' description="Allows incoming ping (ICMP type 8) messages from any address"';
+	$add_rule_command .= ' protocol=icmpv4:8,any';
+	$add_rule_command .= ' action=allow';
+	$add_rule_command .= ' enable=yes';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' localip=any';
+	$add_rule_command .= ' remoteip=any';
+	
+	# Add the firewall rule
+	my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+	
+	if (defined($add_rule_output)  && @$add_rule_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "added firewall rule to enable ping from any address");
+	}
+	elsif (defined($add_rule_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable ping from any address, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable ping from any address");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_ping_private
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_ping_private {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# Get the computer's private IP address
+	my @private_ip_addresses = keys(%{$self->get_private_ip_addresses()});
+	if (!@private_ip_addresses) {
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve private IP addresses");
+		return;
+	}
+	
+	# Join together the IP addresses in case multiple addresses are bound
+	my $private_ip_address_string = join("," , @private_ip_addresses);
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $add_rule_command;
+	$add_rule_command .= 'netsh.exe advfirewall firewall delete rule';
+	$add_rule_command .= ' name=all';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' protocol=icmpv4:8,any';
+	$add_rule_command .= ' ;';
+	
+	$add_rule_command .= ' netsh.exe advfirewall firewall add rule';
+	$add_rule_command .= ' name="VCL: allow incoming ping to: ' . $private_ip_address_string . '"';
+	$add_rule_command .= ' description="Allows incoming ping (ICMP type 8) messages to: ' . $private_ip_address_string . '"';
+	$add_rule_command .= ' protocol=icmpv4:8,any';
+	$add_rule_command .= ' action=allow';
+	$add_rule_command .= ' enable=yes';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' localip=' . $private_ip_address_string;
+	
+	# Add the firewall rule
+	my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+	
+	if (defined($add_rule_output)  && @$add_rule_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "added firewall rule to allow incoming ping to: $private_ip_address_string");
+	}
+	elsif (defined($add_rule_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to allow incoming ping to: $private_ip_address_string, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to allow incoming ping to: $private_ip_address_string");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_disable_ping
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_disable_ping {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $netsh_command;
+	$netsh_command .= 'netsh.exe advfirewall firewall delete rule';
+	$netsh_command .= ' name=all';
+	$netsh_command .= ' dir=in';
+	$netsh_command .= ' protocol=icmpv4:8,any';
+	
+	# Execute the netsh.exe command
+	my ($netsh_exit_status, $netsh_output) = run_ssh_command($computer_node_name, $management_node_keys, $netsh_command);
+	
+	if (defined($netsh_output)  && @$netsh_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "configured firewall to disallow ping");
+	}
+	elsif (defined($netsh_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure firewall to disallow ping, exit status: $netsh_exit_status, output:\n@{$netsh_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to configure firewall to disallow ping");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_rdp
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_rdp {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	# Check if the remote IP was passed as an argument
+	my $remote_ip = shift;
+	if (!defined($remote_ip)) {
+		$remote_ip = 'any';
+	}
+	elsif ($remote_ip !~ /[\d\.\/]/) {
+		notify($ERRORS{'WARNING'}, 0, "remote IP address argument is not a valid IP address: $remote_ip");
+		$remote_ip = 'any';
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $add_rule_command;
+	$add_rule_command .= 'netsh.exe advfirewall firewall delete rule';
+	$add_rule_command .= ' name=all';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=3389';
+	$add_rule_command .= ' ;';
+	
+	$add_rule_command .= ' netsh.exe advfirewall firewall add rule';
+	$add_rule_command .= ' name="VCL: allow RDP from address: ' . $remote_ip . '"';
+	$add_rule_command .= ' description="Allows incoming TCP port 3389 traffic from address: ' . $remote_ip . '"';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' action=allow';
+	$add_rule_command .= ' enable=yes';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' localip=any';
+	$add_rule_command .= ' localport=3389';
+	$add_rule_command .= ' remoteip=' . $remote_ip;
+	
+	# Add the firewall rule
+	my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+	
+	if (defined($add_rule_output)  && @$add_rule_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "added firewall rule to enable RDP from $remote_ip");
+	}
+	elsif (defined($add_rule_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable RDP from $remote_ip, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable RDP from $remote_ip");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_rdp_private
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_rdp_private {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# Get the computer's private IP address
+	my @private_ip_addresses = keys(%{$self->get_private_ip_addresses()});
+	if (!@private_ip_addresses) {
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve private IP addresses");
+		return;
+	}
+	
+	# Join together the IP addresses in case multiple addresses are bound
+	my $private_ip_address_string = join("," , @private_ip_addresses);
+	
+	# First delete any rules which allow RDP and then add a new rule
+	my $add_rule_command;
+	$add_rule_command .= 'netsh.exe advfirewall firewall delete rule';
+	$add_rule_command .= ' name=all';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=3389';
+	$add_rule_command .= ' ;';
+	
+	$add_rule_command .= ' netsh.exe advfirewall firewall add rule';
+	$add_rule_command .= ' name="VCL: allow RDP port 3389 to: ' . $private_ip_address_string . '"';
+	$add_rule_command .= ' description="Allows incoming RDP (TCP port 3389) traffic to: ' . $private_ip_address_string . '"';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=3389';
+	$add_rule_command .= ' action=allow';
+	$add_rule_command .= ' enable=yes';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' localip=' . $private_ip_address_string;
+	
+	# Add the firewall rule
+	my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+	
+	if (defined($add_rule_output)  && @$add_rule_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "added firewall rule to enable RDP to: $private_ip_address_string");
+	}
+	elsif (defined($add_rule_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable RDP to: $private_ip_address_string, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable RDP to: $private_ip_address_string");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_disable_rdp
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_disable_rdp {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $netsh_command;
+	$netsh_command .= 'netsh.exe advfirewall firewall delete rule';
+	$netsh_command .= ' name=all';
+	$netsh_command .= ' dir=in';
+	$netsh_command .= ' protocol=TCP';
+	$netsh_command .= ' localport=3389';
+	
+	# Delete the firewall rule
+	my ($netsh_exit_status, $netsh_output) = run_ssh_command($computer_node_name, $management_node_keys, $netsh_command);
+	
+	if (defined($netsh_output)  && @$netsh_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "deleted firewall rules which enable RDP");
+	}
+	elsif (defined($netsh_output)  && @$netsh_output[-1] =~ /No rules match/i) {
+		notify($ERRORS{'OK'}, 0, "no firewall rules exist which enable RDP");
+	}
+	elsif (defined($netsh_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to delete firewall rules which enable RDP, exit status: $netsh_exit_status, output:\n@{$netsh_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run command to delete firewall rules which enable RDP");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_ssh
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_ssh {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $add_rule_command;
+	$add_rule_command .= 'netsh.exe advfirewall firewall delete rule';
+	$add_rule_command .= ' name=all';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=22';
+	$add_rule_command .= ' ;';
+	
+	$add_rule_command .= ' netsh.exe advfirewall firewall add rule';
+	$add_rule_command .= ' name="VCL: allow SSH port 22 from any address"';
+	$add_rule_command .= ' description="Allows incoming SSH (TCP port 22) traffic from any address"';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=22';
+	$add_rule_command .= ' action=allow';
+	$add_rule_command .= ' enable=yes';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' localip=any';
+	$add_rule_command .= ' remoteip=any';
+	
+	# Add the firewall rule
+	my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+	
+	if (defined($add_rule_output)  && @$add_rule_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "added firewall rule to enable SSH from any address");
+	}
+	elsif (defined($add_rule_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable SSH from any address, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable SSH from any address");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 firewall_enable_ssh_private
+
+ Parameters  : 
+ Returns     : 1 if succeeded, 0 otherwise
+ Description : 
+
+=cut
+
+sub firewall_enable_ssh_private {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+	my $computer_node_name       = $self->data->get_computer_node_name();
+	
+	# Get the computer's private IP address
+	my @private_ip_addresses = keys(%{$self->get_private_ip_addresses()});
+	if (!@private_ip_addresses) {
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve private IP addresses");
+		return;
+	}
+	
+	# Join together the IP addresses in case multiple addresses are bound
+	my $private_ip_address_string = join("," , @private_ip_addresses);
+	
+	# First delete any rules which allow ping and then add a new rule
+	my $add_rule_command;
+	$add_rule_command .= 'netsh.exe advfirewall firewall delete rule';
+	$add_rule_command .= ' name=all';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=22';
+	$add_rule_command .= ' ;';
+	
+	$add_rule_command .= ' netsh.exe advfirewall firewall add rule';
+	$add_rule_command .= ' name="VCL: allow SSH port 22 to: ' . $private_ip_address_string . '"';
+	$add_rule_command .= ' description="Allows incoming SSH (TCP port 22) traffic to: ' . $private_ip_address_string . '"';
+	$add_rule_command .= ' protocol=TCP';
+	$add_rule_command .= ' localport=22';
+	$add_rule_command .= ' action=allow';
+	$add_rule_command .= ' enable=yes';
+	$add_rule_command .= ' dir=in';
+	$add_rule_command .= ' localip=' . $private_ip_address_string;
+	
+	# Add the firewall rule
+	my ($add_rule_exit_status, $add_rule_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_rule_command);
+	
+	if (defined($add_rule_output)  && @$add_rule_output[-1] =~ /Ok\./i) {
+		notify($ERRORS{'OK'}, 0, "added firewall rule to enable SSH to: $private_ip_address_string");
+	}
+	elsif (defined($add_rule_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable SSH to: $private_ip_address_string, exit status: $add_rule_exit_status, output:\n@{$add_rule_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add firewall rule to enable SSH to: $private_ip_address_string");
+		return;
+	}
+	
+	return 1;
+}
+
+##############################################################################
+
+=head1 UTILITY FUNCTIONS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 add_kms_server
+
+ Parameters  : $affiliation_name, $kms_address, $kms_port
+ Returns     : If successful: true
+               If failed: false
+ Description : Adds a kms server to the windows-activation variable for the
+               specified affiliation name.
+               If a KMS server with the same address is already saved in the
+               windows-activation variable, it is deleted and the KMS server
+               specified in the subroutine arguments is added to the end of the
+               configuration list.
+
+=cut
+
+sub add_kms_server {
+	my ($affiliation_name, $kms_address, $kms_port) = @_;
+	
+	# Check the arguments
+	unless ($affiliation_name && $kms_address) {
+		notify($ERRORS{'WARNING'}, 0, "affiliation name and kms server address must be specified as arguments");
+		return;
+	}
+	
+	# Set the default KMS port to 1688 if the argument was not specified
+	$kms_port = 1688 unless $kms_port;
+	
+	# Get a new DataStructure object
+	my $data = VCL::DataStructure->new();
+	if ($data) {
+		notify($ERRORS{'DEBUG'}, 0, "created new DataStructure object");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to create new DataStructure object");
+		return;
+	}
+	
+	# Get the Windows activation data from the windows-activation variable
+	my $activation_data = $data->get_variable('windows-activation');
+	if ($activation_data) {
+		notify($ERRORS{'DEBUG'}, 0, "existing activation data:\n" . format_data($activation_data));
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "activation data could not be retrieved, hopefully this is the first entry being added");
+	}
+	
+	# Loop through the existing configurations for the affiliation
+	for (my $i=0; $i<(@{$activation_data->{$affiliation_name}}); $i++) {
+		my $affiliation_configuration = @{$activation_data->{$affiliation_name}}[$i];
+		
+		# Remove the configuration if it's not defined
+		if (!defined $affiliation_configuration) {
+			splice @{$activation_data->{$affiliation_name}}, $i--, 1;
+			next;
+		}
+		
+		# Check if an identical existing address already exists, if so, delete it
+		my $existing_affiliation_kms_address = $affiliation_configuration->{address};
+		if ($existing_affiliation_kms_address eq $kms_address) {
+			splice @{$activation_data->{$affiliation_name}}, $i--, 1;
+			notify($ERRORS{'DEBUG'}, 0, "deleted identical existing address for $affiliation_name: $existing_affiliation_kms_address");
+		}
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "found existing address for $affiliation_name: $existing_affiliation_kms_address");
+		}
+	}
+	
+	# Add the KMS configuration to the activation data
+	push @{$activation_data->{$affiliation_name}}, {
+																method => 'kms',
+																address => $kms_address,
+																port => $kms_port,
+															  };
+	
+	# Set the variable with the updated data
+	$data->set_variable('windows-activation', $activation_data);
+	
+	# Retrieve the updated configuration data
+	$activation_data = $data->get_variable('windows-activation');
+	if ($activation_data) {
+		notify($ERRORS{'DEBUG'}, 0, "updated activation data:\n" . format_data($activation_data));
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "updated activation data could not be retrieved");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 AUTHOR
+
+ Aaron Peeler <aa...@ncsu.edu>
+ Andy Kurth <an...@ncsu.edu>
+
+=head1 COPYRIGHT
+
+ Apache VCL incubator project
+ Copyright 2009 The Apache Software Foundation
+ 
+ This product includes software developed at
+ The Apache Software Foundation (http://www.apache.org/).
+
+=head1 SEE ALSO
+
+L<http://cwiki.apache.org/VCL/>
+
+=cut

Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6/Vista_mod.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6/Vista_mod.pm?rev=780755&view=auto
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6/Vista_mod.pm (added)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod/Version_6/Vista_mod.pm Mon Jun  1 17:51:52 2009
@@ -0,0 +1,159 @@
+#!/usr/bin/perl -w
+###############################################################################
+# $Id: XP_mod.pm 774457 2009-05-13 18:12:08Z arkurth $
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+=head1 NAME
+
+VCL::Module::OS::Windows_mod::Version_6::Vista_mod.pm - VCL module to support Windows Vista operating system
+
+=head1 SYNOPSIS
+
+ Needs to be written
+
+=head1 DESCRIPTION
+
+ This module provides VCL support for Windows Vista.
+
+=cut
+
+##############################################################################
+package VCL::Module::OS::Windows_mod::Version_6::Vista_mod;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::OS::Windows_mod::Version_6);
+
+# Specify the version of this module
+our $VERSION = '2.00';
+
+# Specify the version of Perl to use
+use 5.008000;
+
+use strict;
+use warnings;
+use diagnostics;
+
+use VCL::utils;
+use File::Basename;
+
+##############################################################################
+
+=head1 CLASS VARIABLES
+
+=cut
+
+=head2 $SOURCE_CONFIGURATION_DIRECTORY
+
+ Data type   : Scalar
+ Description : Location on management node of script/utilty/configuration
+               files needed to configure the OS. This is normally the
+					directory under the 'tools' directory specific to this OS.
+
+=cut
+
+our $SOURCE_CONFIGURATION_DIRECTORY = "$TOOLS/Windows_Vista";
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 pre_capture
+
+ Parameters  :
+ Returns     :
+ Description :
+
+=cut
+
+sub pre_capture {
+	my $self = shift;
+	my $args = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	# Get the node configuration directory
+	my $node_configuration_directory = $self->get_node_configuration_directory();
+	unless ($node_configuration_directory) {
+		notify($ERRORS{'WARNING'}, 0, "node configuration directory could not be determined");
+		return;
+	}
+	
+	notify($ERRORS{'OK'}, 0, "beginning Windows Vista image capture preparation tasks");
+	
+	# Call parent class's pre_capture() subroutine
+	notify($ERRORS{'OK'}, 0, "calling parent class pre_capture() subroutine");
+	if ($self->SUPER::pre_capture($args)) {
+		notify($ERRORS{'OK'}, 0, "successfully executed parent class pre_capture() subroutine");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute parent class pre_capture() subroutine");
+		return 0;
+	}
+	
+	# Add HKLM run key to call run_newsid.cmd after the image comes up
+	if (!$self->add_hklm_run_registry_key('run_newsid.cmd', $node_configuration_directory . '/Scripts/run_newsid.cmd  >> ' . $node_configuration_directory . '/Logs/run_newsid.log')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to create run key to call run_newsid.cmd");
+		return;
+	}
+
+	#Shut down computer unless end_state argument was passed with a value other than 'off'
+	my $end_state = $self->{end_state} || 'off';
+	if ($end_state eq 'off') {
+		unless ($self->shutdown()) {
+			notify($ERRORS{'WARNING'}, 0, "failed to shut down computer");
+			return;
+		}
+	}
+exit;
+	notify($ERRORS{'OK'}, 0, "returning 1");
+	return 1;
+} ## end sub pre_capture
+
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 AUTHOR
+
+ Aaron Peeler <aa...@ncsu.edu>
+ Andy Kurth <an...@ncsu.edu>
+
+=head1 COPYRIGHT
+
+ Apache VCL incubator project
+ Copyright 2009 The Apache Software Foundation
+ 
+ This product includes software developed at
+ The Apache Software Foundation (http://www.apache.org/).
+
+=head1 SEE ALSO
+
+L<http://cwiki.apache.org/VCL/>
+
+=cut