Dictionaries/Dict.OS/Includes/Bootloader/Bootloader.psm1

$Script:SupportedBootLoaders = @('bcd', 'grub2', 'refind', 'syslinux')
function Get-OSBootloader {
    [CmdletBinding(DefaultParameterSetName = 'LISTAVAILABLE')]
    [OutputType([String])]
    Param (
        # List all available Bootloader and their options on this system
        [Parameter(ParameterSetName = 'LISTAVAILABLE')][switch]$ListAvailable,

        # List all available Bootloader and their options on this system
        [Parameter(ParameterSetName = 'LISTAVAILABLE')][switch]$ListBootLabel

        # # Type of the bootloader
        # [Alias('BL', 'BootLoader', 'Type')]
        # [ValidateSet('bcd', 'grub2', 'refind', 'syslinux')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLADERTYPE')]
        # [string]$BootLoaderType = '',

        # # MountPoint of a currently mounted volume or partition
        # [Alias('Volume', 'Letter', 'DriveLetter')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLADERTYPE')]
        # [string]$MountPoint
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $bootloaders = @()
        switch ($PSCmdlet.ParameterSetName) {
            'LISTAVAILABLE' {
                # list all partitions
                $parts = Get-ComputerDiskPartition
                # for each part:
                foreach ($p in $parts) {
                    # try to mount them
                    try {
                        $Mountpoints = Mount-ComputerDiskPartition -InputObject $p -Recurse -Force
                        # partition can have subvolume so we have to iterate through them
                        foreach ($mp in $Mountpoints) {
                            # ignore [SWAP]
                            if ($mp -eq "[SWAP]") { continue }
                            # search for known bootloaders
                            $bootloaders += Find-OSBootloader -Mountpoint $mp
                        }
                        # properly dismount partitions
                        $null = $p | Dismount-ComputerDiskPartition -Mountpoint $mp
                    } catch {
                        Write-Warning $_
                    }
                }
                # return results
                return $bootloaders
            }
        }
        # return $string
    }

    End {
        Write-LeaveFunction
    }
}

