Libraries/Bootloader/Includes/Bootloader.refind.psm1


<#
.SYNOPSIS
Search for a refind configuration

.DESCRIPTION
Search into local partition for a refind.conf file.
Default search for a "refind.conf" file. If config name is overriden, use -Filename to search for custom filename.

.EXAMPLE
Find-BootloaderRefindCfg -Path "/boot"

.EXAMPLE
Find-BootloaderRefindCfg -Path "/boot" -Filename "myrefind.conf"

.NOTES
General notes
#>

function Find-BootloaderRefindCfg {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # Path to start search
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path,
        # Custom filename to search for
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Filename = "refind.conf"
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $filename = Get-ChildItem -Path $Path $Filename -Recurse
        return ${refindcfg}?.fullname
    }

    End {
        Write-LeaveFunction
    }
}
function Get-BootloaderRefindDefaultBoot {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [Alias('ConfigFile')]
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false, ParameterSetName = 'FILENAME')][string]$Filename = "/boot/Refind/Refind.conf",
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false, ParameterSetName = 'CONTENT')][array]$Content
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $rc = (Get-Content $Filename | select-string "^LABEL") | ForEach-Object { $_ -match "^LABEL\s*(?<label>\w+)" }
        if ($rc) {
            return $Matches.label
        } else {
            return $null
        }
    }

    End {
        Write-LeaveFunction
    }
}

function Set-BootloaderRefindDefaultBoot {
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    Param (
        [Alias('ConfigFile')]
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Filename = "/boot/Refind/Refind.conf",
        [Parameter(Mandatory = $true, ValueFromPipeLine = $false)][string]$label
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $Refind = (Get-Content $Filename -Raw) -replace "^DEFAULT .*", "DEFAULT $label"
        $Refind | Out-File $Filename
        return $?
    }

    End {
        Write-LeaveFunction
    }
}

function Get-BootloaderRefindHashtable {
    [CmdletBinding()]
    [OutputType([hashtable])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Filename
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $refind = @{}
        # $content = (Get-Content $Filename | Select-String -Pattern "^[a-zA-Z_0-9]+" -AllMatches | Select-String "menuentry" -NotMatch) -replace '(^[a-zA-Z_0-9]+)', '${1} = ' | ConvertFrom-StringData
        # foreach ($key in $content.keys) {
        # $refind.Add($key, $content.$key)
        # }
        # $content = (Get-Content $Filename | Select-String -Pattern "^[a-zA-Z_0-9]+" -AllMatches | Select-String "menuentry" -NotMatch) -replace '(^[a-zA-Z_0-9]+)', '${1} = ' | ConvertFrom-StringData
        foreach ($line in (Get-Content $Filename)) {
            if ($line -match "^(?<name>[a-zA-Z_0-9]+)\s(?<value>.*)") {
                switch ($matches.name) {
                    'menuentry' { continue }
                    Default {
                        $refind.Add($matches.name, $matches.value)
                    }
                }
            }
        }
        $entries = (Get-Content -Raw $Filename) -split '\r?\n\r?\n' -match '^menuentry'
        $menuentries = @()
        foreach ($entry in $entries) {
            $menuentry = @{}
            # flatten menuentry
            $flatEntry = (($entry -split '\n' -replace '^\s+') -replace '\\', '/' | Select-String "^#" -NotMatch -AllMatches) -replace ' {' -replace '}'
            # convert to hashtable
            $hash = $flatEntry -replace '(^[a-zA-Z_0-9]+)', '${1} = ' | ConvertFrom-StringData
            foreach ($key in $hash.keys) {
                $menuentry.Add($key, $hash.$key)
            }
            $menuentries += $menuentry
        }
        $refind.Add("menuentries", $menuentries)
        return $refind
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Convert a refind.conf file into a usable object

.DESCRIPTION
Load a refind.conf file into an array. We can not convert to a hastable as keys can be declared multiple times.
'default_selection' for example or 'initrd'.

.EXAMPLE
Get-BootloaderRefindArray -ConfigurationFile /boot/EFI/refind/refind.conf

.NOTES
General notes
#>

function Get-BootloaderRefindArray {
    [CmdletBinding()]
    [OutputType([array])]
    Param (
        # Full path to refind.conf to load
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Filename
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $refind = @()
        # $content = (Get-Content $Filename | Select-String -Pattern "^[a-zA-Z_0-9]+" -AllMatches | Select-String "menuentry" -NotMatch) -replace '(^[a-zA-Z_0-9]+)', '${1} = ' | ConvertFrom-StringData
        # foreach ($key in $content.keys) {
        # $refind += @{$key = $content.$key}
        # }
        foreach ($line in (Get-Content $Filename)) {
            # # keep comments
            # if ($line -match "^#") {
            # $refind += $line
            # }

            if ($line -match "^(?<name>[a-zA-Z_0-9]+)\s(?<value>.*)") {
                switch ($matches.name) {
                    'menuentry' { continue }
                    Default {
                        $refind += @{$matches.name = $matches.value}
                    }
                }
            }
        }
        $entries = (Get-Content -Raw $Filename) -split '\r?\n\r?\n' -match '^menuentry'
        $menuentries = @()
        foreach ($entry in $entries) {
            $menuentry = @()
            foreach ($line in ($entry -split '\n' -replace '^\s+')) {
                if ($line -match "^(?<name>[a-zA-Z_0-9]+)\s(?<value>.*)") {
                    switch ($matches.name) {
                        'menuentry' {
                            $menuentry += @{$matches.name = $matches.value -replace ' {'}
                        }
                        Default {
                            $menuentry += @{$matches.name = $matches.value}
                        }
                    }
                }
            }
            $menuentries += @(, $menuentry)
        }
        $refind += @{"menuentries" = $menuentries}
        return $refind
    }

    End {
        Write-LeaveFunction
    }
}

function Get-BootloaderRefind {
    [CmdletBinding()]
    [OutputType([array])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Filename
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return Get-BootloaderRefindArray @PSBoundParameters
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Convert a refind configuration array to a form writable to a file

.DESCRIPTION
Convert a previously loader configuration in a form suitable to be wrote again

.EXAMPLE
$content | Out-BootloaderRefindConf | Out-File /boot/EFI/refind/refind.conf

.NOTES
General notes
#>

function Out-BootloaderRefindConf {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][array]$Content
    )
    Begin {
        Write-EnterFunction
        @"
#
# refind.conf
# Please read refind.conf-sample in the same directory to get explanations
# or consult official help @url https://www.rodsbooks.com/refind/configfile.html
#
"@

    }

    Process {

        for ($i = 0; $i -lt $Content.Count; $i++) {
            foreach ($key in $Content[$i].keys) {
                switch ($key) {
                    'menuentries' {
                        foreach ($menuentry in $Content.menuentries) {
                            ""
                            for ($j = 0; $j -lt $menuentry.Count; $j++) {
                                foreach ($mkey in $menuentry[$j].keys) {
                                    switch ($mkey) {
                                        'menuentry' {
                                            ""
                                            "menuentry $($menuentry[$j].$mkey) {"
                                        }
                                        Default {
                                            " $mkey $($menuentry[$j].$mkey)"
                                        }
                                    }
                                }
                            }
                            "}"
                        }
                    }
                    Default {
                        "$key $($Content[$i].$key)"
                    }
                }
            }
        }
    }

    End {
        ""
        Write-LeaveFunction
    }
}