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 2010/01/15 18:41:27 UTC

svn commit: r899730 - in /incubator/vcl/trunk/managementnode/lib/VCL/Module/OS: Windows.pm Windows/Version_6.pm

Author: arkurth
Date: Fri Jan 15 17:41:26 2010
New Revision: 899730

URL: http://svn.apache.org/viewvc?rev=899730&view=rev
Log:
VCL-145
Removed old run_sysprep and prepare_drivers subroutines from Windows.pm. These have been replaced by subroutines in Version_5.pm.

Updated Version_6.pm to utilize the product key and KMS server information now stored in the winProductKey and winKMS tables.

The subroutines in Version_6.pm which call slmgr.vbs were not working for 64-bit OS's. This has been fixed.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=899730&r1=899729&r2=899730&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Fri Jan 15 17:41:26 2010
@@ -5990,231 +5990,6 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 run_sysprep
-
- Parameters  : None
- Returns     : 1 if successful, 0 otherwise
- Description : -Calls subroutine to prepare the hardware drivers
-               -Copies Sysprep files to C:\Sysprep
-					-Clears out the setupapi.log file
-					-Calls Sysprep.exe with the options to seal and shutdown the computer
-					-Waits for computer to become unresponsive
-					-Waits 3 additional minutes
-					-Calls provisioning module's power_off() subroutine to make sure the computer is powered off
-
-=cut
-
-sub run_sysprep {
-	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();
-
-	# Remove old C:\Sysprep directory if it exists
-	notify($ERRORS{'DEBUG'}, 0, "attempting to remove old C:/Sysprep directory if it exists");
-	if (!$self->delete_file('C:/Sysprep')) {
-		notify($ERRORS{'WARNING'}, 0, "unable to remove existing C:/Sysprep directory");
-		return 0;
-	}
-
-	# Fix the path, xcopy.exe requires backslashes
-	(my $node_configuration_directory = $NODE_CONFIGURATION_DIRECTORY) =~ s/\//\\/g;
-
-	# Copy Sysprep files to C:\Sysprep
-	my $xcopy_command = "xcopy.exe /E /C /I /Q /H /K /O /Y \"$node_configuration_directory\\Utilities\\Sysprep\" \"C:\\Sysprep\"";
-	my ($xcopy_status, $xcopy_output) = run_ssh_command($computer_node_name, $management_node_keys, $xcopy_command);
-	if (defined($xcopy_status) && $xcopy_status == 0) {
-		notify($ERRORS{'OK'}, 0, "copied Sysprep files to C:/Sysprep");
-	}
-	elsif (defined($xcopy_status)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to copy Sysprep files to C:/Sysprep, exit status: $xcopy_status, output:\n@{$xcopy_output}");
-		return 0;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to copy Sysprep files to C:/Sysprep");
-		return 0;
-	}
-	
-	# Copy and scan drivers
-	notify($ERRORS{'DEBUG'}, 0, "attempting to copy and scan drivers");
-	if (!$self->prepare_drivers()) {
-		notify($ERRORS{'WARNING'}, 0, "unable to copy and scan drivers");
-		return 0;
-	}
-	
-	# Configure the firewall to allow the sessmgr.exe program
-	# Sysprep may hang with a dialog box asking to allow this program
-	if (!$self->firewall_enable_sessmgr()) {
-		notify($ERRORS{'WARNING'}, 0, "unable to configure firewall to allow sessmgr.exe program, Sysprep may hang");
-		return 0;
-	}
-
-	# Clear out setupapi.log
-	my $setupapi_command = "/bin/cat C:/Windows/setupapi.log >> C:/Windows/setupapi_save.log && /bin/cp /dev/null C:/Windows/setupapi.log";
-	my ($setupapi_status, $setupapi_output) = run_ssh_command($computer_node_name, $management_node_keys, $setupapi_command);
-	if (defined($setupapi_status) && $setupapi_status == 0) {
-		notify($ERRORS{'OK'}, 0, "cleared out setupapi.log");
-	}
-	elsif (defined($setupapi_status)) {
-		notify($ERRORS{'OK'}, 0, "failed to clear out setupapi.log, exit status: $setupapi_status, output:\n@{$setupapi_output}");
-	}
-	else {
-		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);
-	if (defined($sysprep_status) && $sysprep_status == 0) {
-		notify($ERRORS{'OK'}, 0, "initiated Sysprep.exe, waiting for $computer_node_name to become unresponsive");
-	}
-	elsif (defined($sysprep_status)) {
-		notify($ERRORS{'OK'}, 0, "failed to initiate Sysprep.exe, exit status: $sysprep_status, output:\n@{$sysprep_output}");
-		return 0;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to initiate Sysprep.exe");
-		return 0;
-	}
-
-	# Wait maximum of 5 minutes for the computer to become unresponsive
-	if (!$self->wait_for_no_ping(5)) {
-		# Computer never stopped responding to ping
-		notify($ERRORS{'WARNING'}, 0, "$computer_node_name never became unresponsive to ping");
-		return 0;
-	}
-
-	# Wait for 3 minutes then call provisioning module's power_off() subroutine
-	# Sysprep does not always shut down the computer when it is done
-	notify($ERRORS{'OK'}, 0, "sleeping for 3 minutes to allow Sysprep.exe to finish");
-	sleep 180;
-
-	# Call power_off() to make sure computer is shut down
-	if (!$self->provisioner->power_off()) {
-		# Computer could not be shut off
-		notify($ERRORS{'WARNING'}, 0, "unable to power off $computer_node_name");
-		return 0;
-	}
-
-	return 1;
-} ## end sub run_sysprep
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 prepare_drivers
-
- Parameters  : 
- Returns     :
- Description : 
-
-=cut
-
-sub prepare_drivers {
-	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 $imagemeta_sysprep = $self->data->get_imagemeta_sysprep();
-	
-	my $driver_directory;
-	if ($imagemeta_sysprep) {
-		$driver_directory = 'C:/Sysprep/Drivers';
-	}
-	else {
-		$driver_directory = 'C:/Drivers';
-	}
-	
-
-	# Remove old driver directories if they exists
-	notify($ERRORS{'DEBUG'}, 0, "attempting to remove old C:/Sysprep\\Drivers directory if it exists");
-	if (!$self->delete_file("C:/Sysprep/Drivers")) {
-		notify($ERRORS{'WARNING'}, 0, "unable to remove existing C:/Sysprep/Drivers directory");
-	}
-	notify($ERRORS{'DEBUG'}, 0, "attempting to remove old C:/Drivers directory if it exists");
-	if (!$self->delete_file("C:/Drivers")) {
-		notify($ERRORS{'WARNING'}, 0, "unable to remove existing C:/Drivers directory");
-	}
-	
-	# Copy driver files to C:/Drivers
-	my $cp_command = "mkdir -p \"$driver_directory\" && cp -rf -T \"$NODE_CONFIGURATION_DIRECTORY/Drivers\" \"$driver_directory\"";
-	my ($cp_status, $cp_output) = run_ssh_command($computer_node_name, $management_node_keys, $cp_command);
-	if (defined($cp_status) && $cp_status == 0) {
-		notify($ERRORS{'DEBUG'}, 0, "copied driver files to $driver_directory");
-	}
-	elsif (defined($cp_status)) {
-		notify($ERRORS{'OK'}, 0, "failed to copy driver files to $driver_directory, exit status: $cp_status, output:\n@{$cp_output}");
-		return 0;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to drivers files to $driver_directory");
-		return 0;
-	}
-	
-	# Delete existing DevicePath key
-	my $reg_del_command = $self->get_system32_path() . '/reg.exe DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion" /v DevicePath /f';
-	my ($reg_del_status, $reg_del_output) = run_ssh_command($computer_node_name, $management_node_keys, $reg_del_command);
-	if (defined($reg_del_status) && $reg_del_status == 0) {
-		notify($ERRORS{'DEBUG'}, 0, "deleted existing DevicePath key");
-	}
-	elsif (defined($reg_del_status)) {
-		notify($ERRORS{'OK'}, 0, "failed to delete existing DevicePath key, exit status: $reg_del_status, output:\n@{$reg_del_output}");
-		return 0;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to delete existing DevicePath key");
-		return 0;
-	}
-
-	# Run spdrvscn.exe
-	my $spdrvscn_command = "$NODE_CONFIGURATION_DIRECTORY/Utilities/SPDrvScn/spdrvscn.exe /p \"$driver_directory\" /e inf /d \$SYSTEMROOT\\\\inf /a /s /q";
-	my ($spdrvscn_status, $spdrvscn_output) = run_ssh_command($computer_node_name, $management_node_keys, $spdrvscn_command);
-	if (defined($spdrvscn_status) && $spdrvscn_status == 0) {
-		notify($ERRORS{'OK'}, 0, "executed spdrvscn.exe");
-	}
-	elsif (defined($spdrvscn_status)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to execute spdrvscn.exe, exit status: $spdrvscn_status, output:\n@{$spdrvscn_output}");
-		return 0;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to execute spdrvscn.exe");
-		return 0;
-	}
-	
-	# Query the DevicePath registry value in order to save it in the log for troubleshooting
-	my $reg_query_command = $self->get_system32_path() . '/reg.exe QUERY "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion" /v DevicePath';
-	my ($reg_query_status, $reg_query_output) = run_ssh_command($computer_node_name, $management_node_keys, $reg_query_command, '', '', 1);
-	if (defined($reg_query_status) && $reg_query_status == 0) {
-		notify($ERRORS{'DEBUG'}, 0, "queried DevicePath registry key:\n" . join("\n", @{$reg_query_output}));
-	}
-	elsif (defined($reg_query_status)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to query DevicePath registry key, exit status: $reg_query_status, output:\n@{$reg_query_output}");
-		return 0;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to query DevicePath registry key");
-		return 0;
-	}
-	
-	# Format the string for the log output
-	my ($device_path_string) = grep(/devicepath\s+(reg_.*sz)/i, @{$reg_query_output});
-	$device_path_string =~ s/.*(devicepath\s+reg_.*sz)\s*/$1\n/i;
-	$device_path_string =~ s/;/\n/g;
-	notify($ERRORS{'OK'}, 0, "device path string: $device_path_string");
-	
-	return 1;
-} ## end sub prepare_drivers
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 clean_hard_drive
 
  Parameters  : 
