Scope: this report is about the PowerShell side of the repo (Redfish PowerShell/), checked against the current master branch. The pattern described is specific to PowerShell's break semantics and doesn't apply to the Python modules.
Summary
Several cmdlets use a bare break statement inside catch blocks to abort on error, with no enclosing loop in the function itself. In PowerShell, an unlabeled break with no enclosing loop at the current scope searches up the entire call stack for the nearest enclosing loop — including loops in whatever code called the cmdlet. If the caller happens to invoke the cmdlet from inside a loop (a very normal pattern — e.g. looping over several firmware components to update, or several disks to configure), that break silently terminates the caller's loop instead of just this cmdlet's own error handling, with no exception or error surfaced.
Minimal repro (pure PowerShell language behavior, no Dell hardware needed):
Function Inner {
Try { Throw "simulated failure" }
Catch { break } # no enclosing loop in this function
}
Function Outer {
ForEach ($i in 1..3) {
Write-Host "iteration $i"
Inner
Write-Host "after Inner, iteration $i" # never printed
}
Write-Host "loop finished" # reached immediately after iteration 1
}
Outer
Output is only iteration 1, then straight to loop finished — iterations 2 and 3 never run, and "after Inner" never prints, even though Inner returned without throwing anything the caller could see.
Concrete impact observed
In Set-DeviceFirmwareSimpleUpdateREDFISH.psm1, the catch block around the firmware-upload Invoke-WebRequest call ends in a bare break. When that request fails — e.g. the iDRAC rejects the payload — this break propagated out of the module and out of our own wrapper function, silently terminating our caller's loop over several required firmware components. Our tool stopped checking the remaining firmware components entirely and reported overall success despite the update having failed, with no error or log line indicating anything had gone wrong.
Full scan of the current master branch
Parsed all 77 .psm1 files under Redfish PowerShell/ with System.Management.Automation.Language.Parser and checked every break statement's AST ancestry for a lexically-enclosing loop within its own function. Found 51 such "unsafe" break statements across 9 individual cmdlet files (not counting the same underlying functions duplicated again inside the large combined IdracRedfishSupport.psm1 convenience file):
| File |
Unsafe break count |
Affected function(s) |
Set-DeviceFirmwareSimpleUpdateREDFISH |
10 |
download_image_payload, reboot_server, install_image_payload_query_job_status_reboot_server |
Invoke-SupportAssistCollectionLocalREDFISH |
10 |
get_support_assist_license_agreement, accept_support_assist_license_agreement, register_support_assist_feature, execute_support_assist_collection |
Set-ScheduleRepositoryUpdateREDFISH |
8 |
get_update_schedule_details, get_idrac_time, clear_update_schedule_details, set_scheduled_repository_update |
Set-DeviceFirmwareRollbackREDFISH |
6 |
get_firmware_versions, rollback_image_query_job_status_reboot_server |
Set-DeviceFirmwareSimpleUpdateTransferProtocolREDFISH |
6 |
get_firmware_versions, reboot_server, install_image_payload_query_job_status_reboot_server |
Invoke-SystemEraseREDFISH |
5 |
get_system_erase_components, execute_system_erase, power_on_server, finish_bios_reset_to_default |
Invoke-ExportImportSslCertificateREDFISH |
3 |
export_import_ssl_cert, delete_ssl_cert, restore_factory_defaults |
Invoke-RemoteDiagsREDFISH |
2 |
execute_remote_diags, export_remote_diags_results |
Set-ExportImportServerConfigurationProfileNetworkShareREDFISH |
1 |
Set-ExportImportServerConfigurationProfileNetworkShareREDFISH |
The same functions are duplicated (with the same break statements) inside IdracRedfishSupport.psm1, which bundles many cmdlets into one combined file.
For context on false positives to rule out: several other files also use bare break (e.g. Get-IdracLifecycleLogsREDFISH, Set-NextOneTimeBootVirtualMediaDeviceOemREDFISH), but in those cases the break sits inside an actual while/for loop within the same function, so it's correctly scoped and not a problem — only the ones listed above lack any enclosing loop of their own.
Suggested fix
Where a catch block is meant to abort the current function on error (which appears to be the intent in all cases found), replace the bare break with return (or return $false/an appropriate error/status value). return exits only the current function and cannot escape into a caller's loop, avoiding this class of bug entirely while preserving the "stop processing now" intent.
Environment
- Windows PowerShell 5.1
- Modules loaded via
Import-Module from a calling script that iterates over multiple items (e.g. multiple firmware components) in a loop
Scope: this report is about the PowerShell side of the repo (
Redfish PowerShell/), checked against the currentmasterbranch. The pattern described is specific to PowerShell'sbreaksemantics and doesn't apply to the Python modules.Summary
Several cmdlets use a bare
breakstatement insidecatchblocks to abort on error, with no enclosing loop in the function itself. In PowerShell, an unlabeledbreakwith no enclosing loop at the current scope searches up the entire call stack for the nearest enclosing loop — including loops in whatever code called the cmdlet. If the caller happens to invoke the cmdlet from inside a loop (a very normal pattern — e.g. looping over several firmware components to update, or several disks to configure), thatbreaksilently terminates the caller's loop instead of just this cmdlet's own error handling, with no exception or error surfaced.Minimal repro (pure PowerShell language behavior, no Dell hardware needed):
Output is only
iteration 1, then straight toloop finished— iterations 2 and 3 never run, and "after Inner" never prints, even thoughInnerreturned without throwing anything the caller could see.Concrete impact observed
In
Set-DeviceFirmwareSimpleUpdateREDFISH.psm1, thecatchblock around the firmware-uploadInvoke-WebRequestcall ends in a barebreak. When that request fails — e.g. the iDRAC rejects the payload — thisbreakpropagated out of the module and out of our own wrapper function, silently terminating our caller's loop over several required firmware components. Our tool stopped checking the remaining firmware components entirely and reported overall success despite the update having failed, with no error or log line indicating anything had gone wrong.Full scan of the current
masterbranchParsed all 77
.psm1files underRedfish PowerShell/withSystem.Management.Automation.Language.Parserand checked everybreakstatement's AST ancestry for a lexically-enclosing loop within its own function. Found 51 such "unsafe"breakstatements across 9 individual cmdlet files (not counting the same underlying functions duplicated again inside the large combinedIdracRedfishSupport.psm1convenience file):breakcountSet-DeviceFirmwareSimpleUpdateREDFISHdownload_image_payload,reboot_server,install_image_payload_query_job_status_reboot_serverInvoke-SupportAssistCollectionLocalREDFISHget_support_assist_license_agreement,accept_support_assist_license_agreement,register_support_assist_feature,execute_support_assist_collectionSet-ScheduleRepositoryUpdateREDFISHget_update_schedule_details,get_idrac_time,clear_update_schedule_details,set_scheduled_repository_updateSet-DeviceFirmwareRollbackREDFISHget_firmware_versions,rollback_image_query_job_status_reboot_serverSet-DeviceFirmwareSimpleUpdateTransferProtocolREDFISHget_firmware_versions,reboot_server,install_image_payload_query_job_status_reboot_serverInvoke-SystemEraseREDFISHget_system_erase_components,execute_system_erase,power_on_server,finish_bios_reset_to_defaultInvoke-ExportImportSslCertificateREDFISHexport_import_ssl_cert,delete_ssl_cert,restore_factory_defaultsInvoke-RemoteDiagsREDFISHexecute_remote_diags,export_remote_diags_resultsSet-ExportImportServerConfigurationProfileNetworkShareREDFISHSet-ExportImportServerConfigurationProfileNetworkShareREDFISHThe same functions are duplicated (with the same
breakstatements) insideIdracRedfishSupport.psm1, which bundles many cmdlets into one combined file.For context on false positives to rule out: several other files also use bare
break(e.g.Get-IdracLifecycleLogsREDFISH,Set-NextOneTimeBootVirtualMediaDeviceOemREDFISH), but in those cases thebreaksits inside an actualwhile/forloop within the same function, so it's correctly scoped and not a problem — only the ones listed above lack any enclosing loop of their own.Suggested fix
Where a
catchblock is meant to abort the current function on error (which appears to be the intent in all cases found), replace the barebreakwithreturn(orreturn $false/an appropriate error/status value).returnexits only the current function and cannot escape into a caller's loop, avoiding this class of bug entirely while preserving the "stop processing now" intent.Environment
Import-Modulefrom a calling script that iterates over multiple items (e.g. multiple firmware components) in a loop