VCL-1113 - image capture for Windows system configured as domain controller fails

Windows.pm:
-modified pre_reload: when checking for the computer being joined to any AD domain, added check to see if computer is a domain controller and skip deleting from domain if it is
-modified ad_unjoin: added check toward beginning of subroutine for computer being a domain controller and return early if it is
-added ad_check_domain_controller
diff --git a/managementnode/lib/VCL/Module/OS/Windows.pm b/managementnode/lib/VCL/Module/OS/Windows.pm
index 479fc22..0c7e316 100644
--- a/managementnode/lib/VCL/Module/OS/Windows.pm
+++ b/managementnode/lib/VCL/Module/OS/Windows.pm
@@ -1145,15 +1145,25 @@
 		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
 		return 0;
 	}
-	
+
 	my $computer_name = $self->data->get_computer_short_name();
-	
+
 	# Check if the computer is joined to any AD domain
 	my $computer_current_domain_name = $self->ad_get_current_domain();
 	if ($computer_current_domain_name) {
-		$self->ad_delete_computer();
+		# check that node is not a domain controller
+		my $check_dc = $self->ad_check_domain_controller();
+		if (!defined($check_dc) || $check_dc == 0) {
+			# if call to ad_check_domain_controller fails, still attempt to
+			# delete from domain; unusual for node to be a domain controller
+			notify($ERRORS{'DEBUG'}, 0, "attempting to delete computer from domain");
+			$self->ad_delete_computer();
+		}
+		elsif ($check_dc == 1) {
+			notify($ERRORS{'DEBUG'}, 0, "computer is a domain controller, not attempting to delete computer from its own domain");
+		}
 	}
-	
+
 	return $self->SUPER::pre_reload();
 }
 
@@ -14209,7 +14219,19 @@
 		notify($ERRORS{'DEBUG'}, 0, "$computer_name does not need to be removed from AD because it is not currently joined to a domain");
 		return 1;
 	}
-	
+
+	# check that node is not a domain controller
+	my $check_dc = $self->ad_check_domain_controller();
+	if (!defined($check_dc) || $check_dc == 0) {
+		# if call to ad_check_domain_controller fails, still attempt to
+		# delete from domain; unusual for node to be a domain controller
+		notify($ERRORS{'DEBUG'}, 0, "attempting to delete computer from domain");
+	}
+	elsif ($check_dc == 1) {
+		notify($ERRORS{'DEBUG'}, 0, "computer is a domain controller, not attempting to delete computer from its own domain");
+		return 1;
+	}
+
 	# Expected output:
 	# Executing (\\<COMPUTERNAME>\ROOT\CIMV2:Win32_ComputerSystem.Name="<COMPUTERNAME>")->UnJoinDomainOrWorkgroup()
 	# Method execution successful.s
@@ -14854,6 +14876,50 @@
 
 #//////////////////////////////////////////////////////////////////////////////
 
+=head2 ad_check_domain_controller
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Checks if computer is configured as a domain controller; returns
+               0 if not a domain controller, 1 if a domain controller, and
+               no value on error
+
+=cut
+
+sub ad_check_domain_controller {
+	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 $system32_path = $self->get_system32_path() || return;
+	my $check_dc_command = "echo | cmd.exe /c \"$system32_path/Wbem/wmic.exe /INTERACTIVE:OFF COMPUTERSYSTEM GET DomainRole\"";
+	my ($check_dc_exit_status, $check_dc_output) = $self->execute($check_dc_command);
+	if (!defined($check_dc_output)) {
+		notify($ERRORS{'DEBUG'}, 0, "failed to check for node being a domain controller");
+		return;
+	}
+	elsif (grep(/ERROR/i, @$check_dc_output)) {
+		notify($ERRORS{'DEBUG'}, 0, "failed to check for node being a domain controller, output:\n" . join("\n", @$check_dc_output));
+		return;
+	}
+	elsif (@{$check_dc_output}[1] =~ /^[0-3]$/) {
+		notify($ERRORS{'OK'}, 0, "node is a not a domain controller");
+		return 0;
+	}
+	elsif (@{$check_dc_output}[1] =~ /^[4-5]$/) {
+		notify($ERRORS{'OK'}, 0, "node is a domain controller");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "unexpected output checking for node being a domain controller, output:\n" . join("\n", @$check_dc_output));
+		return;
+	}
+}
+
+#//////////////////////////////////////////////////////////////////////////////
+
 =head2 grant_administrative_access
 
  Parameters  : $username