@@ -7743,7 +7518,7 @@
 	# Get the PROCESSOR_IDENTIFIER environment variable to determine if OS is 32 or 64-bit
 	my ($set_exit_status, $set_output) = run_ssh_command($computer_node_name, $management_node_keys, 'set', '', '', 1);
 	if (defined($set_exit_status) && $set_exit_status == 0) {
-		notify($ERRORS{'OK'}, 0, "executed set command to determine architecture on $computer_node_name");
+		notify($ERRORS{'DEBUG'}, 0, "executed set command to determine architecture on $computer_node_name");
 	}
 	elsif (defined($set_exit_status)) {
 		notify($ERRORS{'WARNING'}, 0, "failed to execute set command to determine architecture on $computer_node_name, exit status: $set_exit_status, output:\n@{$set_output}");
@@ -7820,6 +7595,14 @@
  Description : Retrieves the Windows product name from the registry. This is
                stored at:
                HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProductName
+               
+               The product name stored in the registry is used in the
+               winProductKey table to match a product key up with a product. It
+               must match exactly. Known strings for some versions of Windows:
+               "Microsoft Windows XP"
+               "Microsoft Windows Server 2003"
+               "Windows Server (R) 2008 Datacenter"
+               "Windows Vista (TM) Enterprise"
 
 =cut
 
@@ -8150,14 +7933,9 @@
 		return;
 	}
 	
