powershell $LastExitCode -1073741502 when calling osql or sqlcmd - powershell

I've written a powershell script to call sqlcmd.exe to execute a sql script against a remote sql server. The powershell script checks $LASTEXITCODE. If $LASTEXITCODE is non zero, I throw "Script failed. Return code is $LASTEXITCODE."
The script is used multiple times to execute different sql scripts and is part of a chain of powershell scripts that run during deployment.
The script runs fine most of the time but randomly fails with a return code of -1073741502.
This has only started happening after upgrading to SQL2008 and I cannot reproduce it by running either the single powershell script manually or the sql cmd script manually.
This is the powershell command:
& 'sqlcmd.exe' -S $databaseServer -r -b -E -i '$scriptFullPath'
if($LASTEXITCODE -ne 0)
{
throw "Script failed. Return code is $LASTEXITCODE."
}
The seemingly random nature of the failure is causing a lot of pain. I can't determine if the error is SQL2008, SQLCMD (Although I get the same behaviour with osql.exe) or somehow coupled to powershell.
The actual sql that sqlcmd is executing appears to be unrelated to the problem since a sql script will execute ok for a while and then fail.
The same failure has been seen on many different Workstations and Servers (Win7, Win2003 and Win2008)
Any guidance on how to track this down would be much appreciated.

Don't use sqlcmd and command lines if you are using Powershell!
There are very good built-in tools in V2 that give you a lot more robust interaction with SQL Server, and don't require you to parse the text of return codes to check for errors - they actually return proper error codes.
Here's a technet article on Invoke-SQLCmd
Bear in mind you need to load the snapins first:
Add-PSSnapin SqlServerProviderSnapin100
Add-PSSnapin SqlServerCmdletSnapin100

The root-cause is actually explained elsewhere on here
Exit Code -1073741502 is 0xC0000142 in hex (status_dll_init_failed).
Microsoft's KB2701373 addresses the leaky handles made by Console.Write in Microsoft.powershell.consolehost.dll.
Side-Note: Some "Fixes" on the Internet involve doing something differently, then restarting PowerShell. Yet the actual restart of PowerShell is what addresses the problem (temporarily)

Related

Trying to get a Powershell Script that will run in a 2nd window and monitor in real time other running scripts / report all Errors / ExitCodes

I am fairly new to writing code in Powershell. For my job I have to write multiple Powershell scripts to make changes in the Hardware and Software settings as well as the Registry and Group Policy Editor to get these applications to run. These applications are a little older. Upgrading these software applications or the hardware then run on is NOT an option. as an example, when Microsoft releases the new patches on like Patch Tuesday...when those patches are applied there is a high probability that something will be changed which is where I come in to write a script to fix the issue. I have multiple scripts that I run. When those scripts are ran they may end up terminating because of an Error Code or an Exit Code. A large part of the time I do not that the script has failed immediately.
I am trying to figure out a script that I can run in a 2nd PowerShell Console Window. I am thinking that the only purpose of this script is to just sit there on the screen and wait and monitor. Then when I execute a script or Application (the only file extensions that I am worried about are: EXE, BAT, CMD, PS1) if the script/application that I just ran ends with an exit code or an error code....then output that to the screen...in REAL TIME.
Below, I have a small piece of code that kind of works, but it is not what I am wanting.
I have researched online and read and read tons of stuff. But I just can't seem to find what I am looking for.
Could someone please help me with getting a script that will do what I am wanting.
Thank you for your help!!!!
$ExitErrorCode =
"C:\ThisFolder\ThatFolder\AnotherFolder\SomeApplication.EXE # (this
would
# either be an EXE or CMD or BAT or PS1)"
$proc = Start-Process $ExitErrorCode -PassThru
$handle = $proc.Handle # cache proc.Handle
$proc.WaitForExit();
if ($proc.ExitCode -ne 0) {
Write-Warning "$_ exited with status code $($proc.ExitCode)"
}
Possible duplicate of the approaches shown here:
Monitoring jobs in a PowerShell session from another PowerShell session
Monitoring jobs in a PowerShell session from another PowerShell session
PowerShell script to monitor a log and output progress to another
PowerShell script to monitor a log and output progress to another

Install arguments breaking an automated PowerShell install

