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/03 16:15:51 UTC

svn commit: r781393 - /incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_mod.pm

Author: arkurth
Date: Wed Jun  3 14:15:51 2009
New Revision: 781393

URL: http://svn.apache.org/viewvc?rev=781393&view=rev
Log:
VCL-23
Added subroutines and added calls in pre_capture() to further automate image creation tasks:
disable_windows_defender()
disable_automatic_updates()
disable_security_center_notifications()

Added condition to delete_file() to check for "Circular directory" warning when rm is used. It now catches this and doesn't display a warning. Other deletion methods are then attempted.

Fixed bug in filesystem_entry_exists() if path specified included backslashes. Added regex to convert them to forward slashes before checking if exists. Changed command to enclose path in double quotes instead of single.

Added ipconfig_renew() subroutine and added call to it from enable_dhcp(). This is necessary because the default gateways are sometimes lost when DHCP is enabled.

Added to the POD documentation for a few of the subroutines.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows_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=781393&r1=781392&r2=781393&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 Wed Jun  3 14:15:51 2009
@@ -71,10 +71,14 @@
 
 =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.
+ Data type   : String
+ Description : Location on the management node of the files specific to this OS
+               module which are needed to configure the loaded OS on a computer.
+               This is normally the directory under 'tools' named after this OS
+               module.
+               
+               Example:
+               /usr/local/vcl/tools/Windows
 
 =cut
 
@@ -83,9 +87,14 @@
 
 =head2 $NODE_CONFIGURATION_DIRECTORY
 
- Data type   : Scalar
- Description : Destination location on computer of
-               script/utilty/configuration files needed to configure the OS.
+ Data type   : String
+ Description : Location on computer on which an image has been loaded where
+               configuration files reside. The files residing on the managment
+               node in the directory specified by $NODE_CONFIGURATION_DIRECTORY
+               are copied to this directory.
+               
+               Example:
+               C:\Cygwin\home\root\VCL
 
 =cut
 
@@ -101,10 +110,15 @@
 
 =head2 pre_capture
 
- Parameters  : None, but must be called as an object method
- Returns     : 1 if successful, 0 if failed
- Description : Performs the steps necessary to prepare a Windows OS to be captured.
-               Called by provisioning module's capture() subroutine.
+ Parameters  : Hash containing 'end_state' key
+ Returns     : If successful: true
+               If failed: false
+ Description : Performs the steps necessary to prepare a Windows OS before an
+               image is captured.
+               This subroutine is called by a provisioning module's capture()
+               subroutine.
+               
+               The steps performed are:
 
 =over 3
 
@@ -132,7 +146,7 @@
 
 =item 1
 
-Log off all currently logged in users
+ Log off all currently logged in users
 
 =cut
 
@@ -143,7 +157,7 @@
 
 =item *
 
-Set root account password to known value
+ Set root account password to known value
 
 =cut
 
@@ -154,7 +168,7 @@
 
 =item *
 
-Delete the users assigned to this reservation
+ Delete the users assigned to this reservation
 
 =cut
 
@@ -165,7 +179,7 @@
 
 =item *
 
-Copy the capture configuration files to the computer (scripts, utilities, drivers...)
+ Copy the capture configuration files to the computer (scripts, utilities, drivers...)
 
 =cut
 
@@ -176,7 +190,7 @@
 
 =item *
 
-Disable autoadminlogon before disabling the pagefile and rebooting
+ Disable autoadminlogon before disabling the pagefile and rebooting
 
 =cut
 
@@ -187,7 +201,7 @@
 
 =item *
 
-Disable IPv6
+ Disable IPv6
 
 =cut
 
@@ -197,17 +211,17 @@
 
 =item *
 
-Disable dynamic DNS
+ Disable dynamic DNS
 
 =cut
 
 	if (!$self->disable_dynamic_dns()) {
 		notify($ERRORS{'WARNING'}, 0, "unable to disable dynamic dns");
 	}
-	
+
 =item *
 
-Disable Internet Explorer configuration page
+ Disable Internet Explorer configuration page
 
 =cut
 
@@ -217,7 +231,37 @@
 
 =item *
 
-Call script to clean up the hard drive
+ Disable Windows Defender
+
+=cut
+
+	if (!$self->disable_windows_defender()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable Windows Defender");
+	}
+
+=item *
+
+ Disable Automatic Updates
+
+=cut
+
+	if (!$self->disable_automatic_updates()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable automatic updates");
+	}
+
+=item *
+
+ Disable Security Center notifications
+
+=cut
+
+	if (!$self->disable_security_center_notifications()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable Security Center notifications");
+	}
+
+=item *
+
+ Clean up the hard drive
 
 =cut
 
