4

After writing deployment scripts from within the ISE, we need our continuous integration (CI) server to be able to run them automatically, i.e. from the command line or via a batch file.

I have noticed some significant differences between the following calls:

powershell.exe -File Script.ps1
powershell.exe -Command "& '.\Script.ps1'"
powershell.exe .\Script.ps1

Some simple examples:

  • When using -File, errors are handled in the exact same way as the ISE.
  • The other two calls seem to ignore the $ErrorActionPreference variable, and do not catch Write-Error in try/catch blocks.

When using pSake:

  • The last two calls work perfectly
  • Using the ISE or the -File parameter will fail with the following error:

The variable '$script:context' cannot be retrieved because it has not been set


What are the implications of each syntax, and why they are behaving differently? I would ideally like to find a syntax that works all the time and behaves like the ISE.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Romain
  • 2,318
  • 1
  • 23
  • 31
  • What do you expect this command will produce? `try { remove-item nonexisting -ea 0 } catch { 'err occured' }` and what if I change -ea to 2? IMHO write-error is not trapped in catch block. – stej May 24 '10 at 06:05
  • Thanks for your help stej. Your example worked as I expected, which means the behaviour I mention might be the result of specific calls. I have added a real sample as a separate entry to be more legible than a comment. – Romain May 24 '10 at 07:03

2 Answers2

2

Not an answer, just a note.

I searched for explanation of -file parameter. Most sources say only "Execute a script file.". At http://technet.microsoft.com/en-us/library/dd315276.aspx I read

Runs the specified script in the local scope ("dot-sourced"), so that the functions
and variables that the script creates are available in the current session. Enter
the script file path and any parameters.

After that I tried to call this:

powershell -command ". c:\temp\aa\script.ps1"
powershell -file c:\temp\aa\script.ps1
powershell -command "& c:\temp\aa\script.ps1"

Note that first two stop after Get-Foo, but the last one doesn't.

The problem I describe above is related to modules -- if you define Get-Foo inside script.ps1, all the 3 calls I described stop after call to Get-Foo.

Just try to define it inside the script.ps1 or dotsource the file with Get-Foo and check it. There is a chance it will work :)

stej
  • 28,745
  • 11
  • 71
  • 104
  • Thanks! You're right, the first two calls seem to do the exact same thing, both regarding error handling and *pSake*. Regarding modules, workarounds are hard because in a lot of cases the functions belong to internal libraries or third party modules. If you have the option though, your suggestion to rename the module to `PS1` and then dot source it worked fine! I wonder if it's a safer choice to always use `-File` though, so the behaviour is consistent with what you get while developing in the *ISE*. – Romain May 24 '10 at 23:25
  • As a note, I just found out about this other difference: When using `powershell.exe .\script.ps1` or `-Command "& script.ps1"`, the **Set-StrictMode** commandlet will not catch any syntax errors in the modules you import. When using `-File script.ps1` or `-Command ". script.ps1"`, it will catch everything, just like in the ISE. – Romain May 25 '10 at 01:59
  • Yea, `Set-StrictMode` sets "something", as well as `$errorActionPreference = ..`. It is the same pattern - set something, but it is not used in the module function. Modules are sometimes quite tricky, but in this case I don't know what's going on. – stej May 25 '10 at 07:16
0

Here is a concrete example of the behaviour I described.

MyModule.psm1

function Get-Foo
{
    Write-Error 'Failed'
}

Script.ps1

$ErrorActionPreference = 'Stop'

$currentFolder = (Split-Path $MyInvocation.MyCommand.Path)
Import-Module $currentFolder\MyModule.psm1

try
{
    Get-Foo 
    Write-Host "Success"
}
catch
{
    "Error occurred"
} 

Running Script.ps1:

  • From the ISE, or with the -File parameter

    will output "Error occurred" and stop

  • From the command line without the -File parameter

    will output "Failed" followed by "Success" (i.e. not caught)

Romain
  • 2,318
  • 1
  • 23
  • 31