Run PowerShell script from another script, passing string variables - powershell

I got two Powershell script.
The first, script1.ps1, got some Global string variable.
The second, script2.ps1, must do some operation with values of the string variables, then close without passing any data to the first.
Here pieces of code.
script1.ps1
#[ENG] Global $language contains the language name: EN-US for american english, EN-GB for english of Great Britain, for example.
$global:language = $culture.Name
#[ENG] Global $workPath variable contains the path of the folder with the original files.
$global:workPath = "D:\Documents\Downloads\Emule-Incoming\osis"
#[ENG] Global $scriptPath variable contains the path of the script(s) files.
$local:temp = Split-Path $PSCommandPath
$global:scriptPath = "$temp"
$temp = ""
##########
# mods.d #
##########
#[ENG] Global $modBip variable contains the path of destination of CONF files for BPBiblePortable.
$global:modBip = "D:\Documents\Downloads\Emule-Incoming\BPBiblePortable\App\BPBible\resources\mods.d\"
#[ENG] Global $modXip contains the path of destination of CONF files for xiphos.
$global:modXip = "C:\Users\Emanuele\AppData\Roaming\Sword\mods.d\"
#[ENG] Global $modGit variable contains the path of destination of CONF files in GitHub Desktop to upload and synchronize in GitHub.
$global:modGit = "D:\Documents\GitHub\EmanueleTinari\mods.d\"
$scriptPath = $scriptPath + "\" + 'cei1974.ps1 $language $workPath $scriptPath $modBiP $modXip $modGit'
Invoke-Expression & $scriptPath
script2.ps1
#[ENG] Retrieve Global variable's values.
Param ([string]$language, [string]$workPath, [string]$scriptPath, [string]$modBiP, [string]$modXip, [string]$modGit)
Write-Host $language
Write-Host $workPath
Write-Host $scriptPath
Write-Host $modBiP
Write-Host $modXip
Write-Host $modGit
What I try:
$scriptPath = $scriptPath + "\" + 'cei1974.ps1 -$language $language -$workPath $workPath -$scriptPath $scriptPath -$modBiP $modBiP -$modXip $modXip -$modGit $modGit'
Invoke-Expression & $scriptPath
I add -$[string name] : nothing to do.
$scriptPath = $scriptPath + "\" + 'cei1974.ps1 -$language $language -$workPath $workPath -$scriptPath $scriptPath -$modBiP $modBiP -$modXip $modXip -$modGit $modGit'
Invoke-Expression $scriptPath
Without & near $scriptPath : nothing to do.
I, first write this question, examined and tryed answers in this posts:
Run a PowerShell script from another one
PowerShell Script call out from another PowerShell Script
Invoke powershell script from another
Passing varibale into powershell script that is being executed from another script
How can I achieve to pass strings between this two script? Tnx in advance.

Swap-out the last 2 lines in your script1.ps1 script with this:
. $scriptPath\script2.ps1 -language $language -workPath $workPath -scriptPath $scriptPath -modBiP $modBiP -modXip $modXip -modGit $modGit
Some notes:
Do not use Invoke-Expression followed by the ampersand (&) call operator, as that is unnecessary.
You have all the information necessary to call script2.ps1 directly, rather than build-up a string and rely on expression evaluation.
When specifying script command-line parameters by name, simply use a hyphen (-) followed by the parameter name. For example, -language $language.
I believe you want to use dot-sourcing (.) to call your script2.ps1. You could also defer to using the ampersand (&) call operator. Invoke-Command and Invoke-Expression could be used, but can also be exploited if not handled correctly.
For more information, see Get-Help about_Operators and Get-Help about_Scripts and Get-Help about_Parameters

Related

Problem Executing NirSoft SearchMyFiles.exe from Powershell

