Invoke-SystemEraseREDFISH.psm1

<#
_author_ = Texas Roemer <Texas_Roemer@Dell.com>
_version_ = 12.0
 
Copyright (c) 2020, 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 perform iDRAC System Erase feature. System Erase feature allows you to reset BIOS or iDRAC to default settings, erase ISE drives, HDD drives, diags, driver pack, Lifecycle controller data, NVDIMMs, PERC NV cache or vFlash.
.DESCRIPTION
   iDRAC cmdlet using Redfish API with OEM extension to perform iDRAC System Erase feature. System Erase feature allows you to reset BIOS or iDRAC to default settings, erase ISE drives, HDD drives, diags, driver pack, Lifecycle controller data, NVDIMMs, PERC NV cache or vFlash. WARNING, this feature is desctructive and the main purpose for using this feature is to repurpose or retire server hardware. For erasing hard drives, there is no option to select a specific drive. Once you pass in either CryptographicErasePD or OverwritePD component value to erase drives, iDRAC is going to erase any supported drive it detects for that value. For more details on each supported component, refer to iDRAC Lifecycle Controller User Guide.
   Supported parameters to pass in for cmdlet:
    
   - idrac_ip: Pass in iDRAC IP
   - idrac_username: Pass in iDRAC username
   - 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_supported_system_erase_components: Get the list of supported components for System Erase feature. The string values returned, these exact values will be used for 'execute_system_erase' argument.
   - execute_system_erase: Pass in the system erase component(s) you want to erase. If passing in multiple components, make sure to use comma separator and surround the value with double quotes. Example: "BIOS,IDRAC,DIAG". NOTE: These values are case sensitive, make sure to pass in exact string values you get from 'get_system_erase_components' argument.
   - power_on_server: Pass in argument if you want the server to automatically power ON after system erase process is complete/iDRAC reboot. By default, once the system erase job ID is marked completed, server will be in OFF state, reboot the iDRAC and stay in OFF state.
 
.EXAMPLE
   Invoke-SystemEraseREDFISH -idrac_ip 192.168.0.120 -idrac_username root -idrac_password calvin -get_system_erase_components
   This example will get supported component string values you can pass in for executing System Erase operation
.EXAMPLE
   Invoke-SystemEraseREDFISH -idrac_ip 192.168.0.120 -get_system_erase_components
   This example will first prompt for iDRAC username/password using Get-Credential, then get supported component string values you can pass in for executing System Erase operation
.EXAMPLE
   Invoke-SystemEraseREDFISH -idrac_ip 192.168.0.120 -get_system_erase_components -x_auth_token 7bd9bb9a8727ec366a9cef5bc83b2708
   This example will get supported component string values you can pass in for executing System Erase operation using iDRAC X-Auth token session
.EXAMPLE
   Invoke-SystemEraseREDFISH.ps1 -idrac_ip 192.168.0.120 -idrac_username root -idrac_password calvin -execute_system_erase DIAG -power_on_server y
   This example will execute System Erase operation erasing remote DIAGs on the iDRAC. Once the iDRAC is back up after System Erase process completes, server will get automatically powered ON.
.EXAMPLE
   Invoke-SystemEraseREDFISH.ps1 -idrac_ip 192.168.0.120 -idrac_username root -idrac_password calvin -execute_system_erase "BIOS,IDRAC"
   This example will execute System Erase operation reseting BIOS and iDRAC to default settings. Once the iDRAC is back up after System Erase process completes, server will still be in OFF state.
#>


function Invoke-SystemEraseREDFISH {

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_system_erase_components,
    [Parameter(Mandatory=$False)]
    [string]$execute_system_erase,
    [Parameter(Mandatory=$False)]
    [switch]$power_on_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 set up iDRAC credentials

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)
}
}

# Function to handle iDRAC RTD behavior for iDRAC basic auth setting

function setup_idrac_creds_handle_iDRAC_RTD
{

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12

$idrac_username = "root"
$idrac_password = "calvin"
$pair = "$idrac_username`:$idrac_password"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [Convert]::ToBase64String($bytes)

$global:headers = $headers = @{
    "Authorization" = "Basic $base64"
    "Accept"        = "application/json"
}


}

