Pergunta

Eu quero ser capaz de dizer o caminho que o meu script execução foi executado a partir.
Isso muitas vezes não vai ser de US $ pwd.

Eu preciso chamar outros scripts que estão em uma estrutura de pastas em relação ao meu script e enquanto eu poderia codificar os caminhos, que é tanto mau gosto e um pouco de dor no pescoço ao tentar promover a partir de "dev" para " teste" para "produção".

Foi útil?

Solução

O script onipresente Postado Originalmente por Jeffrey Snover da equipe PowerShell (dada em de Skyler resposta ) e as variações postados por Keith Cedirc e EBGreen, todos sofrem de uma séria desvantagem! - se os relatórios de código que você espera depende de onde você chamá-lo

Meu código abaixo ultrapassa este problema simplesmente fazendo referência roteiro escopo em vez de pai escopo:

function Get-ScriptDirectory
{
    Split-Path $script:MyInvocation.MyCommand.Path
}

Para ilustrar o problema, eu criei um veículo de teste que evalutes a expressão alvo de quatro maneiras diferentes. (Os termos entre parênteses são as chaves para a tabela de resultados seguinte.)

  1. código embutido [linha]
  2. função inline, função ou seja, no programa principal [função inline]
  3. função
  4. Dot-sourced, ou seja, a mesma função mudou-se para um arquivo .ps1 separado [fonte dot]
  5. função do módulo, isto é, a mesma função transferida para um ficheiro separado .psm1 [módulo]

As duas últimas colunas mostram o resultado do uso escopo do script (ou seja, $ script :) ou com escopo pai (com -scope 1). Um resultado de meios "roteiro" que a invocação relatados corretamente a localização do script. "Módulo" significa resultado da invocação relatou a localização do módulo que contém a função, em vez do script que chamou a função; isso indica uma desvantagem de ambas as funções que você não pode colocar a função em um módulo.

Definindo a questão módulo de lado a observação notável da mesa é que usando a abordagem de escopo pai falhar na maioria das vezes (na verdade, duas vezes mais que ele consegue).

tabela de combinações de entrada

Finalmente, aqui é o veículo de teste:

function DoubleNested()
{
    "=== DOUBLE NESTED ==="
    NestCall
}

function NestCall()
{
    "=== NESTED ==="
    "top level:"
    Split-Path $script:MyInvocation.MyCommand.Path
    #$foo = (Get-Variable MyInvocation -Scope 1).Value
    #Split-Path $foo.MyCommand.Path
    "immediate func call"
    Get-ScriptDirectory1
    "dot-source call"
    Get-ScriptDirectory2
    "module call"
    Get-ScriptDirectory3
}

function Get-ScriptDirectory1
{
    Split-Path $script:MyInvocation.MyCommand.Path
    # $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    # Split-Path $Invocation.MyCommand.Path
}

. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force

"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path

"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3

NestCall
DoubleNested

Conteúdo do ScriptDirFinder.ps1:

function Get-ScriptDirectory2
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

Conteúdo do ScriptDirFinder.psm1:

function Get-ScriptDirectory3
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

Eu não estou familiarizado com o que foi introduzido em PowerShell 2, mas poderia muito bem ser que escopo do script não existia no PowerShell 1, no momento Jeffrey Snover publicou seu exemplo.

Eu fiquei surpreso quando, embora eu achei o seu exemplo de código proliferaram por toda parte na web, ele falhou imediatamente quando eu tentei! Mas isso foi porque eu usei-o de forma diferente do que o exemplo de Snover (I chamado não no script do topo, mas a partir de dentro de outra função (meu "nested duas vezes" exemplo).)

2011/09/12 Atualização

Você pode ler sobre isso com outras dicas e truques sobre módulos em meu artigo recém-publicado sobre Simple-Talk.com: Outras Down the Rabbit Hole:. PowerShell Módulos e Encapsulation

Outras dicas

Você marcado sua pergunta para PowerShell versão 1.0, no entanto, se você tem acesso ao PowerShell versão 3.0 você sabe tem $PSCommandPathand$PSScriptRootwhich faz começar o caminho do script um pouco mais fácil. Consulte a "outro script CARACTERÍSTICAS", nesta página para mais informações.

Estamos usando código como este na maioria dos nossos roteiros para vários anos sem problemas:

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1

Eu corri para o mesmo problema recentemente. O seguinte artigo me ajudou a resolver o problema: http: // blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

Se você não está interessado em saber como ele funciona, aqui está todo o código que você precisa pelo artigo:

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

E então você começa o caminho, basta fazer:

$path = Get-ScriptDirectory

Eu acho que você pode encontrar o caminho do script em execução usando

$MyInvocation.MyCommand.Path

Espero que ajude!

Cédric

Este é um daqueles esquisitices (a minha mente pelo menos) em PS. Tenho certeza de que há uma boa razão para isso, mas ainda parece estranho para mim. Assim:

Se você estiver em um script, mas não em uma função, em seguida $ myInvocation.InvocationName lhe dará o caminho completo, incluindo o nome do script. Se você estiver em um script e dentro de uma função, em seguida $ myInvocation.ScriptName vai dar-lhe a mesma coisa.

Obrigado msorens! Isso realmente me ajudou com o meu módulo personalizado. No caso de alguém está interessado em fazer a sua própria, é aqui como meu está estruturado.

MyModule (folder)
 - MyModule.psd1 (help New-ModuleManifest)
 - MyScriptFile.ps1 (ps1 files are easy to test)

Você, então, referência MyScriptFile.ps1 em MyModule.psd1. Referenciando o .ps1 na matriz NestedModules colocará as funções no estado da sessão módulo em vez do estado da sessão global. ( Como escrever um módulo Manifest )

NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')

Conteúdo de MyScriptFile.ps1

function Get-ScriptDirectory {
    Split-Path $script:MyInvocation.MyCommand.Path
}

try {
    Export-ModuleMember -Function "*-*"
}
catch{}

As peles try / catch o erro do Export-ModuleMember ao executar MyScriptFile.ps1

Copie o MyModule para um dos caminhos encontrados aqui $ env: PSModulePath

PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top