I know this is a problem in how I'm passing the arguments but I can't figure it out as it looks like I've successfully escaped the characters that might cause a problem.
PS> $ExecutionPath = "G:\BEKDocs\NonInstPrograms\NirSoftx64"
$PgmName = "Searchmyfiles.exe"
$RunCmd = Join-Path -Path "$ExecutionPath" -ChildPath "$PgmName"
$MyArgs = " `/config `"G:\BEKDocs\TestSMF.cfg`" `/StartSearch `/ExplorerCopy `/stext `"G:\BEKDocs\TestSMF.txt`""
$runcmd += $MyArgs
& $Runcmd
---Results: No file Created no Error messages displayed---
--- Show the Created Command ---
PS> $RunCmd
G:\BEKDocs\NonInstPrograms\NirSoftx64\Searchmyfiles.exe /config "G:\BEKDocs\TestSMF.cfg" /StartSearch /ExplorerCopy /stex
t "G:\BEKDocs\TestSMF.txt"
--- Try to Execute the command from History ---
PS> G:\BEKDocs\NonInstPrograms\NirSoftx64\Searchmyfiles.exe /config "G:\BEKDocs\TestSMF.cfg" /StartSearch /ExplorerCopy /stex
t "G:\BEKDocs\TestSMF.txt"
--- Result: No file created no Error messages displayed. ---
--- Type the command by hand ---
PS> G:\BEKDocs\NonInstPrograms\NirSoftx64\searchmyfiles.exe /config "G:\BEKDocs\TestSMF.cfg" /StartSearch /ExplorerCopy /stext "G:\BEKDocs\TestSMF.txt"
--- Result: File CREATED as expected ---
PS>
I'm at a loss!
In testing it appears that it is treating $Runcmd — both executable path and parameters — as one complete executable path to execute. I believe this is explained by the following section of about_Operators...
The call operator does not parse strings. This means that you cannot use command parameters within a string when you use the call operator.
PS> $c = "Get-Service -Name Spooler"
PS> $c
Get-Service -Name Spooler
PS> & $c
& : The term 'Get-Service -Name Spooler' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Instead, pass the executable path and parameters to the call operator separately...
$ExecutionPath = "G:\BEKDocs\NonInstPrograms\NirSoftx64"
$PgmName = "Searchmyfiles.exe"
$RunPath = Join-Path -Path "$ExecutionPath" -ChildPath "$PgmName"
$MyArgs = #(
'/config', '"G:\BEKDocs\TestSMF.cfg"',
'/StartSearch',
'/ExplorerCopy',
'/stext', '"G:\BEKDocs\TestSMF.txt"'
)
& $RunPath $MyArgs
You'll notice that $MyArgs is now an array and not a [String]. It seems that if $MyArgs is a [String] or a single-element array it gets passed to the executable as one parameter surrounded by double quotes. Stored as above each array element gets passed as a parameter with no additional quoting. If you still want to define $MyArgs using one line of text you could do so like this...
$MyArgsText = '/config "G:\BEKDocs\TestSMF.cfg" /StartSearch /ExplorerCopy /stext "G:\BEKDocs\TestSMF.txt"'
# NOTE: This only works because the path parameters contain no spaces
$MyArgs = $MyArgsText -split ' '
All of the above is why, for anything but ad hoc commands, I would prefer the self-documenting, obvious-as-to-which-string-is-treated-as-which nature of a Start-Process call with explicitly-named parameters over the call operator. Given...
$ExecutionPath = "G:\BEKDocs\NonInstPrograms\NirSoftx64"
$PgmName = "Searchmyfiles.exe"
$RunPath = Join-Path -Path "$ExecutionPath" -ChildPath "$PgmName"
$MyArgsText = '/config "G:\BEKDocs\TestSMF.cfg" /StartSearch /ExplorerCopy /stext "G:\BEKDocs\TestSMF.txt"'
...then both this...
Start-Process -FilePath $RunPath -ArgumentList $MyArgsText
...and this...
# NOTE: This only works because the path parameters contain no spaces
$MyArgs = $MyArgsText -split ' '
Start-Process -FilePath $RunPath -ArgumentList $MyArgs
...execute $RunPath with the same parameters.
I think every time I tried to include both the EXE name and the parameters in the same string, The call operator (&) fails. With that in mind, try something where $Runcmd is pointing only to the EXE and nothing else. This also makes testing easy by temporarily placing the path to EchoArgs in $Runcmd to view the actual parameters the EXE will be receiving.
This code example uses the Stop-parsing token (--%) and environmental variables to build the parameters passed to the EXE in $Runcmd.
$ExecutionPath = "G:\BEKDocs\NonInstPrograms\NirSoftx64"
$PgmName = "Searchmyfiles.exe"
$RunCmd = Join-Path -Path "$ExecutionPath" -ChildPath "$PgmName"
$Env:Config = '"G:\BEKDocs\TestSMF.cfg"'
$Env:SText = '"G:\BEKDocs\TestSMF.txt"'
& $Runcmd --% /config %Config% /StartSearch /ExplorerCopy /stext %SText%

