Como posso obter o arquivo em execução do PowerShell atual?

92

Observação: PowerShell 1.0
, gostaria de obter o nome do arquivo PowerShell em execução no momento. Ou seja, se eu começar minha sessão assim:

powershell.exe .\myfile.ps1

Eu gostaria de obter a string ". \ Myfile.ps1" (ou algo parecido). EDIT : "myfile.ps1" é preferível.
Alguma ideia?

Ron Klein
fonte
Obrigado, as respostas atuais são quase as mesmas, mas eu preciso apenas do nome do arquivo (e não do caminho completo), então a resposta aceita é de @Keith. 1 para ambas as respostas, no entanto. Agora eu sei sobre $ MyInvocation :-)
Ron Klein
Que tal obter o script pai de um script incluído?
Florin Sabau

Respostas:

66

Tentei resumir as várias respostas aqui, atualizadas para PowerShell 5:

  • Se você estiver usando apenas PowerShell 3 ou superior, use $PSCommandPath

  • Se quiser compatibilidade com versões mais antigas, insira o calço:

    if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath; }

    Isso adiciona $PSCommandPathse ainda não existir.

    O código do shim pode ser executado em qualquer lugar (nível superior ou dentro de uma função), embora a $PSCommandPathvariável esteja sujeita às regras normais de escopo (por exemplo, se você colocar o shim em uma função, a variável terá o escopo apenas dessa função).

Detalhes

Existem 4 métodos diferentes usados ​​em várias respostas, então escrevi este script para demonstrar cada um (mais $PSCommandPath):

function PSCommandPath() { return $PSCommandPath; }
function ScriptName() { return $MyInvocation.ScriptName; }
function MyCommandName() { return $MyInvocation.MyCommand.Name; }
function MyCommandDefinition() {
    # Begin of MyCommandDefinition()
    # Note: ouput of this script shows the contents of this function, not the execution result
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()
}
function MyInvocationPSCommandPath() { return $MyInvocation.PSCommandPath; }

Write-Host "";
Write-Host "PSVersion: $($PSVersionTable.PSVersion)";
Write-Host "";
Write-Host "`$PSCommandPath:";
Write-Host " *   Direct: $PSCommandPath";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.ScriptName:";
Write-Host " *   Direct: $($MyInvocation.ScriptName)";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Name:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Name)";
Write-Host " * Function: $(MyCommandName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Definition:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Definition)";
Write-Host " * Function: $(MyCommandDefinition)";
Write-Host "";
Write-Host "`$MyInvocation.PSCommandPath:";
Write-Host " *   Direct: $($MyInvocation.PSCommandPath)";
Write-Host " * Function: $(MyInvocationPSCommandPath)";
Write-Host "";

Resultado:

PS C:\> .\Test\test.ps1

PSVersion: 5.1.19035.1

$PSCommandPath:
 *   Direct: C:\Test\test.ps1
 * Function: C:\Test\test.ps1

$MyInvocation.ScriptName:
 *   Direct:
 * Function: C:\Test\test.ps1

$MyInvocation.MyCommand.Name:
 *   Direct: test.ps1
 * Function: MyCommandName

$MyInvocation.MyCommand.Definition:
 *   Direct: C:\Test\test.ps1
 * Function:
    # Begin of MyCommandDefinition()
    # Note this is the contents of the MyCommandDefinition() function, not the execution results
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()


$MyInvocation.PSCommandPath:
 *   Direct:
 * Function: C:\Test\test.ps1

Notas:

  • Executado de C:\, mas o script real é C:\Test\test.ps1.
  • Nenhum método informa o caminho de invocação passado ( .\Test\test.ps1)
  • $PSCommandPath é a única maneira confiável, mas foi introduzida no PowerShell 3
  • Para versões anteriores a 3, nenhum método funciona dentro e fora de uma função
Gregmac
fonte
7
Para quem está lendo hoje (2017), eles devem estar lendo ESTE post como a resposta correta! +1
Collin Chaffin
2
@CollinChaffin: concordou e agora (2017) o menos compatível atualmente é o Windows 7, então não há razão para não usar $PSCommandPathse o legado (WindowsXP) não for necessário.
tukan
O primeiro exemplo de código é falho, pois contém duas definições da mesma função ( function PSCommandPath) e uma referência à função errada ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)";- ou estou ignorando algo óbvio?
Mike L'Angelo
@ MikeL'Angelo Você está certo! Passou despercebido por 3 anos. Corrigido, obrigado. O resultado e a conclusão são os mesmos.
Gregmac de
81

Embora a Resposta atual esteja certa na maioria dos casos, há certas situações em que ela não fornecerá a resposta correta. Se você usar dentro de suas funções de script:

$MyInvocation.MyCommand.Name 

Retorna o nome da função em vez do nome do nome do script.

function test {
    $MyInvocation.MyCommand.Name
}

Fornecerá um " teste " independentemente do nome do seu script. O comando certo para obter o nome do script é sempre

$MyInvocation.ScriptName

isso retorna o caminho completo do script que você está executando. Se você precisa apenas do nome do arquivo do script, este código deve ajudá-lo:

split-path $MyInvocation.PSCommandPath -Leaf
Lukas Kucera
fonte
6
Observe que, no nível superior, Scriptname é indefinido com posh v4. Eu gosto de usar no nível superior, $ MyInvocation.MyCommand.Definition para o caminho completo ou nome de acordo com as outras respostas.
AnneTheAgile de
30
$MyInvocation.ScriptNameretorna uma string vazia para mim, PS v3.0.
JohnC de
4
@JohnC $MyInvocation.ScriptNamesó funciona dentro de uma função. Veja minha resposta abaixo .
Gregmac
72

