Libraries/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
                    $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
                }
                # 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]@{}
        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) {
            $Exclude = @("proc", "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 | Add-Member -MemberType NoteProperty -Name "Name" -Value $BootLoaderType
                    $bootloader | Add-Member -MemberType NoteProperty -Name "AbsolutePath" -Value $c.fullname
                    $bootloader | Add-Member -MemberType NoteProperty -Name "Mountpoint" -Value $Partition.Mountpoint
                    $bootloader | Add-Member -MemberType NoteProperty -Name "RelativePath" -Value $($c.fullname -replace "^$Mountpoint")
                    $bootloaders += $bootloader
                }
            }
        }
        return $bootloaders
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSBootloaderBootEntry {
    [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' { $entry = Get-OSBootloaderBCDBootEntry -All }
            'grub2' { $entry = Get-OSBootloaderGrub2BootEntry -All }
            'refind' { $entry = Get-OSBootloaderRefindBootEntry -All }
            'syslinux' { $entry = Get-OSBootloaderSyslinuxBootEntry -All }
            Default {}
        }
        $entry | Add-Member -MemberType NoteProperty -Name "BootLoader" -Value $BootLoaderType
        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
    }
}