Detecting error after a powershell statement is executed - powershell

I am using powershell to run sqlplus and I would like PowerShell to detect if there are error after the script was run and to perform some action instead of me looking at the result file.
& 'sqlplus' 'system/myOraclePassword' '#Test' | out-file 'result.txt';
Normally in DOS, there is %errorlevel% when the command encounters error and I wonder if there is similar stuff in PowerShell?
Of course, I can read the log file myself but sometimes, thing got too routine and I may forget.
My Test.sql:
select level from dual
connect by level<5;
select 10/0 from dual;
quit;
There is clearly a division by zero error. The result.txt captures it but I would like powershell to detect it as well
SQL*Plus: Release 12.1.0.2.0 Production on Thu Apr 27 16:24:30 2017
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Last Successful login time: Thu Apr 27 2017 16:17:34 -04:00
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
LEVEL
----------
1
2
3
4
select 10/0 from dual
*
ERROR at line 1:
ORA-01476: divisor is equal to zero
Does the powershell statement return an errorlevel after the statement is executed like DOS?
I have tried:
& 'sqlplus' 'system/myOraclePassword' '#Test' | out-file 'result.txt';
if (errorlevel 1)
{ write-host error;
}
else
{ write-host ok;
}
But that has caused syntax error?
errorlevel : The term 'errorlevel' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and
try again.
What is a proper way to check error in powershell?
UPDATE
I used this:
if ($LASTEXITCODE -ne 0 )
{
write-host error;
}
else
{
write-host ok;
}

Since you are invoking an executable, you probably want to check for the $LASTEXITCODE variable or the return value of sqlplus. In PowerShell each variable has a $ prefix.

Related

Executing sql file with sqlplus in windows 10 powershell

I have created a .bat file to export csv file regulary through windows task scheduling which works fine.
But not working when I switch to Powershell. It returns (both in ISE and right click .ps1 "Run with Powershell") with:
SQL*Plus: Release 19.0.0.0.0 - Production on Sun May 2 14:05:52 2021
Version 19.10.0.0.0
Copyright (c) 1982, 2020, Oracle. All rights reserved.
ERROR: ORA-12154: TNS:could not resolve the connect identifier specified
So.I'm not sure what I'm doing wrong. The variable input are dummies.
In my .bat contains:
SET NLS_LANG=.AL32UTF8
SET hostIp="123.123.1.12"
SET username="user1"
SET password="pass1"
SET port="1521"
SET service="myDBname"
SET sqlPath="C:\My script\TEST_EXPORT.sql"
sqlplus %username%/%password%#%hostIp%:%port%/%service% #"%sqlPath%"
In my .ps1 contains:
cls
$hostIp="123.123.1.12"
$username="user1"
$password="pass1"
$port="1521"
$service="myDBname"
$sqlPath="C:\My script\TEST_EXPORT.sql"
echo "$username/$password#$hostIp`:$port/$service #$sqlPath"
sqlplus "$username/$password#$hostIp`:$port/$service #$sqlPath"
Try using composite formatting to build the parameter string. The upside is that one can build the string and not to worry about quotation issues. Note that there is no need to escape the colon `: in the string, as it is not interpreted as scope operator.
# A variable that contains double quote
$quote = '"'
$("{0}/{1}#{2}:{3}/{4} #{5}{6}{5}" -f $username, $password, $hostIp, $port, $service, $quote, $sqlPath,$quote)
user1/pass1#123.123.1.12:1521/myDBname #"C:\My script\TEST_EXPORT.sql"
Another an alternative for building complex strings is string interpolation. Here are three versions that contain different techniques to include double-quotes. The same works in composite fomatting too.
# Double-doublequote version. I'd avoid this, as multiple double quotes are hard to read
"${username}/${password}#{$hostIp}:${port}/${service} #""${sqlPath}"""
user1/pass1#{123.123.1.12}:1521/myDBname #"C:\My script\TEST_EXPORT.sql"
# Backtick-escape version
"${username}/${password}#{$hostIp}:${port}/${service} #`"${sqlPath}`""
user1/pass1#{123.123.1.12}:1521/myDBname #"C:\My script\TEST_EXPORT.sql"
# Quote in a variable version
"${username}/${password}#{$hostIp}:${port}/${service} #${quote}${sqlPath}${quote}"
user1/pass1#{123.123.1.12}:1521/myDBname #"C:\My script\TEST_EXPORT.sql"

