binaryfunt
binaryfunt

Reputation: 7127

.cmd vs .ps1 in Path

I have added a folder to my Path that contains a foo.cmd batch file and foo.ps1 powershell script. (The batch file is there to run the powershell script with a bypassed execution policy.)

When in powershell/command prompt I run

> foo

it runs foo.ps1 in preference to foo.cmd, which is the opposite of what I want. Is there any way to get round this, without having to type > foo.cmd?

Upvotes: 2

Views: 1501

Answers (1)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200453

Command precedence in PowerShell is defined like this:

If you do not specify a path, PowerShell uses the following precedence order when it runs commands:

  1. Alias
  2. Function
  3. Cmdlet
  4. Native Windows commands

Therefore, if you type "help", PowerShell first looks for an alias named "help", then a function named "Help", and finally a cmdlet named "Help". It runs the first "help" item that it finds.

Precedence of external ("native Windows") commands is then controlled by the PATH and PATHEXT environment variables. The former lists the directories Windows searches for external commands is the command wasn't invoked with a (relative or absolute) path, the latter lists extensions that Windows will auto-append if no match was found. For each environment variable the first match wins, meaning if you have a PATH listing C:\foo;C:\bar and have a folder structure like this:

C:
├─bar
│ └─a.exe
└─foo
  ├─a.cmd
  └─a.vbs

Windows will execute C:\foo\a.cmd when you invoke the command a (without path or extension), because C:\foo comes first in the PATH and .cmd comes before .vbs in the PATHEXT variable.

However, PowerShell scripts seem to rank somewhere between cmdlets and external commands as far as PowerShell is concerned, because their extension not listed in $env:PATHEXT, but you can't supersede builtin cmdlets with PowerShell scripts of the same name. I wasn't able to find documentation about this, though.

Bottom line: I think you'll either have to invoke the batch script with extension or rename the PowerShell script. The latter could be done by appending a fixed suffix to the basename of the file and then invoke it from the batch script like this:

@echo off
set "suffix=-bar"
powershell.exe -ExecutionPolicy ByPass -File "%~dpn0%suffix%.ps1"

Upvotes: 4

Related Questions