@@ -227,7 +271,7 @@
 
 =item *
 
-Apply Windows security templates
+ Apply Windows security templates
 
 =cut
 
@@ -236,16 +280,23 @@
 		notify($ERRORS{'WARNING'}, 0, "unable to apply security templates");
 		return 0;
 	}
-
+	
 =item *
 
-Disable the pagefile
+ Configure the network adapters to use DHCP
 
- ********* node reboots *********
+=cut
+
+	if (!$self->enable_dhcp()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to enable DHCP on the public and private interfaces");
+		return 0;
+	}
 
 =item *
 
-Disable the pagefile, reboot, and delete pagefile.sys
+ Disable the pagefile, reboot, and delete pagefile.sys
+ 
+ ********* node reboots *********
 
 =cut
 
@@ -258,18 +309,7 @@
 
 =item *
 
-Configure the network adapters to use DHCP
-
-=cut
-
-	if (!$self->enable_dhcp()) {
-		notify($ERRORS{'WARNING'}, 0, "unable to enable DHCP on the public and private interfaces");
-		return 0;
-	}
-	
-=item *
-
-Allow users to connect remotely
+ Allow users to connect remotely (this does not enable RDP, but allows general remote access)
 
 =cut
 
@@ -279,7 +319,7 @@
 
 =item *
 
-Disable RDP access from any address by adding a firewall exception
+ Disable RDP access from any IP address
 
 =cut
 
@@ -290,7 +330,7 @@
 
 =item *
 
-Enable SSH access from any IP addresses by adding a firewall exception
+ Enable SSH access from any IP address
 
 =cut
 
@@ -301,7 +341,7 @@
 
 =item *
 
-Enable ping access from any IP addresses by adding a firewall exception
+ Enable ping from any IP address
 
 =cut
 
@@ -312,7 +352,7 @@
 
 =item *
 
-Reenable the pagefile, this will take effect when the saved image boots
+ Reenable the pagefile
 
 =cut
 
@@ -323,7 +363,7 @@
 
 =item *
 
-Set sshd service startup mode to manual
+ Set the Cygwin SSHD service startup mode to manual
 
 =cut
 
@@ -345,10 +385,16 @@
 
 =head2 post_load
 
- Parameters  : reference to an object of this class
- Returns     : 1 if successful, 0 if failed
- Description : Performs the steps necessary to configure a Windows OS after an image has been loaded.
-               Called by provisioning module's load() subroutine.
+ Parameters  : None.
+ Returns     : If successful: true
+               If failed: false
+ Description : Performs the steps necessary to configure a Windows OS after an
+               image has been loaded.
+               
+               This subroutine is called by a provisioning module's load()
+               subroutine.
+               
+               The steps performed are:
 
 =over 3
 
@@ -369,7 +415,10 @@
 
 =item 1
 
-Log off all currently logged in users
+ Log off all currently logged on users
+
+ Do this in case autoadminlogon was enabled during the load process and the user
+ account was not properly logged off.
 
 =cut
 
@@ -379,17 +428,22 @@
 
 =item *
 
-Set the Cygwin SSHD server startup mode to auto
+ Set the Cygwin SSHD service startup mode to automatic
+ 
+ The Cygwin SSHD service startup mode should be set to automatic after an image
+ has been loaded and is ready to be reserved. Access will be lost if the service
+ is not set to automatic and the computer is rebooted.
 
 =cut
 
 	if (!$self->set_service_startup_mode('sshd', 'auto')) {
 		notify($ERRORS{'WARNING'}, 0, "unable to set sshd service startup mode to auto");
+		return 0;
 	}
 	
 =item *
 
-Set the computer name
+ Set the computer name
 
 =cut
 
@@ -399,7 +453,7 @@
 
 =item *
 
-Enable RDP access only from private network by adding a firewall exception
+ Enable RDP access on the private network interface
 
 =cut
 
@@ -410,7 +464,7 @@
 	
 =item *
 
-Enable SSH access only from private IP addresses by adding a firewall exception
+ Enable SSH access on the private network interface
 
 =cut
 
@@ -420,7 +474,7 @@
 
 =item *
 
-Enable ping access only from private IP addresses by adding a firewall exception
+ Enable ping on the private network interface
 
 =cut
 
@@ -430,7 +484,7 @@
 	
 =item *
 
-Set the "My Computer" description to the image pretty name
+ Set the "My Computer" description to the image pretty name
 
 =cut
 
@@ -460,7 +514,7 @@
 
 =item *
 
-Randomize root password
+ Randomize the root account password
 
 =cut
 