-	# Get the product name, could be:
-	# "Microsoft Windows XP"
-	# "Microsoft Windows Server 2003"
+	# Get the product name from the registry on the computer
 	my $product_name = shift || $self->get_product_name();
-	if ($product_name) {
-		notify($ERRORS{'DEBUG'}, 0, "product name: $product_name");
-	}
-	else {
+	if (!$product_name) {
 		notify($ERRORS{'WARNING'}, 0, "product name argument was not passed and could not be determined from computer");
 		return;
 	}

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm?rev=899730&r1=899729&r2=899730&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm Fri Jan 15 17:41:26 2010
@@ -249,10 +249,11 @@
  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.
+ Description : Activates Microsoft Windows. A first attempt is made using a
+               MAK key if one has been configured in the winProductKey table
+               for the version of Windows installed on the computer. If unable
+               to activate using a MAK key, activation is attempting using a
+               KMS server configured in the winKMS table.
 
 =cut
 
@@ -263,136 +264,180 @@
 		return;
 	}
 	
-	my $management_node_keys     = $self->data->get_management_node_keys();
-	my $computer_node_name       = $self->data->get_computer_node_name();
-	my $product_name             = $self->get_product_name();
+	# Check if Windows has already been activated
+	my $license_status = $self->get_license_status();
+	if ($license_status && $license_status =~ /licensed/i) {
+		notify($ERRORS{'OK'}, 0, "Windows has already been activated");
+		return 1;
+	}
+	
+	## Attempt to activate using MAK product key
+	#return 1 if $self->activate_mak();
 	
