diff --git a/common/changes/@microsoft/rush/feat-rush-scan-support-folders_2024-12-16-03-01.json b/common/changes/@microsoft/rush/feat-rush-scan-support-folders_2024-12-16-03-01.json
new file mode 100644
index 00000000000..a84794650c2
--- /dev/null
+++ b/common/changes/@microsoft/rush/feat-rush-scan-support-folders_2024-12-16-03-01.json
@@ -0,0 +1,10 @@
+{
+  "changes": [
+    {
+      "packageName": "@microsoft/rush",
+      "comment": " Modify rush scan, support executing projects under rush and custom scanning folders.",
+      "type": "none"
+    }
+  ],
+  "packageName": "@microsoft/rush"
+}
\ No newline at end of file
diff --git a/libraries/rush-lib/src/cli/actions/ScanAction.ts b/libraries/rush-lib/src/cli/actions/ScanAction.ts
index b99e7da7f63..39bb2f6608f 100644
--- a/libraries/rush-lib/src/cli/actions/ScanAction.ts
+++ b/libraries/rush-lib/src/cli/actions/ScanAction.ts
@@ -3,14 +3,16 @@
 
 import * as path from 'path';
 import builtinPackageNames from 'builtin-modules';
-import { Colorize } from '@rushstack/terminal';
-import type { CommandLineFlagParameter } from '@rushstack/ts-command-line';
-import { FileSystem } from '@rushstack/node-core-library';
+import { Colorize, type ITerminal } from '@rushstack/terminal';
+import type { CommandLineFlagParameter, CommandLineStringListParameter } from '@rushstack/ts-command-line';
+import { FileSystem, FileConstants, JsonFile } from '@rushstack/node-core-library';
+import type FastGlob from 'fast-glob';
 
 import type { RushCommandLineParser } from '../RushCommandLineParser';
 import { BaseConfiglessRushAction } from './BaseRushAction';
+import type { RushConfigurationProject } from '../../api/RushConfigurationProject';
 
