This is a popular question because after installation of PowerShell its scripts (.ps1 files) are not associated with PowerShell.exe, as one may expect. I believe there are many good security reasons for this approach. But in my case this is not suitable for many other good reasons. I want to invoke my scripts from Explorer by mouse double clicks, just like I invoke .bat, .cmd, .js, .vbs, .pl and other script files.
I tried quite a few ways of doing this and I am going to describe just one which is in active use for several years. The PowerShell script below should be invoked once to install the association (actually under the covers it calls Cmd to make the job done by FType):
<# .SYNOPSIS Associates .ps1 files with PowerShell.exe #> cmd /c @" FType Microsoft.PowerShellScript.1=$PSHOME\powershell.exe -NoExit . "'%1'" %*; Exit "@
Basically the command tells to start PowerShell.exe and invoke a script (%1) by dot-sourcing it (operator .) with optional arguments (%*). But the command line also contains two contradicting exit related instructions: switch -NoExit for PowerShell.exe and instruction Exit for PowerShell. Why?
- If a script succeeds its console window is closed due to the Exit statement in the end. Of course, scripts with screen output to look at should not be invoked in this way.
- If a script fails its console window is not closed because of -NoExit switch and not yet executed due to a failure Exit statement.
After a failure one can:
- Read the output and error messages.
- Investigate the variables, environment and etc. Note: a script is dot-sourced (invoked by .), that often makes more variables available in the global scope after failures.
- Fix transient problems and re-run the script in its still opened console with a full set of original parameters simply by typing r immediately or by r 1 after any command invoked.
"'%1'" would be enough for invoking scripts from Explorer. But due to %* the association also works in other scenarios with extra arguments passed in a script. For example in Cmd or Run window it is enough to provide a script path and a few simple (!) arguments, PowerShell.exe can be omitted.
- This approach does not work if a script full path contains '. But I do not really suffer from this limitation because my scripts are never in such paths. As for other scripts, I do not invoke them from Explorer, for mentioned safety reasons, too.
- %* (extra arguments) does not work (directly) with not trivial arguments with spaces and $ or ` symbols. For such scenarios there is yet another approach with -File parameter of PowerShell.exe. But an association command with -File does not provide described above flexibility of exit.
If you use this then responsibility is all yours. Do not invoke unknown or not trivial scripts via association, results may be unwanted. But in trivial cases the described approach really helps to save seconds here and there.