Skip to content

Commit

Permalink
Clean-up WindowsDefenderConfigurator after subsequent check refinements
Browse files Browse the repository at this point in the history
  • Loading branch information
HannesWell committed Mar 21, 2024
1 parent 0de600a commit c2a30db
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 34 deletions.
Expand Up @@ -21,6 +21,7 @@
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
Expand All @@ -29,6 +30,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IProduct;
Expand Down Expand Up @@ -156,27 +158,23 @@ private static Boolean runExclusionCheck(IProgressMonitor m, Optional<Path> inst
}
Display display = Display.getDefault();
HandlingOption decision = askForDefenderHandlingDecision(display);
if (decision != null) {
switch (decision) {
case EXECUTE_EXCLUSION -> {
if (isExclusionTamperProtectionEnabled(monitor.split(1))) {
display.syncExec(() -> MessageDialog.openError(null, "Exclusion failed", //$NON-NLS-1$
bindProductName(WorkbenchMessages.WindowsDefenderConfigurator_exclusionFailed_Protected)));
savePreference(ConfigurationScope.INSTANCE, PREFERENCE_STARTUP_CHECK_SKIP, "true"); //$NON-NLS-1$
return null; // Consider selection as 'aborted' and don't show the dialog again on startup
}
try {
WindowsDefenderConfigurator.excludeDirectoryFromScanning(monitor.split(2));
savePreference(ConfigurationScope.INSTANCE, PREFERENCE_EXCLUDED_INSTALLATION_PATH,
installLocation.map(Path::toString).orElse("")); //$NON-NLS-1$
} catch (IOException e) {
display.syncExec(() -> MessageDialog.openError(null, "Exclusion failed", //$NON-NLS-1$
bindProductName(WorkbenchMessages.WindowsDefenderConfigurator_exclusionFailed)));
}
if (decision == HandlingOption.EXECUTE_EXCLUSION) {
if (isExclusionTamperProtectionEnabled(monitor.split(1))) {
display.syncExec(() -> MessageDialog.openError(null, "Exclusion failed", //$NON-NLS-1$
bindProductName(WorkbenchMessages.WindowsDefenderConfigurator_exclusionFailed_Protected)));
savePreference(ConfigurationScope.INSTANCE, PREFERENCE_STARTUP_CHECK_SKIP, "true"); //$NON-NLS-1$
return null; // Consider selection as 'aborted' and don't show the dialog again on startup
}
case IGNORE_THIS_INSTALLATION -> savePreference(ConfigurationScope.INSTANCE, PREFERENCE_STARTUP_CHECK_SKIP,
"true"); //$NON-NLS-1$
try {
WindowsDefenderConfigurator.excludeDirectoryFromScanning(monitor.split(2));
savePreference(ConfigurationScope.INSTANCE, PREFERENCE_EXCLUDED_INSTALLATION_PATH,
installLocation.map(Path::toString).orElse("")); //$NON-NLS-1$
} catch (IOException e) {
display.syncExec(() -> MessageDialog.openError(null, "Exclusion failed", //$NON-NLS-1$
bindProductName(WorkbenchMessages.WindowsDefenderConfigurator_exclusionFailed)));
}
} else if (decision == HandlingOption.IGNORE_THIS_INSTALLATION) {
savePreference(ConfigurationScope.INSTANCE, PREFERENCE_STARTUP_CHECK_SKIP, "true"); //$NON-NLS-1$
}
return decision == HandlingOption.EXECUTE_EXCLUSION ? Boolean.TRUE : null;
}
Expand Down Expand Up @@ -285,9 +283,8 @@ private static List<Path> getExecutablePath() {
private static boolean isExclusionTamperProtectionEnabled(IProgressMonitor monitor) {
// https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/manage-tamper-protection-intune?view=o365-worldwide#how-to-determine-whether-antivirus-exclusions-are-tamper-protected-on-a-windows-device
try { // Query the Windows Registry
List<String> result = runProcess(List.of("powershell.exe", "-Command", //$NON-NLS-1$//$NON-NLS-2$
"Get-ItemPropertyValue -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows Defender\\Features' -Name 'TPExclusions'"), //$NON-NLS-1$
monitor);
List<String> result = runPowershell(monitor, "-Command", //$NON-NLS-1$
"Get-ItemPropertyValue -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows Defender\\Features' -Name 'TPExclusions'"); //$NON-NLS-1$
return result.size() == 1 && "1".equals(result.get(0)); //$NON-NLS-1$
} catch (IOException e) {
return false;
Expand All @@ -298,8 +295,7 @@ private static boolean isWindowsDefenderServiceRunning(IProgressMonitor monitor)
// https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-service?view=powershell-7.4
// https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicecontrollerstatus?view=dotnet-plat-ext-8.0
try {
List<String> result = runProcess(List.of("powershell.exe", "-Command", "(Get-Service 'WinDefend').Status"), //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
monitor);
List<String> result = runPowershell(monitor, "-Command", "(Get-Service 'WinDefend').Status"); //$NON-NLS-1$ //$NON-NLS-2$
return result.size() == 1 && "Running".equalsIgnoreCase(result.get(0)); //$NON-NLS-1$
} catch (IOException e) {
ILog.get().error("Failed to obtain 'WinDefend' service state", e); //$NON-NLS-1$
Expand All @@ -308,10 +304,9 @@ private static boolean isWindowsDefenderServiceRunning(IProgressMonitor monitor)
}

private static boolean isWindowsDefenderActive(IProgressMonitor monitor) throws CoreException {
// https://learn.microsoft.com/en-us/powershell/module/defender/get-mpcomputerstatus
List<String> command = List.of("powershell.exe", "-Command", "(Get-MpComputerStatus).AMRunningMode"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
// https://learn.microsoft.com/en-us/powershell/module/defender/get-mpcomputerstatus?view=windowsserver2019-ps
try {
List<String> lines = runProcess(command, monitor);
List<String> lines = runPowershell(monitor, "-Command", "(Get-MpComputerStatus).AMRunningMode"); //$NON-NLS-1$ //$NON-NLS-2$
String onlyLine = lines.size() == 1 ? lines.get(0) : ""; //$NON-NLS-1$
return switch (onlyLine) {
// Known values as listed in
Expand All @@ -329,8 +324,8 @@ public static String createAddExclusionsPowershellCommand(String extraSeparator)
List<Path> paths = getExecutablePath();
// For detailed explanations about how to read existing exclusions and how to
// add new ones see:
// https://learn.microsoft.com/en-us/powershell/module/defender/add-mppreference
// https://learn.microsoft.com/en-us/powershell/module/defender/get-mppreference
// https://learn.microsoft.com/en-us/powershell/module/defender/add-mppreference?view=windowsserver2019-ps
// https://learn.microsoft.com/en-us/powershell/module/defender/get-mppreference?view=windowsserver2019-ps
//
// For .NET's stream API called LINQ see:
// https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable
Expand All @@ -351,7 +346,7 @@ private static void excludeDirectoryFromScanning(IProgressMonitor monitor) throw
// a second one with elevated rights is started and runs the
// add-exclusions-command. For a detailed explanation of the Start-process
// parameters see
// https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process#parameters
// https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-7.4#parameters
//
// In order to avoid quoting when passing a command through multiple
// process-calls/command line processors, the command is passed as
Expand All @@ -360,11 +355,13 @@ private static void excludeDirectoryFromScanning(IProgressMonitor monitor) throw
// https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe#-encodedcommand-base64encodedcommand
String encodedCommand = Base64.getEncoder()
.encodeToString(exclusionsCommand.getBytes(StandardCharsets.UTF_16LE)); // encoding as specified
List<String> command = List.of("powershell.exe", //$NON-NLS-1$
// Launch child powershell with administrator privileges
runPowershell(monitor, // Launch child powershell with administrator privileges
"Start-Process", "powershell", "-Verb", "RunAs", "-Wait", //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
"-ArgumentList", "'-EncodedCommand " + encodedCommand + "'"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
runProcess(command, monitor);
}

private static List<String> runPowershell(IProgressMonitor monitor, String... arguments) throws IOException {
return runProcess(Stream.concat(Stream.of("powershell.exe"), Arrays.stream(arguments)).toList(), monitor); //$NON-NLS-1$
}

private static List<String> runProcess(List<String> command, IProgressMonitor monitor) throws IOException {
Expand Down
Expand Up @@ -569,7 +569,7 @@ CheckedTreeSelectionDialog_select_all=Select &All
CheckedTreeSelectionDialog_deselect_all=&Deselect All

WindowsDefenderConfigurator_statusCheck=Windows Defender Exclusion Check
WindowsDefenderConfigurator_exclusionCheckMessage=Microsoft''s Windows Defender is active and could significantly decrease the startup and overall performance of {0}.\n\
WindowsDefenderConfigurator_exclusionCheckMessage=Microsoft Windows Defender is active and could significantly decrease the startup and overall performance of {0}.\n\
Select how this installation should be handled by Windows Defender:
WindowsDefenderConfigurator_exclusionInformation=If Windows Defender is active and scans {0} it can significantly slow down its startup and overall performance.\n\
To prevent a decrease in performance {0} can exclude itself and all files opened from real-time scanning by Windows Defender.\n\
Expand Down

0 comments on commit c2a30db

Please sign in to comment.