What type of object is $<drivename>: (such as `$code:`) in Powershell?
Asked Answered
T

2

2

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 and I wanted to expand is called $document_name. When I typed $do<tab>, the shell did indeed expand what I had typed to $document_name but for some reason, I typed <tab> a second time and that's when the expanded text changed to $docs:.

I explored further and found that this type of variable exists for each of my PSDrives, or at least tab expansion suggests that it does.

More formally, for every PSDrive PSD, tab expansion believes that $PSD: is a valid thing.

My question is simple: what the heck are these? Here are some observations I've made so far:

  • These names are prefixed with $, so they look like PS variables. For the rest of this discussion (and in the earlier discussion above), I will assume they are variables and refer to them as such.
  • Although they appear to be variables, they are not listed in the Variable: PSDrive like most variables. In this way, it behaves like the $env "variable," which also is not listed in Variable:. I have a feeling if I could find documentation about $env, then I'd understand these objects also.
  • In some ways, they behave like pointers to filesystem objects. For example, if there is a file name readme.txt containing the text "Hello, world!" on a PSDrive named code, then all of the following are possible interactions with Powershell.

Fetch the contents of the file.

λ  ${code:\readme.txt}
Hello, world!

Just to prove that the type of the above result is String:

λ  ${code:\readme.txt} | % { $_.GetType().Name }
String

Trying to use this as a reference to the PSDrive doesn't work well for many operations, such as cd:

C:\
λ  cd ${code:}
At line:1 char:4
+ cd ${code:}
+    ~~~~~~~~
Variable reference is not valid. The variable name is missing.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidBracedVariableReference

I could go on, but I'm stumped. If I pass $code: (or $env:, for that matter) to Get-Member, I get an error saying Variable reference is not valid.

So just what the heck are "variables" like $env and $<PSDrive>: (such as $code:)? Are they expressions? Built-in expressions? Some kind of object? Thanks for any help.

Talyah answered 7/3, 2019 at 1:0 Comment(0)
F
6

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).

Terminology and documentation note:

  • As of this writing, the docs briefly explain namespace variable notation in the conceptual about_Scopes help topic, albeit without using that term and, somewhat confusingly, discuss it in the context of scope modifiers; while namespace qualifiers (such as $env:) are unrelated to scope modifiers (such as $script:), they use the same basic syntax form, however.[1]

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:

  • Environment (drive Env:)
  • Function (drive Function:)
  • Alias (drive Alias:)
  • FileSystem (drives C:, ...)
  • Variable (drive 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.

[1] Previously, the feature wasn't documented at all; GitHub docs issue #3343 led to the current documentation, albeit not in the way that said issue proposed.

Furmark answered 7/3, 2019 at 5:13 Comment(0)
R
1

$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://learn.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://learn.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.

Reichard answered 7/3, 2019 at 1:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.