I'm installing SQL Data Tools via a PowerShell script. I run my script, but the final part where the Data Tools are installed fails (inside of the SQL installer window). If I run the script without that part, and install Data Tools manually it works.
The error is:
VS Shell installation has failed with exit code -2147205120.
The parts before this install .NET and SQL Server Management Studio. I don't think they're relevant to my issue, but I will post that part if requested. Here are the relevant parts. The first try block installs SQL SP1 (removed now for readability), the second installs Data Tools and SNAC_SDK.
try
{
Write-Host "Lauching SQL Server Data Tools install ..."
& "\\mynetworkpath\SSDTBI_x86_ENU.exe" "/ACTION=INSTALL" "/FEATURES=SSDTBI,SNAC_SDK" "/Q" "/IACCEPTSQLSERVERLICENSETERMS"
Write-Host "Installer launched ..."
}
catch
{
Write-Host "SQL Server Data Tools installation failed"
exit
}
I have tried juggling around the arguments for the Data Tools install part, and playing with the -wait verb to make sure SP1 is done for sure, but no luck.
EDIT: Per Matt's suggestion I added /NORESTART to my argument list, but now it doesn't install anything, and doesn't error either...
EDIT: Added updated code with quoted arguments. Still doesn't work, but I think it's closer than it was originally.
I think the comma in the arguments is the culprit here because powershell interprets entities separated by comma as an array.
You can see how parameters get passed with this little hack
& { $args } /ACTION=INSTALL /FEATURES=SSDTBI,SNAC_SDK /Q /IACCEPTSQLSERVERLICENSETERMS
which gives
/ACTION=INSTALL
/FEATURES=SSDTBI
SNAC_SDK
/Q
/IACCEPTSQLSERVERLICENSETERMS
To get rid of this problem you need to quote at least the FEATURES argument. I usually quote everything in those cases, just to be consistent, so
& { $args } "/ACTION=INSTALL" "/FEATURES=SSDTBI,SNAC_SDK" "/Q" "/IACCEPTSQLSERVERLICENSETERMS"
gives you the wanted parameters:
/ACTION=INSTALL
/FEATURES=SSDTBI,SNAC_SDK
/Q
/IACCEPTSQLSERVERLICENSETERMS
Update: Many installers return immediately after they have been called while the install process still runs in the background, which can be a bugger when the rest of the script depends on the install.
There are several methods to make powershell wait for a process exit. One of the shortest is to use Out-Null like this:
& "\\mynetworkpath\SSDTBI_x86_ENU.exe" "/ACTION=INSTALL" "/FEATURES=SSDTBI,SNAC_SDK" "/Q" "/IACCEPTSQLSERVERLICENSETERMS" | Out-Null
You may also want to look at $? or $LASTEXITCODE afterwards to check for errors.

How do I get errors to propagate in the TeamCity PowerShell runner

