tl;dr:
Don't use ~ - use $HOME to refer to the current user's home directory, typically inside "...":
[System.IO.File]::Exists("$HOME/foo")
Or, preferably, use PowerShell's Test-Path cmdlet:
Test-Path -LiteralPath "$HOME/foo"
Note:
* PowerShell and .NET types accept / and \ interchangeably as the path separators; with a view toward potential cross-platform compatibilty, choose /.
* Strictly speaking, since "$HOME/foo" is passed to Test-Path in argument mode (command-line style), enclosing in "..." isn't necessary in this case (try Write-Output $HOME/foo), but enclosing in "..." is a good habit to form, because it works in a wider range of scenarios.
PowerShell's ~ is not fully equivalent to ~ on Unix (in POSIX-like shells) and may not work the way you expect it to in PowerShell:
As explained in this TechNet article[1], ~ in PowerShell refers to the home location as defined by the current location's drive provider, which:
- may or may not be the filesystem.
- may or may not be defined.
On Windows, consider the following example, which uses the registry drive provider:
Set-location HKCU:\Software
Set-Location ~
which yields the following error:
Set-Location : Home location for this provider is not set. To set the home location, call "(get-psprovider 'Registry').Home = 'path'".
...
As you can see, because the current location was on a drive of the registry provider, ~ was interpreted as that provider's idea of the home location, which, however, happens not to be defined.
An additional crucial difference:
On Unix, ~ is a shell feature: it must be used unquoted, in which case it is expanded to the full, literal home-directory by the shell, before the target command sees the path, so that the target command sees a literal path and doesn't need to know about ~, and, in fact, the standard utilities do not know about ~, which you can verify by contrasting ls ~ (OK) with ls '~' (tries to list a file/dir literally named ~).
In PowerShell, ~ is a PowerShell drive-provider feature: ~ is passed as-is to drive-provider cmdlets such as Get-ChildItem and they interpret ~ as referring to the current drive's home location. External utilities (e.g., findstr.exe on Windows) and the .NET Framework do not follow this convention and therefore interpret the ~ as a literal filename.
By contrast, automatic variable $HOME is the PowerShell equivalent of Unix ~, with added flexibility:
While Unix ~ has to be unquoted in order to expand to the user's home directory, PowerShell's automatic $HOME variable can be referenced inside double-quoted strings as well (as part of normal string expansion (interpolation)).
Finally, .NET types such as [System.IO.File] themselves support neither ~ nor $HOME, but by using "$HOME/..." it is PowerShell that ensures that $HOME is replaced with the actual, literal home-directory path before the path string is passed to a .NET method.
[1] Get-Help about_Locations and Get-Help about_Path_Syntax, the official help topics on the subject, should contain information about ~,
but as of this writing do not.