dell / iDRAC-Redfish-Scripting

Python and PowerShell scripting for Dell EMC PowerEdge iDRAC REST API with DMTF Redfish
GNU General Public License v2.0
584 stars 273 forks source link

Replace certutil with native pwsh #294

Closed crlogic closed 3 months ago

crlogic commented 3 months ago

Remove binary executable dependency

texroemer commented 3 months ago

Hi @crlogic

Tried your code changes and it's not working (see below). I was running into the same issues when trying to leverage native code, reason why i switched to use certutil to get import encoded base64 license string working.

PS C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH> .\Invoke-IdracLicenseManagementREDFISH.ps1 -idrac_ip 192.168.0.120 -idrac_username root -idrac_password calvin -share_type local -import_license C:\Users\Administrator\Downloads\15g-idrac-evaluation.xml

- INFO, importing license for iDRAC 192.168.0.120
Exception calling "ReadAllBytes" with "1" argument(s): "Could not find file 'C:\Users\Administrator\15g-idrac-evaluation.xml'."
At C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH\Invoke-IdracLicenseManagementREDFISH.ps1:615 char:5
+     $base64Str = [Convert]::ToBase64String([IO.File]::ReadAllBytes($F ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : FileNotFoundException

Cannot index into a null array.
At C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH\Invoke-IdracLicenseManagementREDFISH.ps1:617 char:9
+         $base64Str[0..63] -join ''
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

Cannot index into a null array.
At C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH\Invoke-IdracLicenseManagementREDFISH.ps1:618 char:39
+         $base64Str = $base64Str[64..$($base64Str.length)]
+                                       ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

Remove-Item : Cannot find path 'C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH\dummy_file.txt' because it does not exist.
At C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH\Invoke-IdracLicenseManagementREDFISH.ps1:641 char:1
+ Remove-Item dummy_file.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\Admini...\dummy_file.txt:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

{"error":{"@Message.ExtendedInfo":[{"Message":"Resource allocation 
failure.","MessageArgs":[""],"MessageArgs@odata.count":1,"MessageId":"IDRAC.2.9.LIC902","RelatedProperties":[],"RelatedProperties@odata.count":0,"Resolution":"Reset iDRAC and retry the 
operation.","Severity":"Critical"}],"code":"Base.1.12.GeneralError","message":"A general error has occurred. See ExtendedInfo for more information"}}

Thanks Tex

crlogic commented 3 months ago

Lots of errors there all stemming from Exception calling "ReadAllBytes" with "1" argument(s): "Could not find file 'C:\Users\Administrator\15g-idrac-evaluation.xml'."

I didn't want to touch all the logic you had around file handling. It seemed odd to be honest. Your requirements for all that weren't clear.

I was using Get-Content which provides a .FullName property so you don't have to do all the path splitting etc..

[edit] - typo

texroemer commented 3 months ago

Did you test your code changes and confirm XML license imports? Here's my original native code i was using where the license is in the same directory as running the cmdlet and fails to import.

$xml_file = Get-Content -Path $import_license -Raw
$bytes = [System.Text.Encoding]::UTF8.GetBytes($xml_file)
$base64String = [Convert]::ToBase64String($bytes)
$JsonBody = @{"FQDD"="iDRAC.Embedded.1";"ImportOptions"="Force";"LicenseFile"=$base64String}
$uri = "https://$idrac_ip/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLicenseManagementService/Actions/DellLicenseManagementService.ImportLicense"
$JsonBody = $JsonBody | ConvertTo-Json -Compress

PS C:\Users\Administrator\Documents\WindowsPowerShell\Modules\Invoke-IdracLicenseManagementREDFISH> .\Invoke-IdracLicenseManagementREDFISH.ps1 -idrac_ip 192.168.0.120 -idrac_username root -idrac_password calvin -share_type local -import_license C:\Users\Administrator\Downloads\15g-idrac-evaluation.xml

- INFO, importing license for iDRAC 192.168.0.120

{"error":{"@Message.ExtendedInfo":[{"Message":"The license file is corrupted, has not been unzipped, or is not a valid license 
file.","MessageArgs":[""],"MessageArgs@odata.count":1,"MessageId":"IDRAC.2.9.LIC017","RelatedProperties":[],"RelatedProperties@odata.count":0,"Resolution":"Download the license file, unzip and import the 
license.","Severity":"Critical"}],"code":"Base.1.12.GeneralError","message":"A general error has occurred. See ExtendedInfo for more information"}}
crlogic commented 3 months ago

Sorry my earlier response was amid a distracting time and I didn't give a good example.

Per your example, when I first read the API guide, I tried this too and it failed.

$bytes = [System.Text.Encoding]::UTF8.GetBytes($xml_file)
$base64String = [Convert]::ToBase64String($bytes)

The API guide is incomplete. The .xml needs to be base64 encoded AND padded 64 char per line.

Assuming $import_license is a string path to the .xml file try this..

Function ConvertTo-PaddedBase64 {
    Param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({Test-Path $_})]
        $File
    )
    $base64Str = [Convert]::ToBase64String([IO.File]::ReadAllBytes($File))
    $paddedStr = do {
        $base64Str[0..63] -join ''
        $base64Str = $base64Str[64..$($base64Str.length)]
    } until ($base64Str.Length -eq 0)
    $paddedStr | Out-String
}

$LicenseFile = Get-Item $import_license
[string]$hostLicContent = ConvertTo-PaddedBase64 $LicenseFile.FullName
$JsonBody = @{"FQDD"="iDRAC.Embedded.1";"ImportOptions"="Force";"LicenseFile"=$hostLicContent}
$uri = "https://$idrac_ip/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLicenseManagementService/Actions/DellLicenseManagementService.ImportLicense"
$JsonBody = $JsonBody | ConvertTo-Json -Compress
texroemer commented 3 months ago

Thanks, latest code you posted is working, cmdlet has been updated and posted. I'll also escalate internally to get our API guide updated with correct information.

Thanks again for all the help!

-Tex