Andy
Andy

Reputation: 1423

Why PowerShell.exe There is no way to dot source a script?

The help document says that the script will be executed in 'dot-sourced' mode, but it doesn't. why?

I read the full text of the help document and couldn't find the reason, so I came for help.

PS> PowerShell.exe -File '.\dot-source-test.ps1'
PS> $theValue
PS> . '.\dot-source-test.ps1'
PS> $theValue
theValue
PS>

The content of 'dot-source-test.ps1' is $theValue = 'theValue'.

If the value of File is a file path, the script runs in the local scope ("dot-sourced"), so that the functions and variables that the script creates are available in the current session.

about_PowerShell_exe - PowerShell | Microsoft Docs

Upvotes: 3

Views: 4707

Answers (2)

mklement0
mklement0

Reputation: 438198

To prevent conceptual confusion:

In order to dot-source a script, i.e. execute it directly in the caller's scope (as opposed to a child scope, which is the default), so that the script's variables, function definitions, ... are seen by the caller:

  • In the current PowerShell session, just use ., the dot-sourcing operator, directly:

    # Dot-source in the caller's scope.
    # When executed at the prompt in an interactive PowerShell session,
    # the script's definitions become globally available.
    . '.\dot-source-test.ps1'
    
  • Via powershell.exe, the Windows PowerShell CLI[1]:

    • Note: Whatever dot-sourcing you perform this way is limited to the child process in which powershell.exe runs and its PowerShell session; it has no impact on the caller's session.

    • Dot-sourcing via the CLI makes sense only in two scenarios:

      • Scenario A: You're passing commands via the (possibly positionally implied) -Command (-c) parameter that relies on definitions that must first be dot-sourced from a script file, and you want the session to exit automatically when the commands have finished executing.

      • Scenario B: You're entering a (possibly nested) interactive PowerShell session into which you want to dot-source (pre-load) definitions from a script file; as any interactive session, you will need to exit it manually, typically with exit.

Scenario A: Pre-load definitions, execute commands that rely on them, then exit:

The following starts a (new) PowerShell session as follows:

  • Script file .\dot-source-test.ps1 is dot-sourced, which defines variable $theValue in the caller's (here: the global) scope.

  • The value of $theValue is output.

  • The new session is automatically exited on completing the commands.

PS> powershell -c '. .\dot-source-test.ps1; $theValue'
theValue

Scenario B: Enter a (new) interactive session with pre-loaded definitions:

Simply add the -noexit switch in order to enter an interactive session in which script file .\dot-source-test.ps1 has been dot-sourced:

powershell -noexit -c '. .\dot-source-test.ps1'
# You're now  in a (new) interactive session in which $theValue is defined,
# and which you must eventually exit manually.

Note:

  • If neither -File nor a command (via explicit or implied -Command / -c) are specified, -noexit is implied.
    Because -c is needed here for dot-sourcing, -noexit must be specified to keep the session open.

  • While using -File for dot-sourcing instead - powershell -noexit -File '.\dot-source-test.ps1' - works too, I suggest avoiding it for conceptual reasons:

    • While it is technically true that a script passed to -File is dot-sourced in the new session, that is (a) unexpected, given that scripts executed from inside a session are not (they run in a child scope) and (b) by far the most typical use case for -File is to execute a given script and then exit - in which case the aspect of dot-sourcing is irrelevant.

    • As such, it is better to think of this behavior as an implementation detail, and it is unfortunate that the CLI help mentions it so prominently - causing the confusion that prompted this question.


[1] The same applies analogously to the PowerShell [Core] 7+ CLI, pwsh, except that it defaults to -File rather than -Command.

Upvotes: 7

Guy S
Guy S

Reputation: 472

It's about the way the path to the file is passed through the command line. See the below example when used in Command Prompt. (test.ps1 contains the line $theValue = 'theValue')

CMD window example

Without using the "-File" toggle, it's treated differently, as an argument to be passed to the PowerShell process being triggered.

Seeing the same thing when calling in PowerShell.

PowerShell Window sample

The specific part you reference is under the " -File" toggle, which needs to be used.

If the value of File is "-", the command text is read from standard input. Running powershell -File - without redirected standard input starts a regular session. This is the same as not specifying the File parameter at all.

If the value of File is a file path, the script runs in the local scope ("dot-sourced"), so that the functions and variables that the script creates are available in the current session.

(source: Microsoft Docs > About PowerShell.exe)

Upvotes: 2

Related Questions