Powershell ScheduledTask to report error - powershell

So if we use the following to create a scheduled task in powershell
Register-ScheduledJob -Name TestJob3 -ScriptBlock {
throw "This is an ugly error that should be visible"
} -Credential $cred
...and then run this task.
The task scheduler reports success.
So we can slightly improve on this by changing the scriptblock to something like the following
try{
throw "This is an ugly error that should be visible"
} catch {
Exit -1
}
Now if you look very carefully you can see that the task scheduler is reporting a last run result of something other than 0 (0xFFFFFFF).
However all we have in the history tab is bunch of infomation logging saying that the task and action have completed.
What I would really like is to get some big loud exception level logging in the history view preferably with the nice descriptive error that has been thrown.
Anyone know how this can be achieved?

Unfortunately, it looks like Task Scheduler doesn't respect exit codes. As far as it is concerned, running the program and seeing it exit is a success. So logging your exceptions will probably need to be done either manually or through Write-EventLog.
Out of curiosity, since this is a ScheduledJob instead of a ScheduledTask, does running Get-ScheduledJob show that the job completed without errors also?

Related

How can I change the default PowerShell error for when a command needs elevation?

I have a lot of code in a PowerShell script that are mix of commands that need elevation to run and commands that don't, those that need elevation show errors in PowerShell console like:
"You don't have enough permissions to perform the requested operation"
and
"Requested registry access is not allowed."
is there a way to globally suppress only the kinds of errors that PowerShell shows due to lack of necessary privileges?
I thought about a function that checks for elevation and performs actions based on the result, like this:
https://devblogs.microsoft.com/scripting/use-function-to-determine-elevation-of-powershell-console/
Function Test-IsAdmin
{
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal $identity
$principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}
and
if(-NOT (Test-IsAdmin))
{ write-host "Skipping Admin command" }
else { $code }
but I don't know how to apply it globally to the whole script, so that commands that don't need elevation run, and those that need elevation show a custom message or skip that part silently.
another thing that can help my situation would be to find out if a PowerShell command needs elevation before actually running it and causing it to show errors in console due to lack of privileges.
It seems that errors stemming from a lack of privileges typically - but not necessarily - involve a System.UnauthorizedAccessException or System.Security.SecurityException .NET exception behind the scenes, whose name is then reflected as part of the .FullyQualifiedErrorId property of the resulting PowerShell error record, which is of type System.Management.Automation.ErrorRecord.
Assuming that this applies to all errors you care about, you can use a (rarely used anymore) trap statement as follows:
trap {
if ($_.FullyQualifiedErrorId -match 'UnauthorizedAccessException|SecurityException') {
Write-Warning "Skipping admin command ($($_.InvocationInfo.Line.Trim()))"
continue # Suppress the original error and continue.
}
# If the error was created with `throw`, emit the error and abort processing.
# SEE CAVEAT BELOW.
elseif ($_.Exception.WasThrownFromThrowStatement) { break }
# Otherwise: emit the error and continue.
}
# ... your script
Caveat:
If your script implicitly raises script-terminating errors - via -ErrorAction Stop or $ErrorActionPreference = 'Stop' - the above solution in effect turns them into statement-terminating errors and continues execution (only explicit script-terminating errors created with a throw statement are recognized as such in the code above, and result in the script getting aborted).
Unfortunately, as of PowerShell 7.2.x, there is no way to generally discover whether a given error is (a) non-terminating, (b) statement-terminating or (c) script-terminating (fatal).
See GitHub issue #4781 for a proposal to add properties to [System.Management.Automation.ErrorRecord] to allow such discovery in the future.

Powershell 5.1 Workflow not retrying

I'm trying to learn Workflows to process some long running steps. I have to use Powershell 5.1 for various reasons. I really like what I've learnt so far, Workflows can definitely reduce the amount of PS code you have to create. One thing that I'm really stuck on is the retry parameter :
InlineScript {
Write-Output "test"
0/0
} -PSComputerName $computer -PSConfigurationName "testuser" -PSActionRetryCount 3 -PSActionRetryIntervalSec 5
Without writing some additional code or using jobs. Can anybody give me some pointers as to why this is failing. I'm trying to force an error but the Workflow just seems to hang and then not retry for a 2nd time.
Thanks!

Powershell try block not working on VSTS build

I'm running a command in Powershell through VSTS to affect Azure. The command works, but it gives an error after. The params and connection are working as evidenced by the fact that the group gets permission from the command. I figure a workaround is to put the command in a try block, have it run, and then when the error comes up go to the catch block and end without throwing the error.
When I run this script, I still get the same error, like the try block is ignored. Do I have the syntax wrong?
Try
{
New-AzureRmRoleAssignment -ObjectId "xxxx" -RoleDefinitionName $roleName -ResourceGroupName pentest-$featureName
}
Catch
{
Write-Output "Whoops"
}
Edit: I added $ErrorActionPreference = "Stop" before the try-block and it caught the error properly.
The try block was ignored because of the wrong $ErrorActionPreference. Changing it from "Continue" to "Stop" fixed it.

Script stops execution when faces an error

