diff --git a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
index 3add00384d27a4bf753d5f269d74c91f06549e4a..1a195e360067a55c75931ae294c340663fd467d1 100644
--- a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
+++ b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
@@ -70,7 +70,7 @@ label getExposedPatchId(const polyMesh& mesh, const word& patchName)
 
     Info<< "Adding exposed internal faces to "
         << (patchId == -1 ? "new" : "existing")
-        << " patch \"" << patchName << "\"" << nl << endl;
+        << " patch: " << patchName << nl << endl;
 
     return patchId;
 }
@@ -357,6 +357,12 @@ int main(int argc, char *argv[])
         "Add exposed internal faces to closest of specified patches"
         " instead of \"oldInternalFaces\""
     );
+    argList::addOption
+    (
+        "exclude-patches",
+        "wordRes",
+        "Exclude single or multiple patches from the -patches selection"
+    );
     argList::addBoolOption
     (
         "zone",
@@ -400,52 +406,59 @@ int main(int argc, char *argv[])
     // Default exposed patch id
     labelList exposedPatchIDs(one{}, -1);
 
-    if (args.found("patches"))
-    {
-        const wordRes patchNames(args.getList<wordRe>("patches"));
+    wordRes includePatches, excludePatches;
 
-        if (patchNames.size() == 1 && patchNames.front().isLiteral())
+    if (!args.readListIfPresent<wordRe>("patches", includePatches))
+    {
+        if (args.found("patch"))
         {
-            exposedPatchIDs.front() =
-                getExposedPatchId(mesh, patchNames.front());
+            includePatches.resize(1);
+            includePatches.front() = args.get<word>("patch");
         }
-        else
-        {
-            // Patches selected
-            labelHashSet patchIds
-            (
-                mesh.boundaryMesh().patchSet(patchNames)
-            );
-
-            // Only retain initial, non-processor patches
-            label nNonProcessor
-            (
-                mesh.boundaryMesh().nNonProcessor()
-            );
-
-            patchIds.filterKeys
-            (
-                [=](label patchi) { return (patchi < nNonProcessor); }
-            );
+    }
+    args.readListIfPresent<wordRe>("exclude-patches", excludePatches);
 
-            exposedPatchIDs = patchIds.sortedToc();
+    if (includePatches.size() == 1 && includePatches.front().isLiteral())
+    {
+        // Select a single patch - no exclude possible
+        exposedPatchIDs.front() =
+            getExposedPatchId(mesh, includePatches.front());
+    }
+    else if (!includePatches.empty())
+    {
+        // Patches selected (sorted order)
+        exposedPatchIDs =
+            mesh.boundaryMesh().indices(includePatches, excludePatches);
 
-            Info<< "Adding exposed internal faces to nearest of patches "
-                << flatOutput(patchNames) << nl << endl;
+        // Only retain initial, non-processor patches
+        const label nNonProcessor
+        (
+            mesh.boundaryMesh().nNonProcessor()
+        );
 
-            if (exposedPatchIDs.empty())
+        forAll(exposedPatchIDs, i)
+        {
+            if (exposedPatchIDs[i] > nNonProcessor)
             {
-                FatalErrorInFunction
-                    << nl << "No patches matched. Patches: "
-                    << flatOutput(mesh.boundaryMesh().names()) << nl
-                    << exit(FatalError);
+                exposedPatchIDs.resize(i);
+                break;
             }
         }
-    }
-    else if (args.found("patch"))
-    {
-        exposedPatchIDs.front() =
-            getExposedPatchId(mesh, args.get<word>("patch"));
+
+        const wordList allPatchNames(mesh.boundaryMesh().names());
+
+        Info<< "Adding exposed internal faces to nearest of patches:" << nl
+            << "    include: " << flatOutput(includePatches) << nl
+            << "    exclude: " << flatOutput(excludePatches) << nl
+            << nl;
+
+        if (exposedPatchIDs.empty())
+        {
+            FatalErrorInFunction
+                << nl << "No patches matched. Patches: "
+                << flatOutput(allPatchNames) << nl
+                << exit(FatalError);
+        }
     }
     else
     {
diff --git a/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C b/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C
index c833d486c6b007262f79455b4b2fa4d98f11e795..21a9a20fc7d3c37ccb18ebe8dc94051aa168cb63 100644
--- a/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C
+++ b/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2022 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -145,12 +145,13 @@ int main(int argc, char *argv[])
     );
     argList::addOption
     (
-        "excludePatches",
+        "exclude-patches",
         "wordRes",
-        "Specify single patch or multiple patches to exclude from writing."
+        "Specify single patch or multiple patches to exclude from -patches."
         " Eg, 'outlet' or '( inlet \".*Wall\" )'",
         true  // mark as an advanced option
     );
+    argList::addOptionCompat("exclude-patches", {"excludePatches", 2306});
 
     #include "setRootCase.H"
     #include "createTime.H"
@@ -167,16 +168,13 @@ int main(int argc, char *argv[])
     Info<< "Extracting surface from boundaryMesh ..." << nl << nl;
 
     const bool includeProcPatches =
-       !(
-            args.found("excludeProcPatches")
-         || Pstream::parRun()
-        );
+        (!UPstream::parRun() && !args.found("excludeProcPatches"));
 
     if (includeProcPatches)
     {
         Info<< "Including all processor patches." << nl << endl;
     }
-    else if (Pstream::parRun())
+    else if (UPstream::parRun())
     {
         Info<< "Excluding all processor patches." << nl << endl;
     }
@@ -187,7 +185,7 @@ int main(int argc, char *argv[])
         Info<< "Including patches " << flatOutput(includePatches)
             << nl << endl;
     }
-    if (args.readListIfPresent<wordRe>("excludePatches", excludePatches))
+    if (args.readListIfPresent<wordRe>("exclude-patches", excludePatches))
     {
         Info<< "Excluding patches " << flatOutput(excludePatches)
             << nl << endl;
diff --git a/applications/utilities/surface/surfaceSplitByPatch/surfaceSplitByPatch.C b/applications/utilities/surface/surfaceSplitByPatch/surfaceSplitByPatch.C
index 940c15848f35fa8b0b0af899828eff50d2559d10..e4674a5b63954146870213343727b259205c059b 100644
--- a/applications/utilities/surface/surfaceSplitByPatch/surfaceSplitByPatch.C
+++ b/applications/utilities/surface/surfaceSplitByPatch/surfaceSplitByPatch.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2020-2021 OpenCFD Ltd.
+    Copyright (C) 2020-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -45,11 +45,11 @@ Usage
           -patches '( front \".*back\" )'
         \endverbatim
 
-      - \par -excludePatches NAME | LIST
+      - \par -exclude-patches NAME | LIST
         Exclude single or multiple patches (name or regex) from extracting.
         For example,
         \verbatim
-          -excludePatches '( inlet_1 inlet_2 "proc.*")'
+          -exclude-patches '( inlet_1 inlet_2 "proc.*" )'
         \endverbatim
 
 \*---------------------------------------------------------------------------*/
@@ -79,11 +79,12 @@ int main(int argc, char *argv[])
     );
     argList::addOption
     (
-        "excludePatches",
+        "exclude-patches",
         "wordRes",
         "Exclude single or multiple patches (name or regex) from extracting.\n"
         "Eg, 'outlet' or '( inlet \".*Wall\" )'"
     );
+    argList::addOptionCompat("exclude-patches", {"excludePatches", 2306});
 
     argList::addArgument("input", "The input surface file");
 
@@ -114,7 +115,7 @@ int main(int argc, char *argv[])
         Info<< "Including patches " << flatOutput(includePatches)
             << nl << endl;
     }
-    if (args.readListIfPresent<wordRe>("excludePatches", excludePatches))
+    if (args.readListIfPresent<wordRe>("exclude-patches", excludePatches))
     {
         Info<< "Excluding patches " << flatOutput(excludePatches)
             << nl << endl;
diff --git a/etc/config.sh/completion_cache b/etc/config.sh/completion_cache
index 8c2c396df3494cea8db4085d44afc4c10a024d78..c53d6a48a4c376273e0b3a8a7ee77e69f3cf0d17 100644
--- a/etc/config.sh/completion_cache
+++ b/etc/config.sh/completion_cache
@@ -233,7 +233,7 @@ _of_complete_cache_[SRFSimpleFoam]="-case -decomposeParDict -fileHandler -world
 _of_complete_cache_[star4ToFoam]="-case -fileHandler -scale | -ascii -noFunctionObjects -solids -doc -help"
 _of_complete_cache_[steadyParticleTracks]="-case -dict -fileHandler -region -time | -constant -latestTime -noFunctionObjects -noZero -verbose -doc -help"
 _of_complete_cache_[stitchMesh]="-case -dict -fileHandler -region -toleranceDict | -integral -intermediate -overwrite -partial -perfect -doc -help"
-_of_complete_cache_[subsetMesh]="-case -decomposeParDict -fileHandler -patch -patches -region -resultTime -world | -mpi-threads -overwrite -parallel -zone -doc -help"
+_of_complete_cache_[subsetMesh]="-case -decomposeParDict -exclude-patches -fileHandler -patch -patches -region -resultTime -world | -mpi-threads -overwrite -parallel -zone -doc -help"
 _of_complete_cache_[surfaceAdd]="-case -fileHandler -points -scale | -mergeRegions -noFunctionObjects -verbose -doc -help"
 _of_complete_cache_[surfaceBooleanFeatures]="-case -fileHandler -scale -trim | -invertedSpace -no-cgal -noFunctionObjects -perturb -surf1Baffle -surf2Baffle -doc -help"
 _of_complete_cache_[surfaceCheck]="-case -fileHandler -outputThreshold -writeSets | -blockMesh -checkSelfIntersection -noFunctionObjects -splitNonManifold -verbose -doc -help"
@@ -249,7 +249,7 @@ _of_complete_cache_[surfaceInflate]="-case -featureAngle -fileHandler -nSmooth |
 _of_complete_cache_[surfaceLambdaMuSmooth]="-featureFile | -doc -help"
 _of_complete_cache_[surfaceMeshConvert]="-case -dict -fileHandler -from -read-format -read-scale -to -write-format -write-scale | -clean -noFunctionObjects -tri -verbose -doc -help"
 _of_complete_cache_[surfaceMeshExport]="-case -dict -fileHandler -from -name -read-scale -to -write-format -write-scale | -clean -noFunctionObjects -verbose -doc -help"
-_of_complete_cache_[surfaceMeshExtract]="-case -decomposeParDict -excludePatches -faceZones -fileHandler -patches -region -time -world | -constant -excludeProcPatches -latestTime -mpi-threads -noFunctionObjects -noZero -parallel -doc -help"
+_of_complete_cache_[surfaceMeshExtract]="-case -decomposeParDict -exclude-patches -faceZones -fileHandler -patches -region -time -world | -constant -excludeProcPatches -latestTime -mpi-threads -noFunctionObjects -noZero -parallel -doc -help"
 _of_complete_cache_[surfaceMeshImport]="-case -dict -fileHandler -from -name -read-format -read-scale -to -write-scale | -clean -noFunctionObjects -verbose -doc -help"
 _of_complete_cache_[surfaceMeshInfo]="-case -fileHandler -scale | -areas -noFunctionObjects -xml -doc -help"
 _of_complete_cache_[surfaceOrient]="-case -fileHandler -scale | -inside -noFunctionObjects -usePierceTest -doc -help"
@@ -257,7 +257,7 @@ _of_complete_cache_[surfacePatch]="-case -dict -fileHandler | -noFunctionObjects
 _of_complete_cache_[surfacePointMerge]="-case -fileHandler -scale | -noFunctionObjects -doc -help"
 _of_complete_cache_[surfaceRedistributePar]="-case -decomposeParDict -fileHandler -world | -keepNonMapped -mpi-threads -noFunctionObjects -parallel -doc -help"
 _of_complete_cache_[surfaceRefineRedGreen]="-case -fileHandler -steps | -noFunctionObjects -doc -help"
-_of_complete_cache_[surfaceSplitByPatch]="-case -excludePatches -fileHandler -patches | -noFunctionObjects -doc -help"
+_of_complete_cache_[surfaceSplitByPatch]="-case -exclude-patches -fileHandler -patches | -noFunctionObjects -doc -help"
 _of_complete_cache_[surfaceSplitByTopology]=" | -doc -help"
 _of_complete_cache_[surfaceSplitNonManifolds]="-case -fileHandler | -debug -noFunctionObjects -doc -help"
 _of_complete_cache_[surfaceSubset]="-case -fileHandler | -noFunctionObjects -doc -help"