Getting the first argument passed to the cli

Trying just to write a simple script that would return the SHA256 signature of a file using the file name passed to my ps1 script :
The scriptname is sha256sum.ps1.
The first argument will be any file, example :
sha256sum.ps1 dummy.exe
I tried these inside sha256sum.ps1 :
Get-FileHash -algo SHA256 %1
Get-FileHash -algo SHA256 $1
Get-FileHash -algo SHA256 $args[1]
but none of them worked.
Is there a simple way to do that ?
EDIT : Here is the final version of my script thanks to your help, guys :)
#!/usr/bin/env pwsh
param( $firstArg )
function calcSignature( $filename ) {
$scriptName = Split-Path -Leaf $PSCommandPath
switch( $scriptName ) {
"md5sum.ps1" { $algo = "MD5"; Break }
"sha1sum.ps1" { $algo = "SHA1"; Break }
"sha256sum.ps1" { $algo = "SHA256"; Break }
"sha384sum.ps1" { $algo = "SHA384"; Break }
"sha512sum.ps1" { $algo = "SHA512"; Break }
}
(Get-FileHash -algo $algo $filename).Hash + " " + $filename
}
calcSignature( $firstArg )
Now I only have one script and the others are links pointing to sha256sum.ps1.
I'm guessing you're looking for "How to pass an argument to your .ps1 script".
This is an example of how the script sha256sum.ps1 would look:
param(
[parameter(mandatory)]
[validatescript({
Test-Path $_ -PathType Leaf
})]
[system.io.fileinfo]$File
)
(Get-FileHash $File -Algorithm SHA256).Hash
Now, if we were to call this script, as an example:
PS \> .\sha256sum.ps1 .\test.html
1B24ED8C7929739D296DE3C5D6695CA40D8324FBF2F0E981CF03A8A6ED778C9C
Note: the current directory is where the script and the html file are located, if that was not the case, you should use the absolute path.
I would recommend you to the official docs to get a concept on functions and the param(...) block.
Santiago's helpful answer shows how you to properly declare parameters for your script, which is generally preferable.
As for what you tried:
The automatic $args variable contains arguments not bound to any declared parameters. In other words: if your script doesn't declare any parameters, $args is the only way to access any arguments that were passed.
The first argument is at index 0, not 1.
Note:
This differs from other shells / programming language where the element at index 0 reflects the script / program being called.
To get the full path of the enclosing script in PowerShell, use the automatic $PSCommandPath variable.
Thus, for instance, %1 in a batch file and $1 in a bash script - both of which contain the first argument - correspond to $args[0] in PowerShell.
Therefore, Get-FileHash -algo SHA256 $args[0] should have worked.

remote Multiple invocations using Powershell

I appreciate you taking the time to read this.
My issue is as follows: I'm trying to create a program that uses powershell to do the following:
Take a table generated outside of powershell
Loop calls to a powershell script with the parameters from the table
The powershell script calls a special type of .cmd file and then runs commands on it that are located in a different shared location.
Now my problem is with the 3rd point.
I'm currently using the following to call my script (and the arguements are just hard coded to get it working, they'll be generated by the calls from step 2 later on):
powershell.exe -ExecutionPolicy Bypass -Command {invoke-command -file \\sharedlocation\test5.ps1 -computername server1121 -argumentlist 7058,Jason}
The inside of test5.ps1 is currently:
param(
[Parameter(Mandatory=$true)]
[string] $Var1,
[Parameter(Mandatory=$true)]
[string] $Var2
)
$CommandsPath = "\\sharedlocation\testcommands.cmd"
$path = "C:\"+$Var1+"\TOOLS\"+$Var2+"launchtool.cmd"
$scriptPath = [scriptblock]::Create($path)
$out | invoke-command {PARAM($MyArg) $scriptPath } -ArgumentList $CommandsPath
I've also tried using
$CommandsPath = "\\sharedlocation\testcommands.cmd"
$path = "C:\"+$Var1+"\TOOLS\"+$Var2+"\launchtool.cmd & " + $CommandsPath
$scriptPath = [scriptblock]::Create($path)
$out | invoke-command {$scriptPath }
I've also tried to call with hardcoded testcommands instead of them being in a file.
Now my problem is in both cases, it DOES run launchtool.cmd, but it doesn't pass the testcommands.cmd file.
However when on the machine i run
C:\7058\TOOLS\Jason\launchtool.cmd & \\sharedlocation\testcommands.cmd
It works fine.
Any ideas what I'm doing wrong?
Try, invoke-expression "cmd.exe /c C:\7058\TOOLS\Jason\launchtool.cmd & \sharedlocation\testcommands.cmd"
cmd.exe /c is my best way to ensure consistency between cmd and powershell
Is the UNC Path accessible from powershell? Copy the testcommands.cmd to a local path and try if it works!
$CommandsPath = "\\sharedlocation\testcommands.cmd"
if(Test-Path $CommandsPath)
{
$path = "C:\"+$Var1+"\TOOLS\"+$Var2+"\launchtool.cmd & " + $CommandsPath
$scriptPath = [scriptblock]::Create($path)
$out | invoke-command {$scriptPath }
}