I have a master script master.ps1 which calls two scripts One.ps1 and Two.ps1 like:
&".\One.ps1"
&".\Two.ps1"
When the One.ps1 script has an error, the execution gets stopped without continuing the execution of Two.ps1
How to continue execution of Two.ps1 even if there is an error in One.ps1?
You have to set the $ErrorActionPreference to continue:
Determines how Windows PowerShell responds to a non-terminating
error (an error that does not stop the cmdlet processing) at the
command line or in a script, cmdlet, or provider, such as the
generated by the Write-Error cmdlet.
You can also use the ErrorAction common parameter of a cmdlet to
override the preference for a specific command.
Source.
$ErrorActionPreference = 'continue'
Note: As a best practice I would recommend to first determine the current error action preference, store it in a variable and reset it after your script:
$currentEAP = $ErrorActionPreference
$ErrorActionPreference = 'continue'
&".\One.ps1"
&".\Two.ps1"
$ErrorActionPreference = $currentEAP
#Martin is correct assuming that the success or failure of .\One.ps1 does not impact .\Two.ps1 and if you don't care about logging or otherwise dealing with the error. but if you would prefer to handle the error rather than just continue past it you could also use a Try{}Catch{} block as below to log the error (or take any other action you would like in the Catch{})
Try{
&".\One.ps1"
} Catch {
$error | Out-File "OneError.txt"
}
Try{
&".\Two.ps1"
} Catch {
$error | Out-File "TwoError.txt"
}
Other ways to format this but you get the idea.

Jenkins powershell plugin always builds successfully

I'm using Jenkins PowerShell plugin to build a project.
However, I found that Jenkins always considers my build successful no matter what I type inside Windows PowerShell command.
Here's an example:
As you can see, asdf isn't a legal command. Jenkins should give me FAILURE after the build.
But the console output gives me:
Started by user admin
Building in workspace C:\Users\Administrator\.jenkins\jobs\Test\workspace
[workspace] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Users\ADMINI~1\AppData\Local\Temp\hudson2092642221832331776.ps1'"
The term 'asdf' 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.
At C:\Users\ADMINI~1\AppData\Local\Temp\hudson2092642221832331776.ps1:1 char:5
+ asdf <<<<
+ CategoryInfo : ObjectNotFound: (asdf:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Finished: SUCCESS
I think the execution result of PowerShell should depend on $lastexitcode.
Is this a bug of PowerShell plugin?
As of 1.3, the plugin will not handle exceptions such as those from missing commands. You can do this yourself with try/catch:
try
{
asdf
}
catch
{
write-host "Caught an exception"
exit 1
}
See MSDN for more.
For me, I wanted the script to stop and fail in Jenkins soon as it hit an error. This was accomplished by adding this to the start of the script:
$ErrorActionPreference = "Stop"
This is discussed here: [How to stop a PowerShell script on the first error?][1]
[1]: How to stop a PowerShell script on the first error?. ..................
Per the latest version of the plugin (Version 1.3 Sept 18 2015), you must use $LastExitCode to fail a build.
Version 1.3 (Sept 18 2015)
PowerShell now runs in Non-Interactive mode to prevent interactive prompts from hanging the build
PowerShell now runs with ExcecutionPolicy set to "Bypass" to avoid execution policy issues
Scripts now exit with $LastExitCode, causing non-zero exit codes to mark a build as failed
Added help and list of available environment variables (including English and French translations)
I want to add here that I just ran into a quirk: you must have the powershell script end with exit and not return.
My jenkins pipe looked like:
script {
result = powershell(returnStatus: true, script: '''...if(error condition) { return 1 }''')
if(result) { error }
}
I was using if(error condition) { return 1 } and while the 1 was showing up as the return value in the jenkins console, it was not failing the build. When i used if(error condition) { exit 1 }, the build failed as expected.
I think this is a helpful addition to this thread - the need to use exit and not return. But I don't understand this part: the pipe is checking for result to be non-zero. What is the difference between exit and return in a powershell directive that makes if(result) { error } not work as expected when using return?
Update Feb-16-2021: Coming back to this to add some more notes from my experience: I think what I was doing and what a lot of people do that confuses things, is to use returnStdout or returnStatus and not check them and/or not fully understand what's coming back.
If you use either of those params, Jenkins will not do anything for you based on their value. You have to check them yourself and act accordingly. On the other hand, if you don't use them, Jenkins will recognize a failure code and fail the pipe if one comes back.
Think about it: If you set returnStatus, you're getting the exit code back from the step as a return value and not as something for Jenkins itself to worry about. If you set returnStdout, you're getting the stdout stream - and not any error codes or anything from stderr. So you must check the return for what you want or you will not get the behavior you are expecting.
What I've been doing for a while is actually not setting either of those params and making sure to set $ErrorActionPreference = 'Stop' at the start of any and all PowerShell scripts running in my pipes. That way any powershell failures automatically fail the pipe as expected, without having to check it.
This is how I implemented RRIROWER's solution. Hope it helps.
<yourscript>.ps1; exit $lastexitcode
Make sure your powershell scripts does exit with the desired value.
Run "exit <value>" as the last line.
Ultimately, I had to resort to the following configuration in Jenkins as none of the solutions here worked for me. Chris Nelson's answer got me on the right track. We're invoking chef-client remotely so we had to do a little magic to get the remote PS session to talk the local and then pass status on to Jenkins.
$res gives the output of chef-client.
$lastsuccess is true or false according to PS rules of engagment.
Of course, you'll have to supply your own evironment variables! :)
Write-host "Deploying $env:Computer with $env:Databag data bag... "
$secstr = ConvertTo-SecureString $env:Password -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $env:User, $secstr
$s = New-PSSession -ComputerName $env:Computer -Credential $cred
$res = Invoke-Command -Session $s -ScriptBlock { try {chef-client} catch {exit 1}}
$lastsuccess = Invoke-Command -Session $s -ScriptBlock {$?}
Remove-PSSession $s
write-host " --- "
write-host $res
write-host " --- "
if($lastsuccess)
{
write-host "chef deployment completed"
exit 0
}
write-host "chef deployment had errors"
exit 1