Chef: Two contradicting not_if powershell guard statements evaluating to true

So I am working with chef and need to chain some resources together if a precondition is true. I need to check if the version of a process is what I want it to be if so do things. I was seeing odd behavior and was noticing that my guard statements are not being evaludated in the way I would expect. So I made this tests
log 'log_version' do
message 'Peregrin Took'
level :error
guard_interpreter :powershell_script
not_if <<-EOH
(C:\\Program Files\\telegraf\\telegraf.exe --version) -Like '*1.7.2*'
EOH
end
log 'log_version' do
message 'Meriadoc Brandybuck'
level :error
guard_interpreter :powershell_script
not_if <<-EOH
(C:\\Program Files\\telegraf\\telegraf.exe --version) -NotLike '*1.7.2*'
EOH
end
And when I run this I get
Recipe: win-telegraf::telegraf
* log[log_version] action write[2018-07-24T07:31:42-07:00] INFO: Processing log[log_version] action write (win-telegraf::telegraf line 47)
[2018-07-24T07:31:42-07:00] INFO: Processing powershell_script[Guard resource] action run (dynamically defined)
[2018-07-24T07:31:43-07:00] ERROR: Peregrin Took
* log[log_version] action write[2018-07-24T07:31:43-07:00] INFO: Processing log[log_version] action write (win-telegraf::telegraf line 57)
[2018-07-24T07:31:43-07:00] INFO: Processing powershell_script[Guard resource] action run (dynamically defined)
[2018-07-24T07:31:43-07:00] ERROR: Meriadoc Brandybuck
Why are both of these statements logging? When I run these powershell snippets in the vm I get one returning true and the other returning false. So I would expect only one log line to write. But when I run both of them are writing.
After doing some reading it seems that the guard statement makes its decision off the $LASTEXITCODE and in the case of my statement both will have a $LASTEXITCODE of 0
So I have tried changing my guard statement to force an exit code of something other than 0
log 'log_version' do
message 'Peregrin Took'
level :error
guard_interpreter :powershell_script
not_if <<-EOH
if((C:\\Program Files\\telegraf\\telegraf.exe --version) -Like '*1.7.2*') { exit 1 }
EOH
end
log 'log_version opposite' do
message 'Meriadoc Brandybuck'
level :error
guard_interpreter :powershell_script
not_if <<-EOH
if((C:\\Program Files\\telegraf\\telegraf.exe --version) -NotLike '*1.7.2*') { exit 1 }
EOH
end
Though this has not changed results and I am still seeing both log resources executed.
So I got a working guard, the issue was with the space in Program Files and the --version being interpreted as Powershell code. by making my guard string like this
"(&'c:\\Program Files\\telegraf\\telegraf.exe' --version) -like '*#{node['windows']['telegraf']['version']}*'"
By single quoting the path the path was correctly interpreted by powershell, and I needed the & operator so that the string in the parentheses was interpreted like a commandlet.

Return messages instead of exit code for msi in powershell

