I was using tab autocompletion for a variable name in Powershell 5.1 today and noticed that one of the choices was the name of a PSDrive. The drive name is docs
What you're seeing is namespace variable notation, which is a variable-based way to access the content of items in PowerShell drives whose underlying provider implements content-based access (i.e., implements the IContentCmdletProvider
interface).
The general syntax is:
${<drive>:<path>} # same as: Get-Content <drive>:<path>
${<drive>:<path>} = ... # same as: Set-Content <drive>:<path> -Value ...
The enclosing {...}
aren't necessary if both the <drive>
name and the <path>
can syntactically serve as a variable name; e.g.:
$env:HOME # no {...} needed
${env:ProgramFiles(x86)} # {...} needed due to "(" and ")"
In practice, as of Windows PowerShell v5.1, the following in-box drive providers support namespace variable notation:
Env:
)Function:
)Alias:
)C:
, ...)Variable:
) - though virtually pointless, given that omitting the drive part accesses variables by default (e.g., $variable:HOME
is the same as just $HOME
).Of these, the Env:
drive is by far the most frequently used with namespace variable notation, even though most users aren't aware of what underlies an environment-variable references such as $env:HOME
.
On occasion you see it used with a filesystem drive - e.g., ${c:\foo\file.txt}
- but the fact that you can only use literal paths and that you cannot control the character encoding limits its usefulness.
It allows interesting uses, however; e.g.:
PS> $alias:foreach # Get the definition of alias 'foreach'
ForEach-Object
PS> $function:prompt # Get the body of the 'prompt' function
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";
# .Link
# https://go.microsoft.com/fwlink/?LinkID=225750
# .ExternalHelp System.Management.Automation.dll-help.xml
# Define a function foo that echoes 'hi' and invoke it.
PS> $function:foo = { 'hi' }; foo
hi
Note:
Because ${<drive>:<path>}
and ${<drive>:<path>} = <value>
are equivalent to Get-Content -Path <drive>:<path>
and Set-Content -Path <drive>:<path> <value>
, paths are interpreted as wildcard expressions (because that's what -Path
does, as opposed to -LiteralPath
), which can cause problems with paths that look like wildcards - see this answer for an example and a workaround.
As of this writing, namespace variable notation isn't officially documented yet, but this GitHub issue suggests doing so.
$env
is the Windows environment variables, the same as what you get when you do SET
in a command prompt. There are a few that are PS-specific.
The variable is providing access to the Environment Provider. https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-6
There are a bunch of other Providers that are described here: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_providers?view=powershell-6
As it says in the doco:
The model for data presentation is a file system drive. To use data that the provider exposes, you view it, move through it, and change it as though it were data on a hard drive. Therefore, the most important information about a provider is the name of the drive that it supports.