diff --git a/README.md b/README.md
index 41d0bcf3a..5934e8ce3 100644
--- a/README.md
+++ b/README.md
@@ -169,7 +169,8 @@ If you are already using other analyzers, you can check [which rules are duplica
|[MA0151](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0151.md)|Usage|DebuggerDisplay must contain valid members|⚠️|✔️|❌|
|[MA0152](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0152.md)|Performance|Use Unwrap instead of using await twice|ℹ️|✔️|❌|
|[MA0153](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0153.md)|Design|Do not log symbols decorated with DataClassificationAttribute directly|⚠️|✔️|❌|
-|[MA0154](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0154.md)|Design|Use langword in XML comment|ℹ️|✔️|❌|
+|[MA0154](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0154.md)|Design|Use langword in XML comment|ℹ️|✔️|✔️|
+|[MA0155](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0155.md)|Usage|UseShellExecute must be explicitly set|⚠️|❌|❌|
diff --git a/docs/README.md b/docs/README.md
index e332969cd..b3842c964 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -153,7 +153,8 @@
|[MA0151](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0151.md)|Usage|DebuggerDisplay must contain valid members|⚠️|✔️|❌|
|[MA0152](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0152.md)|Performance|Use Unwrap instead of using await twice|ℹ️|✔️|❌|
|[MA0153](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0153.md)|Design|Do not log symbols decorated with DataClassificationAttribute directly|⚠️|✔️|❌|
-|[MA0154](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0154.md)|Design|Use langword in XML comment|ℹ️|✔️|❌|
+|[MA0154](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0154.md)|Design|Use langword in XML comment|ℹ️|✔️|✔️|
+|[MA0155](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0155.md)|Usage|UseShellExecute must be explicitly set|⚠️|❌|❌|
|Id|Suppressed rule|Justification|
|--|---------------|-------------|
@@ -622,6 +623,9 @@ dotnet_diagnostic.MA0153.severity = warning
# MA0154: Use langword in XML comment
dotnet_diagnostic.MA0154.severity = suggestion
+
+# MA0155: UseShellExecute must be explicitly set
+dotnet_diagnostic.MA0155.severity = none
```
# .editorconfig - all rules disabled
@@ -1085,4 +1089,7 @@ dotnet_diagnostic.MA0153.severity = none
# MA0154: Use langword in XML comment
dotnet_diagnostic.MA0154.severity = none
+
+# MA0155: UseShellExecute must be explicitly set
+dotnet_diagnostic.MA0155.severity = none
```
diff --git a/docs/Rules/MA0155.md b/docs/Rules/MA0155.md
new file mode 100644
index 000000000..ebb7636e6
--- /dev/null
+++ b/docs/Rules/MA0155.md
@@ -0,0 +1,43 @@
+# MA0155 - UseShellExecute must be explicitly set
+
+Detects when `Process.Start` is called without specifying the value of `UseShellExecute`.
+
+The goal is to help for those two cases:
+- The default value for this property is true on .NET Framework apps and false on .NET Core apps.
+- It must be set to to false when redirecting I/O.
+
+
+````c#
+using System.Diasgnostics;
+
+// Non compliant
+
+Process.Start("cmd"); // Intent is not clear if you want to use ShellExecute or not
+
+Process.Start("https://www.meziantou.net/"); // Will fail on .NET Core apps
+
+Process.Start(new ProcessStartInfo("cmd")
+{
+ RedirectStandardOutput = true,
+ UseShellExecute = true,
+}); // It will throw with error "UseShellExecute must be set to false when redirecting I/O"
+
+Process.Start(new ProcessStartInfo("cmd")
+{
+ RedirectStandardOutput = true,
+}); // It will throw with error "UseShellExecute must be set to false when redirecting I/O" on .NET Framework apps
+
+// Compliant
+
+Process.Start(new ProcessStartInfo("https://www.meziantou.net/")
+{
+ UseShellExecute = true,
+});
+
+Process.Start(new ProcessStartInfo("cmd")
+{
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+});
+
+````
\ No newline at end of file
diff --git a/src/Meziantou.Analyzer/Rules/UseShellExecuteAnalyzer.cs b/src/Meziantou.Analyzer/Rules/UseShellExecuteAnalyzer.cs
index 466efab4c..c7a5bb0ce 100644
--- a/src/Meziantou.Analyzer/Rules/UseShellExecuteAnalyzer.cs
+++ b/src/Meziantou.Analyzer/Rules/UseShellExecuteAnalyzer.cs
@@ -57,8 +57,11 @@ public override void Initialize(AnalysisContext context)
ctx.RegisterOperationAction(analyzerContext.AnalyzeInvocation, OperationKind.Invocation);
ctx.RegisterOperationAction(analyzerContext.AnalyzeObjectCreation, OperationKind.ObjectCreation);
});
+
}
+
+
private sealed class AnalyzerContext(Compilation compilation)
{
private readonly INamedTypeSymbol? _processStartInfoSymbol = compilation.GetBestTypeByMetadataName("System.Diagnostics.ProcessStartInfo");