function Find-OSBootloader {
    [CmdletBinding()]
    [OutputType([hashtable[]])]
    Param (
        # MountPoint of a currently mounted volume or partition
        [Alias('Volume', 'Letter', 'DriveLetter')]
        [Parameter(Mandatory = $true, ParameterSetName = 'MOUNTPOINT')]
        [string]$MountPoint,

        # Type of the bootloader
        [Alias('BL', 'BootLoader', 'Type')]
        [ValidateSet('auto', 'bcd', 'grub2', 'refind', 'syslinux')]
        [Parameter(Mandatory = $false)]
        [string]$BootLoaderType = 'auto'
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $bootloaders = @()
        $bootloader = [PSCustomObject]@{
            Name = ""
            AbsolutePath = ""
            Mountpoint = ""
            RelativePath = ""
        }
        switch ($BootLoaderType) {
            'auto' {
                foreach ($blt in $Script:SupportedBootLoaders) {
                    $null = $PSBoundParameters.Remove("BootLoaderType")
                    $bootloaders += Find-OSBootloader @PSBoundParameters -BootLoaderType $blt
                }
            }
            'bcd' {
                # $cfg = Find-OSBootloaderbcdCfg -Path $MountPoint
                $Path = "EFI/Microsoft"
                $Filename = "BCD"
            }
            'grub2' {
                # $cfg = Find-OSBootloaderGrub2Cfg -Path $MountPoint
                $Path = ""
                $Filename = "grub.cfg"
            }
            'refind' {
                # $cfg = Find-OSBootloaderRefindCfg -Path $MountPoint
                $Path = ""
                $Filename = "refind.conf"
            }
            'syslinux' {
                # $cfg = Find-OSBootloadersyslinuxCfg -Path $MountPoint
                $Path = ""
                $Filename = "syslinux.cfg"
            }
        }
        if ($Filename) {
            try {
                $Exclude = @("proc", "Recovery", "run", "System Volume Information", "Temp*", "tmp")
                $LiteralPath = "$Mountpoint/$Path".replace("//", "/")
                $cfg = Get-ChildItem -LiteralPath $LiteralPath -Exclude $Exclude -Directory -ErrorAction SilentlyContinue | ForEach-Object { Get-ChildItem -Path $_ $Filename -Recurse -Depth 3 }
                $Partition = Get-ComputerDiskPartition -Mountpoint $Mountpoint
                if ($cfg) {
                    foreach ($c in $cfg) {
                        Write-Debug "Found $BootLoaderType bootloader configuration file '$($c.fullname)'."
                        $bootloader.Name = $BootLoaderType
                        $bootloader.AbsolutePath = $c.fullname
                        $bootloader.Mountpoint = $Partition.Mountpoint
                        $mnt = "$Mountpoint" -replace "\\", "/"
                        $fullname = $c.fullname -replace "\\", "/"
                        $bootloader.RelativePath = ($fullname -replace "^$mnt") -replace "/", "\"
                        $bootloaders += $bootloader
                    }
                }
            } catch {
                Write-Warning $_
            }
        }
        return $bootloaders
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSBootloaderBootEntries {
    [CmdletBinding()]
    [OutputType([object])]
    Param (
        # Type of the bootloader
        [Alias('BL', 'BootLoader', 'Type')]
        [ValidateSet('bcd', 'grub2', 'refind', 'syslinux')]
        [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLADERTYPE')]
        [string]$BootLoaderType,

        # MountPoint of a currently mounted volume or partition
        [Alias('Volume', 'Letter', 'DriveLetter')]
        [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLADERTYPE')]
        [string]$MountPoint
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $entries = @()
        switch ($BootLoaderType) {
            'bcd' { $entries = Get-OSBootloaderBCDBootEntries -All }
            'grub2' { $entries = Get-OSBootloaderGrub2BootEntries -All }
            'refind' { $entries = Get-OSBootloaderRefindBootEntries -All }
            'syslinux' { $entries = Get-OSBootloaderSyslinuxBootEntries -All }
            Default {}
        }
        return $entries
    }

    End {
        Write-LeaveFunction
    }
}

function Set-OSBootLoaderDefaultBoot {
    [CmdletBinding()]
    [OutputType([void])]
    Param (
        # Label of the bootloader to boot
        [Alias('Label', 'PartitionLabel')]
        [string]$BootLoaderLabel,

        # Type of the bootloader
        [Alias('BL', 'BootLoader')]
        [ValidateSet('auto', 'bcd', 'grub2', 'refind', 'syslinux')]
        [string]$BootLoaderType = 'auto',

        [string]$Mountpoint
    )
    Begin {
        Write-EnterFunction
        $bootloaders = Find-OSBootloader -MountPoint $Mountpoint
    }

    Process {
        switch ($BootLaderType) {
            'all' {
                foreach ($bl in $bootloaders) {
                    Set-OSBootLoaderDefaultBoot -Mountpoint $Mountpoint -OSBootloaderType $bl.name -OSBootloaderLabel $BootLoaderLabel
                }
            }
            'bcd' {
                $bl = $bootloaders | Where-Object { $_.name -eq $BootLoaderType }
                Set-OSBootloaderBCDDefaultBoot -ConfigFile $bl.cfgFullname -Label $BootLoaderLabel
            }
            'grub2' {
                $bl = $bootloaders | Where-Object { $_.name -eq $BootLoaderType }
                Set-OSBootloaderGrub2DefaultBoot -ConfigFile $bl.cfgFullname -Label $BootLoaderLabel
            }
            'refind' {
                $bl = $bootloaders | Where-Object { $_.name -eq $BootLoaderType }
                Set-OSBootloaderRefindDefaultBoot -ConfigFile $bl.cfgFullname -Label $BootLoaderLabel
            }
            'syslinux' {
                $bl = $bootloaders | Where-Object { $_.name -eq $BootLoaderType }
                Set-OSBootloaderSyslinuxDefaultBoot -ConfigFile $bl.cfgFullname -Label $BootLoaderLabel
            }
            default {
                Write-Error "Bootloader $BootLaderType is not yet supported."
            }
        }
    }

    End {
        Write-LeaveFunction
    }
}