Powershell equivalent of python's if __name__ == '__main__':
Asked Answered
F

5

21

I am really fond of python's capability to do things like this:

if __name__ == '__main__':
    #setup testing code here
    #or setup a call a function with parameters and human format the output
    #etc...

This is nice because I can treat a Python script file as something that can be called from the command line but it remains available for me to import its functions and classes into a separate python script file easily without triggering the default "run from the command line behavior".

Does Powershell have a similar facility that I could exploit? And if it doesn't how should I be organizing my library of function files so that i can easily execute some of them while I am developing them?

Frugal answered 14/1, 2011 at 17:24 Comment(0)
P
6

$MyInvocation has lots of information about the current context, and those of callers. Maybe this could be used to detect if a script is being dot-sourced (i.e. imported) or executed as a script.

A script can act like a function: use param as first non-common/whitespace in the file to defined parameters. It is not clear (one would need to try different combinations) what happens if you dot-source a script that starts param...

Modules can directly execute code as well as export functions, variables, ... and can take parameters. Maybe $MyInvocation in a module would allow the two cases to be detected.

EDIT: Additional:

$MyInvocation.Line contains the command line used to execute the current script or function. Its Line property has the scrip text used for the execution, when dot-sourcing this will start with "." but not if run as a script (obviously a case to use a regex match to allow for variable whitespace around the period).

In a script run as a function

