Monthly Archives: February 2016

Decoding Robocopy Exit Codes

Sometimes, you write a script that uses robocopy to copy or move files around efficiently, and you need to confirm that no errors occurred during robocopy’s run. Unfortunately, robocopy doesn’t use the standard error return mechanism of 0 for no errors and 1 (or some other non-zero number) if an error occurred. Microsoft documents robocopy exit codes in KB 954404, but the information isn’t complete. A better explanation can be found in a Deployment Guys blog post and shows that the exit codes are bitmapped:

Code Meaning
0 No errors occurred and no files were copied.
1 One of more files were copied successfully.
2 Extra files or directories were detected.  Examine the log file for more information.
4 Mismatched files or directories were detected.  Examine the log file for more information.
8 Some files or directories could not be copied and the retry limit was exceeded.
16 Robocopy did not copy any files.  Check the command line parameters and verify that Robocopy has enough rights to write to the destination folder.

These codes are combined to give a complete indication of the results of the run. For example, if the exit code is 3, that indicates that files were copied successfully and that extra files or directories were detected (1 + 2 = 3). The important conclusion is to note that any return code with 0x8 or 0x16 set indicates that some or all of the files were not copied.

To decode these exit codes in Powershell, use the bitwise and operator –band to test for the bits we are interested in. In binary, the important bits are 011000, which converts to decimal 24. So, you can do your robocopy operation like this:

$cmd_args = @($source, $target, $action, $options)
& robocopy.exe @cmd_args
If ($LastExitCode -band 24) {
    Write-Host “Everything is OK”
 } else {
    Write-Host “Errors happened”
}

					

Using the .Net RNGCryptoServiceProvider in Powershell

I was working on a password generator function, and I wanted to use something that was a better random number generator than Powershell’s Get-Random cmdlet. I’m not a crypto expert, so I’ll leave the discussions about how good each random number generator is, but Matt Graeber wrote a nice article that discusses how to test the effectiveness of a random number generator. According to Matt’s testing, the RNGCryptoServiceProvider class is a better random number generator that Powershell’s Get-Random for cryptographic purposes. I liked the way Get-Random worked, so I decided to implement a function that worked in a similar manner. Note, Get-Random works two ways: it either returns a random number or returns a random object from a collection of objects. This implementation only returns a random number.

RNGCryptoServiceProvider implements a GetType method that is passed an array of bytes and returns it filled with random byte values. The trick here is, that I want to return a single unsigned 32 bit integer but GetType returns an array of bytes. I need to use the System.BitConverter .NET class to convert an array of bytes to a single uint32 value. The other challenge I ran into is how to implement minimum and maximum values. I decided to use the mod operator to return a value in the range I need.

Here is the function I came up with:

Function Get-RandomInt {
    [cmdletbinding()]
    Param(
        [uint32]$max=[UInt32]::MaxValue,
        [uint32]$min=[UInt32]::MinValue
    )
    if ($min -lt $max) {
        #initialize everything
        $diff=$max-$min+1
        [Byte[]] $bytes = 1..4  #4 byte array for int32/uint32
        $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
        #generate the number
        $rng.getbytes($bytes)
        $number = [System.BitConverter]::ToUInt32(($bytes),0)
        $number = $number % $diff + $min
        return $number    
    } else {
        Write-Warning 'Min must be less than Max'
        return -1
    }
}

Use it like this:

Get-RandomInt -min 1 -max 100

to get a random number between 1 and 100.

 

…Tim