Se você deseja apenas o nome do arquivo (não o caminho completo), use este:

$ScriptName = $MyInvocation.MyCommand.Name
Keith Hill
fonte
32

Tente o seguinte

$path =  $MyInvocation.MyCommand.Definition 

Isso pode não fornecer o caminho real digitado, mas fornecerá um caminho válido para o arquivo.

JaredPar
fonte
1
@Hamish, a pergunta diz especificamente se invocada a partir de um arquivo.
JaredPar
Para sua informação: Isso fornece o caminho completo e o nome do arquivo (Powershell 2.0)
Ralph Willgoss
Eu estava procurando exatamente este comando. Obrigado, JaredPar! :)
sqlfool
Usar Split-Path para obter o diretório? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse
7

Se você está procurando o diretório atual no qual o script está sendo executado, você pode tentar este:

$fullPathIncFileName = $MyInvocation.MyCommand.Definition
$currentScriptName = $MyInvocation.MyCommand.Name
$currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "")

Write-Host $currentExecutingPath
Ryk
fonte
1
Isso não funcionaria corretamente C:\ilike.ps123\ke.ps1, não é?
fridojet
@fridojet - Não tenho certeza, não perto de um terminal PS para testá-lo. Por que você não tenta e vê?
Ryk
Não, só uma pergunta retórica ;-) - Seria lógico porque o Replace()método substitui todas as ocorrências da agulha (não apenas a última ocorrência) e eu também testei. No entanto, é uma boa ideia fazer algo como a subtração de cordas.
fridojet
... E sobre String.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName))? - Está funcionando corretamente: "Ich bin Hamster".TrimEnd("ster")retorna Ich bin Hame "Ich bin Hamsterchen".TrimEnd("ster")retorna Ich bin Hamsterchen(em vez de Ich bin Hamchen) - Tudo bem!
fridojet
$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
YP
7

cuidado: Ao contrário das variáveis ​​automáticas $PSScriptRoote $PSCommandPath, as propriedades PSScriptRoote PSCommandPathda $MyInvocationvariável automática contêm informações sobre o invocador ou o script de chamada, não o script atual.

por exemplo

PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ...
=!C:\Users\S_ms\OneDrive\Documents\DPM.ps1

... onde DPM.ps1contém

Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath)
MWR
fonte
4

Eu diria que existe um método melhor, definindo o escopo da variável $ MyInvocation.MyCommand.Path:

ex> $ script : MyInvocation.MyCommand.Name

Este método funciona em todas as circunstâncias de invocação:

EX: Somescript.ps1

function printme () {
    "In function:"
    ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
    ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
    ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
}
"Main:"
( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
" "
printme
exit

RESULTADO:

PS> powershell C:\temp\test.ps1
Main:
MyInvocation.ScriptName:
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: test.ps1

In function:
MyInvocation.ScriptName: C:\temp\test.ps1
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: printme

Observe como a resposta aceita acima NÃO retorna um valor quando chamada de Main. Além disso, observe que a resposta aceita acima retorna o caminho completo quando a pergunta solicitou apenas o nome do script. A variável com escopo funciona em todos os lugares.

Além disso, se você quiser o caminho completo, basta chamar:

$script:MyInvocation.MyCommand.Path
Daddio
fonte
3

Conforme observado nas respostas anteriores, o uso de "$ MyInvocation" está sujeito a problemas de escopo e não necessariamente fornece dados consistentes (valor de retorno vs. valor de acesso direto). Descobri que o método "mais limpo" (mais consistente) para obter informações de script, como caminho de script, nome, parâmetros, linha de comando, etc., independentemente do escopo (em chamadas de função principal ou subsequentes / aninhadas) é usar "Get- Variável "em" MyInvocation "...

# Get the MyInvocation variable at script level
# Can be done anywhere within a script
$ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value

# Get the full path to the script
$ScriptPath = $ScriptInvocation.MyCommand.Path

# Get the directory of the script
$ScriptDirectory = Split-Path $ScriptPath

# Get the script name
# Yes, could get via Split-Path, but this is "simpler" since this is the default return value
$ScriptName = $ScriptInvocation.MyCommand.Name

# Get the invocation path (relative to $PWD)
# @GregMac, this addresses your second point
$InvocationPath = ScriptInvocation.InvocationName

Portanto, você pode obter as mesmas informações de $ PSCommandPath, mas muito mais no negócio. Não tenho certeza, mas parece que "Get-Variable" não estava disponível até o PS3, então não é uma grande ajuda para sistemas realmente antigos (não atualizados).

Existem também alguns aspectos interessantes ao usar "-Scope", pois você pode retroceder para obter os nomes, etc. da (s) função (ões) de chamada. 0 = atual, 1 = pai, etc.

Espero que isso seja de alguma forma útil.

Ref, https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable

AntGut
fonte
1

Fiz alguns testes com o seguinte script, tanto no PS 2 quanto no PS 4 e obteve o mesmo resultado. Espero que isso ajude as pessoas.

$PSVersionTable.PSVersion
function PSscript {
  $PSscript = Get-Item $MyInvocation.ScriptName
  Return $PSscript
}
""
$PSscript = PSscript
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

""
$PSscript = Get-Item $MyInvocation.InvocationName
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

Resultados -

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1      

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts
Mark Crashley
fonte
1

Isso pode funcionar na maioria das versões do PowerShell:

(& { $MyInvocation.ScriptName; })

Isso pode funcionar para trabalho agendado

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
improvável
fonte