I have a TeamCity 7 Build Configuration which is pretty much only an invocation of a .ps1 script using various TeamCity Parameters.
I was hoping that might be a simple matter of setting:
Script
File
Script File
%system.teamcity.build.workingDir%/Script.ps1
Script execution mode
Execute .ps1 script with "-File" argument
Script arguments
%system.teamcity.build.workingDir% -OptionB %BuildConfigArgument% %BuildConfigArg2%
And then I would expect:
if I mess up my arguments and the script won't start, the Build fails
if my Script.ps1 script throws, the Build fails
If the script exits with a non-0 Error Level I want the Build to Fail (maybe this is not idiomatic PS error management - should a .ps1 only report success by the absence of exceptions?)
The question: It just doesn't work. How is it supposed to work? Is there something I'm doing drastically wrong that I can fix by choosing different options?
As doc'd in the friendly TeamCity manual:
Setting Error Output to Error and adding build failure condition
In case syntax errors and exceptions are present, PowerShell writes them to stderr. To make TeamCity fail the build, set Error Output option to Error and add a build failure condition that will fail the build on any error output.
The keys to making this work is to change two defaults:
At the top level in the Build Failure Conditions, switch on an error message is logged by build runner:
In the [PowerShell] Build Step, Show advanced options and set Error output: Error
In 9.1 the following works (I wouldn't be surprised if it works for earlier versions too):
create a PowerShell Build Step with the default options
change the dropdown to say Script: Source code
Add a trap { Write-Error "Exception $_" ; exit 98 } at the top of the script
(Optional but more correct IMO for the kind of scripting that's appropriate for within TeamCity build scripts)
Show advanced options and switch on Options: Add -NoProfile argument
(Optional, but for me this should be the default as it renders more clearly as suggested by #Jamal Mavadat)
Show advanced options and switch on Error output: Error
(ASIDE #JetBrains: if the label was "Format stderr output as" it would be less misleading)
This covers the following cases:
Parse errors [bubble up as exceptions and stop execution immediately]
Exceptions [thrown directly or indirectly in your PS code show and trigger an exit code for TC to stop the build]
An explicit exit n in the script propagates out to the build (and fails it if non-zero)
There is an known bug in TeamCity that causes the behavior that the original poster noticed.
It is easy to work around, however.
At the end of your PowerShell script, add output indicating that the end of the script has been reached:
Echo "Packaging complete (end of script reached)"
Then, set up a new Build Failure Condition on your build to fail if the text you are echoing is NOT present in the output.
You're over-thinking things. Try this:
Script
File
Script File
Script.ps1
You don't need to give this a path - by default, it's relative to the checkout directory.
Script execution mode
Put script into PowerShell stdin with "-Command -" arguments
This is exactly what I use to run a bunch of powershell scripts within Teamcity.
Update
I missed the bit in the original post about having failures in the powershell script fail the build. Apologies!
I've solved that part of the puzzle in two different ways.
For regular powershell scripts
Wrap the main code block in a try...catch; if an exception occurs, return a non-zero integer value. For successful execution, return 0.
This convention of returning zero for success dates back a very long way in history - it's used by Unix/Linux systems, DOS, CP/M and more.
For PSake build scripts
Use a wrapper powershell script to invoke psake and directly set the result of the teamcity build by writing a response message to stdout.
At the start of the script, define a status message that represents failure:
$global:buildResult = "#teamcity[buildStatus status='FAILURE' text='It died.']
Within the psake script, update $global:buildResult to indicate success in a dedicated task that's run last of all.
$global:buildResult = "#teamcity[buildStatus status='SUCCESS' text='It lives.']
At the end of the wrapper script, output the status message
write-host $global:buildResult
If anything in the build script fails, that last task won't run, and the default message (indicating failure) will be output.
Either way, Teamcity will pick up on the message and set the build status appropriately.
An alternative to the accepted answer that works for me On TeamCity 9 (I don't like changing the 'Build Failure Conditions' option as it affects all build steps):-
I wanted PowerShell errors to fail the build step, but with a pretty message.
So I wanted to throw an error message AND return an error code.... try / catch / finally to the rescue.
EDIT for clarity: This script is supposed to fail. It is demonstrating that it is possible to throw an exception AND to return an exit code.
So you get both, the exit code for TeamCity to deal with, and, in my case, a nice clear debug message that shows where the issue was.
My demo script:
Try {
Write-Host "Demoing the finally bit"
# Make sure if anything goes wrong in the script we get an exception
$ErrorActionPreference = "Stop"
# This will fail and throw an exception (unless you add the file)
Get-Content IDontExist.txt
}
Catch
{
# Throwing like this gives a pretty error message in the build log
throw $_
# These give less pretty/helpful error messages
# Write-Host $_
# Write-Host $_.Exception.Message
}
Finally
{
# 69 because it's more funny than 1
exit(69)
}
If newer TeamCity versions are within your reach then it is worth checking out some of PowerShell build runner improvements.
In particular, changing Error Output from default warning to error may interest you.
Just praise the lawd you don't need to work with Jenkins.. Can't use the PowerShell step for similar issues. Instead we need to use a "cmd" step that calls the following magic wrapper that will fail the step on exception and exit codes:
%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -Command "& { $ErrorActionPreference = 'Stop'; & 'path\to\script.ps1 -arg1 -arg2; EXIT $LASTEXITCODE }"
This has been superseded by options afforded by 9.x, but I'll leave it here as it definitely was bullet proof at the time and I couldn't find any other solution I liked better.
You could just do something that works. The following has been tested with
errors in the script bit
missing files
script exiting with non-0 ERRORLEVEL
In the TeamCity Powershell runner options, set it as follows:
Script File
Source code
Script source
$ErrorActionPreference='Stop'
powershell -NoProfile "Invoke-Command -ScriptBlock { `$errorActionPreference='Stop'; %system.teamcity.build.workingDir%/Script.ps1 %system.teamcity.build.workingDir% --OptionB %BuildConfigArgument% %BuildConfigArg2%; exit `$LastExitCode }"
(unwrapped version: powershell -NoProfile "Invoke-Command -ScriptBlock { $errorActionPreference='Stop'; %system.teamcity.build.workingDir%/Script.ps1 %system.teamcity.build.workingDir% --OptionB %BuildConfigArgument% %BuildConfigArg2%; exit$LastExitCode }"
Script execution mode
Put script into PowerShell stdin with "-Command -" arguments
Additional command line parameters
-NoProfile
I'm hoping against hope this isn't the best answer!
This checks the last error code and exits if is not 0.
If ($LASTEXITCODE -ne 0) {
Write-Host "The result was of the previous script was " $LASTEXITCODE
Exit $LASTEXITCODE
}
Powershell v2 atleast had an issue with the -File option messing up error codes. There is some details about how it messes up and stuff.
The answer is either switch to -Command option and/or wrap it with a bat file that checks the LastErrorCode and returns 1+ if its supposed to fail.
http://zduck.com/2012/powershell-batch-files-exit-codes/
Use something like this:
echo "##teamcity[buildStatus status='FAILURE' text='Something went wrong while executing the script...']";
For reference, take a look on Reporting Build Status from Teamcity

Automatically stop powershell script on bat errors

Generally one can use $ErrorActionPreference to stop the execution of a PS script on error as in the example below that uses an invalid subversion command. The script exits after the first command.
$ErrorActionPreference='Stop'
svn foo
svn foo
Trying the same thing with the maven command (mvn.bat) executes both commands.
$ErrorActionPreference='Stop'
mvn foo
mvn foo
Initially I suspected that mvn.bat does not set an error code and PS just doesn't see the error. However, $? is set properly as demonstrated by the following, when PS exits after the first error:
mvn foo
if (-not $?) {exit 1}
mvn foo
So here's my question: Given that both svn.exe and mvn.bat set an error code on failure, why does the PS script not stop after the mvn error. I find it a lot more convenient to set "$ErrorActionPreference=Stop" globally rather than doing "if (-not $?) {exit 1}" after each command to terminate on error.
Not all command line programs provide errors in the same way. Some set an exit code. Some don't. Some use the error stream, some don't. I've seen some command line programs actually output everything to error, and always output non-zero return codes.
So there's not a real safe guess one could ever make as to it having run successfully, and therefore it's next to impossible to codify that behavior into PowerShell.
$errorActionPreference will actually stop a script whenever a .exe writes to the error stream, but many .exes will write regular output to the console and never populate the error stream.
But it will not reliably work. Neither, for that matter, will $?. If an exe returns 0 and doesn't write to error $? will be true.
While it might be a pain in the butt to deal with each of these individual .exes and their errors in PowerShell, it's a great example of why PowerShell's highly structured Output/Error/Verbose/Warning/Debug/Progress streams and consistent error behavior in Cmdlets beats out plain old .EXE tools.
Hope this Helps
$ErrorActionPreference controls PowerShell's behavior with regard to commandlets and PowerShell functions -- it is not sensitive to exit codes of "legacy" commands. I'm still looking for a work-around for this design decision myself -- for this issue, refer to this thread: How to stop a PowerShell script on the first error?. You'll probably conclude that this custom "exec" function is the best solution: http://jameskovacs.com/2010/02/25/the-exec-problem/
With regard to the stop-on-stderr behavior, I can't reproduce this behavior in PowerShell 3:
Invoke-Command
{
$ErrorActionPreference='Stop'
cmd /c "echo hi >&2" # Output to stderr (this does not cause termination)
.\DoesNotExist.exe # Try to run a program that doesn't exist (this throws)
echo bye # This never executes
}
Update: The stop-on-stderr behavior appears to take effect when using PS remoting.

Running a program on a remote machine as part of continuous integration

We use TeamCity, nant and psexec to run a command on a remote machine as part of the release packaging. Everything works fine when I run the nant from the console but when running from teamcity psexec hangs (freezes) 50% of the times.
I looked through many forums and there seems to be workarounds that increase complexity of the call and involve loosing the output and the errorcode of the command.
Does anyone know an easier way to run a command on a remote machine?
I don't mind setting up some application on the remote machine, like a telnet server, any advices on what to do?
Thanks
I have solved this issue with a combination of RemCom and a custom MSBuild task called ExecParse.
RemCom, because it doesn't do odd things with STDOUT (thus hanging the build). We used, and ExecParse to capture the output of the remote task, and parse the Exit Code from the output, because the standard MSBuild Exec task does not capture output. Some NAnt equivalent that captures the output would work.
I've detailed this in a blog post: "Continuous Integration: Executing Remote Tasks with TeamCity, MSBuild, RemCom, and ExecParse"
PsExec does some funky things with the standard input/output, and invoking this from Java (which TeamCity is built on) raises all kinds of problems and stability issues. psexec -d did not work wither.
I solved it by using Powershell in Team City.
The script below stops an IIS 7 ApplicationPool on a remote server:
[string]$HostName = "myWebServer"
[string]$Cmd = "C:\Windows\System32\inetsrv\appcmd.exe stop apppool MyMainAppPool”
Invoke-WmiMethod -class Win32_process -name Create -ArgumentList ($Cmd) -ComputerName $HostName
More about it on my blog: http://blog.degree.no/2012/03/executing-commands-and-programs-on-a-remote-machine-using-powershell/
How about putting a (nant) time-out on the psexec and repeat the call until no time-out happens?
I use PSExec with the -d option (don't wait for it to finish) and capture the return code. The return code when you used -d is the process ID of the process running on the remote system. then I use PSList to poll the remote system for the process ID until I don't find it on the remote system any longer.
What happens if you setup TeamCity build agent on remote machine and let it perform the operation locally, passing it the binaries with "Artifact Dependencies"?