3

I have the following line on my D:\Documents\WindowsPowerShell\profile.ps1 profile file:

Set-Location $env:HOMEDRIVE

Worth noting that $env:HOMEDRIVE equals to C:. The expected behavior is that whenever I open a PS shell I would be put in C:, but that's not what I'm getting, instead I get placed in $env:HOMEPATH, which equals to C:\Users\<my username here>.

Why this behavior and how to "fix"?


Info regarding my PS version:

PS C:\Users\...> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.14393.2068
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14393.2068
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
JChris
  • 1,638
  • 5
  • 19
  • 37
  • I am unable to reproduce it on PS 5.1.15063.909 – Martin Brandl Feb 17 '18 at 22:12
  • Why not use `cd c:\ ` ? – G42 Feb 17 '18 at 22:12
  • 1
    @gms0ulman because (1) I want something scalable, `C:` is not the `HOMEDRIVE` in all my systems, this `profile.ps1` is used on many systems at home and at work, even if all of them were `C:` I'd never use static paths in any code, this is just bad practice; and (2) I want to use PS syntax, `cd` is nothing more than an alias to `Set-Location`. Anyway, I tried with `cd C:` and didn't work... – JChris Feb 17 '18 at 22:16

3 Answers3

4

Setting the location to a drive letter with no path (ie. C:) just switches to the location stack of that drive, it doesn't actually change the path. Change it to:

Set-Location (Join-Path $env:HOMEDRIVE '\')
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1

To test. I put this in my profile.ps1:

Set-Location $env:HOMEDRIVE
Write-Host $env:HOMEDRIVE

Output

C:
PS C:\Users\<my username>>

Resolution

Set-Location "$($env:HOMEDRIVE)\"
Write-Host $env:HOMEDRIVE

Output

C:
PS C:\>
G42
  • 9,791
  • 2
  • 19
  • 34
1

To complement Mathias R. Jessen's helpful answer with background information:

PowerShell's

Set-Location $env:HOMEDRIVE

is equivalent to cmd.exe's:

cd /d %HOMEDRIVE%
  • That is, the reference to environment variable HOMEDRIVE is replaced with its value (expanded) - typically C: - and that drive is changed to. Note how PowerShell does not require an analog to the /d switch to make the drive change take effect.

  • However, in both shells, changing to a drive spec. only - without a path component - changes to whatever the shell considers the current directory on that drive, which may or may not be the root directory.

    • In order to change to a specific directory - such as the root directory - its path must be specified too.

While Set-Location (Join-Path $env:HOMEDRIVE '\') is a robust and generic way to construct and pass the path to the root directory of the drive spec. stored in environment variable HOMEDRIVE, PowerShell offers a more concise alternative:

Set-Location $env:HOMEDRIVE\ # or, with variable name disambiguated: ${env:HOMEDRIVE}\

The above works, because, simply put, PowerShell parses string arguments implicitly as if they were expandable strings (double-quoted strings with embedded variable references or even commands).

That is, the above is equivalent to all of the following:

Set-Location "$env:HOMEDRIVE\"      # expandable string
Set-Location "${env:HOMEDRIVE}\"    # ditto, variable name disambiguated
Set-Location "$(${env:HOMEDRIVE})\" # $(...) embeds full commands (not necessary here)

In addition to Join-Path being a more robust way to join path components, there are pitfalls associated with the unquoted-argument approach, such as subtle differences between unquoted and double-quoted arguments (interior whitespace requires double-quoting, as do certain characters that are shell metacharacters); when in doubt, pass the argument to Write-Output to see what it expands to; for details, see this answer of mine.

mklement0
  • 382,024
  • 64
  • 607
  • 775