-export interface IJsonOutput {
+export interface IScanResult {
   /**
    * Dependencies scan from source code
    */
@@ -26,8 +28,11 @@ export interface IJsonOutput {
 }
 
 export class ScanAction extends BaseConfiglessRushAction {
+  private readonly _terminal: ITerminal;
   private readonly _jsonFlag: CommandLineFlagParameter;
   private readonly _allFlag: CommandLineFlagParameter;
+  private readonly _folders: CommandLineStringListParameter;
+  private readonly _projects: CommandLineStringListParameter;
 
   public constructor(parser: RushCommandLineParser) {
     super({
@@ -40,7 +45,7 @@ export class ScanAction extends BaseConfiglessRushAction {
         ` declaring them as dependencies in the package.json file.  Such "phantom dependencies"` +
         ` can cause problems.  Rush and PNPM use symlinks specifically to protect against phantom dependencies.` +
         ` These protections may cause runtime errors for existing projects when they are first migrated into` +
-        ` a Rush monorepo.  The "rush scan" command is a handy tool for fixing these errors. It scans the "./src"` +
+        ` a Rush monorepo.  The "rush scan" command is a handy tool for fixing these errors. It default scans the "./src"` +
         ` and "./lib" folders for import syntaxes such as "import __ from '__'", "require('__')",` +
         ` and "System.import('__').  It prints a report of the referenced packages.  This heuristic is` +
         ` not perfect, but it can save a lot of time when migrating projects.`,
@@ -56,14 +61,31 @@ export class ScanAction extends BaseConfiglessRushAction {
       parameterLongName: '--all',
       description: 'If this flag is specified, output will list all detected dependencies.'
     });
+    this._folders = this.defineStringListParameter({
+      parameterLongName: '--folder',
+      parameterShortName: '-f',
+      argumentName: 'FOLDER',
+      description:
+        'The folders that need to be scanned, default is src and lib.' +
+        'Normally we can input all the folders under the project directory, excluding the ignored folders.'
+    });
+    this._projects = this.defineStringListParameter({
+      parameterLongName: '--only',
+      parameterShortName: '-o',
+      argumentName: 'PROJECT',
+      description: 'Projects that need to be checked for phantom dependencies.'
+    });
+    this._terminal = parser.terminal;
   }
 
-  protected async runAsync(): Promise<void> {
-    const packageJsonFilename: string = path.resolve('./package.json');
-
-    if (!FileSystem.exists(packageJsonFilename)) {
-      throw new Error('You must run "rush scan" in a project folder containing a package.json file.');
-    }
+  private async _scanAsync(params: {
+    packageJsonFilePath: string;
+    folders: readonly string[];
+    glob: typeof FastGlob;
+    terminal: ITerminal;
+  }): Promise<IScanResult> {
+    const { packageJsonFilePath, folders, glob, terminal } = params;
+    const packageJsonFilename: string = path.resolve(packageJsonFilePath);
 
     const requireRegExps: RegExp[] = [
       // Example: require('something')
@@ -114,8 +136,13 @@ export class ScanAction extends BaseConfiglessRushAction {
 
     const requireMatches: Set<string> = new Set<string>();
 
-    const { default: glob } = await import('fast-glob');
-    const scanResults: string[] = await glob(['./*.{ts,js,tsx,jsx}', './{src,lib}/**/*.{ts,js,tsx,jsx}']);
+    const scanResults: string[] = await glob(
+      [
+        './*.{ts,js,tsx,jsx}',
+        `./${folders.length > 1 ? '{' + folders.join(',') + '}' : folders[0]}/**/*.{ts,js,tsx,jsx}`
+      ],
+      { cwd: path.dirname(packageJsonFilePath), absolute: true }
+    );
     for (const filename of scanResults) {
       try {
         const contents: string = FileSystem.readFile(filename);
@@ -131,7 +158,8 @@ export class ScanAction extends BaseConfiglessRushAction {
         }
       } catch (error) {
         // eslint-disable-next-line no-console
-        console.log(Colorize.bold('Skipping file due to error: ' + filename));
+        console.log(error);
+        terminal.writeErrorLine(Colorize.bold('Skipping file due to error: ' + filename));
       }
     }
 
@@ -175,8 +203,7 @@ export class ScanAction extends BaseConfiglessRushAction {
         }
       }
     } catch (e) {
-      // eslint-disable-next-line no-console
-      console.error(`JSON.parse ${packageJsonFilename} error`);
+      terminal.writeErrorLine(`JSON.parse ${packageJsonFilename} error`);
     }
 
     for (const detectedPkgName of detectedPackageNames) {
@@ -200,65 +227,108 @@ export class ScanAction extends BaseConfiglessRushAction {
       }
     }
 
-    const output: IJsonOutput = {
+    const output: IScanResult = {
       detectedDependencies: detectedPackageNames,
       missingDependencies: missingDependencies,
       unusedDependencies: unusedDependencies
     };
 
+    return output;
+  }
+
+  private _getPackageJsonPathsFromProjects(projectNames: readonly string[]): string[] {
+    const result: string[] = [];
+    if (!this.rushConfiguration) {
+      throw new Error(``);
+    }
+    for (const projectName of projectNames) {
+      const project: RushConfigurationProject | undefined =
+        this.rushConfiguration.getProjectByName(projectName);
+      if (!project) {
+        throw new Error(``);
+      }
+      const packageJsonFilePath: string = path.join(project.projectFolder, FileConstants.PackageJson);
+      result.push(packageJsonFilePath);
+    }
+    return result;
+  }
+
+  protected async runAsync(): Promise<void> {
+    const packageJsonFilePaths: string[] = this._projects.values.length
+      ? this._getPackageJsonPathsFromProjects(this._projects.values)
+      : [path.resolve('./package.json')];
+    const { default: glob } = await import('fast-glob');
+    const folders: readonly string[] = this._folders.values.length ? this._folders.values : ['src', 'lib'];
+
+    const output: Record<string, IScanResult> = {};
+
+    for (const packageJsonFilePath of packageJsonFilePaths) {
+      if (!FileSystem.exists(packageJsonFilePath)) {
+        throw new Error(`${packageJsonFilePath} is not exist`);
+      }
+      const packageName: string = JsonFile.load(packageJsonFilePath).name;
+      const scanResult: IScanResult = await this._scanAsync({
+        packageJsonFilePath,
+        folders,
+        glob,
+        terminal: this._terminal
+      });
+      output[packageName] = scanResult;
+    }
     if (this._jsonFlag.value) {
-      // eslint-disable-next-line no-console
-      console.log(JSON.stringify(output, undefined, 2));
+      this._terminal.writeLine(JSON.stringify(output, undefined, 2));
     } else if (this._allFlag.value) {
-      if (detectedPackageNames.length !== 0) {
-        // eslint-disable-next-line no-console
-        console.log('Dependencies that seem to be imported by this project:');
-        for (const packageName of detectedPackageNames) {
-          // eslint-disable-next-line no-console
-          console.log('  ' + packageName);
+      for (const [packageName, scanResult] of Object.entries(output)) {
+        this._terminal.writeLine(`-------------------- ${packageName} result start --------------------`);
+        const { detectedDependencies } = scanResult;
+        if (detectedDependencies.length !== 0) {
+          this._terminal.writeLine(`Dependencies that seem to be imported by this project ${packageName}:`);
+          for (const detectedDependency of detectedDependencies) {
+            this._terminal.writeLine('  ' + detectedDependency);
+          }
+        } else {
+          this._terminal.writeLine(`This project ${packageName} does not seem to import any NPM packages.`);
         }
-      } else {
-        // eslint-disable-next-line no-console
-        console.log('This project does not seem to import any NPM packages.');
+        this._terminal.writeLine(`-------------------- ${packageName} result end --------------------`);
       }
     } else {
-      let wroteAnything: boolean = false;
-
-      if (missingDependencies.length > 0) {
-        // eslint-disable-next-line no-console
-        console.log(
-          Colorize.yellow('Possible phantom dependencies') +
-            " - these seem to be imported but aren't listed in package.json:"
-        );
-        for (const packageName of missingDependencies) {
-          // eslint-disable-next-line no-console
-          console.log('  ' + packageName);
+      for (const [packageName, scanResult] of Object.entries(output)) {
+        this._terminal.writeLine(`-------------------- ${packageName} result start --------------------`);
+        const { missingDependencies, unusedDependencies } = scanResult;
+        let wroteAnything: boolean = false;
+
+        if (missingDependencies.length > 0) {
+          this._terminal.writeWarningLine(
+            Colorize.yellow('Possible phantom dependencies') +
+              " - these seem to be imported but aren't listed in package.json:"
+          );
+          for (const missingDependency of missingDependencies) {
+            this._terminal.writeLine('  ' + missingDependency);
+          }
+          wroteAnything = true;
         }
-        wroteAnything = true;
-      }
 
-      if (unusedDependencies.length > 0) {
-        if (wroteAnything) {
-          // eslint-disable-next-line no-console
-          console.log('');
+        if (unusedDependencies.length > 0) {
+          if (wroteAnything) {
+            this._terminal.writeLine('');
+          }
+          this._terminal.writeWarningLine(
+            Colorize.yellow('Possible unused dependencies') +
+              " - these are listed in package.json but don't seem to be imported:"
+          );
+          for (const unusedDependency of unusedDependencies) {
+            this._terminal.writeLine('  ' + unusedDependency);
+          }
+          wroteAnything = true;
         }
-        // eslint-disable-next-line no-console
-        console.log(
-          Colorize.yellow('Possible unused dependencies') +
-            " - these are listed in package.json but don't seem to be imported:"
-        );
-        for (const packageName of unusedDependencies) {
-          // eslint-disable-next-line no-console
-          console.log('  ' + packageName);
+
+        if (!wroteAnything) {
+          this._terminal.writeLine(
+            Colorize.green('Everything looks good.') + '  No missing or unused dependencies were found.'
+          );
         }
-        wroteAnything = true;
-      }
 
-      if (!wroteAnything) {
-        // eslint-disable-next-line no-console
-        console.log(
-          Colorize.green('Everything looks good.') + '  No missing or unused dependencies were found.'
-        );
+        this._terminal.writeLine(`-------------------- ${packageName} result end --------------------`);
       }
     }
   }
diff --git a/libraries/rush-lib/src/cli/actions/test/ScanAction.test.ts b/libraries/rush-lib/src/cli/actions/test/ScanAction.test.ts
new file mode 100644
index 00000000000..8c5cf588fd0
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/ScanAction.test.ts
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+import '../../test/mockRushCommandLineParser';
+
+import '../../test/mockRushCommandLineParser';
+import { ScanAction } from '../ScanAction';
+import { RushCommandLineParser } from '../../RushCommandLineParser';
+
+import { Terminal } from '@rushstack/terminal';
+
+describe.skip(ScanAction.name, () => {
+  describe('basic "rush remove" tests', () => {
+    let terminalMock: jest.SpyInstance;
+    let oldExitCode: number | undefined;
+    let oldArgs: string[];
+
+    beforeEach(() => {
+      terminalMock = jest.spyOn(Terminal.prototype, 'write').mockImplementation(() => {});
+
+      jest.spyOn(process, 'exit').mockImplementation();
+
+      oldExitCode = process.exitCode;
+      oldArgs = process.argv;
+    });
+
+    afterEach(() => {
+      jest.clearAllMocks();
+      process.exitCode = oldExitCode;
+      process.argv = oldArgs;
+    });
+
+    describe("'scan' action", () => {
+      it(`scan the repository to find phantom dependencies. `, async () => {
+        const aPath: string = `${__dirname}/scanRepo/a`;
+
+        const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: aPath });
+
+        jest.spyOn(process, 'cwd').mockReturnValue(aPath);
+
+        process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'scan', '--json'];
+        await expect(parser.executeAsync()).resolves.toEqual(true);
+        expect(terminalMock).toHaveBeenCalledTimes(1);
+      });
+    });
+  });
+});
diff --git a/libraries/rush-lib/src/cli/actions/test/scanRepo/.gitignore b/libraries/rush-lib/src/cli/actions/test/scanRepo/.gitignore
new file mode 100644
index 00000000000..6ddd556a5a2
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/scanRepo/.gitignore
@@ -0,0 +1 @@
+common/temp
diff --git a/libraries/rush-lib/src/cli/actions/test/scanRepo/a/index.ts b/libraries/rush-lib/src/cli/actions/test/scanRepo/a/index.ts
new file mode 100644
index 00000000000..9cbb014c4b4
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/scanRepo/a/index.ts
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+/* eslint-disable @typescript-eslint/no-unused-vars */
+/* eslint-disable import/no-extraneous-dependencies */
+import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal';
diff --git a/libraries/rush-lib/src/cli/actions/test/scanRepo/a/package.json b/libraries/rush-lib/src/cli/actions/test/scanRepo/a/package.json
new file mode 100644
index 00000000000..fa82832c694
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/scanRepo/a/package.json
@@ -0,0 +1,8 @@
+{
+  "name": "a",
+  "version": "1.0.0",
+  "description": "Test package a",
+  "dependencies": {
+    "assert": "workspace:*"
+  }
+}
diff --git a/libraries/rush-lib/src/cli/actions/test/scanRepo/b/package.json b/libraries/rush-lib/src/cli/actions/test/scanRepo/b/package.json
new file mode 100644
index 00000000000..a345432fe3c
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/scanRepo/b/package.json
@@ -0,0 +1,9 @@
+{
+  "name": "b",
+  "version": "1.0.0",
+  "description": "Test package b",
+  "dependencies": {
+    "assert": "workspace:*",
+    "rimraf": "workspace:*"
+  }
+}
diff --git a/libraries/rush-lib/src/cli/actions/test/scanRepo/b/test-folder1/index.ts b/libraries/rush-lib/src/cli/actions/test/scanRepo/b/test-folder1/index.ts
new file mode 100644
index 00000000000..9cbb014c4b4
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/scanRepo/b/test-folder1/index.ts
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+/* eslint-disable @typescript-eslint/no-unused-vars */
+/* eslint-disable import/no-extraneous-dependencies */
+import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal';
diff --git a/libraries/rush-lib/src/cli/actions/test/scanRepo/rush.json b/libraries/rush-lib/src/cli/actions/test/scanRepo/rush.json
new file mode 100644
index 00000000000..f39da1606c4
--- /dev/null
+++ b/libraries/rush-lib/src/cli/actions/test/scanRepo/rush.json
@@ -0,0 +1,17 @@
+{
+  "npmVersion": "6.4.1",
+  "rushVersion": "5.5.2",
+  "projectFolderMinDepth": 1,
+  "projectFolderMaxDepth": 99,
+
+  "projects": [
+    {
+      "packageName": "a",
+      "projectFolder": "a"
+    },
+    {
+      "packageName": "b",
+      "projectFolder": "b"
+    }
+  ]
+}