Useful PowerShell Function: Use-Location

It’s a simple one, but useful. And it can clean up some of your ugly scripts that have a lot of redundant paths embedded in strings.

# Reduced for the sake of the example
# The full advanced function is included at the end.
function Use-Location($Path, $Body) {

    Push-Location $Path

    try { &$Body }
    finally { Pop-Location }

}

Usage of the function couldn’t be simpler and uses a C#-style scope syntax.

Use-Location "C:Temp" {

    mkdir textfiles
    dir *.txt | move textfiles

    mkdir images
    dir *.jpg,*.png | move images

}

Obviously you could just as well use Push-Location and Pop-Location in a try/catch yourself but why? This way enforces clean scoping and ensures you don’t forget the call to pop.

##############################################################################
#.SYNOPSIS
# Executes a ScriptBlock within the context of the specified working directory.
#
#.DESCRIPTION
# This function sets the current location to the specified Path and executes a
# ScriptBlock. All relative paths in the ScriptBlock will be based on the new
# current directory. When the ScriptBlock exits, the old current directory
# will be restored.
#
#.PARAMETER Path
# The working directory to use for the duration of the ScriptBlock.
#
#.PARAMETER ScriptBlock
# The code to execute within the context of the new current directory.
#
#.PARAMETER Create
# Creates the directory if it does not exist.
#
#.EXAMPLE
# Use-Location "C:Temp" {
#
#    mkdir textfiles
#    dir *.txt | move textfiles
#
#    mkdir images
#    dir *.jpg,*.png | move images
#
# }
#
#.LINK 
# Push-Location
# Pop-Location
##############################################################################
function Use-Location {

    [CmdletBinding()]
    param(
        
        [Alias('PSPath')]
        [Alias('LiteralPath')]
        [Parameter(Position=1, Mandatory=$true)]
        [String]$Path,
        
        [Parameter(Position=2, Mandatory=$true)]
        [ScriptBlock]$ScriptBlock,
        
        [Parameter()]
        [Switch]$Create
        
    )

    $ErrorActionPreference = 'Stop'

    # Create if necessary
    if ($Create) {
        $Exists = Test-Path -LiteralPath $Path -PathType Container
        if (-not $Exists) {
            New-Item $Path -ItemType Directory | Out-Null
        }
    }

    Push-Location $Path -StackName 'Use-Location'

    try { &$ScriptBlock }
    finally { Pop-Location -StackName 'Use-Location' }

}