Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell bitwise comparison for robocopy exit codes

I can't get my head around this bitwise conversion problem.

Robocopy exit codes don't conform to the normal 0(success), 1(failure) pattern so I want to wrap my robocopy calls in the powershell script below to make my TeamCity build configurations fail or proceed appropriately when robocopy terminates.

That first part was solved using a tip from the net with: ($LastExitCode -band 24) which correctly treats exit codes 8 through 16 as failures (1) and all others as success (0).

Now I want to echo a message corresponding to the exit code. How do I convert and round/floor the integer exit code (0 - 16) to its hexadecimal equivalent (0x00 - 0x10)?

param(
    [string] $source,
    [string] $target,
    [string[]] $action = @("/MIR"),
    [string[]] $options = @("/R:2", "/W:1", "/FFT", "/Z", "/XA:H")
)
$cmd_args = @($source, $target, $action, $options)
& robocopy.exe @cmd_args
$returnCodeMessage = @{
    0x00 = "[INFO]: No errors occurred, and no copying was done. The source and destination directory trees are completely synchronized."
    0x01 = "[INFO]: One or more files were copied successfully (that is, new files have arrived)."
    0x02 = "[INFO]: Some Extra files or directories were detected. Examine the output log for details."
    0x04 = "[WARN]: Some Mismatched files or directories were detected. Examine the output log. Some housekeeping may be needed."
    0x08 = "[ERROR]: Some files or directories could not be copied (copy errors occurred and the retry limit was exceeded). Check these errors further."
    0x10 = "[ERROR]: Usage error or an error due to insufficient access privileges on the source or destination directories."
}
Write-Host $returnCodeMessage[($LastExitCode <what goes here?>)]
exit ($LastExitCode -band 24)
like image 307
grenade Avatar asked Oct 21 '22 15:10

grenade


2 Answers

In your case you do not need to convert it. You do not need conversion because Hashtable keys are converted to [int] on pre-compiation stage. If you lookup for $returnCodeMessage.Keys , you will see decimal numbers, not hex numbers

To display all messages you should use

$exitcode = $LastExitCode    
Write-Host $( @( $returnCodeMessage.Keys | Where-Object { $_ -band $exitcode } | ForEach-Object {return $returnCodeMessage[$_]}   ) -join "`r`n")

IF you want to show Hex-encoded $LastExitCode, do

$exitcode = $LastExitCode
Write-Host $('0x' + [System.Convert]::ToString([int]$exitcode,[int]16) )
return $exitcode

String System.Convert.ToString(Int32, Int32)

like image 80
filimonic Avatar answered Nov 03 '22 05:11

filimonic


As filimonic mentioned, 0x10 and 16 are just different ways of writing the same underlying numeric value (i.e. 0x10 -eq 16 evaluates to true), so no conversion is needed.

To display each message in the combined return code, you can test each of the individual flag values in turn:

if( $returnCodeMessage.ContainsKey( $LastExitCode ) ) {
    $returnCodeMessage[$LastExitCode]
}
else {
    for( $flag = 1; $flag -le 0x10; $flag *= 2 ) {
        if( $LastExitCode -band $flag ) {
            $returnCodeMessage[$flag]
        }
    }
}

For a return code like 0x00 (no change) or 0x04 (mismatch) that contains only one message, we look it up directly. Otherwise, for a composite code like 0x09 (some copied, some not) or 0x13 (some copied, some extras, access denied), we check for each possibility and output those that match.

Also, since "Any value greater than 8 indicates that there was at least one failure during the copy operation", you could use $LastExitCode -ge 8 instead of $LastExitCode -band 24 to test for errors.

like image 44
Emperor XLII Avatar answered Nov 03 '22 03:11

Emperor XLII