1

I have the following code:

$ExitCode = Get-Random -InputObject 0, 1

Exit $ExitCode

It seems to always return 0 as an exit code.

I don't know if I have coded the exit wrong or if Get-Random does not allow setting it to a variable.

All the samples I see on the internet of Get-Random have it printing to the console.

How do I get the code to exit with a random 0 or 1?

[EDIT] I am beginning to think the problem is with the Exit.

I coded this:

$ExitCode = Get-Random -InputObject 0, 1
#Exit $ExitCode
Exit 1

and I still get exit code 0. I am running this script from VisualCron. So it could also be VisualCron mucking with the exit code. I have run it at least 12 times I don't think Get-Random could be returning 0 every time.

mklement0
  • 382,024
  • 64
  • 607
  • 775
Be Kind To New Users
  • 9,672
  • 13
  • 78
  • 125
  • 1
    with such a TINY range ... you are just getting a random selection that happens to be `0`. [*grin*] i tried your code and am getting lots of `1` and only a few `0` so far - about 5 to 1. ///// as an aside, you may want to _explicitly_ give the cmdlet a collection by using `@(0, 1)` OR `0..1`. that is only for readability, tho, so use what fits your style. – Lee_Dailey May 12 '19 at 00:19

2 Answers2

1

It seems to always return 0 as an exit code.

No: With just 2 possible random values, it's not uncommon to receive the same value multiple times in a row.

In other words: your code intrinsically works fine, it may just be surprising that the same value can be reported multiple times in a row.

However, independently, the actual exit code may get lost, depending on how your script is invoked via the PowerShell CLI, which is what VisualCron also allows you to use - see bottom section.

You can verify that you'll eventually get both values with the following snippet, which prints the - randomly varying - number of iterations until both values have been returned:

$count = 0
$have0 = $have1 = $false
do {
  ++$count
  $val = Get-Random -InputObject 0, 1
  if ($val -eq 0) { $have0 = $true }
  else            { $have1 = $true }
  if ($have0 -and $have1) { break }
} while ($true)
"Both 0 and 1 returned after $count attempts."

You'll typically see values in the single-digit range, i.e., fewer than 10 invocations.


Exit-code reporting when the PowerShell CLI is used:

The problem is that the PowerShell CLI (calling powershell.exe with arguments) doesn't always pass a script's exit code value through, depending on how it was invoked:

  • If you use -File to invoke the script (which you should, if all you do is invoke a single script), the script's exit code - assuming it is explicitly set with exit - is properly passed through (reported as powershell.exe's exit code.

  • By contrast, if you use -Command (-c), it is the success status - as PowerShell internally reflected in the automatic $? variable - of the last command or expression that is reported, which has the following implications:

    • If invocation of your script is the last command passed to -Command, its exit code gets mapped onto 0 or 1; that is, 0 is passed through, but any nonzero value is reported as 1.

    • If invocation of your script is not the last command, it is that last command's success status that determines the overall exit code (again, 0 or 1); note that something as subtle as enclosing your script invocation in (...) makes it no longer the last command in versions up to 6.x.

See this answer for additional information.

Therefore, to ensure that your script's exit code set with exit <n> is passed through:

  • Use -File, if possible.

  • If you must use -Command, because additional commands must be executed:

    • append ; exit $LASTEXITCODE to your -Command argument (which you would also do if you called an external program whose exit code you wanted to pass through).

    • alternatively, as in your own answer, you can use throw inside your script to force reporting of exit code 1, but note that throw aborts processing instantly, so that the remaining commands passed to -Command are then not executed.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

This modification served my purpose:

$ExitCode = Get-Random -InputObject 1, 0

if ($ExitCode -ne 0) {
    Throw "exit code is other than 0"
}

Exit 0

The problem was that powershell itself returns 0 or 1. 1 if the script threw an exception, and 0 if the script did not throw an exception. The purpose of this script is to simulate scripts failing so we can test our monitoring system, so throwing an exception is just fine for my purposes.

Out of a sense of fair play I don't accept my own answers until I give a good chance for others to answer. If a newbie wants to copy my answer and add something to it please do and I will accept your answer and delete mine.

Be Kind To New Users
  • 9,672
  • 13
  • 78
  • 125
  • To summarize: The `Get-Random` part of your question is a red herring, and `Get-Random` works as expected. The - unrelated - problem is how the PowerShell CLI relays exit codes from scripts. Using `Throw` rather than `exit` forces PowerShell to report exit code `1`, but there are better alternatives to modifying your script - I've updated my answer to show them, and to discuss the logic of exit-code reporting in general. In their present form your question focuses on the red herring, and your answer doesn't address that aspect, and neither does it explain why `Throw` makes a difference. – mklement0 May 12 '19 at 13:12
  • @mklement0 I am going to check your answer as correct. My problem is that I am invoking powershell from a job controller and I don't know how to invoke it as tho it is done with the --File. I will ask the VisualCron support people for guidance but I my answer works for my very constrained case. – Be Kind To New Users May 12 '19 at 14:03
  • Thanks; your answer does work, but modifying your script shouldn't be necessary. I'm not familiar with VisualCron; are you saying that _it_ constructs the call to `powershell.exe` behind the scenes? You can try the `; exit $LASTEXITCODE` technique from my answer. – mklement0 May 12 '19 at 14:08
  • 1
    visualcron seems to run powershell from in internally linked version of powershell. They also allow external commands to be run, which I could use the --File scheme. I will do that for other scripts I want to run. The purpose of this particular code is to return a random failure so we can see our monitoring system is detecting failures. So this is just throw away script anyway. – Be Kind To New Users May 12 '19 at 14:58