# 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 System Erase Supported Components

function get_system_erase_components
{
Write-Host "`n- Supported Components for System Erase iDRAC Feature -`n"
$uri = "https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService"
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_content_key=$result.Content | ConvertFrom-Json
$system_erase_action="#DellLCService.SystemErase"
$allow_values = "Component@Redfish.AllowableValues"
$get_content_key.Actions.$system_erase_action.$allow_values
Write-Host
return
}


# Function to execute System Erase feature

$Global:job_id = $null
$Global:bios_component = $null

function execute_system_erase
{

# Create body payload for POST command


if ($execute_system_erase.Contains(","))
{
$string_split = $execute_system_erase.Split(",")
    if ($string_split.Contains("BIOS"))
    {
    $Global:bios_component = "yes"
    }
    else
    {
    $Global:bios_component = "no"
    }
$JsonBody = @{"Component"=[System.Collections.ArrayList]@()}
    foreach ($item in $string_split)
    {
    $JsonBody["Component"]+=$item
    }
Write-Host "`n- Keys and Values being passed in for POST action 'SystemErase' -`n"
$JsonBody
$JsonBody = $JsonBody | ConvertTo-Json -Compress
}
else
{
    if ($execute_system_erase.Contains("BIOS"))
    {
    $Global:bios_component = "yes"
    }
    else
    {
    $Global:bios_component = "no"
    }
$JsonBody = @{"Component"=[System.Collections.ArrayList]@()}
$JsonBody["Component"]+=$execute_system_erase

   
Write-Host "`n- Keys and Values being passed in for POST action 'SystsemErase' -`n"
$JsonBody

$JsonBody = $JsonBody | ConvertTo-Json -Compress
}

$uri = "https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService/Actions/DellLCService.SystemErase"

if ($x_auth_token)
{
try
    {
    if ($global:get_powershell_version -gt 5)
    {
    
    $post_result = 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
    $post_result = 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)
    {
    
    $post_result = 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
    $post_result = 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 ($post_result.StatusCode -eq 202 -or $post_result.StatusCode -eq 200)
{
    $job_id_search=$post_result.Headers['Location']
    $Global:job_id=$job_id_search.Split("/")[-1]
    [String]::Format("`n- PASS, statuscode {0} returned successfully for POST command to create update job ID '{1}'",$post_result.StatusCode, $Global:job_id)
    Start-Sleep 10
    Write-Host
    return
}
else
{
    [String]::Format("- FAIL, statuscode {0} returned. Detail error message: {1}",$post_result.StatusCode,$post_result)
    return
}

}


function loop_job_status
{

$job_message_old = ""
$get_time_old=Get-Date -DisplayHint Time
$start_time = Get-Date
$end_time = $start_time.AddMinutes(50)
$force_count = 0
$retry_count = 0
Write-Host "- INFO, script will now loop polling the job status until marked completed`n"
while ($true)
{

if ($retry_count -eq 30)
{
Write-Host "- WARNING, retry count of 30 has been hit for GET request, cmdlet will exit"
return
}

$loop_time = Get-Date
$uri ="https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/Jobs/$Global:job_id"

if ($x_auth_token)
{
 try
    {
    if ($global:get_powershell_version -gt 5)
    {
    $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -SkipHttpErrorCheck -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
    {
    if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
    {
    Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
    Start-Sleep 30
    $retry_count ++
    continue
    }
    Write-Host
    $RespErr
    return
    } 
}

else
{
    try
    {
    if ($global:get_powershell_version -gt 5)
    {
    $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -SkipHttpErrorCheck -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
    {
    if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
    {
    Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
    Start-Sleep 30
    $retry_count ++
    continue
    }
    Write-Host
    $RespErr
    return
    } 
}

if ($result.StatusCode -eq 200)
{
}
elseif ($result.StatusCode -eq 400)
{
[String]::Format("- FAIL, status code 400 returned for bad request, GET request will retry in 1 minute")
$retry_count ++
Start-Sleep 60
continue
}
elseif ($result.StatusCode -eq 404)
{
[String]::Format("- FAIL, status code 404 returned for resource not found, GET request will retry in 1 minute")
$retry_count ++
Start-Sleep 60
continue
}
elseif ($result.StatusCode -eq 500)
{
[String]::Format("- FAIL, status code 500 returned for internal server error, GET request will retry in 1 minute")
$retry_count ++
Start-Sleep 60
continue
}
elseif ($result.StatusCode -eq 503)
{
[String]::Format("- FAIL, status code 503 returned for service unavailable, GET request will retry in 1 minute")
$retry_count ++
Start-Sleep 60
continue
}
elseif ($result.StatusCode -eq 401)
{
[String]::Format("- FAIL, status code 401 detected for authentication credential failure. If iDRAC component erased, default password has now been set, cmdlet will exit")
return
}
else
{
[String]::Format("- FAIL, GET command failed to check job status, statuscode {0} returned. Detail error message: {1}",$result.StatusCode,$result)
$retry_count ++
Start-Sleep 30
continue
}

$get_output = $result.Content | ConvertFrom-Json
$job_message_new = $get_output.Message

$overall_job_output=$result.Content | ConvertFrom-Json
if ($overall_job_output.Message.Contains("Fail") -or $overall_job_output.Message.Contains("Failed") -or $overall_job_output.Message.Contains("fail") -or $overall_job_output.Message.Contains("failed") -or $overall_job_output.Message.Contains("already"))
{
Write-Host
[String]::Format("- FAIL, job id $Global:job_id marked as failed, error message: {0}",$overall_job_output.Message)
return
}
elseif ($overall_job_output.Message.Contains("partially") -or $overall_job_output.Message.Contains("part"))
{
Write-Host
[String]::Format("- INFO, job id $Global:job_id completed with issues, check iDRAC Lifecyle Logs for more details. Final job message: {0}",$overall_job_output.Message)
$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 "`n- PASS, job ID '$Global:job_id' successfully marked as completed"
Write-Host "`nSystem Erase job execution time:"
$final_completion_time
break
}
elseif ($loop_time -gt $end_time)
{
Write-Host "- FAIL, timeout of 50 minutes has been reached before marking the job completed"
return
}
elseif ($overall_job_output.Message -eq "The System Erase Operation is completed successfully." -or $overall_job_output.Message -eq  "Job completed successfully." -or $overall_job_output.Message.Contains("complete"))
{
$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 "`n- PASS, job ID '$Global:job_id' successfully marked as completed"
Write-Host "`nSystem Erase job execution time:"
$final_completion_time
break
}
else
{
    if ($job_message_new -ne $job_message_old)
    {
    Write-Host "- Job ID '$Global:job_id' not marked completed, checking job status again. Current job message: $job_message_new"
        if ($job_message_new -eq "Access to Lifecycle Controller internal storage was not acquired.")
        {
        Write-Host "- FAIL, unable to access to Lifecycle Controller internal storage, job failed"
        return
        }
        else
        {
        $job_message_old = $job_message_new
        }
    }
    else
    {
    }
}


}

}

# Function to power on server

function power_on_server

{
$JsonBody = @{ "ResetType" = "On"
    } | ConvertTo-Json -Compress

$uri = "https://$idrac_ip/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset"
# POST command to power ON the server

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
    {
    $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
    {
    $RespErr
    return
    }
}


if ($result1.StatusCode -eq 204)
{
    [String]::Format("- PASS, statuscode {0} returned successfully to power ON the server",$result1.StatusCode)
}
else
{
    [String]::Format("- FAIL, statuscode {0} returned",$result1.StatusCode)
    return
}

}

# Function to finish BIOS reset to default operation once the iDRAC is back up

function finish_bios_reset_to_default
{

$JsonBody = @{ "ResetType" = "On"
    } | ConvertTo-Json -Compress

$uri = "https://$idrac_ip/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset"
# POST command to power ON the server

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
{
if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
{
Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
Start-Sleep 30
continue
}
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
{
if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
{
Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
Start-Sleep 30
continue
}
Write-Host
$RespErr
return
} 
}

if ($result1.StatusCode -eq 204)
{
    [String]::Format("- PASS, statuscode {0} returned successfully to power ON the server. Cmdlet will now loop checking the server power status until reported OFF",$result1.StatusCode)
    Start-Sleep 120
}
else
{
    [String]::Format("- FAIL, statuscode {0} returned",$result1.StatusCode)
    return
}

$retry_count = 0
while ($true)
{

if ($retry_count -eq 20)
{
Write-Host "- FAIL, retry count of 20 has been hit, cmdlet will exit"
return
}

$uri = "https://$idrac_ip/redfish/v1/Systems/System.Embedded.1/"
 if ($x_auth_token)
{
 try
    {
    if ($global:get_powershell_version -gt 5)
    {
    $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -SkipHttpErrorCheck -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
    {
    if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
    {
    Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
    Start-Sleep 30
    continue
    }
    Write-Host
    $RespErr
    return
    } 
}

else
{
    try
    {
    if ($global:get_powershell_version -gt 5)
    {
    $result = Invoke-WebRequest -SkipCertificateCheck -SkipHeaderValidation -SkipHttpErrorCheck -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
    {
    if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
    {
    Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
    Start-Sleep 30
    continue
    }
    Write-Host
    $RespErr
    return
    } 
}

$result_output = $result.Content | ConvertFrom-Json
$power_state = $result_output.PowerState
    if ($power_state -eq "Off")
    { 
    Write-Host "- PASS, verified server is in OFF state, BIOS reset to default process is complete"
    return
    }
    else
    {
    Write-Host "- INFO, server still in ON state, checking server power status again in 1 minute"
    Start-Sleep 60
    $retry_count ++
    }


}




}

# Function to check iDRAC API status, confirm iDRAC is back in ready state after reboot

function check_iDRAC_API_status_check
{
$retry_count = 0
while ($true)

{
if ($retry_count -eq 10)
{
Write-Host "- INFO, retry count of 10 has been hit, cmdlet will now exit"
return
}

$JsonBody = @{} | ConvertTo-Json -Compress
$uri = "https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService/Actions/DellLCService.GetRemoteServicesAPIStatus"

if ($x_auth_token)
{
try
{
    if ($global:get_powershell_version -gt 5)
    {
    
    $post_result = Invoke-WebRequest -UseBasicParsing -SkipHeaderValidation -SkipCertificateCheck -SkipHttpErrorCheck -Uri $uri -Body $JsonBody -Method Post -ContentType 'application/json' -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} -ErrorVariable RespErr
    }
    else
    {
    Ignore-SSLCertificates
    $post_result = Invoke-WebRequest -UseBasicParsing -Uri $uri -Method Post -ContentType 'application/json' -Headers @{"Accept" = "application/json"; "X-Auth-Token" = $x_auth_token} -Body $JsonBody -ErrorVariable RespErr
    }
}
catch
{
if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
{
Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
Start-Sleep 30
$retry_count ++
continue
}
Write-Host
$RespErr
return
} 
}


else
{
try
{
    if ($global:get_powershell_version -gt 5)
    {
    
    $post_result = Invoke-WebRequest -UseBasicParsing -SkipHeaderValidation -SkipCertificateCheck -SkipHttpErrorCheck -Uri $uri -Credential $credential -Body $JsonBody -Method Post -ContentType 'application/json' -Headers @{"Accept"="application/json"} -ErrorVariable RespErr
    }
    else
    {
    Ignore-SSLCertificates
    $post_result = Invoke-WebRequest -UseBasicParsing -Uri $uri -Credential $credential -Method Post -ContentType 'application/json' -Headers @{"Accept"="application/json"} -Body $JsonBody -ErrorVariable RespErr
    }
}
catch
{
if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
{
Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
Start-Sleep 30
$retry_count ++
continue
}
Write-Host
$RespErr
return
} 
}


if ($post_result.StatusCode -eq 200 -or $post_result.StatusCode -eq 204)
{
}
elseif ($result.StatusCode -eq 400)
{
[String]::Format("- FAIL, status code 400 returned for bad request, POST request will retry in 30 seconds")
$retry_count ++
Start-Sleep 30
continue
}
elseif ($result.StatusCode -eq 404)
{
[String]::Format("- FAIL, status code 404 returned for resource not found, POST request will retry in 30 seconds")
$retry_count ++
Start-Sleep 30
continue
}
elseif ($result.StatusCode -eq 500)
{
[String]::Format("- FAIL, status code 500 returned for internal server error, POST request will retry in 30 seconds")
$retry_count ++
Start-Sleep 30
continue
}
elseif ($result.StatusCode -eq 503)
{
[String]::Format("- FAIL, status code 503 returned for service unavailable, POST request will retry in 30 seconds")
$retry_count ++
Start-Sleep 30
continue
}
elseif ($result.StatusCode -eq 401)
{
[String]::Format("- FAIL, status code 401 detected for authentication credential failure. If iDRAC component erased, default password has now been set, cmdlet will exit")
return
}
else
{
[String]::Format("- FAIL, general POST request failure, retry in 30 seconds")
Start-Sleep 30
$retry_count ++
continue
}

$get_post_result = $post_result.Content | ConvertFrom-Json

if ($get_post_result.error)
{
$message_id = $get_post_result.error.'@Message.ExtendedInfo'[0].MessageId
if ($message_id -match "ServiceTemporarilyUnavailable")
{
$retry_secs = [int]$get_post_result.error.'@Message.ExtendedInfo'[0].MessageArgs[0]
Write-Host "- INFO, iDRAC service temporarily unavailable, retry in $retry_secs seconds"
Start-Sleep $retry_secs
$retry_count ++
continue
}
}

if ($get_post_result.LCStatus -eq "Ready" -and $get_post_result.Status -eq "Ready")
{
Write-Host "- PASS, iDRAC in ready state, both LC status and server status properties report Ready"
break
}
else
{
Write-Host "- INFO, iDRAC not ready, both LC status and server status properties report NotReady, retry in 30 seconds"
Start-Sleep 30
$retry_count ++
}
}


}

# Function to ping iDRAC and confirm the network is back up after iDRAC reboot

function check_iDRAC_network_up 
{
$retry_count = 0
while ($true)
{
    if ($retry_count -eq 10)
    {
    Write-Host "- WARNING, failed to successfully ping iDRAC IP after 10 attempts, cmdlet will exit"
    return
    }
    elseif (Test-Connection -ComputerName $idrac_ip -Count 1 -Quiet) 
    {
    Write-Host "- PASS, successfully ping request to iDRAC IP, script will now wait 1 minute before running API status check to confirm iDRAC is back up in ready state"
    Start-Sleep 60
    break
    }
    else
    {
    $retry_count ++
    Write-Host "- INFO, attempt $retry_count/10 failed to ping iDRAC IP. Retry in 30 seconds"
    Start-Sleep 30       
    }
}

}


# Function to enable, disable basic auth for iDRAC. This is needed if iDRAC component was erased and reset to default.

function enable_disable_basic_auth ($attribute_value)
{

$retry_count = 0
while ($true)
{

if ($retry_count -eq 10)
{
Write-Host "- INFO, retry count of 10 has been hit, cmdlet will now exit"
return
}

$JsonBody = @{"Attributes"=@{"Redfish.1.BasicAuthState"=$attribute_value}} | ConvertTo-Json -Compress
$uri = "https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/iDRAC.Embedded.1"

try
{
    if ($global:get_powershell_version -gt 5)
    {
    
    $patch_result = Invoke-WebRequest -UseBasicParsing -SkipHeaderValidation -SkipCertificateCheck -SkipHttpErrorCheck -Uri $uri -Credential $credential -Body $JsonBody -Method Patch -ContentType 'application/json' -Headers $global:headers -ErrorVariable RespErr
    }
    else
    {
    Ignore-SSLCertificates
    $patch_result = Invoke-WebRequest -UseBasicParsing -Uri $uri -Credential $credential -Method Patch -ContentType 'application/json' -Headers $global:headers -Body $JsonBody -ErrorVariable RespErr
    }
}
catch
{
if ($_.Exception.Response.StatusCode -eq "ServiceUnavailable" -or $RespErr -match "ServiceTemporarilyUnavailable")
{
Write-Host "- INFO, iDRAC service temporarily unavailable, retry in 30 seconds"
Start-Sleep 30
$retry_count ++
continue
}
Write-Host
$RespErr
return
} 



if ($patch_result.StatusCode -eq 200 -or $patch_result.StatusCode -eq 204)
{
Write-Host "- PASS, successfully set iDRAC Redfish.1.BasicAuthState attribute to $attribute_value"
return
}
else
{
Write-Host "- WARNING, PATCH command failed to set iDRAC Redfish.1.BasicAuthState attribute to $attribute_value, cmdlet will now exit"
return
}

}

}



# Run cmdlet

get_powershell_version
setup_idrac_creds

# Check to validate iDRAC version detected supports this feature

$uri = "https://$idrac_ip/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService"
 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
    Write-Host "`n- WARNING, iDRAC version detected does not support this feature using Redfish API or incorrect iDRAC user credentials passed in.`n"
    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
    }
}

if ($result.StatusCode -eq 200 -or $result.StatusCode -eq 202)
{
$get_actions = $result.Content | ConvertFrom-Json
$system_erase_action_name = "#DellLCService.SystemErase"
$validate_supported_idrac = $get_actions.Actions.$system_erase_action_name
    try
    {
    $test = $validate_supported_idrac.GetType()
    }
    catch
    {
    Write-Host "`n- WARNING, iDRAC version detected does not support this feature using Redfish API or incorrect iDRAC user credentials passed in.`n"
    return
    }
}
else
{
Write-Host "`n- WARNING, iDRAC version detected does not support this feature using Redfish API or incorrect iDRAC user credentials passed in.`n"
return
}

if ($get_system_erase_components)
{
get_system_erase_components
}

elseif ($execute_system_erase)
{

execute_system_erase
loop_job_status
    if ($Global:bios_component -eq "yes")
    {
    Write-Host "- INFO, BIOS component detected. Cmdlet will wait 6 minutes for iDRAC to come back up, then power ON server to complete BIOS reset to default (RTD) process"
    Start-Sleep 360
    check_iDRAC_network_up
    if ($execute_system_erase.ToLower().Contains("idrac"))
    {
    Write-Host "- INFO, iDRAC component erased, cmdlet will now attempt to use root default password calvin (if selected from the factory) to complete BIOS RTD process. Note: If randomized default password was selected from the factory cmdlet will fail."
    Write-Host "- INFO, due to iDRAC basic auth default setting of unadvertised, cmdlet will need to wait another 3 minutes before attempting to enable, complete this workflow."
    Start-Sleep 180
    setup_idrac_creds_handle_iDRAC_RTD
    enable_disable_basic_auth ("Enabled")
    $user = "root"
    $pass= "calvin"
    $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
    $global:credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
    }
    check_iDRAC_API_status_check
    finish_bios_reset_to_default
        if ($power_on_server)
        {
        Write-Host "`n- User selected to power ON server after System Erase process completes"
        power_on_server
        if ($execute_system_erase.ToLower().Contains("idrac"))
        {
        enable_disable_basic_auth ("Unadvertised")
        }
        return
        }
    }
    if ($power_on_server)
    {
    Write-Host "`n- User selected to power ON server after System Erase process completes. Cmdlet will wait 6 minutes for iDRAC to come back up before executing power ON"
    Start-Sleep 360
    check_iDRAC_network_up 
    if ($execute_system_erase.ToLower().Contains("idrac"))
    {
    Write-Host "- INFO, iDRAC component erased, cmdlet will now attempt to use root default password calvin (if selected from the factory) to power back on the server. Note: If randomized default root password was selected from the factory cmdlet will fail."
    Write-Host "- INFO, due to iDRAC basic auth default setting of unadvertised, cmdlet will need to wait another 3 minutes before attempting to enable, complete this workflow."
    Start-Sleep 180
    setup_idrac_creds_handle_iDRAC_RTD
    enable_disable_basic_auth ("Enabled")
    Start-Sleep 15
    $user = "root"
    $pass= "calvin"
    $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
    $global:credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
    }
    check_iDRAC_API_status_check
    power_on_server
    if ($execute_system_erase.ToLower().Contains("idrac"))
    {
    enable_disable_basic_auth ("Unadvertised")
    }
    return
    }
}

else
{
Write-Host "- FAIL, either incorrect parameter(s) used or missing required parameters(s)"
}


}