I keep getting burned by this one – hopefully writing this post will cement this dichotomy into my brain for the foreseeable future…

In PowerShell, there is a big difference between the “~” path shortcut and the value of the $home automatic variable:

  • “~” is a shortcut to the home path for the PowerShell provider backing the current location.  In other words, the value of “~” changes depending on what type of drive you’re currently working (e.g., File System, registry, etc).
  • $home is set to the user’s home directory; e.g.: C:\users\yourusername or whatever your corporate overseers want it to be.  $home never changes.

I keep using ~ when I mean to use $home.  Why?  Because ~ in Linux is the semantic equivalent to $home in PowerShell.  PowerShell got it close, but not quite “right.”  Consider:

~ and $home are identical if you’re working on a file system drive.  For example:

PS C:\> resolve-path ~


PS C:\> $home

When you move to a drive for a different provider, the value of ~ changes, usually to an undefined value:

PS C:\> cd cert:
PS cert:\> resolve-path ~
Resolve-Path : Home location for this provider is not set. To set the home location, call
"(get-psprovider 'Certificate').Home = 'path'".
At line:1 char:13
+ resolve-path <<<< ~
+ CategoryInfo : InvalidOperation: (:) [Resolve-Path], PSInvalidOperationEx
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.ResolvePath

In fact, the only core PowerShell provider that defines a value for ~ is the file system provider:

PS C:\> get-psprovider | where {$_.home}

Name                 Capabilities                       Drives
----                 ------------                       ------
FileSystem           Filter, ShouldProcess              {C, D}

PS C:\>

In that respect, using ~ in scripts is fairly fragile unless you set-location to a file system path first.  $home is a better choice since it’s an absolute path.