Set-BiosDateTimeREDFISH.psm1
|
<#
_author_ = Texas Roemer <Texas_Roemer@Dell.com> _version_ = 1.0 Copyright (c) 2026, Dell, Inc. This software is licensed to you under the GNU General Public License, version 2 (GPLv2). There is NO WARRANTY for this software, express or implied, including the implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 along with this software; if not, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt #> <# .Synopsis iDRAC cmdlet using Redfish API with OEM extension to set BIOS date and time. .DESCRIPTIO iDRAC cmdlet using Redfish API with OEM extension to set BIOS date and time. Latest platform BIOS version along with supported iDRAC version is required to support this feature. Note iDRAC introduced feature support starting in iDRAC9 7.20.80.50 and iDRAC10 1.30.10.50. - idrac_ip: Pass in idrac IP - idrac_username: Pass in idrac user name - idrac_password: Pass in idrac password - x_auth_token: Pass in iDRAC X-Auth token session to execute cmdlet instead of username / password (recommended) - get_idrac_time: Get current iDRAC time. Note iDRAC time syncs with BIOS time, currently there is no iDRAC support to get BIOS time directly so this method must be used as a workaround. - set_bios_datetime: Set BIOS date and time, pass in the string value in this format: YYYY-MM-DDTHH:MM:SS+-HH:MM. - dst: Specifies whether Daylight Saving Time (DST) is enabled or not, pass in a value of True or False. - reboot_server: Pass in argument to reboot the server now to execute config job. If argument is not passed in, next manual server reboot job will be execute. .EXAMPLE SetBiosDateTimeREDFISH.py -ip 192.168.0.120 -u root -p calvin -get_idrac_time, This example will return iDRAC current time which syncs with BIOS time. .EXAMPLE SetBiosDateTimeREDFISH.py -ip 192.168.0.120 -u root -p calvin -set_bios_datetime 2026-01-13T15:10:00-05:00 -dst True -reboot This example will reboot the server now to set BIOS date and time. #> function Set-BiosDateTimeREDFISH { param( [Parameter(Mandatory=$True)] [string]$idrac_ip, [Parameter(Mandatory=$False)] [string]$idrac_username, [Parameter(Mandatory=$False)] [string]$idrac_password, [Parameter(Mandatory=$False)] [string]$x_auth_token, [Parameter(Mandatory=$False)] [switch]$get_idrac_time, [Parameter(Mandatory=$False)] [string]$set_bios_datetime, [ValidateSet("True", "False")] [Parameter(Mandatory=$False)] [string]$dst, [Parameter(Mandatory=$False)] [switch]$reboot_server ) # Function to ignore SSL certs function Ignore-SSLCertificates { $Provider = New-Object Microsoft.CSharp.CSharpCodeProvider $Compiler = $Provider.CreateCompiler() $Params = New-Object System.CodeDom.Compiler.CompilerParameters $Params.GenerateExecutable = $false $Params.GenerateInMemory = $true $Params.IncludeDebugInformation = $false $Params.ReferencedAssemblies.Add("System.DLL") > $null $TASource=@' namespace Local.ToolkitExtensions.Net.CertificatePolicy { public class TrustAll : System.Net.ICertificatePolicy { public bool CheckValidationResult(System.Net.ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem) { return true; } } } '@ $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource) $TAAssembly=$TAResults.CompiledAssembly $TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll") [System.Net.ServicePointManager]::CertificatePolicy = $TrustAll } # Function to get Powershell version function get_powershell_version { $get_host_info = Get-Host $major_number = $get_host_info.Version.Major $global:get_powershell_version = $major_number } get_powershell_version function setup_idrac_creds { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12 if ($x_auth_token) { $global:x_auth_token = $x_auth_token } elseif ($idrac_username -and $idrac_password) { $user = $idrac_username $pass= $idrac_password $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force $global:credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd) } else { $get_creds = Get-Credential $global:credential = New-Object System.Management.Automation.PSCredential($get_creds.UserName, $get_creds.Password) } } setup_idrac_creds function check_supported_idrac_version { $uri = "https://$idrac_ip/redfish/v1/Systems/System.Embedded.1/Bios?`$select=Actions" if ($x_auth_token) { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"; "X-Auth-Token" = $x_auth_token} } } catch { $RespErr return } } else { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } } catch { $RespErr return } } $get_results = $result.Content | ConvertFrom-Json if ($result.StatusCode -eq 200) { $action_name = "#DellBios.SetBiosTime" try { $get_results.Actions.Oem.$action_name.GetType() | Out-Null } catch { Write-Host "`n- WARNING, iDRAC version detected does not support this OEM action" return } } else { [String]::Format("- FAIL, statuscode {0} returned",$result.StatusCode) return } } function get_idrac_time { $uri = "https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1?`$select=DateTime" if ($x_auth_token) { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"; "X-Auth-Token" = $x_auth_token} } } catch { $RespErr return } } else { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } } catch { $RespErr return } } $get_result = $result.Content | ConvertFrom-Json if ($result.StatusCode -eq 200) { [String]::Format("`n - Current iDRAC time: {0}",$get_result.DateTime) return } else { [String]::Format("- FAIL, statuscode {0} returned",$result.StatusCode) return } } function set_bios_time { $JsonBody = @{"BiosDateTime" = $set_bios_datetime} if ($reboot_server) { $JsonBody["@Redfish.OperationApplyTime"] = "Immediate" } else { $JsonBody["@Redfish.OperationApplyTime"] = "OnReset" } if ($dst.ToLower() -eq "true") { $JsonBody["DaylightSavingsEnabled"] = $true } else { $JsonBody["DaylightSavingsEnabled"] = $false } $JsonBody = $JsonBody | ConvertTo-Json -Compress $uri = "https://$idrac_ip/redfish/v1/Systems/System.Embedded.1/Bios/Actions/Oem/DellBios.SetBiosTime" if ($x_auth_token) { try { if ($global:get_powershell_version -gt 5) { $result1 = Invoke-WebRequest -UseBasicParsing -SkipHeaderValidation -SkipCertificateCheck -Uri $uri -Method Post -Body $JsonBody -ContentType 'application/json' -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} -ErrorVariable RespErr } else { Ignore-SSLCertificates $result1 = Invoke-WebRequest -UseBasicParsing -Uri $uri -Method Post -Body $JsonBody -ContentType 'application/json' -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} -ErrorVariable RespErr } } catch { Write-Host $RespErr return } } else { try { if ($global:get_powershell_version -gt 5) { $result1 = Invoke-WebRequest -UseBasicParsing -SkipHeaderValidation -SkipCertificateCheck -Uri $uri -Credential $credential -Method Post -Body $JsonBody -ContentType 'application/json' -Headers @{"Accept"="application/json"} -ErrorVariable RespErr } else { Ignore-SSLCertificates $result1 = Invoke-WebRequest -UseBasicParsing -Uri $uri -Credential $credential -Method Post -Body $JsonBody -ContentType 'application/json' -Headers @{"Accept"="application/json"} -ErrorVariable RespErr } } catch { Write-Host $RespErr return } } if ($result1.StatusCode -eq 202 -or $result1.StatusCode -eq 200) { [String]::Format("`n- PASS, POST command passed to set BIOS time pending value and create config job") } else { [String]::Format("- FAIL, statuscode {0} returned",$result1.StatusCode) return } $raw_content = $result1.RawContent | ConvertTo-Json -Compress try { $jobID_search = [regex]::Match($raw_content, "JID_.+?r").captures.groups[0].value $global:job_id = $jobID_search.Replace("\r","") } catch { Write-Host "- FAIL, unable to location job ID in headers output" return } start-sleep 20 $uri ="https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/Jobs/$job_id" if ($x_auth_token) { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"; "X-Auth-Token" = $x_auth_token} } } catch { $RespErr return } } else { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } } catch { $RespErr return } } $overall_job_output=$result.Content | ConvertFrom-Json if ($overall_job_output.JobState -eq "Scheduled") { [String]::Format("- PASS, {0} job ID successfully marked as scheduled",$job_id) if (-not $reboot_server) { Write-Host "- INFO, argument reboot_server not detected, job is still scheduled and will run on next manual server reboot." return } elseif ($reboot_server) { Write-Host "- INFO, server will now automatically reboot to apply config changes" } } else { Write-Host [String]::Format("- FAIL, {0} job ID not marked as scheduled",$job_id) [String]::Format("- Extended error details: {0}",$overall_job_output) return } } function check_job_status { Write-Host "`n- INFO, cmdlet will now poll job ID every 10 seconds until marked completed`n" $get_time_old=Get-Date -DisplayHint Time $start_time = Get-Date $end_time = $start_time.AddMinutes(30) while ($overall_job_output.JobState -ne "Completed") { $loop_time = Get-Date $uri ="https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/Jobs/$job_id" if ($x_auth_token) { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"; "X-Auth-Token" = $x_auth_token} } } catch { $RespErr return } } else { try { if ($global:get_powershell_version -gt 5) { $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } else { Ignore-SSLCertificates $result = Invoke-WebRequest -Uri $uri -Credential $credential -Method Get -UseBasicParsing -ErrorVariable RespErr -Headers @{"Accept"="application/json"} } } catch { $RespErr return } } $overall_job_output=$result.Content | ConvertFrom-Json if ($overall_job_output.JobState -eq "Failed") { Write-Host [String]::Format("- FAIL, job marked as failed, detailed error info: {0}",$overall_job_output) return } elseif ($loop_time -gt $end_time) { Write-Host "- FAIL, timeout of 30 minutes has been reached before marking the job completed" return } else { [String]::Format("- INFO, current job status is: {0}",$overall_job_output.Message) Start-Sleep 5 } } Write-Host Start-Sleep 10 [String]::Format("- PASS, {0} job ID marked as completed!",$job_id) $get_current_time=Get-Date -DisplayHint Time $final_time=$get_current_time-$get_time_old $final_completion_time=$final_time | select Minutes,Seconds Write-Host " Job completed in $final_completion_time" } # Run code get_powershell_version setup_idrac_creds check_supported_idrac_version if ($get_idrac_time) { get_idrac_time } elseif ($set_bios_datetime -and $dst) { set_bios_time check_job_status } else { Write-Host "`n- FAIL, either invalid parameter value passed in or missing required parameter" return } } |