Absolutely deplorable that Digi doesn't supply a tool for flashing the programmable XBee. What? They think in a production environment we are going to let assembly personnel fire up CodeWarrior and bit bang 50000 XBees? Digi! Pull your head out!
Fortunately, XMODEM is a reasonably simple protocol and IggMoe has published a fine bit of C# code for it on the GHIElectronics Community website. Web search for "XMODEM_FullDotNET site:ghielectronics.com". You can embed his C# code in the following PowerShell wrapper and you are good to go:
$Source = @"
<IggMoes Code Goes Here - change the namespace to match the one in the New-Object statement>
"@
Add-Type -TypeDefinition $Source -Language CSharp
$myCom = [System.IO.Ports.SerialPort]::GetPortNames()[0]
#$Port = New-Object System.IO.Ports.SerialPort($myCom,115200,'None',8,1)
$XModem = New-Object XbeeXmodemNS.XMODEM_FullDotNET( $myCom,'XModemCRC')
$Port = $XModem.Port
$Port.BaudRate = 115200
$Port.Parity = 'None'
$Port.DataBits = 8
$Port.StopBits =1
$Port.ReadTimeout = 100
$Port.WriteTimeout = 100
$Port.Open()
$Port.RtsEnable = $false
$Port.DtrEnable = $true
$Port.BreakState = $true
$cr = Read-Host "Reset target and press Return"
# Clear break (takes a few seconds)
$Port.BreakState = $false
Start-Sleep -Seconds 3
# Send return
$Port.WriteLine('')
for ($i=1;$i -lt 10;$i++) {
if ( $Port.BytesToRead -gt 0 ) { $Port.ReadExisting();}
Start-Sleep -Milliseconds 50;
}
# Send 'F' wait for 'C'
$Port.Write('F')
for ($i=1;$i -lt 10;$i++) {
if ( $Port.BytesToRead -gt 0 ) {
$C = $Port.ReadExisting();
}
if ($C = 'C') {
break;
}
Start-Sleep -Milliseconds 50;
}
# Load and send the file
$Filename = '

\Work\XbeeXmodem\WMLCv6.5.abs.bin'
$Data = [System.IO.File]::ReadAllBytes($Filename)
Write-Host "Starting XMODEM, sending " $Data.LongLength "bytes"
$BytesSent = $XModem.Send($Data);
if ($BytesSent -eq $Data.LongLength) {
Write-Host "File was successfully sent."
} else {
Write-Host "Error!! File upload failed!"
}
$Port.Close()