Executing Powershell script from command line with quoted parameters

I am automating the build of a legacy MS Access application, and in one of the steps, I am trying to make an Access executable (.ADE). I have come up with the following code, which is stored in a file (PSLibrary.ps1):
Add-Type -AssemblyName Microsoft.Office.Interop.Access
function Access-Compile {
param (
[Parameter(Mandatory=$TRUE,Position=1)][string]$source,
[Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
Write-Output "Starting MS Access"
$access = New-Object -ComObject Access.Application
$access.Visible = $FALSE
$access.AutomationSecurity = 1
if (!(Test-Path $source)) { Throw "Source '$source' not found" }
if ((Test-Path $destination)) {
Write-Output "File '$destination' already exists - deleting..."
Remove-Item $destination
}
Write-Output "Compiling '$source' to '$destination'"
$result = $access.SysCmd(603, $source, $destination)
$result
Write-Output "Exiting MS Access"
$access.quit()
}
If I go into the PowerShell ISE and run the command below, then everything works fine, and the expected output is created:
PS C:>& "C:\Temp\PSLibrary.ps1"
PS C:>Access-Compile "C:\Working\Project.adp" "C:\Working\Project.ade"
However, I can't seem to generate the right hocus-pocus to get this running from the command line, as I would in an automated build. For instance,
powershell.exe -command "& \"C:\\Temp\\PSLibrary.ps1\" Access-Compile \"C:\\Temp\\Project.adp\" \"C:\\Temp\\Project.ade\""
What am I doing wrong?
For complex parameters, you can use Powershell's -EncodedCommand parameter. It will accept a Base64 encoded string. No escaping is needed for quotes, slashes and such.
Consider a test function that will print its parameters. Like so,
function Test-Function {
param (
[Parameter(Mandatory=$TRUE,Position=1)][string]$source,
[Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
write-host "src: $source"
write-host "dst: $destination"
}
Create command to load the script and some parameters. Like so,
# Load the script and call function with some parameters
. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
After the command syntax is OK, encode it into Base64 form. Like so,
[System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes('. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""'))
You'll get a Base64 string. Like so,
LgAgAEMAOgBcAFQAZQBtAHAAXABDAGEAbABsAGkAbgBnAC0AVABlAHMAdAAuAHAAcwAxADsAIAAgAFQAZQBzAHQALQBGAHUAbgBjAHQAaQBvAG4AIAAiAHMAbwBtAGUAXABzAHAAZQBjAGkAYQBsADoAYwBoAGEAcgBhAGMAdABlAHIAcwA/ACIAIAAiAGAAIgBjADoAXABtAHkAIABwAGEAdABoAFwAdwBpAHQAaABcAHMAcABhAGMAZQBzACAAdwBpAHQAaABpAG4ALgBlAHgAdABgACIAIgA=
Finally, start Powershell and pass the encoded string as a parameter. Like so,
# The parameter string here is abreviated for readability purposes.
# Don't do this in production
C:\>powershell -encodedcommand LgAgA...
Output
src: some\special:characters?
dst: "c:\my path\with\spaces within.ext"
Should you later want to reverse the Base64 encoding, pass it into decoding method. Like so,
$str = " LgAgA..."
[Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($str))
# Output
. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
PowerShell like Bash can take single or double quotes
PS C:\Users\Steven> echo "hello"
hello
PS C:\Users\Steven> echo 'hello'
hello
this can alleviate some of the headache, also I think you can use the literal backslashes without escaping.
To run PowerShell, choose
Start Menu Programs Accessories
Windows Powershell Windows Powershell

How can I get the current PowerShell executing file?

Note: PowerShell 1.0
I'd like to get the current executing PowerShell file name. That is, if I start my session like this:
powershell.exe .\myfile.ps1
I'd like to get the string ".\myfile.ps1" (or something like that). EDIT: "myfile.ps1" is preferable.
Any ideas?
I've tried to summarize the various answers here, updated for PowerShell 5:
If you're only using PowerShell 3 or higher, use $PSCommandPath
If want compatibility with older versions, insert the shim:
if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath }
This adds $PSCommandPath if it doesn't already exist.
The shim code can be executed anywhere (top-level or inside a function), though $PSCommandPath variable is subject to normal scoping rules (eg, if you put the shim in a function, the variable is scoped to that function only).
Details
There's 4 different methods used in various answers, so I wrote this script to demonstrate each (plus $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: $(PSCommandPath)"
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 ""
Output:
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
Notes:
Executed from C:\, but actual script is C:\Test\test.ps1.
No method tells you the passed invocation path (.\Test\test.ps1)
$PSCommandPath is the only reliable way, but was introduced in PowerShell 3
For versions prior to 3, no single method works both inside and outside of a function
While the current Answer is right in most cases, there are certain situations that it will not give you the correct answer. If you use inside your script functions then:
$MyInvocation.MyCommand.Name
Returns the name of the function instead name of the name of the script.
function test {
$MyInvocation.MyCommand.Name
}
Will give you "test" no matter how your script is named.
The right command for getting the script name is always
$MyInvocation.ScriptName
this returns the full path of the script you are executing. If you need just the script filename than this code should help you:
split-path $MyInvocation.PSCommandPath -Leaf
If you only want the filename (not the full path) use this:
$ScriptName = $MyInvocation.MyCommand.Name
Try the following
$path = $MyInvocation.MyCommand.Definition
This may not give you the actual path typed in but it will give you a valid path to the file.
beware:
Unlike the $PSScriptRoot and $PSCommandPath automatic variables, the
PSScriptRoot and PSCommandPath properties of the $MyInvocation automatic
variable contain information about the invoker or calling script, not the
current script.
e.g.
PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ...
=!C:\Users\S_ms\OneDrive\Documents\DPM.ps1
...where DPM.ps1 contains
Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath)
If you are looking for the current directory in which the script is being executed, you can try this one:
$fullPathIncFileName = $MyInvocation.MyCommand.Definition
$currentScriptName = $MyInvocation.MyCommand.Name
$currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "")
Write-Host $currentExecutingPath
As noted in previous responses, using "$MyInvocation" is subject to scoping issues and doesn't necessarily provide consistent data (return value vs. direct access value). I've found that the "cleanest" (most consistent) method for getting script info like script path, name, parms, command line, etc. regardless of scope (in main or subsequent/nested function calls) is to use "Get-Variable" on "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
So, you can get the same info as $PSCommandPath, but a whole lot more in the deal. Not sure, but it looks like "Get-Variable" was not available until PS3 so not a lot of help for really old (not updated) systems.
There are also some interesting aspects when using "-Scope" as you can backtrack to get the names, etc. of the calling function(s). 0=current, 1=parent, etc.
Hope this is somewhat helpful.
Ref, https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable
I would argue that there is a better method, by setting the scope of the variable $MyInvocation.MyCommand.Path:
ex> $script:MyInvocation.MyCommand.Name
This method works in all circumstances of invocation:
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
OUTPUT:
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
Notice how the above accepted answer does NOT return a value when called from Main. Also, note that the above accepted answer returns the full path when the question requested the script name only. The scoped variable works in all places.
Also, if you did want the full path, then you would just call:
$script:MyInvocation.MyCommand.Path
A short demonstration of #gregmac's (excellent and detailed) answer, which essentially recommends $PSCommandPath as the only reliable command to return the currently running script where Powershell 3.0 and above is used.
Here I show returning either the full path or just the file name.
Test.ps1:
'Direct:'
$PSCommandPath # Full Path
Split-Path -Path $PSCommandPath -Leaf # File Name only
function main () {
''
'Within a function:'
$PSCommandPath
Split-Path -Path $PSCommandPath -Leaf
}
main
Output:
PS> .\Test.ps1
Direct:
C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1
Test.ps1
Within a function:
C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1
Test.ps1
Did some testing with the following script, on both PS 2 and PS 4 and had the same result. I hope this helps people.
$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
Results -
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
This can works on most powershell versions:
(& { $MyInvocation.ScriptName; })
This can work for Scheduled Job
Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command