-	# 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");
+	# Attempt to activate using KMS server
+	return 1 if $self->activate_kms();
+	
+	notify($ERRORS{'WARNING'}, 0, "failed to activate Windows using MAK or KMS methods");
+	return;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 activate_mak
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Attempts to activate Windows using a MAK key stored in the
+               winProductKey table.
+
+=cut
+
+sub activate_mak {
+	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;
+	}
+	
+	# Attempt to get the product key stored in the winProductKey table
+	# This will return the correct key for the affiliation and version of Windows installed on the computer
+	my $product_key = $self->get_product_key();
+	if ($product_key) {
+		notify($ERRORS{'DEBUG'}, 0, "retrieved MAK product key from the winProductKey table: $product_key");
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "image affiliation name could not be retrieved, using default licensing configuration");
-		$image_affiliation_name = 'default';
+		notify($ERRORS{'OK'}, 0, "MAK product key could not be retrieved from the winProductKey table");
+		return;
 	}
 	
-	# 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));
+	# Attempt to install the MAK product key
+	if ($self->run_slmgr_ipk($product_key)) {
+		notify($ERRORS{'DEBUG'}, 0, "installed MAK product key: $product_key");
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "activation data could not be retrieved");
+		notify($ERRORS{'WARNING'}, 0, "failed to install MAK product key: $product_key");
 		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));
+	# Attempt to activate the license
+	if ($self->run_slmgr_ato()) {
+		notify($ERRORS{'OK'}, 0, "activated Windows using MAK product key: $product_key");
+		return 1;
 	}
 	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;
-		}
+		notify($ERRORS{'WARNING'}, 0, "failed to activate Windows using MAK product key: $product_key");
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 activate_kms
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Attempts to activate Windows using a KMS server configured in
+               the winKMS table.
+
+=cut
+
+sub activate_kms {
+	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;
+	}
+	
+	# Get the KMS server info from the winKMS table
+	my $kms_server_info = $self->get_kms_servers();
+	if (!$kms_server_info) {
+		notify($ERRORS{'WARNING'}, 0, "KMS server information could not be retrieved");
+		return;
+	}
+	
+	# Attempt to get the KMS client product key
+	# This is a publically available key that needs to be installed in order to activate via KMS
+	my $product_key = $self->get_kms_client_product_key();
+	if ($product_key) {
+		notify($ERRORS{'DEBUG'}, 0, "retrieved KMS client product key: $product_key");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "KMS client product key could not be retrieved");
+		return;
 	}
 	
