Home > Software engineering >  Why do some of my PowerShell scripts stop working when I set PowerShell as the default application?
Why do some of my PowerShell scripts stop working when I set PowerShell as the default application?

Time:10-23

Here are 2 of my scripts. The first shows a list of directories with more than one file. The second is just a test because I never used $PSScriptRoot before.

Get-ChildItem -Path $PSScriptRoot -Directory -Name -Recurse |
Write-Output
  Where-Object { (Get-ChildItem $_ -File).Count -ge 2 }|
  ForEach-Object { ".\$_"} |
  Invoke-Item

# If running in the console, wait for input before closing.
if ($Host.Name -eq "ConsoleHost")
{
    Write-Host "Press any key to continue..."
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}
Write-Output $PSScriptRoot


# If running in the console, wait for input before closing.
if ($Host.Name -eq "ConsoleHost")
{
    Write-Host "Press any key to continue..."
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}

In the beginning, I did not have the -Path $PSScriptRoot and I ran my scripts using "Run with Powershell" in the context menu. This way the scripts seemed to use the scripts directory as the working directory. When I changed the default app to PowerShell, it started using PowerShell's install directory as the working directory. So I added -Path $PSScriptRoot and now the first script does not work; it opens a console and closes it right away. The second script works just fine.

Also, The first script still runs correctly if I "Run with Powershell" using the context menu.

What Am I doing wrong in the first script?

CodePudding user response:

I am guessing that the path to your script has spaces in it. The problem has to do with the way windows passes the file argument to the application and the way the path to the script is being parsed.

When you run your script with "Run with Powershell", the following command is sent to the shell:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'C:\Temp\with spaces\scriptRoot.ps1'"

You'll notice that the command is wrapped in quotes. Which means that the shell will pass the quoted part as an argument to the powershell executable and effectively strips the outer " quotes. So powershell sees this as a command:

if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'C:\Temp\with spaces\scriptRoot.ps1'

Now you'll notice that the path to the script is still wrapped in single quotes and everything still works even though the path has spaces.

When you run the script as "Open with ..." powershell, windows (the explorer shell) will just pass the path to the script wrapped in quotes. It looks like this:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "C:\Temp\with spaces\scriptRoot.ps1"

If I open an command prompt and try to run the above command, I get the following:

#>"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "C:\Temp\with spaces\scriptRoot.ps1"
C:\Temp\with : The term 'C:\Temp\with' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
  C:\Temp\with spaces\scriptRoot.ps1
  ~~~~~~~~~~~~
      CategoryInfo          : ObjectNotFound: (C:\Temp\with:String) [], CommandNotFoundException
      FullyQualifiedErrorId : CommandNotFoundException

That's because powershell itself never sees the outer quotes. If I add an extra layer of '' it works:

#>"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "'C:\Temp\with spaces\scriptRoot.ps1'"
C:\Temp\with spaces\scriptRoot.ps1

Unfortunately, I'm not sure how to fix this other than getting rid of the spaces in your path.

  • Related