Is there a way I could make msiexec return the error/success message instead of the default exit code? for instance:
msiexec /i "D:/path/installer.msi"
might return 1603, and referencing the lookup table explains that
A fatal error occurred during installation.
I would like the message, or even the error code ERROR_INSTALL_FAILURE to be returned instead of the exit code 1603.
Note: Not sure if the effort poured into this answer serves a real-world purpose, but it may be of interest for demonstrating various advanced PowerShell techniques: Advanced regex matching using the automatic $matches variable, scraping a web page via Invoke-WebRequest, and calling the Windows API via Add-Type.
Find function friendlyMsiExec below, which
scrapes the MSDN page to get the official table of defined MSI error codes (exit codes)
if that fails - scraping is not the most robust technique (page structures and URLs change) - the function issues a warning and uses a hard-coded table instead.
Invokes msiexec synchronously, looks up the exit code in the scraped/built-in table and outputs the error message corresponding to the exit code.
Once defined, you can invoke it as follows:
> friendlyMsiExec /i "D:/path/installer.msi" # assume the exit code is 1603
A fatal error occurred during installation. (1603)
Note:
The exit code will be available as $LASTEXITCODE after the function returns.
Scraping is not only not the most robust, but the page download and parsing takes a few seconds, although in the context of an MSI installation that probably won't matter much.
An exit code may also be a regular Windows API error code ("any error in Winerror.h"), so, as a fallback, the FormatMessage Windows API function is consulted, courtesy of an adaptation of this helpful C# answer.
function friendlyMsiExec {
# Try to scrape the MSDN page for the complete list of error codes (exit codes).
# Note: This is not the most robust approach as web pages aren't designed for
# programmatic data extraction, and the format of the page may change over time.
$htErrors = #{}
# Table is in a <table> element with attritubte 'summary="table"'.
$tbl = (Invoke-WebRequest 'https://msdn.microsoft.com/en-us/library/windows/desktop/aa376931(v=vs.85).aspx').ParsedHtml.getElementsByTagName('table') | ? { $_.getAttribute('summary') -eq 'table' }
# Parse the text representation (.InnerText) using regular expressions.
$tbl.InnerText -split '\r?\n' | % { if ($_ -match "^(ERROR_.+?)(\d+)(.+)$") { $htErrors.Add([int] $matches[2], #( $matches[1], $matches[3] )) } }
if ($htErrors.Count -eq 0) { # Scraping failed, use hard-coded table (current as of 2 Nov 2016).
Write-Warning "Scraping the MSDN page for error codes failed, falling back to hard-coded table."
$htErrors = #{
0 = 'ERROR_SUCCESS', 'The action completed successfully.'
13 = 'ERROR_INVALID_DATA', 'The data is invalid.'
87 = 'ERROR_INVALID_PARAMETER', 'One of the parameters was invalid.'
120 = 'ERROR_CALL_NOT_IMPLEMENTED', 'This value is returned when a custom action attempts to call a function that cannot be called from custom actions. The function returns the value ERROR_CALL_NOT_IMPLEMENTED. Available beginning with Windows Installer version 3.0.'
1259 = 'ERROR_APPHELP_BLOCK', 'If Windows Installer determines a product may be incompatible with the current operating system, it displays a dialog box informing the user and asking whether to try to install anyway. This error code is returned if the user chooses not to try the installation.'
1601 = 'ERROR_INSTALL_SERVICE_FAILURE', 'The Windows Installer service could not be accessed. Contact your support personnel to verify that the Windows Installer service is properly registered.'
1602 = 'ERROR_INSTALL_USEREXIT', 'The user cancels installation.'
1603 = 'ERROR_INSTALL_FAILURE', 'A fatal error occurred during installation.'
1604 = 'ERROR_INSTALL_SUSPEND', 'Installation suspended, incomplete.'
1605 = 'ERROR_UNKNOWN_PRODUCT', 'This action is only valid for products that are currently installed.'
1606 = 'ERROR_UNKNOWN_FEATURE', 'The feature identifier is not registered.'
1607 = 'ERROR_UNKNOWN_COMPONENT', 'The component identifier is not registered.'
1608 = 'ERROR_UNKNOWN_PROPERTY', 'This is an unknown property.'
1609 = 'ERROR_INVALID_HANDLE_STATE', 'The handle is in an invalid state.'
1610 = 'ERROR_BAD_CONFIGURATION', 'The configuration data for this product is corrupt. Contact your support personnel.'
1611 = 'ERROR_INDEX_ABSENT', 'The component qualifier not present.'
1612 = 'ERROR_INSTALL_SOURCE_ABSENT', 'The installation source for this product is not available. Verify that the source exists and that you can access it.'
1613 = 'ERROR_INSTALL_PACKAGE_VERSION', 'This installation package cannot be installed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.'
1614 = 'ERROR_PRODUCT_UNINSTALLED', 'The product is uninstalled.'
1615 = 'ERROR_BAD_QUERY_SYNTAX', 'The SQL query syntax is invalid or unsupported.'
1616 = 'ERROR_INVALID_FIELD', 'The record field does not exist.'
1618 = 'ERROR_INSTALL_ALREADY_RUNNING', 'Another installation is already in progress. Complete that installation before proceeding with this install.'
1619 = 'ERROR_INSTALL_PACKAGE_OPEN_FAILED', 'This installation package could not be opened. Verify that the package exists and is accessible, or contact the application vendor to verify that this is a valid Windows Installer package.'
1620 = 'ERROR_INSTALL_PACKAGE_INVALID', 'This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer package.'
1621 = 'ERROR_INSTALL_UI_FAILURE', 'There was an error starting the Windows Installer service user interface. Contact your support personnel.'
1622 = 'ERROR_INSTALL_LOG_FAILURE', 'There was an error opening installation log file. Verify that the specified log file location exists and is writable.'
1623 = 'ERROR_INSTALL_LANGUAGE_UNSUPPORTED', 'This language of this installation package is not supported by your system.'
1624 = 'ERROR_INSTALL_TRANSFORM_FAILURE', 'There was an error applying transforms. Verify that the specified transform paths are valid.'
1625 = 'ERROR_INSTALL_PACKAGE_REJECTED', 'This installation is forbidden by system policy. Contact your system administrator.'
1626 = 'ERROR_FUNCTION_NOT_CALLED', 'The function could not be executed.'
1627 = 'ERROR_FUNCTION_FAILED', 'The function failed during execution.'
1628 = 'ERROR_INVALID_TABLE', 'An invalid or unknown table was specified.'
1629 = 'ERROR_DATATYPE_MISMATCH', 'The data supplied is the wrong type.'
1630 = 'ERROR_UNSUPPORTED_TYPE', 'Data of this type is not supported.'
1631 = 'ERROR_CREATE_FAILED', 'The Windows Installer service failed to start. Contact your support personnel.'
1632 = 'ERROR_INSTALL_TEMP_UNWRITABLE', 'The Temp folder is either full or inaccessible. Verify that the Temp folder exists and that you can write to it.'
1633 = 'ERROR_INSTALL_PLATFORM_UNSUPPORTED', 'This installation package is not supported on this platform. Contact your application vendor.'
1634 = 'ERROR_INSTALL_NOTUSED', 'Component is not used on this machine.'
1635 = 'ERROR_PATCH_PACKAGE_OPEN_FAILED', 'This patch package could not be opened. Verify that the patch package exists and is accessible, or contact the application vendor to verify that this is a valid Windows Installer patch package.'
1636 = 'ERROR_PATCH_PACKAGE_INVALID', 'This patch package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer patch package.'
1637 = 'ERROR_PATCH_PACKAGE_UNSUPPORTED', 'This patch package cannot be processed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.'
1638 = 'ERROR_PRODUCT_VERSION', 'Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs in Control Panel.'
1639 = 'ERROR_INVALID_COMMAND_LINE', 'Invalid command line argument. Consult the Windows Installer SDK for detailed command-line help.'
1640 = 'ERROR_INSTALL_REMOTE_DISALLOWED', 'The current user is not permitted to perform installations from a client session of a server running the Terminal Server role service.'
1641 = 'ERROR_SUCCESS_REBOOT_INITIATED', 'The installer has initiated a restart. This message is indicative of a success.'
1642 = 'ERROR_PATCH_TARGET_NOT_FOUND', 'The installer cannot install the upgrade patch because the program being upgraded may be missing or the upgrade patch updates a different version of the program. Verify that the program to be upgraded exists on your computer and that you have the correct upgrade patch.'
1643 = 'ERROR_PATCH_PACKAGE_REJECTED', 'The patch package is not permitted by system policy.'
1644 = 'ERROR_INSTALL_TRANSFORM_REJECTED', 'One or more customizations are not permitted by system policy.'
1645 = 'ERROR_INSTALL_REMOTE_PROHIBITED', 'Windows Installer does not permit installation from a Remote Desktop Connection.'
1646 = 'ERROR_PATCH_REMOVAL_UNSUPPORTED', 'The patch package is not a removable patch package. Available beginning with Windows Installer version 3.0.'
1647 = 'ERROR_UNKNOWN_PATCH', 'The patch is not applied to this product. Available beginning with Windows Installer version 3.0.'
1648 = 'ERROR_PATCH_NO_SEQUENCE', 'No valid sequence could be found for the set of patches. Available beginning with Windows Installer version 3.0.'
1649 = 'ERROR_PATCH_REMOVAL_DISALLOWED', 'Patch removal was disallowed by policy. Available beginning with Windows Installer version 3.0.'
1650 = 'ERROR_INVALID_PATCH_XML', 'The XML patch data is invalid. Available beginning with Windows Installer version 3.0.'
1651 = 'ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT', 'Administrative user failed to apply patch for a per-user managed or a per-machine application that is in advertise state. Available beginning with Windows Installer version 3.0.'
1652 = 'ERROR_INSTALL_SERVICE_SAFEBOOT', 'Windows Installer is not accessible when the computer is in Safe Mode. Exit Safe Mode and try again or try using System Restore to return your computer to a previous state. Available beginning with Windows Installer version 4.0.'
1653 = 'ERROR_ROLLBACK_DISABLED', 'Could not perform a multiple-package transaction because rollback has been disabled. Multiple-Package Installations cannot run if rollback is disabled. Available beginning with Windows Installer version 4.5.'
1654 = 'ERROR_INSTALL_REJECTED', 'The app that you are trying to run is not supported on this version of Windows. A Windows Installer package, patch, or transform that has not been signed by Microsoft cannot be installed on an ARM computer.'
3010 = 'ERROR_SUCCESS_REBOOT_REQUIRED', 'A restart is required to complete the install. This message is indicative of a success. This does not include installs where the ForceReboot action is run. '
}
}
# Execute msiexec synchronously.
$psInfo = Start-Process -PassThru -NoNewWindow -Wait msiexec -ArgumentList $Args
# Get the exit code.
$ec = $psInfo.ExitCode
# Look up the exit code returned in the hashtable and extract the error *message*.
if ($htErrors[$ec]) {
# Use subscript [0] to extract the *symbolic name* instead.
$errMsg = $htErrors[$ec][1] # -replace '\r'
} else { # not found in table
# See if it's a Windows (system) error code.
# Helper type for getting Windows (system) error messages by error code.
# Returns $null if no message is found.
# Example:
# [net.same2u.pshelper.WinErrMsg]::Get(2) # -> "The system cannot find the file specified."
Add-Type -TypeDefinition #'
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace net.same2u.pshelper {
public static class WinErrMsg {
[DllImport("kernel32.dll")]
static extern int FormatMessage(int dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, System.Text.StringBuilder lpBuffer, int nSize, IntPtr Arguments);
public static string Get(int errCode) {
const int CAPACITY = 512;
const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
StringBuilder sb = new StringBuilder(CAPACITY);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, errCode, 0, sb, sb.Capacity, IntPtr.Zero);
// Remove trailing CRLF
int i = sb.Length;
if (i>0 && sb[i - 1] == 10) i--;
if (i>0 && sb[i - 1] == 13) i--;
sb.Length = i;
return sb.Length > 0 ? sb.ToString() : null;
}
}
}
'#
$errMsg = [net.same2u.pshelper.WinErrMsg]::Get($ec)
# Determine fallback message, if no match was found.
if (-not $errMsg) { $errMsg = "An unknown exit code was reported."}
}
# Set $LASTEXITCODE, so that the caller can inspect the exit code later.
Set-Variable -Scope 1 LASTEXITCODE $ec
# Output the message, suffixed with the exit code.
"$errMsg ($ec)"
}
No, the msi can't replace the Error Code with the message itself.
Like Ansgar Wiechers said the msi was meant to create an log file on each machine you execute it, on the same folder ( e.g. C:\Windows\Temp). With the /l parameters you can modify the output in that file. If you need an comprehensive log you should start with voicewarmupx.
Well an MSI install doesn't always return 1603. The primary reason for a 1603 is a failing custom action where Windows Installer doesn't know why the custom action code failed, and that custom action code was not robust enough to handle its own errors and provide a message before causing the install to fail (and probably roll back). The verbose log should tell you why it failed.
So if it's your MSI you have the opportunity to correct it, otherwise you are at the mercy of the quality of development of the MSI.
Also, your question contains a contradiction: you say you would like the error code ERROR_INSTALL_FAILURE to be returned instead of the exit code, but the 1603 exit code is ERROR_INSTALL_FAILURE.

sqlcmd not showing RESTORE database stats

The following command in a cmd window
sqlcmd -S. -Usa -Ppass -dmaster -Q "RESTORE DATABASE [MYDATABASE] FROM DISK = 'D:\SQL Server\MYDATABASE.BAK' WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 10"
displays the following progress output:
10 percent processed.
20 percent processed.
30 percent processed.
40 percent processed.
50 percent processed.
60 percent processed.
70 percent processed.
80 percent processed.
90 percent processed.
100 percent processed.
Processed 32320 pages for database 'MYDATABASE', file 'MYDATABASE' on file 1.
Processed 7 pages for database 'MYDATABASE', file 'MYDATABASE_log' on file 1.
But it turns that the progress is shown only after the entire restore, turning the stats during the process useless.
Any advice?
Here is the version of sqlcmd tool:
Microsoft (R) SQL Server Command Line Tool
Version 12.0.2000.8 NT
Copyright (c) 2014 Microsoft. All rights reserved.
Update Dec-2016:
Just including the comment from Microsoft Connect link shared in comments:
SQLCMD was rewritten in SQL 2012 to use ODBC. Here is a small
regression error that appears to have sneaked in.
It's the same effect reported when calling RAISERROR('Hello', 0, 1) WITH NOWAIT along a script.
I believe you can look in the SQL logs to see the progress ongoing.
you can query percent_complete in sys.dm_exec_requests
use start to open a separate window and issue a select percent_complete from sys.dm_exec_requests where percent_complete > 0

Return code of scheduled task prefixed with 0x8007000 in list view, registered as 0 in the event log

I am currently trying to setup monitoring of windows scheduled tasks in Zabbix. It seemed easy enough to just monitor the Microsoft-Windows-TaskScheduler/Operational event log filtered by 201 events and regexing on the return code, but when I started simulating errors to test the monitoring, nothing happened.
It turns out that all our windows 2012 servers always log "return code 0" in the event log, even though it actually, sort of, displays it correctly in the Task Scheduler list view. When I say "sort of", it's because the "Last Run Result" actually displays 0x80070001 if the exit code of the program run by the scheduled task is 1.
I have spend a lot of time tweaking the settings, like user account, Run only when user is logged on, Run whether user is logged on or not, setting path on the action, Run with highest privileges, Configure for Vista/7/2012, etc. Nothing helped.
Finally I did some testing on my local machine, Windows 7, and a 2008R2 server, both of which just worked as expected.
The specific task I was testing ran a PowerShell script, using -Command so that it properly propagates the exit, but to rule out any PS issues I also tested with a batch file containing "exit 1" and finally with a small C# console program, that just returns whatever you supply on the command line.
PS, batch and console program all work fine on 7 and 2008, but they all fail in the same manner on 2012.
I've google this to death, but keep coming up short. Apparently 0x80070005 and other similar error codes are have some meaning, but that's not what happens in my case. In my case it seems that my exit code is bitwise or'ed with 0x80070000.
I should note that in all the cases, even 2012, the program started by the task, actually executes and run to the end, it's just the exit code which is handled weirdly.
Following is the output from the test runs:
From Powershell (my shell writes :( if $LASTEXITCODE > 0 ):
54 :( .\ExitCodeTest.exe 1
55 :( $LASTEXITCODE
1
56 :) .\ExitCodeTest.exe 10
57 :( $LASTEXITCODE
10
Windows Server 2008 R2 Standard:
Last Run Result (from list view): 0xA
Event 201 from event log Microsoft-Windows-TaskScheduler/Operational:
Task Scheduler successfully completed task "\ErrorTest" ,
instance "{b67a26cf-7fd8-461a-93d9-a5e48e72e558}" ,
action "D:\Tasks\ExitCodeTest.exe" with return code 10.
Windows Server 2012 Datacenter (notice that the return code in the event log is 0):
Last Run Result (from list view): 0x8007000A
Event 201 from event log Microsoft-Windows-TaskScheduler/Operational:
Task Scheduler successfully completed task "\error test" ,
instance "{2bde46b8-2858-4772-a7ec-d66b29d893a6}" ,
action "D:\Tasks\ExitCodeTest.exe" with return code 0.
Source for ExitCodeTest.exe:
static void Main( string[] args )
{
int exitCode = 0;
if ( args.Length > 0 )
{
exitCode = Convert.ToInt32( args[0] );
}
Environment.Exit( exitCode );
}
Please help, I am at my wits end.
Thanks,
John
(this is NOT an answer, but StackOverflow is refusing to let me add comments - when I click 'add comment', browser scrolls to top of page :-/)
You may be misinterpreting the Last Run Result column. According to Wikipedia (http://en.wikipedia.org/wiki/Windows_Task_Scheduler), LRR values of 0, 1 and 10 are common. Ignore the 0x8007 prefix - this just indicates a WIN32 error code transformed into an HRESULT (http://msdn.microsoft.com/en-us/library/gg567305.aspx).
Try running the test and forcing an exit code of something other than 1 or 10 to see if this influences LRR.
This does not explain of course why action return code is 0 in 2012. Error code 10 is defined as 'environment is incorrect'. Could it be that 2012 server does not want to run 32bit executable?
One other suggestion (and I'm a little out of my depth); according to (http://msdn.microsoft.com/en-us/library/system.environment.exit(v=vs.110).aspx): "Exit requires the caller to have permission to call unmanaged code. The return statement does not.". Might be worth re-compiling ExitCodeTest as follows:
static int Main(string[] args)
{
int exitCode = 0;
if ( args.Length > 0 )
{
exitCode = Convert.ToInt32( args[0] );
}
return exitCode;
}
I'm seeing a similar issue on Server 2012 with a batch file that looks like it succeeds, shows a return value of 0 in event log, but a Last Run Result of 0x80070001.
I see MSFT has a hotfix available for Server 2012 which might address this issue:
http://support.microsoft.com/kb/3003689
I had this problem and fixed it this way.
Instead of calling a batch file move the commands into the actions section of the scheduled task.
I realize this may not work for you as some batch files are long.
I suspect it has to do with circumventing security on a scheduled task -- if you can change the batch file then you could get a scheduled task to run as the identity without windows being the wiser.