PowerShell: Executar comando do diretório do script

144

Eu tenho um script do PowerShell que faz algumas coisas usando o diretório atual do script. Portanto, quando dentro desse diretório, a execução .\script.ps1funciona corretamente.

Agora, quero chamar esse script de um diretório diferente sem alterar o diretório de referência do script. Então, eu quero chamar ..\..\dir\script.ps1e ainda quero que esse script se comporte como foi chamado de dentro de seu diretório.

Como faço isso ou como modifico um script para que ele possa ser executado em qualquer diretório?

cutucar
fonte

Respostas:

200

Você quer dizer que deseja o próprio caminho do script para poder fazer referência a um arquivo próximo ao script? Tente o seguinte:

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

Você pode obter muitas informações em $ MyInvocation e suas propriedades.

Se você deseja fazer referência a um arquivo no diretório de trabalho atual, pode usar Resolve-Path ou Get-ChildItem:

$filepath = Resolve-Path "somefile.txt"

EDIT (com base no comentário do OP):

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

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

Provavelmente existem outras maneiras de obter algo semelhante usando o Invoke-Command também.

JohnL
fonte
1
Hmm, ok, talvez eu devesse ter sido um pouco mais claro sobre o meu roteiro. Na verdade, é um script que chama antcom alguns parâmetros. Então, eu tenho que ligar antdessa pasta para garantir que ele encontre o arquivo de configuração corretamente. Idealmente, estou procurando algo para alterar temporariamente o diretório de execução localmente dentro desse script.
cutucar
3
Ah, então nesse caso você vai querer Push-LocationePop-Location
johnl
5
cuidado com isso, $ MyInvocation é sensível ao contexto, eu costumo fazer $ ScriptPath = (Get-Variable MyInvocation -Scope Script) .Value.MyCommand.Path que funciona a partir de qualquer tipo de nidificação ou função
Ion Todirel
39

Se você estiver chamando aplicativos nativos, não se preocupe com [Environment]::CurrentDirectoryo $PWDdiretório atual do PowerShell . Por vários motivos, o PowerShell não define o diretório de trabalho atual do processo quando você define o local ou o local do envio, portanto, certifique-se de fazê-lo se estiver executando aplicativos (ou cmdlets) que esperam que seja definido.

Em um script, você pode fazer isso:

$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

Não há alternativa infalível para isso. Muitos de nós colocamos uma linha em nossa função de prompt para definir [Environment] :: CurrentDirectory ... mas isso não ajuda quando você está alterando o local em um script.

Duas notas sobre o motivo pelo qual isso não é definido automaticamente pelo PowerShell:

  1. O PowerShell pode ser multiencadeado. Você pode ter vários Runspaces (consulte RunspacePool e o módulo PSThreadJob) sendo executados simultaneamente em um único processo. Cada espaço de execução possui seu próprio $PWDdiretório de trabalho atual, mas há apenas um processo e apenas um Ambiente.
  2. Mesmo quando você é um thread único, $PWDnem sempre é um CurrentDirectory legal (você pode colocar um CD no provedor de registro, por exemplo).

Se você quiser colocá-lo em seu prompt (que seria executado apenas no espaço de execução principal, com um único encadeamento), será necessário usar:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
Jaykul
fonte
4
Isso não muda o diretório processo de trabalho por causa de provedores de caminho: você pode ser CD'ing no registro, um banco de dados SQL ou um IIS colmeia etc ...
piers7
1
Sim. Eu sei, esse foi o ponto dessa última "nota final". Eles poderiam ter (como eu faço na minha função de prompt) atualizado para o local atual do provedor do FileSystem, como qualquer outro shell do mundo.
Jaykul
2
Deuses sagrados dos scripts, estou tão decepcionado .\_/.- por isso matou metade do meu dia! Pessoas, sério? Sério? ..
ulidtko
2
Agora é praticamente desnecessário, pois as versões mais modernas do PowerShell definem o diretório de trabalho ao iniciar aplicativos binários.
21417 Jaykul
1
Este método falha ao restaurar o original [Environment]::CurrentDirectoryquando isso é diferente $PWD. O correto seria armazená-lo em uma variável $origEnvDir = [Environment]::CurrentDirectorye depois restaurá-lo [Environment]::CurrentDirectory = $origEnvDir.
Strom
37

Existem respostas com grande número de votos, mas quando li sua pergunta, pensei que você queria saber o diretório onde o script está, não aquele em que o script está sendo executado. Você pode obter as informações com as variáveis ​​automáticas do powershell

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

Por exemplo, eu tenho o script $ profile que localiza o arquivo de solução do visual studio e o inicia. Eu queria armazenar o caminho completo, assim que um arquivo de solução fosse iniciado. Mas eu queria salvar o arquivo onde o script original existe. Então eu usei $ PsScriptRoot.

Andy
fonte
12

Eu costumava usar o código a seguir para importar um módulo que fica no mesmo diretório do script em execução. Primeiro, ele obterá o diretório no qual o PowerShell está sendo executado

$ currentPath = Caminho-de-divisão ((Get-Variable MyInvocation -Scope 0) .Value) .MyCommand.Path

módulo de importação "$ currentPath \ sqlps.ps1"

Daniel Wu
fonte
pretende definir o -Scope para Script
Ion Todirel
9

Isso funcionaria bem.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir
ArunSK
fonte
Não se esqueça de ligar Pop-Locationno final para retornar o caminho ao seu estado original.
21818 Lam Le
2

Bem, eu estava procurando solução para isso por um tempo, sem nenhum script apenas da CLI. É assim que eu faço xD:

  • Navegue para a pasta na qual você deseja executar o script (o importante é que você tenha conclusões de tabulação)

    ..\..\dir

  • Agora coloque a localização entre aspas duplas e, dentro delas cd, adicione , para que possamos invocar outra instância do PowerShell.

    "cd ..\..\dir"

  • Adicione outro comando para executar o script separado por ;, com um separador de comandos no powershell

    "cd ..\..\dir\; script.ps1"

  • Finalmente, execute-o com outra instância do PowerShell

    start powershell "cd..\..\dir\; script.ps1"

Isso abrirá uma nova janela do PowerShell, vá para ..\..\dir, execute script.ps1e feche a janela.


Observe que ";" apenas separa os comandos, como você os digitou um por um, se primeiro falhar, o segundo será executado e o próximo e o próximo depois ... Se você quiser manter a nova janela do PowerShell aberta, adicione -noexit no comando passado. Observe que eu primeiro naveguei para a pasta desejada para poder usar as conclusões da guia (você não pode usar aspas duplas).

start powershell "-noexit cd..\..\dir\; script.ps1"

Use aspas duplas ""para poder passar diretórios com espaços nos nomes, por exemplo,

start powershell "-noexit cd '..\..\my dir'; script.ps1"

IGRACH
fonte
0

Criei uma solução única da solução @ JohnL:

$MyInvocation.MyCommand.Path | Split-Path | Push-Location
sashoalm
fonte