@@ -471,7 +525,7 @@
 
 =item *
 
-Randomize Administrator password
+ Randomize the Administrator account password
 
 =cut
 
@@ -482,7 +536,7 @@
 
 =item *
 
-Check if imagemeta postoption is set to reboot
+ Check if the imagemeta postoption is set to reboot, reboot if necessary
 
 =cut
 
@@ -815,6 +869,9 @@
 	elsif (defined($rm_exit_status) && $rm_exit_status == 0) {
 		notify($ERRORS{'OK'}, 0, "file either deleted or does not exist on $computer_node_name: $path, output:\n@{$rm_output}");
 	}
+	elsif (defined($rm_output) && grep(/Circular directory structure/i, @{$rm_output})) {
+		notify($ERRORS{'DEBUG'}, 0, "circular directory structure found, rm can't handle this, attempting next deletion method");
+	}
 	elsif ($rm_exit_status) {
 		notify($ERRORS{'WARNING'}, 0, "failed to delete file on $computer_node_name: $path, exit status: $rm_exit_status, output:\n@{$rm_output}");
 	}
@@ -829,6 +886,8 @@
 		return 1;
 	}
 	
+	notify($ERRORS{'DEBUG'}, 0, "file still exists: $path, attempting to delete it using cmd.exe /c del");
+	
 	# rm didn't get rid of the file, try del
 	# Assemble the Windows shell del command and execute it
 	my $del_command = '$SYSTEMROOT/System32/cmd.exe /c "del /s /q /f /a \\"' . $path . '\\""';
@@ -855,6 +914,8 @@
 		notify($ERRORS{'DEBUG'}, 0, "confirmed file does not exist: $path");
 		return 1;
 	}
+	
+	notify($ERRORS{'DEBUG'}, 0, "file still exists: $path, attempting to delete it using cmd.exe /c rmdir");
 
 	# Assemble the Windows shell rmdir command and execute it
 	my $rmdir_command = '$SYSTEMROOT/System32/cmd.exe /c "rmdir /s /q \\"' . $path . '\\""';
@@ -1021,16 +1082,19 @@
 		notify($ERRORS{'WARNING'}, 0, "unable to detmine if file exists, path was not specified as an argument");
 		return;
 	}
+	
+	# Replace backslashes with forward slashes
+	$path =~ s/\\+/\//;
 
 	# Assemble the ls command and execute it
-	my $ls_command = "ls -la '$path'";
+	my $ls_command = "ls -la \"$path\"";
 	my ($ls_exit_status, $ls_output) = run_ssh_command($computer_node_name, $management_node_keys, $ls_command, '', '', 1);
 	if (defined($ls_exit_status) && $ls_exit_status == 0) {
 		notify($ERRORS{'DEBUG'}, 0, "filesystem entry exists on $computer_node_name: $path");
 		return 1;
 	}
 	elsif (defined($ls_exit_status) && $ls_exit_status == 2) {
-		notify($ERRORS{'DEBUG'}, 0, "filesystem entry does NOT exist on $computer_node_name: $path");
+		notify($ERRORS{'DEBUG'}, 0, "filesystem entry does NOT exist on $computer_node_name: $path\noutput:\n" . join("\n", @$ls_output));
 		return 0;
 	}
 	elsif ($ls_exit_status) {
@@ -4663,7 +4727,7 @@
 			notify($ERRORS{'OK'}, 0, "dhcp is already enabled on interface '$interface_name'");
 		}
 		elsif (defined($set_dhcp_status)) {
-			notify($ERRORS{'OK'}, 0, "unable to set interface '$interface_name' to use dhcp, exit status: $set_dhcp_status, output:\n@{$set_dhcp_output}");
+			notify($ERRORS{'WARNING'}, 0, "unable to set interface '$interface_name' to use dhcp, exit status: $set_dhcp_status, output:\n@{$set_dhcp_output}");
 			return 0;
 		}
 		else {
@@ -4671,11 +4735,59 @@
 			return 0;
 		}
 	} ## end for my $interface_name (@interface_names)