+	# Attempt to install the KMS client product key
+	if ($self->run_slmgr_ipk($product_key)) {
+		notify($ERRORS{'DEBUG'}, 0, "installed KMS client product key: $product_key");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to install KMS client product key: $product_key");
+		return;
+	}
 	
-	# Loop through the activation methods for the affiliation
-	for my $activation_config (@$affiliation_config) {
-		my $activation_method = $activation_config->{method};
+	# Loop through the KMS servers, set KMS server, attempt to activate
+	for my $kms_server (@{$kms_server_info}) {
+		my $kms_address = $kms_server->{address};
+		my $kms_port = $kms_server->{port};
+		notify($ERRORS{'DEBUG'}, 0, "attempting to set KMS server: $kms_address:$kms_port");
 		
-		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");
-			
-			# Attempt to install the KMS client product key
-			# This must be done or else the slmgr.vbs -skms option won't be available
-			if ($self->install_kms_client_product_key()) {
-				notify($ERRORS{'DEBUG'}, 0, "installed the KMS client product key");
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to install the KMS client product key");
-				next;
-			}
+		# Run slmgr.vbs -skms to configure the computer to use the KMS server
+		if ($self->run_slmgr_skms($kms_address, $kms_port)) {
+			notify($ERRORS{'OK'}, 0, "set KMS server: $kms_address:$kms_port");
 			
-			# Run slmgr.vbs -skms to configure the computer to use the KMS server
-			if ($self->set_kms($kms_address, $kms_port)) {
-				notify($ERRORS{'DEBUG'}, 0, "set KMS address");
+			# Attempt to activate the license
+			if ($self->run_slmgr_ato()) {
+				notify($ERRORS{'OK'}, 0, "activated Windows using KMS server: $kms_address:$kms_port");
+				return 1;
 			}
 			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to set KMS address");
+				notify($ERRORS{'WARNING'}, 0, "failed to activate Windows using KMS server: $kms_address:$kms_port");
 				next;
 			}
 		}
-		elsif ($activation_method =~ /mak/i) {
-			my $mak_key = $activation_config->{key};
-			my $mak_product = $activation_config->{product};
-			
-			if ($mak_product eq $product_name) {
-				notify($ERRORS{'DEBUG'}, 0, "attempting to set install MAK key for $mak_product: $mak_key");
-			}
-			else {
-				notify($ERRORS{'DEBUG'}, 0, "MAK key product ($mak_product) does not match installed version of Windows ($product_name)");
-				next;
-			}
-			
-			# Attempt to install the MAK product key
-			if ($self->install_product_key($mak_key)) {
-				notify($ERRORS{'DEBUG'}, 0, "installed MAK product key: $mak_key");
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to install MAK product key: $mak_key");
-				next;
-			}
-		}
-		else  {
-			notify($ERRORS{'WARNING'}, 0, "unsupported activation method: $activation_method");
-			next;
-		}
-		
-		# Attempt to activate the license
-		if ($self->activate_license()) {
-			notify($ERRORS{'OK'}, 0, "activated license");
-			return 1;
-		}
 		else {
-			notify($ERRORS{'WARNING'}, 0, "failed to activate license");
+			notify($ERRORS{'WARNING'}, 0, "failed to set KMS server: $kms_address:$kms_port");
 			next;
 		}
 	}
 	
-	notify($ERRORS{'WARNING'}, 0, "failed to activate license on $computer_node_name using any configured method");
+	notify($ERRORS{'WARNING'}, 0, "failed to activate Windows using any KMS servers configured in the winKMS table");
 	return;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 install_kms_client_product_key
+=head2 get_kms_client_product_key
 
- Parameters  : None
- Returns     : If successful: true
+ Parameters  : $product_name (optional
+ Returns     : If successful: string
                If failed: false
- Description : 
+ Description : Returns a KMS client product key based on the version of Windows
+               either specified as an argument or installed on the computer. A
+               KMS client product key is a publically shared product key which
+               must be installed before activating using a KMS server.
 
 =cut
 
-sub install_kms_client_product_key {
+sub get_kms_client_product_key {
 	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;
 	}
 	
+	# Get the product name
+	my $product_name = shift || $self->get_product_name();
+	if (!$product_name) {
+		notify($ERRORS{'WARNING'}, 0, "product name was not passed as an argument and could not be retrieved from computer");
+		return;
+	}
+	
+	# Remove (TM) or (R) from the product name
+	$product_name =~ s/ \([tmr]*\)//ig;
+	
 	# Create a hash of KMS setup product keys
 	# These are publically available from Microsoft's Volume Activation 2.0 Deployment Guide
 	my %kms_product_keys = (
@@ -410,42 +455,28 @@
 		'Windows Web Server 2008'                        => 'WYR28-R7TFJ-3X2YQ-YCY4H-M249D',
 	);
 	
-	# Get the KMS setup product key from the hash
-	my $product_name = $self->get_product_name();
-	
-	# Remove (TM) or (R) from the product name
-	$product_name =~ s/ \([tmr]*\)//ig;
-	
+	# Get the matching product key from the hash for the product name
 	my $product_key = $kms_product_keys{$product_name};
 	if (!$product_key) {
-		notify($ERRORS{'WARNING'}, 0, "failed to retrieve KMS setup key for Windows product: $product_name");
-		return;
-	}
-	notify($ERRORS{'DEBUG'}, 0, "KMS client setup key for $product_name: $product_key");
-	
-	# Install the KMS client product key
-	if ($self->install_product_key($product_key)) {
-		notify($ERRORS{'OK'}, 0, "installed KMS client product key");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to install KMS client product key");
+		notify($ERRORS{'WARNING'}, 0, "unsupported product name: $product_name, KMS client product key is not known");
 		return;
 	}
+	notify($ERRORS{'DEBUG'}, 0, "returning KMS client setup key for $product_name: $product_key");
+	return $product_key;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 install_product_key
+=head2 run_slmgr_ipk
 
  Parameters  : None
  Returns     : If successful: true
                If failed: false
- Description : 
+ Description : Runs slmgr.vbs -ipk to install a product key.
 
 =cut
 
-sub install_product_key {
+sub run_slmgr_ipk {
 	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");
@@ -454,6 +485,7 @@
 	
 	my $management_node_keys     = $self->data->get_management_node_keys();
 	my $computer_node_name       = $self->data->get_computer_node_name();
+	my $system32_path = $self->get_system32_path();
 	
 	# Get the arguments
 	my $product_key = shift;
@@ -463,7 +495,7 @@
 	}
 	
 	# Run cscript.exe slmgr.vbs -ipk to install the product key
-	my $ipk_command = 'cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -ipk ' . $product_key;
+	my $ipk_command = "$system32_path/cmd.exe /c cscript.exe //NoLogo C:/Windows/System32/slmgr.vbs -ipk $product_key";
 	my ($ipk_exit_status, $ipk_output) = run_ssh_command($computer_node_name, $management_node_keys, $ipk_command);
 	if (defined($ipk_exit_status) && $ipk_exit_status == 0 && grep(/successfully/i, @$ipk_output)) {
 		notify($ERRORS{'OK'}, 0, "installed product key: $product_key");
@@ -482,16 +514,16 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 set_kms
+=head2 run_slmgr_skms
 
  Parameters  : None
  Returns     : If successful: true
                If failed: false
- Description : 
+ Description : Runs slmgr.vbs -skms to set the KMS server on a Windows client.
 
 =cut
 
-sub set_kms {
+sub run_slmgr_skms {
 	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");
@@ -500,6 +532,7 @@
 	
 	my $management_node_keys     = $self->data->get_management_node_keys();
 	my $computer_node_name       = $self->data->get_computer_node_name();
+	my $system32_path = $self->get_system32_path();
 	
 	# Get the KMS address argument
 	my $kms_address = shift;
@@ -512,7 +545,8 @@
 	my $kms_port = shift || 1688;
 	
 	# Run slmgr.vbs -skms to configure the computer to use the KMS server
-	my $skms_command = 'cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -skms ' . "$kms_address:$kms_port";
+	# slmgr.vbs must be run in a command shell using the correct System32 path or the task it's supposed to do won't really take effect
+	my $skms_command = "$system32_path/cmd.exe /c cscript.exe //NoLogo C:/Windows/System32/slmgr.vbs -skms $kms_address:$kms_port";
 	my ($skms_exit_status, $skms_output) = run_ssh_command($computer_node_name, $management_node_keys, $skms_command);
 	if (defined($skms_exit_status) && $skms_exit_status == 0 && grep(/successfully/i, @$skms_output)) {
 		notify($ERRORS{'OK'}, 0, "set kms server to $kms_address:$kms_port");
@@ -531,16 +565,16 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 activate_license
+=head2 run_slmgr_ato
 
  Parameters  : None
  Returns     : If successful: true
                If failed: false
- Description : 
+ Description : Runs slmgr.vbs -ato to activate Windows.
 
 =cut
 
-sub activate_license {
+sub run_slmgr_ato {
 	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");
@@ -549,9 +583,10 @@
 	
 	my $management_node_keys     = $self->data->get_management_node_keys();
 	my $computer_node_name       = $self->data->get_computer_node_name();
+	my $system32_path = $self->get_system32_path();
 	
 	# Run cscript.exe slmgr.vbs -ato to install the product key
-	my $ato_command = 'cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -ato';
+	my $ato_command = "$system32_path/cmd.exe /c cscript.exe //NoLogo C:/Windows/System32/slmgr.vbs -ato";
 	my ($ato_exit_status, $ato_output) = run_ssh_command($computer_node_name, $management_node_keys, $ato_command);
 	if (defined($ato_exit_status) && $ato_exit_status == 0 && grep(/successfully/i, @$ato_output)) {
 		notify($ERRORS{'OK'}, 0, "activated license");
@@ -570,6 +605,50 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_license_status
+
+ Parameters  : None
+ Returns     : If successful: string
+               If failed: false
+ Description : Runs slmgr.vbs -dlv to determine the licensing status. The value
+               of the "License Status" line is returned.
+
+=cut
+
+sub get_license_status {
+	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 $system32_path = $self->get_system32_path();
+	
+	# Run cscript.exe slmgr.vbs -dlv to get the activation status
+	my $dlv_command = "$system32_path/cmd.exe /c cscript.exe //NoLogo C:/Windows/System32/slmgr.vbs -dlv";
+	my ($dlv_exit_status, $dlv_output) = run_ssh_command($computer_node_name, $management_node_keys, $dlv_command, '', '', 0);
+	if ($dlv_output && grep(/License Status/i, @$dlv_output)) {
+		#notify($ERRORS{'DEBUG'}, 0, "retrieved license information");
+	}
+	elsif (defined($dlv_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to retrieve activation status, exit status: $dlv_exit_status, output:\n@{$dlv_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to retrieve activation status");
+		return;
+	}
+	
+	my ($license_status_line) = grep(/License Status/i, @$dlv_output);
+	my ($license_status) = $license_status_line =~ /: (\w+)/;
+	notify($ERRORS{'DEBUG'}, 0, "retrieved license status: $license_status");
+	return $license_status;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 deactivate
 
  Parameters  : None
@@ -590,6 +669,7 @@
 	
 	my $management_node_keys     = $self->data->get_management_node_keys();
 	my $computer_node_name       = $self->data->get_computer_node_name();
+	my $system32_path = $self->get_system32_path();
 	
 	my $registry_string .= <<'EOF';
 Windows Registry Editor Version 5.00
@@ -610,7 +690,7 @@
 	}
 	
 	# Run slmgr.vbs -rearm
-	my $rearm_command = 'cscript.exe //NoLogo $SYSTEMROOT/System32/slmgr.vbs -rearm';
+	my $rearm_command = "$system32_path/cmd.exe /c cscript.exe //NoLogo C:/Windows/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");
@@ -1157,97 +1237,6 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=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;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 run_sysprep
 
  Parameters  : None