Search code examples
powershell

How can I navigate to a specific directory in Powershell?


I am new to Powershell and am unable to navigate to specific directories. I know where the directory is, but the command below doesn't work when I try to navigate to the directory.

Get-ChildItem -Directory | Select-Object -Last 1

I then want to Set-Location to that but I can't figure out how to call it with the output of the above.

I was trying something like:

Get-ChildItem -Directory | Select-Object -Last 1

Set-Variable -Name "Dir" -Value { Get-ChildItem -Directory | Select-Object -Last 1 }

Set-Location -Path $Dir

but that doesn't work at all. Any pointers?


Solution

  • There's good information in the comments, let me try to summarize and complement them:

    • { ... } is a script block literal in PowerShell: a reusable piece of code to be invoked later with &, the call operator; that is, what's inside the curly braces is not executed right away.

    • Given that you want the execute and return the output from a command as the argument to another command, use (), the grouping operator[1].

    Set-Variable -Name Dir -Value (Get-ChildItem -Directory | Select-Object -Last 1)
    

    However, there is rarely a need to use the Set-Variable cmdlet, given that simple assignments - $Dir = ... work too, in which case you don't even need the parentheses:

    $Dir = Get-ChildItem -Directory | Select-Object -Last 1
    

    Of course, just like you can pass an (...) expression to Set-Variable, you can pass it to Set-Location directly, in which case you don't need an intermediate variable at all (parameter -Path is positionally implied):

    Set-Location (Get-ChildItem -Directory | Select-Object -Last 1)
    

    You can make this more concise by directly indexing the Get-ChildItem call's output[2]; [-1] refers to the last array element (output object):

    Set-Location (Get-ChildItem -Directory)[-1]
    

    The alternative is to use the pipeline (see about_Pipelines):

    Get-ChildItem -Directory | Select-Object -Last 1 | Set-Location
    

    Note that there are subtle differences between the last 3 commands in the event that no subdirectories exist in the current directory (meaning that Get-ChildItem -Directory produces no output):

    • Set-Location (Get-ChildItem -Directory | Select-Object -Last 1) will report an error, because you're then effectively passing $null as the -Path argument.

    • Set-Location (Get-ChildItem -Directory)[-1] will also report an error, because you cannot apply an index to a $null value.

    • Get-ChildItem -Directory | Select-Object -Last 1 | Set-Location, by contrast, will be a no-op, because Set-Location effectively won't be invoked at all, due to not receiving input via the pipeline.

    If not having subdirectories is an unexpected condition, you can force the script to abort by adding -ErrorAction Stop to one of the first two commands - see about_CommonParameters.


    [1] While $(...), the subexpression operator, works too, it's usually not necessary - see this answer.

    [2] Note that doing so means that all output from the Get-ChildItem call is then collected in memory first, but that is unlikely to be a problem in this case. See this answer for more information.