This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git


The following commit(s) were added to refs/heads/master by this push:
     new 688f8c463 Use PowerShell instead of WMIC for detecting zombie process 
on Windows (#3258)
688f8c463 is described below

commit 688f8c46390a0d495a0c4169c873389b9c9b21b6
Author: jbliznak <[email protected]>
AuthorDate: Mon Feb 9 22:05:11 2026 +0100

    Use PowerShell instead of WMIC for detecting zombie process on Windows 
(#3258)
    
    * Use PowerShell instead of WMIC for detecting zombie process on Windows
    
    WMIC is not available in recent Windows versions.
    The new solution with PowerShell should work for Windows 8 and newer
    and Windows Server 2012 and newer.
    
    The change is deliberately as small as possible, leaving most
    of the old WMIC handling in place because there is a plan to deprecate
    this class anyway.
    
    On performance note: executing the check via PowerShell is notably
    slower than with WMIC (low hundreds of millis vs tens of millis).
    However, since this check is used only to detect zombie process
    and only once per tens of seconds, this will hopefully be good enough.
    Much better and faster implementation could be done once the minimal
    supported Java moves to 9 or later via ProcessHandle, until then
    this should do.
---
 .github/workflows/maven-verify.yml                 |  2 +-
 .../apache/maven/surefire/booter/PpidChecker.java  | 32 ++++++++++++++--------
 .../maven/surefire/booter/PpidCheckerTest.java     | 10 +++----
 3 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/.github/workflows/maven-verify.yml 
b/.github/workflows/maven-verify.yml
index 51567b81d..2d827a276 100644
--- a/.github/workflows/maven-verify.yml
+++ b/.github/workflows/maven-verify.yml
@@ -49,4 +49,4 @@ jobs:
         !**/hs_err_pid*
         
!surefire-its/target/ConsoleOutputIT_*/target/surefire-reports/*-jvmRun*-events.bin
       timeout-minutes: 600
-      os-matrix: '[ "ubuntu-latest", "windows-2022", "macos-latest" ]'
+      os-matrix: '[ "ubuntu-latest", "windows-latest", "macos-latest" ]'
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
index 2c836ea21..b8891e822 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/PpidChecker.java
@@ -70,9 +70,9 @@ final class PpidChecker {
             IS_OS_WINDOWS ? createWindowsCreationDateFormat() : null;
     private static final String WMIC_CREATION_DATE = "CreationDate";
     private static final String WINDOWS_SYSTEM_ROOT_ENV = "SystemRoot";
-    private static final String RELATIVE_PATH_TO_WMIC = "System32\\Wbem";
-    private static final String SYSTEM_PATH_TO_WMIC =
-            "%" + WINDOWS_SYSTEM_ROOT_ENV + "%\\" + RELATIVE_PATH_TO_WMIC + 
"\\";
+    private static final String RELATIVE_PATH_TO_POWERSHELL = 
"System32\\WindowsPowerShell\\v1.0";
+    private static final String SYSTEM_PATH_TO_POWERSHELL =
+            System.getenv(WINDOWS_SYSTEM_ROOT_ENV) + "\\" + 
RELATIVE_PATH_TO_POWERSHELL + "\\";
     private static final String PS_ETIME_HEADER = "ELAPSED";
     private static final String PS_PID_HEADER = "PID";
 
@@ -192,6 +192,7 @@ ProcessInfo windows() {
             @Nonnull
             ProcessInfo consumeLine(String line, ProcessInfo 
previousProcessInfo) throws Exception {
                 if (previousProcessInfo.isInvalid() && !line.isEmpty()) {
+                    // we still use WMIC output format even though we now use 
PowerShell to produce it
                     if (hasHeader) {
                         // now the line is CreationDate, e.g. 
20180406142327.741074+120
                         if (line.length() != WMIC_CREATION_DATE_VALUE_LENGTH) {
@@ -210,13 +211,19 @@ ProcessInfo consumeLine(String line, ProcessInfo 
previousProcessInfo) throws Exc
                 return previousProcessInfo;
             }
         };
-        String wmicPath = hasWmicStandardSystemPath() ? SYSTEM_PATH_TO_WMIC : 
"";
-        return reader.execute(
-                "CMD",
-                "/A",
-                "/X",
-                "/C",
-                wmicPath + "wmic process where (ProcessId=" + ppid + ") get " 
+ WMIC_CREATION_DATE);
+
+        String psPath = hasPowerShellStandardSystemPath() ? 
SYSTEM_PATH_TO_POWERSHELL : "";
+        // mimic output format of the original check:
+        // wmic process where (ProcessId=<ppid>) get CreationDate
+        String psCommand = String.format(
+                "Add-Type -AssemblyName System.Management; "
+                        + "$p = Get-CimInstance Win32_Process -Filter 
'ProcessId=%2$s'; "
+                        + "if ($p) { "
+                        + "    Write-Output '%1$s'; "
+                        + "    
[System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($p.CreationDate)
 "
+                        + "}",
+                WMIC_CREATION_DATE, ppid);
+        return reader.execute(psPath + "powershell", "-NoProfile", 
"-NonInteractive", "-Command", psCommand);
     }
 
     void destroyActiveCommands() {
@@ -254,9 +261,10 @@ private static boolean canExecuteStandardUnixPs() {
         }
     }
 
-    private static boolean hasWmicStandardSystemPath() {
+    private static boolean hasPowerShellStandardSystemPath() {
         String systemRoot = System.getenv(WINDOWS_SYSTEM_ROOT_ENV);
-        return isNotBlank(systemRoot) && new File(systemRoot, 
RELATIVE_PATH_TO_WMIC + "\\wmic.exe").isFile();
+        return isNotBlank(systemRoot)
+                && new File(systemRoot, RELATIVE_PATH_TO_POWERSHELL + 
"\\powershell.exe").isFile();
     }
 
     static long fromDays(Matcher matcher) {
diff --git 
a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
 
b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
index 78f35716f..5b05d1a46 100644
--- 
a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
+++ 
b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/PpidCheckerTest.java
@@ -365,15 +365,15 @@ public void shouldParseBusyboxHoursEtime() {
     }
 
     @Test
-    public void shouldHaveSystemPathToWmicOnWindows() throws Exception {
+    public void shouldHaveSystemPathToPowerShellOnWindows() throws Exception {
         assumeTrue(IS_OS_WINDOWS);
         assumeThat(System.getenv("SystemRoot"), is(notNullValue()));
         assumeThat(System.getenv("SystemRoot"), is(not("")));
-        assumeTrue(new File(System.getenv("SystemRoot"), 
"System32\\Wbem").isDirectory());
-        assumeTrue(new File(System.getenv("SystemRoot"), 
"System32\\Wbem\\wmic.exe").isFile());
-        assertThat((Boolean) invokeMethod(PpidChecker.class, 
"hasWmicStandardSystemPath"))
+        assumeTrue(new File(System.getenv("SystemRoot"), 
"System32\\WindowsPowerShell\\v1.0").isDirectory());
+        assumeTrue(new File(System.getenv("SystemRoot"), 
"System32\\WindowsPowerShell\\v1.0\\powershell.exe").isFile());
+        assertThat((Boolean) invokeMethod(PpidChecker.class, 
"hasPowerShellStandardSystemPath"))
                 .isTrue();
-        assertThat(new File(System.getenv("SystemRoot"), 
"System32\\Wbem\\wmic.exe"))
+        assertThat(new File(System.getenv("SystemRoot"), 
"System32\\WindowsPowerShell\\v1.0\\powershell.exe"))
                 .isFile();
     }
 

Reply via email to