Paleopsychology answered 14/1, 2011 at 17:38 Comment(2)
So something along the lines of: if (! $MyInvocation.Line.Trim().StartsWith(". ")) { #Scripty type invocation happens here }Frugal
@MarkMascolino: after a quick test, can have .<tab>script, not just a space. I would use -match '^\s+\.\s+'.Paleopsychology
L
8

$MyInvocation.Invocation has information about how the script was started.

If ($MyInvocation.InvocationName -eq '&') {
    "Called using operator: '$($MyInvocation.InvocationName)'"
} ElseIf ($MyInvocation.InvocationName -eq '.') {
    "Dot sourced: '$($MyInvocation.InvocationName)'"
} ElseIf ((Resolve-Path -Path $MyInvocation.InvocationName).ProviderPath -eq $MyInvocation.MyCommand.Path) {
    "Called using path: '$($MyInvocation.InvocationName)'"
}
Lynda answered 7/4, 2011 at 14:26 Comment(0)
P
6

$MyInvocation has lots of information about the current context, and those of callers. Maybe this could be used to detect if a script is being dot-sourced (i.e. imported) or executed as a script.

A script can act like a function: use param as first non-common/whitespace in the file to defined parameters. It is not clear (one would need to try different combinations) what happens if you dot-source a script that starts param...

Modules can directly execute code as well as export functions, variables, ... and can take parameters. Maybe $MyInvocation in a module would allow the two cases to be detected.

EDIT: Additional:

$MyInvocation.Line contains the command line used to execute the current script or function. Its Line property has the scrip text used for the execution, when dot-sourcing this will start with "." but not if run as a script (obviously a case to use a regex match to allow for variable whitespace around the period).

In a script run as a function

Paleopsychology answered 14/1, 2011 at 17:38 Comment(2)
So something along the lines of: if (! $MyInvocation.Line.Trim().StartsWith(". ")) { #Scripty type invocation happens here }Frugal
@MarkMascolino: after a quick test, can have .<tab>script, not just a space. I would use -match '^\s+\.\s+'.Paleopsychology
C
2

As of now I see 2 options that work

if ($MyInvocation.InvocationName -ne '.') {#do main stuff}

and

if ($MyInvocation.CommandOrigin -eq 'Runspace') {#do main stuff}
Corpuz answered 28/12, 2019 at 17:45 Comment(0)
I
1

Disclaimer: This is only tested on Powershell Core on Linux. It may not work the same for Windows. If anyone tries it on Windows I would appreciate if you could verify in the comments.

function IsMain() {
  (Get-Variable MyInvocation -Scope Local).Value.PSCommandPath -Eq (Get-Variable MyInvocation -Scope Global).Value.InvocationName
}

Demonstrated with a gist

Indamine answered 28/12, 2017 at 7:20 Comment(1)
This worked for me in Windows 10 VM, $PSVersionTable:PSVersion = 5.1.17763.107Poetize
W
0

Not an answer and only tested with PS 7.3.4, but the questions above made me wonder how $MyInvocation changes in various scopes/runspaces. So i wrote the below code which painted a pretty clear picture.

Also, CommandOrigin and MyCommand.CommandType can eval as a string or int32

<#
.\ifNameMain_discovery.ps1    # direct
. .\ifNameMain_discovery.ps1  # dot sourced
#>

$data = [System.Collections.Generic.List[object]]@()

# direct script
$iRanFrom = 'direct script'
$data.Add([PSCustomObject]@{
        IranFrom       = $iRanFrom
        scope          = 'global'
        CommandOrigin  = [string]$global:MyInvocation.CommandOrigin
        CommandOriginN = [Int32]$global:MyInvocation.CommandOrigin
        CommandType    = [string]$global:MyInvocation.MyCommand.CommandType
        CommandTypeN   = [Int32]$global:MyInvocation.MyCommand.CommandType
        Name           = $global:MyInvocation.MyCommand.Name
} )
$data.Add([PSCustomObject]@{
        IranFrom       = $iRanFrom
        scope          = 'local'
        CommandOrigin  = [string]$MyInvocation.CommandOrigin
        CommandOriginN = [Int32]$MyInvocation.CommandOrigin
        CommandType    = [string]$MyInvocation.MyCommand.CommandType
        CommandTypeN   = [Int32]$MyInvocation.MyCommand.CommandType
        Name           = $MyInvocation.MyCommand.Name
} )

# scriptblock
$scriptB = [scriptblock] {
    begin {
        $iRanFrom = 'scriptblock'
    }
    process {
        [PSCustomObject]@{
            IranFrom       = $iRanFrom
            scope          = 'global'
            CommandOrigin  = [string]$global:MyInvocation.CommandOrigin
            CommandOriginN = [Int32]$global:MyInvocation.CommandOrigin
            CommandType    = [string]$global:MyInvocation.MyCommand.CommandType
            CommandTypeN   = [Int32]$global:MyInvocation.MyCommand.CommandType
            Name           = $global:MyInvocation.MyCommand.Name
        },
        [PSCustomObject]@{
            IranFrom       = $iRanFrom
            scope          = 'local'
            CommandOrigin  = [string]$MyInvocation.CommandOrigin
            CommandOriginN = [Int32]$MyInvocation.CommandOrigin
            CommandType    = [string]$MyInvocation.MyCommand.CommandType
            CommandTypeN   = [Int32]$MyInvocation.MyCommand.CommandType
            Name           = $MyInvocation.MyCommand.Name
        }
    }
}
$data.AddRange( (&$scriptB) )

# in a function
function inAFunc() {
    $iRanFrom = 'a function'
    $fdata = [System.Collections.Generic.List[object]]@()
    $fdata.Add([PSCustomObject]@{
            IranFrom       = $iRanFrom
            scope          = 'global'
            CommandOrigin  = [string]$global:MyInvocation.CommandOrigin
            CommandOriginN = [Int32]$global:MyInvocation.CommandOrigin
            CommandType    = [string]$global:MyInvocation.MyCommand.CommandType
            CommandTypeN   = [Int32]$global:MyInvocation.MyCommand.CommandType
            Name           = $global:MyInvocation.MyCommand.Name
        } )
    $fdata.Add([PSCustomObject]@{
            IranFrom       = $iRanFrom
            scope          = 'local'
            CommandOrigin  = [string]$MyInvocation.CommandOrigin
            CommandOriginN = [Int32]$MyInvocation.CommandOrigin
            CommandType    = [string]$MyInvocation.MyCommand.CommandType
            CommandTypeN   = [Int32]$MyInvocation.MyCommand.CommandType
            Name           = $MyInvocation.MyCommand.Name
        } )
    return $fdata
}
$dfunc = inAFunc
$data.AddRange( $dfunc ) 

# in a function in a function
function inAFuncINAFUNC() {
    $iRanFrom = 'deep inside a func'
    $fdata = inAFunc
    foreach ($f in $fdata) {
        $f.IranFrom = $iRanFrom
    }
    return $fdata
}
$doubleFunc = inAFuncINAFUNC
$data.AddRange( $doubleFunc )

# output
$data | format-table -AutoSize
Watusi answered 8/8, 2024 at 21:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.