Checks the installed firmware version, or uploads and installs a firmware image, across a list of Raritan PDU IPs.
- What it does
- What it does not do
- How --check works
- How --update works
- Same-version and downgrade protection
- Requirements
- Windows setup
- The IP list file
- Password
- Usage
- Command-line options
- Common results
- Troubleshooting
- Exit codes
- A note on Ctrl+C during --update
- Safety notes
- Source references
This script has two modes, exactly one of which must be given:
| Flag | Behavior |
|---|---|
--check |
Read-only. Reports the currently installed firmware version. |
--update |
Uploads a firmware image and installs it. |
- Does not change the admin password (see
bootstrap_pdu_passwords.py) - Does not turn outlets on or off
- Does not change network settings
- Does not configure SNMP, syslog, NTP, DNS, users, roles, or names
- Does not create or delete accounts
- Does not automate firmware downgrades — see Same-version and downgrade protection
For each PDU:
- Log in as
admin. - Read the currently installed firmware version.
- Report
OK - firmware=<version>.
Nothing is uploaded and nothing changes. --dry-run has no effect here (it only applies to --update) and the script will warn you if you combine them.
For each PDU:
- Log in and read the current firmware version.
- If
--dry-run, stop here and reportOK - would_update; current=<version>; image=<path>— no file is uploaded. - Upload the image file to the PDU.
- Read the PDU's own assessment of the image:
version,valid,compatible,product,platform,min_required_version,min_downgrade_version. - Reject invalid or incompatible images. If the PDU reports the image as not valid, or not compatible with this specific device, the image is discarded and the update is never started — reported as an
ERROR. - Skip same-version images by default — see below.
- Reject downgrade-looking images — see below.
- If the version can't be compared from the version strings, the script proceeds anyway (logged as a warning), since the image was already confirmed valid and compatible in step 5.
- Start the update and poll the PDU's firmware update status until it reports success, failure, or a timeout. The PDU reboots during this window, so temporary communication failures here are expected and only logged at debug level.
- After success, wait for the management interface to respond again and confirm the new version.
- Report
OK - changed; old=<version>; image_version=<version>; new=<version>.
The script compares the version number in the uploaded image against the currently installed version (e.g. 4.3.13 or 4.3.13-52884):
| Comparison | Behavior |
|---|---|
| Same version | Skipped by default, reported as OK - skipped_same_version. Use --allow-same-version to install anyway. |
| Image is older (downgrade) | Always treated as a failure — there is no flag to override this. Downgrades are intentionally not automated by this script. If you need to downgrade a PDU, do it manually per Raritan's guidance. |
| Can't be determined | The script proceeds, since the PDU itself already confirmed the image is valid and compatible. |
- Python 3.8+
- The
raritanPython package:pip install raritan - HTTPS access (usually TCP 443) from your machine to each PDU's management interface
- The current admin password for the PDUs
- A
pdus.txtfile listing the PDU IPs - For updates: the correct firmware image file (
.bin) for your PDU model
- Install Python. Download from python.org/downloads and run the installer, enabling Add python.exe to PATH if offered. (Alternatively, the Python install manager via
winget install 9NQ7512CXL7Tor the Microsoft Store also works.) - Open PowerShell. A normal user window is fine; you don't usually need Administrator.
- Confirm Python works:
If that doesn't work, try
py --versionpython --version. At least one should succeed. - Create a working folder and put the script (and firmware image, if updating) there:
mkdir C:\pdu-firmware cd C:\pdu-firmware
- Create
pdus.txt(see The IP list file below). - Create and activate a virtual environment:
If PowerShell blocks activation with an execution-policy error:
py -m venv .venv .\.venv\Scripts\Activate.ps1Your prompt should now start withSet-ExecutionPolicy -Scope CurrentUser RemoteSigned .\.venv\Scripts\Activate.ps1
(.venv). - Install the Raritan package:
python -m pip install --upgrade pip python -m pip install raritan python -c "import raritan.rpc; print('raritan import OK')"
Default filename: pdus.txt, one PDU management IP per line, in the same folder you run the script from (unless you pass --ips).
notepad .\pdus.txt# Example group of PDUs
10.10.5.10
10.10.5.11
10.10.5.12
Blank lines are ignored. Lines starting with # are ignored. Duplicate IPs are skipped automatically.
The script needs one password: the current admin password. It can be supplied three ways, in order of preference:
- Typed at an interactive prompt (safest)
- The
PDU_ADMIN_PASSWORDenvironment variable --passwordon the command line (supported, but visible in shell history — avoid unless you have a specific reason)
Use an environment variable to avoid retyping it:
$env:PDU_ADMIN_PASSWORD = "your-current-password"
python .\bootstrap_pdu_firmware.py --ips .\pdus.txt --checkThis only applies to the current PowerShell session — close the window when done, and avoid this while screen-sharing or recording.
Step 1 — check current firmware (always read-only, no risk):
python .\bootstrap_pdu_firmware.py --ips .\pdus.txt --check -v2026-07-04 10:12:04 INFO Processing 1 PDU(s) [CHECK, concurrency=1, verify_cert=False]...
2026-07-04 10:12:05 INFO 10.10.5.137: OK - firmware=4.3.0.5-51180
2026-07-04 10:12:05 INFO Done. OK=1 Failed=0
Step 2 — dry-run the update (no file is uploaded, nothing changes):
python .\bootstrap_pdu_firmware.py --ips .\pdus.txt --update --image .\pdu-firmware.bin --dry-run -v2026-07-04 10:20:11 INFO Processing 1 PDU(s) [UPDATE DRY RUN, concurrency=1, verify_cert=False]...
2026-07-04 10:20:12 INFO 10.10.5.137: OK - would_update; current=4.3.0.5-51180; image=.\pdu-firmware.bin
2026-07-04 10:20:12 INFO Done. OK=1 Failed=0
The line to look for: <IP>: OK - would_update.
Step 3 — live update. This takes noticeably longer than a password change — the script uploads the image, waits for the PDU to validate it, starts the update, and polls until it reports success or failure. The PDU reboots during this, so it can take several minutes per PDU. Don't close PowerShell or disconnect the network while this runs.
python .\bootstrap_pdu_firmware.py --ips .\pdus.txt --update --image .\pdu-firmware.bin -v --log-file .\pdu-firmware.log2026-07-04 10:30:02 INFO Processing 1 PDU(s) [UPDATE LIVE, concurrency=1, verify_cert=False]...
2026-07-04 10:30:03 INFO 10.10.5.137: current firmware=4.3.0.5-51180; uploading image=.\pdu-firmware.bin
2026-07-04 10:30:07 INFO 10.10.5.137: uploaded image info - version=4.3.13; valid=True; compatible=True; ...
2026-07-04 10:30:07 INFO 10.10.5.137: starting firmware update from 4.3.0.5-51180 to 4.3.13
2026-07-04 10:30:17 INFO 10.10.5.137: update status - state=UPDATE
2026-07-04 10:34:52 INFO 10.10.5.137: update status - state=SUCCESS
2026-07-04 10:35:10 INFO 10.10.5.137: OK - changed; old=4.3.0.5-51180; image_version=4.3.13; new=4.3.13
2026-07-04 10:35:10 INFO Done. OK=1 Failed=0
The line to look for: <IP>: OK - changed.
Step 4 — rerun safely, any time. If a PDU already has the image version installed, it reports OK - skipped_same_version — this is expected, not a problem. Use --allow-same-version if you specifically want to reinstall the same version anyway.
Recommended rollout process:
- Put one test PDU in
pdus.txt. --checkits current firmware.--update --dry-runit.- If that looks good, run the live update.
- Confirm the new version with
--check. - Add the remaining PDU IPs to
pdus.txt. - Check → dry-run → live-update again for the full batch.
- Save the log file for your records.
Other common commands:
# Different IP list file
python .\bootstrap_pdu_firmware.py --ips .\my-pdus.txt --check
# Longer timeout for slow networks
python .\bootstrap_pdu_firmware.py --ips .\pdus.txt --check --timeout 30Keep --concurrency 1 (the default) for first use, and generally for firmware updates — an interrupted or failed update on one PDU is a bigger operational concern than an interrupted password change.
| Flag | Default | Description |
|---|---|---|
--check |
— | Read-only firmware version check. Required unless --update is used; can't combine with it |
--update |
— | Upload and install a firmware image. Required unless --check is used; can't combine with it; requires --image |
--ips PATH |
pdus.txt |
IP list file |
--image PATH |
none | Firmware image file to upload. Required with --update; unused with --check |
--password PASSWORD |
(env/prompt) | Admin password. Supported but not recommended on the CLI — can appear in shell history |
--timeout SECONDS |
10 |
Timeout for ordinary API calls (login, reading version, etc.) |
--update-timeout SECONDS |
1800 (30 min) |
Max time to wait for the update itself to report success/failure |
--availability-timeout SECONDS |
600 (10 min) |
Max time to wait for the PDU to respond again after it reboots post-update |
--poll-interval SECONDS |
10 |
How often to check update status while waiting |
--concurrency NUMBER |
1 |
Number of PDUs processed in parallel. Invalid values like 0 or negative numbers are blocked |
--dry-run |
off | For --update: check connectivity/current version only, no upload or install. No effect with --check |
--allow-same-version |
off | Install even if the image version matches what's currently installed |
-v, --verbose |
off | Debug logging |
--log-file PATH |
none | Also write logs to this file |
--no-insecure |
— | Require valid, trusted HTTPS certificates |
--insecure |
on by default | Disable HTTPS certificate verification (default, since most PDUs use self-signed certs) |
| Result | Meaning |
|---|---|
OK - firmware=<version> |
--check mode: currently installed version |
OK - would_update |
--update --dry-run: reports current version and the image that would be uploaded; nothing changed |
OK - changed |
Update completed, confirmed successful, new version confirmed afterward |
OK - skipped_same_version |
Image version matched what's installed; discarded, nothing installed |
ERROR - uploaded firmware image is not valid |
PDU rejected the file as an invalid firmware image |
ERROR - uploaded firmware image is not compatible with this device |
PDU accepted the file as valid, but it's not compatible with this specific model |
ERROR - uploaded firmware image appears older than installed firmware |
Looked like a downgrade — discarded; this script never automates downgrades |
ERROR - firmware update did not report success |
Update started but didn't succeed before --update-timeout, or reported failure |
ERROR - device did not return before timeout |
Update likely finished, but the PDU didn't respond again within --availability-timeout |
| Problem | Fix |
|---|---|
No IPs found in pdus.txt |
Make sure pdus.txt exists in the folder you're running from, with one IP per line |
python is not recognized / py is not recognized |
Python isn't installed correctly or isn't on PATH — reinstall and enable the PATH option |
No module named raritan |
Activate your virtual environment and run python -m pip install raritan |
--image is required with --update. |
Add --image pointing at your firmware .bin file |
Firmware image not found / Firmware image is empty |
Check the path; confirm the file downloaded completely and isn't 0 bytes |
uploaded firmware image is not valid |
The file likely isn't a genuine/uncorrupted Raritan firmware image — re-download it |
uploaded firmware image is not compatible with this device |
Wrong firmware for this PDU model — confirm you have the correct file for this specific model/family |
uploaded firmware image appears older than installed firmware |
This script won't automate downgrades — do it manually per Raritan's guidance, or contact Raritan Support |
firmware update did not report success |
Check the PDU directly — it may still be mid-update or may have failed. Consider raising --update-timeout for slower devices |
device did not return before timeout |
Update likely finished but took longer than --availability-timeout — check the PDU directly and consider raising the timeout |
| Connection timed out / refused / no route to host | Check the IP, that the PDU is online, that your network can reach it, and firewall rules for TCP 443 |
| Some PDUs updated, others failed | Review the failed IPs, check each directly, fix the issue, --check them before attempting --update again |
| Code | Meaning |
|---|---|
0 |
All PDUs processed successfully |
1 |
Local setup/input problem (no IPs, missing/empty image, missing --image with --update, invalid concurrency or poll-interval) before any PDU was contacted |
2 |
One or more PDUs failed |
130 |
Interrupted with Ctrl+C |
If you interrupt the script after a PDU's firmware update has already started, the update keeps running on that PDU — interrupting the script only stops the script from monitoring it, not the update itself. Check any PDU that had already started an update directly before assuming anything about its state.
- Run
--checkfirst to see what every PDU is currently running. - Run
--update --dry-runbefore any live update. - Keep
--concurrency 1, especially for firmware — an interrupted update is a bigger deal than an interrupted password change. - Keep the IP list small and controlled for a first live update.
- Confirm you have the correct, current firmware image for this PDU model before running against your full fleet.
- Don't interrupt (Ctrl+C) a live update once it's started for a given PDU — see above.
- Never paste real passwords into tickets, chat, email, or screenshots.
- Prefer the interactive password prompt over
--passwordon the CLI. - Close PowerShell after using
$env:PDU_ADMIN_PASSWORD. - Save a log file for audit records.