Home > Net >  How to make custom PowerShell Modules override programs in path?
How to make custom PowerShell Modules override programs in path?

Time:12-12

I have a custom PowerShell 7 Module called grep located at C:\Program Files\PowerShell\Modules\grep.

In my system environment path, there is also a grep.exe installed through msys2.

When calling grep in the terminal, grep.exe from the path is invoked. However, I want to call the grep from the module. How can I do that?

PS C:\> Get-Command grep

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     grep.exe                                           0.0.0.0    C:\msys64\usr\bin\grep.exe
PS C:\> Get-Module -ListAvailable | where Name -EQ grep

    Directory: C:\Program Files\PowerShell\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Script     0.0                   grep                                Desk      grep

CodePudding user response:

boxdog has provided the crucial pointers in a comment:

  • Given PowerShell's command precedence, aliases, cmdlets, functions and, on Windows, even scripts (located in $env:PATH)[1] take precedence over external programs (executables).

  • Therefore, once your module has been imported, it's grep command should preempt grep.exe.

  • However, PowerShell's auto-loading mechanism does not trigger import of modules containing a command with a given name, if a command with that name is already available, notably in the form of an external program.

In other words: For your grep module's grep command to preempt grep.exe, you must ensure that your module has been imported first.

To do that implicitly, as part of a single command, you can do the following, using a module-name prefix:

# Use module prefix 'grep\' to explicitly target a command in it.
# This automatically triggers the module's import, if not already loaded.
grep\grep ...

If you want to be able to use grep as-is to invoke your module function, you must ensure that your module is imported first, which you can achieve in one of two ways, via your $PROFILE file (but note that profile loading can be bypassed via the PowerShell CLI with -NoProfile):

  • Unconditionally import your module on startup:

    • Place the following in your $PROFILE file:

      Import-Module grep
      
  • Define an alias on startup, which explicitly references the module function, as above, which triggers implicit importing:

    • Place the following in your $PROFILE file:

      Set-Alias grep grep\grep
      

[1] On Windows, unless an .exe file is invoked with its extension, PowerShell gives precedence to .ps1 files with a given (extension-less) name. On Unix-like platforms, where executables usually do not have filename extensions, the latter take precedence.

  • Related