Tilde issue

I wanted to use the shortcut “~” (a.k.a tilde) in a PowerShell console but it didn’t work.

dir "~/"

I encountered actually the following error:
Get-ChildItem : Cannot retrieve the dynamic parameters for the cmdlet. Home location for this provider is not set. To set the home location, call “(get-psprovider ‘FileSystem’).Home = ‘path'”.

I remembered Windows PowerShell MVP Jim Christopher writing about the difference between ~ and $home.

I also experienced the same gotcha in a runas account.

I wanted to know what was really going on and decided to compare a trace on a failing computer and on a safe one by executing

Trace-Command -Name PathResolution -Expression { 
    Resolve-Path ~ 
} -PSHost

The interesting lines are after “Resolving HOME relative path.”:

Getting home path for provider: FileSystem (on the working one)
ERROR: HOME path not set for provider: FileSystem (on the failing one)

What is really “~”?
The answer is located in the example 3 of the Convert-Path cmdlet and the example 4 of Get-PSProvider cmdlet.

Get-help '~'
Get-help Convert-Path -Examples
Get-help Get-PSProvider -Examples

May I propose my definition 😛
~ is a relative path that is resolved from the home property of the current provider.

There’s more…

Get-PSProvider "FileSystem" | Get-Member

The definition returned also indicates that I can set my favorite “MSH Path” on every provider.

Now, there are 2 options:
You can either define custom values for all the default providers:

(Get-PSProvider Alias).Home = "Alias:"
(Get-PSProvider Environment).Home = "Env:"
(Get-PSProvider FileSystem).Home = "$home"
(Get-PSProvider Function).Home = "Function:"
(Get-PSProvider Registry).Home = "HKCU:\"
(Get-PSProvider Variable).Home = "Microsoft.PowerShell.Core\Variable:"
(Get-PSProvider Certificate).Home = "Microsoft.PowerShell.Security\Certificate::CurrentUser\My"
(Get-PSProvider WSMan).Home = "WSMan:"

Set a home path for all PSProviders that don’t have one already defined:

# Overwrite my home for the FileSystem provider as
# in my env, $home -ne $env:userprofile
(Get-PSProvider -PSProvider FileSystem).Home = $($env:USERPROFILE)
# Dynamically define a home for all the other providers
Get-PSProvider |
Where { -not($_.Home) -and -not($_.Name -eq 'FileSystem')} | 
ForEach-Object {
    if ($_.Drives) {
        (Get-PSProvider $_.Name).Home = (
        '{0}:' -f ($_.Drives | Select -Last 1).Name
        Write-Verbose "Set home for provider $($_.Name) to $($_.Drives | Select -Last 1)" -Verbose
    } else {
        Write-Warning -Message "Drives not found for provider  $($_.Name)"
# View the PSProviders and their home
Get-PSProvider | Select Name,Capabilities,Drives,Home

The list of PSProviders returned by the Get-PSProvider cmdlet may vary because

To force things a little bit and get the nice picture below, I’ve already interacted with the default classic PSproviders and ActiveDirectory module before dynamically defining home path properties of the PSProviders with the above code

Get-PSProvider 'Alias','Environment','FileSystem','Function',
'Registry','Variable','Certificate','WSMan' | Out-Null
if (Get-Module -ListAvailable | Where Name -eq ActiveDirectory) { 
    Get-ADUser $($env:USERNAME) -ErrorAction SilentlyContinue | Out-Null

By setting the above home paths, the automatic expansion of “~” feature started to work again 😎

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s