-	return 1;
+	
+	# Run ipconfig /renew after setting the adapters to use DHCP
+	# The default gateway gets lost otherwise
+	return $self->ipconfig_renew();
 } ## end sub enable_dhcp
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 ipconfig_renew
+
+ Parameters  : 
+ Returns     :
+ Description : 
+
+=cut
+
+sub ipconfig_renew {
+	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 $interface_name_argument = shift;
+	
+	# Assemble the ipconfig command, include the interface name if argument was specified
+	my $ipconfig_command = '$SYSTEMROOT/System32/ipconfig.exe /renew';
+	if ($interface_name_argument) {
+		$ipconfig_command .= " \"$interface_name_argument\"";
+	}
+	
+	# Run ipconfig
+	my ($ipconfig_status, $ipconfig_output) = run_ssh_command($computer_node_name, $management_node_keys, $ipconfig_command);
+	if (defined($ipconfig_status) && $ipconfig_status == 0) {
+		notify($ERRORS{'OK'}, 0, "ran ipconfig /renew");
+	}
+	elsif (defined($ipconfig_status)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to run ipconfig /renew, exit status: $ipconfig_status, output:\n@{$ipconfig_output}");
+		return 0;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to to run ipconfig /renew");
+		return 0;
+	}
+	
+	return 1;
+} 
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 delete_capture_configuration_files
 
  Parameters  : 
@@ -6448,7 +6560,7 @@
 
 =head2 get_node_configuration_directory
 
- Parameters  : None
+ 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
@@ -6464,7 +6576,7 @@
 
 =head2 set_computer_name
 
- Parameters  : $computer_name
+ Parameters  : $computer_name (optional)
  Returns     : If successful: true
                If failed: false
  Description : Sets the registry keys to set the computer name. This subroutine
@@ -6523,6 +6635,173 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 disable_security_center_notifications
+
+ Parameters  : None.
+ Returns     : If successful: true
+               If failed: false
+ Description : Disables Windows Security Center notifications which are
+               displayed in the notification area (system tray).
+
+=cut
+
+sub disable_security_center_notifications {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+
+	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\SOFTWARE\Microsoft\Security Center]
+"AntiSpywareDisableNotify"=dword:00000001
+"AntiVirusDisableNotify"=dword:00000001
+"FirewallDisableNotify"=dword:00000001
+"UacDisableNotify"=dword:00000001
+"UpdatesDisableNotify"=dword:00000001
+"FirstRunDisabled"=dword:00000001
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Security Center\Svc]
+"AntiVirusOverride"=dword:00000001
+"AntiSpywareOverride"=dword:00000001
+"FirewallOverride"=dword:00000001
+EOF
+
+	# Import the string into the registry
+	if ($self->import_registry_string($registry_string)) {
+		notify($ERRORS{'OK'}, 0, "set the registry keys to disable security center notifications");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to set the registry key to disable security center notifications");
+		return 0;
+	}
+
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 disable_automatic_updates
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Disables Windows Automatic Updates by configuring a local group
+               policy:
+               HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU\NoAutoUpdate=1
+               
+               This must be done using a policy in order to prevent
+               Windows Security Center will display a warning icon in the
+               notification area. Windows Update can be disabled via the GUI
+               which configures the following key but a warning will be
+               presented to the user:
+               HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update
+
+=cut
+
+sub disable_automatic_updates {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+
+	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\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU]
+"NoAutoUpdate"=dword:00000001
+EOF
+
+	# Import the string into the registry
+	if ($self->import_registry_string($registry_string)) {
+		notify($ERRORS{'OK'}, 0, "disabled automatic updates");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to set the registry key to disable automatic updates");
+		return 0;
+	}
+
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 disable_windows_defender
+
+ Parameters  : None
+ Returns     : If successful: true
+               If failed: false
+ Description : Disables Windows Defender by doing the following:
+               -Configures local group policy to disable Windows Defender
+               -Removes HKLM...Run registry key to start Windows Defender at logon
+               -Stops the Windows Defender service
+               -Disables the Windows Defender service
+
+=cut
+
+sub disable_windows_defender {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+
+	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\SOFTWARE\Policies\Microsoft\Windows Defender]
+"DisableAntiSpyware"=dword:00000001
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
+"Windows Defender"=-
+EOF
+
+	# Import the string into the registry
+	if ($self->import_registry_string($registry_string)) {
+		notify($ERRORS{'DEBUG'}, 0, "set the registry keys to disable Windows defender");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to set the registry key to disable Windows defender");
+		return 0;
+	}
+	
+	# Stop the Windows Defender service
+	if ($self->stop_service('WinDefend')) {
+		notify($ERRORS{'DEBUG'}, 0, "stopped the Windows Defender service");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to stop the Windows Defender service");
+		return 0;
+	}
+	
+	# Disable the Windows Defender service
+	if ($self->set_service_startup_mode('WinDefend', 'disabled')) {
+		notify($ERRORS{'DEBUG'}, 0, "disabled the Windows Defender service");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to disable the Windows Defender service");
+		return 0;
+	}
+	
+	notify($ERRORS{'OK'}, 0, "disabled Windows Defender");
+
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__