From c732f16be430f11d85d1227c55a0f88bddda326e Mon Sep 17 00:00:00 2001
From: chanelyoung
Date: Mon, 15 Jun 2026 22:21:06 +0100
Subject: [PATCH] Reframe Invoke-Expression query as quality guidance
Lower the DoNotUseInvokeExpression metadata to a recommendation and remove the security-severity so the alert is treated as code-quality backlog guidance rather than a high-severity vulnerability. Update qhelp and tests to make clear command-injection queries cover security-critical flows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../cwe-078/DoNotUseInvokeExpression.ql | 18 ++++++++-------
.../cwe-078/DoNotuseInvokeExpression.qhelp | 23 +++++++++++++++----
.../DoNotUseInvokeExpression.expected | 3 ++-
.../cwe-078/DoNotUseInvokeExpression/test.ps1 | 4 +++-
4 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/powershell/ql/src/queries/security/cwe-078/DoNotUseInvokeExpression.ql b/powershell/ql/src/queries/security/cwe-078/DoNotUseInvokeExpression.ql
index ed2fe8df398c..86aace308774 100644
--- a/powershell/ql/src/queries/security/cwe-078/DoNotUseInvokeExpression.ql
+++ b/powershell/ql/src/queries/security/cwe-078/DoNotUseInvokeExpression.ql
@@ -1,16 +1,18 @@
/**
* @name Use of Invoke-Expression
- * @description Do not use Invoke-Expression
+ * @description Avoid using Invoke-Expression when safer command invocation is possible.
* @kind problem
- * @problem.severity error
- * @security-severity 9.8
- * @precision high
+ * @problem.severity recommendation
+ * @precision medium
* @id powershell/microsoft/public/do-not-use-invoke-expression
- * @tags security
+ * @tags quality
+ * maintainability
+ * correctness
*/
+
import powershell
-import semmle.code.powershell.dataflow.DataFlow
-from CmdCall call
+from CmdCall call
where call.matchesName("Invoke-Expression")
-select call, "Do not use Invoke-Expression. It is a command injection risk."
+select call,
+ "Prefer direct command invocation, splatting, or the call operator over Invoke-Expression."
diff --git a/powershell/ql/src/queries/security/cwe-078/DoNotuseInvokeExpression.qhelp b/powershell/ql/src/queries/security/cwe-078/DoNotuseInvokeExpression.qhelp
index 1209d21faa88..a039cdd0f579 100644
--- a/powershell/ql/src/queries/security/cwe-078/DoNotuseInvokeExpression.qhelp
+++ b/powershell/ql/src/queries/security/cwe-078/DoNotuseInvokeExpression.qhelp
@@ -4,20 +4,35 @@
-Invoke-Expression cmdlet should only be used as a last resort. In most scenarios, safer and more robust alternatives are available. Using Invoke-Expression can lead to arbitrary commands being executed
+The Invoke-Expression cmdlet evaluates a string as PowerShell code. This
+can make scripts harder to understand, harder to analyze, and more fragile than
+using normal command invocation. This query treats uses of
+Invoke-Expression as code-quality backlog items rather than as
+high-severity security vulnerabilities.
+
-Avoid using Invoke-Expression in your powershell code.
+
+Avoid using Invoke-Expression in PowerShell code. Prefer direct command
+calls, splatting, or the command invocation operator & for command paths
+stored in variables. If Invoke-Expression is unavoidable, keep the
+dynamically generated command text small, explicit, and easy to review.
+
-If you’re running some command and the command path has spaces in it, then you need the command invocation operator &
+
+Security-critical cases where attacker-controlled data reaches command execution
+are covered by the command-injection queries. This query reports all uses of
+Invoke-Expression, including constant or otherwise trusted command text, as
+best-practice warnings for safer and more maintainable command execution.
+
-Powershell:
+PowerShell:
Invoke-Expression considered harmful.
diff --git a/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected b/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected
index 3d7443847750..07d91f0016a9 100644
--- a/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected
+++ b/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected
@@ -1 +1,2 @@
-| test.ps1:2:1:2:26 | Call to invoke-expression | Do not use Invoke-Expression. It is a command injection risk. |
+| test.ps1:2:1:2:26 | Call to invoke-expression | Prefer direct command invocation, splatting, or the call operator over Invoke-Expression. |
+| test.ps1:4:1:4:28 | Call to invoke-expression | Prefer direct command invocation, splatting, or the call operator over Invoke-Expression. |
diff --git a/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/test.ps1 b/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/test.ps1
index da72cffb946d..006655c089e6 100644
--- a/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/test.ps1
+++ b/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/test.ps1
@@ -1,2 +1,4 @@
$command = "Get-Process"
-Invoke-Expression $Command # $ Alert
\ No newline at end of file
+Invoke-Expression $Command # $ Alert
+
+Invoke-Expression "Get-Date" # $ Alert - constant command text still triggers best-practice query