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

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

commit 549ad0d4ce213c98d8507e678676bdc1fa45b0dd
Author: tibordigana <[email protected]>
AuthorDate: Sat Feb 21 21:25:30 2026 +0100

    Supporting WMIC and PowerShell
---
 .../apache/maven/surefire/booter/PpidChecker.java  | 92 +++++++++++++++-------
 .../apache/maven/surefire/booter/ProcessInfo.java  |  3 +-
 .../maven/surefire/booter/PpidCheckerTest.java     |  2 +-
 3 files changed, 68 insertions(+), 29 deletions(-)

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..0100cd78e 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
@@ -23,6 +23,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InterruptedIOException;
+import java.math.BigDecimal;
 import java.nio.file.Path;
 import java.text.SimpleDateFormat;
 import java.util.Queue;
@@ -62,17 +63,23 @@
  * @since 2.20.1
  */
 final class PpidChecker {
+    private static final BigDecimal THOUSAND = new BigDecimal(1000);
     private static final long MINUTES_TO_MILLIS = 60L * 1000L;
     // 25 chars 
https://superuser.com/questions/937380/get-creation-time-of-file-in-milliseconds/937401#937401
     private static final int WMIC_CREATION_DATE_VALUE_LENGTH = 25;
     private static final int WMIC_CREATION_DATE_TIMESTAMP_LENGTH = 18;
     private static final SimpleDateFormat WMIC_CREATION_DATE_FORMAT =
             IS_OS_WINDOWS ? createWindowsCreationDateFormat() : null;
+    private static final Pattern POWERSHELL_CPU_PATTERN = 
Pattern.compile("^\\d+(\\.\\d+)?$");
     private static final String WMIC_CREATION_DATE = "CreationDate";
+    private static final String POWERSHELL_CMD_HEADER = "CPU";
     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_WMIC32 = "System32\\Wbem";
+    private static final String RELATIVE_PATH_TO_WMIC64 = "SysWOW64\\Wbem";
+    private static final String SYSTEM_PATH_TO_WMIC32 =
+            "%" + WINDOWS_SYSTEM_ROOT_ENV + "%\\" + RELATIVE_PATH_TO_WMIC32 + 
"\\";
+    private static final String SYSTEM_PATH_TO_WMIC64 =
+        "%" + WINDOWS_SYSTEM_ROOT_ENV + "%\\" + RELATIVE_PATH_TO_WMIC64 + "\\";
     private static final String PS_ETIME_HEADER = "ELAPSED";
     private static final String PS_PID_HEADER = "PID";
 
@@ -159,7 +166,7 @@ ProcessInfo unix() {
         ProcessInfoConsumer reader = new ProcessInfoConsumer(charset) {
             @Override
             @Nonnull
-            ProcessInfo consumeLine(String line, ProcessInfo 
previousOutputLine) {
+            protected ProcessInfo consumeLine(String line, ProcessInfo 
previousOutputLine) {
                 if (previousOutputLine.isInvalid()) {
                     if (hasHeader) {
                         Matcher matcher = UNIX_CMD_OUT_PATTERN.matcher(line);
@@ -187,36 +194,61 @@ ProcessInfo consumeLine(String line, ProcessInfo 
previousOutputLine) {
     }
 
     ProcessInfo windows() {
-        ProcessInfoConsumer reader = new ProcessInfoConsumer("US-ASCII") {
+        class WindowsProcessInfoConsumer extends ProcessInfoConsumer {
+            private boolean isPowershell;
+
+            WindowsProcessInfoConsumer() {
+                super("US-ASCII");
+            }
+
             @Override
             @Nonnull
-            ProcessInfo consumeLine(String line, ProcessInfo 
previousProcessInfo) throws Exception {
+            protected ProcessInfo consumeLine(String line, ProcessInfo 
previousProcessInfo) throws Exception {
                 if (previousProcessInfo.isInvalid() && !line.isEmpty()) {
                     if (hasHeader) {
-                        // now the line is CreationDate, e.g. 
20180406142327.741074+120
-                        if (line.length() != WMIC_CREATION_DATE_VALUE_LENGTH) {
-                            throw new IllegalStateException("WMIC CreationDate 
should have 25 characters " + line);
+                        if (isPowershell) {
+                            if 
(POWERSHELL_CPU_PATTERN.matcher(line).matches()) {
+                                long etime = new 
BigDecimal(line).multiply(THOUSAND).longValue();
+                                return windowsProcessInfo(ppid, etime);
+                            }
+                        } else {
+                            // now the line is CreationDate, e.g. 
20180406142327.741074+120
+                            if (line.length() != 
WMIC_CREATION_DATE_VALUE_LENGTH) {
+                                throw new IllegalStateException("WMIC 
CreationDate should have 25 characters " + line);
+                            }
+                            String startTimestamp = line.substring(0, 
WMIC_CREATION_DATE_TIMESTAMP_LENGTH);
+                            int indexOfTimeZone = 
WMIC_CREATION_DATE_VALUE_LENGTH - 4;
+                            long startTimestampMillisUTC = 
WMIC_CREATION_DATE_FORMAT.parse(startTimestamp).getTime()
+                                - parseInt(line.substring(indexOfTimeZone)) * 
MINUTES_TO_MILLIS;
+                            return windowsProcessInfo(ppid, 
startTimestampMillisUTC);
                         }
-                        String startTimestamp = line.substring(0, 
WMIC_CREATION_DATE_TIMESTAMP_LENGTH);
-                        int indexOfTimeZone = WMIC_CREATION_DATE_VALUE_LENGTH 
- 4;
-                        long startTimestampMillisUTC =
-                                
WMIC_CREATION_DATE_FORMAT.parse(startTimestamp).getTime()
-                                        - 
parseInt(line.substring(indexOfTimeZone)) * MINUTES_TO_MILLIS;
-                        return windowsProcessInfo(ppid, 
startTimestampMillisUTC);
                     } else {
-                        hasHeader = WMIC_CREATION_DATE.equals(line);
+                        hasHeader = WMIC_CREATION_DATE.equals(line) || 
POWERSHELL_CMD_HEADER.equals(line);
                     }
                 }
                 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);
+
+            ProcessInfo checkPpid() {
+                if (hasWmicStandardSystemPath64()) {
+                    return execute("CMD", "/A", "/X", "/C",
+                        SYSTEM_PATH_TO_WMIC64
+                            + "wmic process where (ProcessId=" + ppid + ") get 
" + WMIC_CREATION_DATE);
+                } else if (hasWmicStandardSystemPath32()) {
+                    return execute("CMD", "/A", "/X", "/C",
+                        SYSTEM_PATH_TO_WMIC32
+                            + "wmic process where (ProcessId=" + ppid + ") get 
" + WMIC_CREATION_DATE);
+                } else {
+                    isPowershell = true;
+                    return execute("CMD", "/A", "/X", "/C",
+                        "powershell", " \"Get-Process -Id " + ppid + " | 
Select-Object -Property CPU" + "\"");
+                }
+            }
+        }
+
+        WindowsProcessInfoConsumer reader = new WindowsProcessInfoConsumer();
+        return reader.checkPpid();
+
     }
 
     void destroyActiveCommands() {
@@ -254,9 +286,14 @@ private static boolean canExecuteStandardUnixPs() {
         }
     }
 
-    private static boolean hasWmicStandardSystemPath() {
+    private static boolean hasWmicStandardSystemPath32() {
+        String systemRoot = System.getenv(WINDOWS_SYSTEM_ROOT_ENV);
+        return isNotBlank(systemRoot) && new File(systemRoot, 
RELATIVE_PATH_TO_WMIC32 + "\\wmic.exe").isFile();
+    }
+
+    private static boolean hasWmicStandardSystemPath64() {
         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_WMIC64 + "\\wmic.exe").isFile();
     }
 
     static long fromDays(Matcher matcher) {
@@ -337,7 +374,8 @@ abstract class ProcessInfoConsumer {
             this.charset = charset;
         }
 
-        abstract @Nonnull ProcessInfo consumeLine(String line, ProcessInfo 
previousProcessInfo) throws Exception;
+        protected abstract @Nonnull ProcessInfo consumeLine(String line, 
ProcessInfo previousProcessInfo)
+            throws Exception;
 
         ProcessInfo execute(String... command) {
             ProcessBuilder processBuilder = new ProcessBuilder(command);
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
index 771445965..11f77f852 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ProcessInfo.java
@@ -34,6 +34,7 @@
 final class ProcessInfo {
     static final ProcessInfo INVALID_PROCESS_INFO = new ProcessInfo(null, 0);
     static final ProcessInfo ERR_PROCESS_INFO = new ProcessInfo(null, 0);
+    static final ProcessInfo ERR_CMD_NOT_FOUND = new ProcessInfo(null, 0);
 
     /**
      * On Unix we do not get PID due to the command is interested only to 
etime of PPID:
@@ -65,7 +66,7 @@ boolean isInvalid() {
     }
 
     boolean isError() {
-        return this == ERR_PROCESS_INFO;
+        return this == ERR_PROCESS_INFO || this == ERR_CMD_NOT_FOUND;
     }
 
     String getPID() {
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..83e5f8dbe 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
@@ -371,7 +371,7 @@ public void shouldHaveSystemPathToWmicOnWindows() throws 
Exception {
         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"))
+        assertThat((Boolean) invokeMethod(PpidChecker.class, 
"hasWmicStandardSystemPath32"))
                 .isTrue();
         assertThat(new File(System.getenv("SystemRoot"), 
"System32\\Wbem\\wmic.exe"))
                 .isFile();

Reply via email to