PowerShell: The hated, to be hated, born with a cursed fate

One will not be able to believe

That how Microsoft can give birth to something that is even more cursed than VBScript.

The strange and weird naming and casing conventions aside, there are far more unbelievable caveats one can run into.

Resolve path resolve only existing paths

Why? How come it is even possible?
Believe it or not, see for your own eyes.

A quick search reveal a fix however you probably know a common file system operation should not be a mine field.

Here is a sample implementation that will work with non-existing paths.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Force-Resolve-Path {
<#
.SYNOPSIS
Calls Resolve-Path but works for files that don't exist.
.REMARKS
From http://devhawk.net/blog/2010/1/22/fixing-powershells-busted-resolve-path-cmdlet
#>
param (
[Parameter(Mandatory = $true)]
[string] $FileName
)
$FileName = Resolve-Path $FileName -ErrorAction SilentlyContinue `
-ErrorVariable _frperror
if (-Not $FileName) {
$FileName = $_frperror[0].TargetObject
}
return $FileName
}

Square brackets in file name bites

When you have square brackets in file name, it will be treated as wildcard.

Escape it shouldn’t be that hard you think?

Good luck, because if you’re using single-quote strings, a bracket needs two backticks to escape it. If you’re using double-quote strings, a bracket needs four backticks to escape it.

You may soon realize there are a second option that will allow you to avoid special characters being treated as wildcard, by using -LiteralPath.

Sure, try following code with some existing paths.

1
2
3
Test-Path -Path ".\folder"
Test-Path -LiteralPath ".\folder"
Test-Path -LiteralPath ".\[label]folder"

Yes, that is right, the -LiteralPath don’t take relative path, now revisit the aforementioned caveat about Resolve-Path.

What for more, not all file system operations support -LiteralPath, you’ll have a fun time figuring that out.

If above are just features, the following are really nothing but bugs

  • When New-Item -Path is combined with -Name, the -Path argument is inappropriately treated as a wildcard expression
    GitHub Issue

  • Split-Path switches (-Leaf, -Parent, …) do not work with -LiteralPath
    GitHub Issue

You can find more weird bugs floating around the Internet.

I personally had encountered a less known bug that can occur when PowerShell script is executed from a path containing special characters.

Following is the fix I implemented.

1
2
3
4
# Handle weird PowerShell bug that causing current folder being "C:\Windows\System32\WindowsPowerShell\v1.0" instead of the one this script is in
if ($PSScriptRoot -ne $nil) {
Push-Location -LiteralPath $PSScriptRoot
}

There are even more strange things only in the PowerShell world

Try catch only work with terminating error. But what is a terminating error, is it a type of error or what?

Run following code to find out. Set $Path to a non-existing path.

1
2
3
4
5
6
7
8
9
10
11
try {
$Item = Get-Item -LiteralPath $Path -Force
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Host "`nPath $Path does not exist?"
}
try {
$Item = Get-Item -LiteralPath $Path -Force -ErrorAction stop
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Host "`nPath $Path does not exist."
}

The terminating error seems to be an unique concept for PowerShell.

There are many ways to do a thing

And not all of them are created equal.

For example in order to implement Press any key to continue prompt the following methods maybe used.

1
2
3
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
[Console]::ReadKey()
$Answer = Read-Host "Continue?" # Only accept Enter

Bearing different syntax styles aside, all of the above are valid PowerShell code. You may read more here.

Meanwhile, why NoEcho,IncludeKeyDown is needed here?

One last answer for today’s adventure.

Ref:

  1. PSHostRawUserInterface.ReadKey Method
  2. Read-Host
  3. Console.ReadKey Method

Update after a week

I’m completely ditching PowerShell and moving on to another automation option.

For some strange reasons, when I try to launch PowerShell scripts from within Windows Sandbox, I’m getting following error:

1
2
C:\Users\WDAGUtilityAccount>powershell
Version v4.0.30319 of the .NET Framework is not installed and it is required to run version 3 of Windows PowerShell.

However I’m pretty sure the host machine has .NET Framework satiesfying the requirements because PowerShell runs fine on host machine directly.

When try to launch .NET Framework installer from within Windows Sandbox it tells me my environment doesn’t meet minimal requirements for the installer to run.

This might due to Windows Sandbox or a recent .NET Framework patch from Windows Update(I highly suspect the later).

Just one minor inconvenience as it might looked like, ~90% of my PowerShell scripts are used to automate environment setup for Windows Sandbox and moving data in or out of it so not being able to run any PowerShell script obviously defeats such purpose. I was expecting it to be more robust than Windows Command Prompt as well as working out of the box for most Windows machines.

A quick search on Internet indicates this is probably a regression issue as someone encountered it back in 2022. That being said, I’ve completely lost interest in PowerShell and decided to migrate to another automation option.