PowerShell: Run command from script's directory

I have a PowerShell script that does some stuff using the script’s current directory. So when inside that directory, running .\script.ps1 works correctly.

Now I want to call that script from a different directory without changing the referencing directory of the script. So I want to call ..\..\dir\script.ps1 and still want that script to behave as it was called from inside its directory.

How do I do that, or how do I modify a script so it can run from any directory?


Do you mean you want the script's own path so you can reference a file next to the script? Try this:

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"

You can get a lot of info from $MyInvocation and its properties.

If you want to reference a file in the current working directory, you can use Resolve-Path or Get-ChildItem:

$filepath = Resolve-Path "somefile.txt"

EDIT (based on comment from OP):

# temporarily change to the correct folder
Push-Location $dir

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

There's probably other ways of achieving something similar using Invoke-Command as well.


There are answers with big number of votes, but when I read your question, I thought you wanted to know the directory where the script is, not that where the script is running. You can get the information with powershell's auto variables

$PSScriptRoot     # the directory where the script exists, not the
                  # target directory the script is running in
$PSCommandPath    # the full path of the script

For example, I have a $profile script that finds a Visual Studio solution file and starts it. I wanted to store the full path, once a solution file is started. But I wanted to save the file where the original script exists. So I used $PsScriptRoot.


If you're calling native apps, you need to worry about [Environment]::CurrentDirectory not about PowerShell's $PWD current directory. For various reasons, PowerShell does not set the process' current working directory when you Set-Location or Push-Location, so you need to make sure you do so if you're running applications (or cmdlets) that expect it to be set.

In a script, you can do this:

$CWD = [Environment]::CurrentDirectory

Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
##  Your script code calling a native executable
Pop-Location

# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD

There's no foolproof alternative to this. Many of us put a line in our prompt function to set [Environment]::CurrentDirectory ... but that doesn't help you when you're changing the location within a script.

Two notes about the reason why this is not set by PowerShell automatically:

  1. PowerShell can be multi-threaded. You can have multiple Runspaces (see RunspacePool, and the PSThreadJob module) running simultaneously withinin a single process. Each runspace has it's own $PWD present working directory, but there's only one process, and only one Environment.
  2. Even when you're single-threaded, $PWD isn't always a legal CurrentDirectory (you might CD into the registry provider for instance).

If you want to put it into your prompt (which would only run in the main runspace, single-threaded), you need to use:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem

This would work fine.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir