Powershell unexpected behavior of uncaught exception inside a catch block - powershell

The following powershell script produce a very unexcepted output:
try {
throw "some exception"
echo "check point"
}
catch
{
echo "catch"
throw "some other exception"
exit(-1)
}
echo "finish"
output:
catch
finish
I would except the script to exit either by the uncaught exception throw "some exception" and for the script not reach finish.
Even if Powershell is set to continue after uncaught exception, I would expect it to execute exit(-1) and never reach finish.
Can anyone explain this behavior?

exit(-1) is unreachable because the previous line, throw "some other exception", throws an exception which bypasses the rest of the block.
I see "finish" being reached in two cases:
As Bacon Bits said, when $ErrorActionPreference is set to "SilentlyContinue".
The code is pasted into the interactive shell (as opposed to run from a .ps1 file), in which case it runs the final line as a manual command.

Related

BTSKTask AddResource - How to raise an error in case the command fails

We are using the following command to deploy BizTalk assemblies via PowerShell:
BTSTask AddResource /ApplicationName:$App /Type:$BizTalkAssemblyType /Overwrite /Source:$Source /Options:GacOnAdd,GacOnInstall,GacOnImport
See: https://learn.microsoft.com/en-us/biztalk/core/addresource-command-biztalk-assembly
There are certain reasons this command can fail, e.g. an orchestration is not in the unenlisted state or one or more instances of the orchestration exists.
In this case the command does not raise an error so the script continues with an output like
Command failed with 1 errors, 0 warnings.
Because in this situation the assembly does not get deployed we would like to fail the PowerShell script e.g. by raising an error. How to achieve this?
You need to capture the output and check it for the failure, or rather, check for success and fail if it doesn't.
[array] $cmdOutput = BTSTask AddResource /ApplicationName:$App /Type:$BizTalkAssemblyType /Overwrite /Source:$Source /Options:"GacOnAdd,GacOnInstall,GacOnImport"
$line = $cmdOutput.Count-2
if ( $cmdOutput[$line] -eq "Command succeeded with 0 errors, 0 warnings.")
{
Write-Output "Deploy suceeded"
}
else
{
Throw "Deploy failed $cmdOutput"
}

FindItems() does not work in first run but works in the second run

I am trying to fetch latest mail from my Outlook Exchange server mailbox using PowerShell. I have seen that the most common solution is to do a FindItems() method on the inbox object. However, I find that that running the code first time throws error stating
Exception calling "FindItems" with "1" argument(s): "The request failed.
When I run it once again, the script completes successfully returning the last mail from my mailbox. In order to make it more clear, I wrote a script to execute the FindItems() method to execute twice in a while loop as shown below:
# bind to the Inbox folder of the target mailbox
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($ews,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
echo outsideWhile
$i = 0
while ($i -ne 2) {
echo insideWhileBefore
$inbox.FindItems(1)
echo insideWhileAfter
$i += 1
}
The first execution of $inbox.FindItems(1) fails but the second execution goes through fine returning the desired results.
The result output is as shown below
outsideWhile
insideWhileBefore
Exception calling "FindItems" with "1" argument(s): "The request failed. The remote server returned an error: (501)" ........
insideWhileAfter
insideWhileBefore
<MAIL CONTENTS>
insideWhileAfter
Please help me out in understanding why this happening so and how I can overcome it.

PowerShell executes the wrong exception handler

I think I have found a nasty bug in PowerShell 4.0 exception handling but I'm new to PowerShell scripting and want to be sure I didn't miss something.
I managed to find a code that reproduces the problem:
foreach ($id in 1..20) {
try {
# The objective is to generate basic exceptions and see how they are caught
throw "#$id"
}
# Oddly, if the following block is removed or commented, there is no problem
catch [System.ArithmeticException] {
Write-Host ("[ArithmeticException] {0}" -f $_.Exception.Message)
throw
}
# Problem is, at some point in time, the following catch block is run,
# even if the exception is not a System.ArgumentException
catch [System.ArgumentException] {
Write-Host ("[ArgumentException] {0}" -f $_.Exception.Message)
if ($_.Exception.GetType().Name -ne "ArgumentException") {
Write-Warning ("Expected [ArgumentException] but got [{0}]" -f $_.Exception.GetType().Name)
}
}
# The exceptions should all be caught here
catch {
Write-Host ("[Generic] {0}" -f $_.Exception.Message)
}
}
Basically, I have a try{} with 3 catch{} blocks:
The first catch{} just rethrows a specific exception. It should never be executed as that exception is never generated.
The second catch{} logs the message of a specific exception. It should never be executed as that exception is never generated.
The third catch{} is the default one. It should be always executed.
The expected result of running this code is as follow:
[Generic] #1
[Generic] #2
...
[Generic] #20
And it is what I get for the first executions of the script.
However, after a varying number of executions of the script (usually 2 or 3), I get this :
[ArgumentException] #2
WARNING:Expected [ArgumentException] but got [RuntimeException]
It means the second catch{} block is executed instead of the third.
Once this occurs (the id may vary), it happens until I close the PowerShell host and start a new one. So far, I can reproduce that problem on a Windows 7 32bits desktop and a Windows 2012 R2 server.
If it wasn't odd enough, the problem disappears if I remove the first catch{} block.
So, have I missed something or is it a bug ?
I can repro this on the latest PS 5 as of now (5.0.10586.117 according to $PSVersionTable) with a single attempt by making the loop run from 1.100 as suggested in the question's comments.
It does appear to have been fixed in PS Core; I could not reproduce it on 6.0.3. The loop always enters the [Generic] catch block.
There does appear to be a bug about this on the PS UserVoice forum already. This bug references this now-unavailable Connect item, which in turn references this other SO question with a similar issue as yours. It's probably worth linking both these SO questions / code samples to the UserVoice directly.

How do I get topshelf to return error code when command fails?

I am trying to start my service with powershell but currently it fails. I don't know why it fails but that is not the point here. When trying to start the host all I don't get the correct exit code so my automatic deploy fails silently.
What I'm trying to do is:
$cmd = "$folder" + "\MyService.exe"
try
{
& $cmd stop
& $cmd uninstall
& $cmd install
& $cmd start
}
catch
{
Write-Host "Error: Update of service failed"
exit 1
}
The start command fails with the following messge:
Topshelf.Hosts.StartHost Error: 0 : The service failed to start., System.InvalidOperationException: Cannot start service MyService on computer '.'. ---> System.ComponentModel.Win32Exception: The service cannot be started, either because it is disabled or because it has no enabled devices associated with it
--- End of inner exception stack trace ---
at System.ServiceProcess.ServiceController.Start(String[] args)
at System.ServiceProcess.ServiceController.Start()
at Topshelf.Runtime.Windows.WindowsHostEnvironment.StartService(String serviceName)
at Topshelf.Hosts.StartHost.Run()
and I never get into the catch statement of my powershell script.
UPDATE:
Note that I am asking for how to get the method to the catch statement and not the solution to the actual exception. I have solved the actual exception but I want better feedback in the future if it fails, and that is want the catch statement to be executed which it isn't in case of error.
try/catch in PowerShell doesn't work with exe.
After myservice.exe calls you need to check the automatic variable $LastExitCode.
Try something like this:
$out = & $cmd start
if ($LastExitCode -ne 0) # if exe returns 0 on success, if not change the condition accordingly
{
"ERROR: $out"
return # to exit script or do something else.
}

Is there a way to add errors from build step in TeamCity to the email notification?

I have a Powershell build step, and I'd like to add some messages fromt the script to the resulting email that is sent to people on the notification list. I see this happen for tests where the number of failures and the error is added to the email. But, how can I add my custom messages from the PowerShell build step to the resulting email?
Have you tried using service messages?
See here:http://confluence.jetbrains.com/display/TCD7/Build+Script+Interaction+with+TeamCity
You could use
write-host "##teamcity[message text='Its broken again' errorDetails='Your exception message' status='FAILURE']"
In order for the errors to be included in emails, I found I needed to add "compilationStarted" and "compilationFinished" tags, e.g:
##teamcity[compilationStarted compiler='Solution.sln']
##teamcity[message text='1>File.cpp(1): error C2065: "stackoverflow" : undeclared identifier' status='ERROR']
##teamcity[compilationFinished compiler='Solution.sln']
I use a Python script to parse the output from devenv, looking for specific strings to add as errors and warnings. The email adds these under a "compilation errors" section.
If you mean to pipe the output of an error that occurred in the Powershell script you are running then try piping the error object to a TeamCity service message after it has been caught
This is untested code but it might work for you:
trap [SystemException]
{
write-host "##teamcity[message text='An error occurred' errorDetails='$_' status='ERROR']";exit 1
}
OR
try
{
# Something...
}
catch
{
write-host "##teamcity[message text='An error occurred' errorDetails='$_' status='ERROR']";exit 1
}