Dictionaries/Dict.Linux/Dict.Linux.psm1

<#
 
  ###### ####### ## ## ######## ## ## ######## ######## ########
 ## ## ## ## ### ### ## ## ## ## ## ## ## ##
 ## ## ## #### #### ## ## ## ## ## ## ## ##
 ## ## ## ## ### ## ######## ## ## ## ###### ########
 ## ## ## ## ## ## ## ## ## ## ## ##
 ## ## ## ## ## ## ## ## ## ## ## ## ##
  ###### ####### ## ## ## ####### ## ######## ## ##
 
#>


<#
.SYNOPSIS
Get the computer name
 
.DESCRIPTION
 
.PARAMETER localhost
request localhost's ComputerName
 
.EXAMPLE
$name = Get-ComputerName -Localhost
 
.NOTES
This function comes from Dict.Unix module.
#>

function Get-ComputerName {
    [CmdletBinding()]Param (
        [switch]$localhost
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Localhost) {
            return hostname
        }
    }

    End {
        Write-LeaveFunction
    }
}

function Get-ComputerDomain {
    hostname -d
}

function Get-ComputerManufacturer {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$localhost
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return (New-HashtableFromCommand -Command "dmidecode | awk '/^System Information/,/^$/'" -sep ":" -SkipFirstLines 1).manufacturer
    }

    End {
        Write-LeaveFunction
    }
}

function Get-ComputerModel {
    [CmdletBinding()]Param (
        [switch]$localhost
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return (dmidecode | awk '/^System Information/,/^$/' | Select-Object -Skip 1 | ConvertFrom-StringData -Delimiter ":")."product name"
        # return (New-HashtableFromCommand -Command "dmidecode | awk '/^System Information/,/^$/'" -sep ":" -SkipFirstLines 1)."product name"
    }

    End {
        Write-LeaveFunction
    }
}

function Get-ComputerSerialNumber {
    [CmdletBinding()]Param (
        [switch]$localhost
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return (New-HashtableFromCommand -Command "dmidecode | awk '/^System Information/,/^$/'" -sep ":" -SkipFirstLines 1)."serial number"
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Get the computer boot order
 
.DESCRIPTION
Fetch the computer order from UEFI
 
.EXAMPLE
Get-ComputerBootOrderUEFI
 
.NOTES
General notes
#>

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

    Process {
        $BootOrderIds = (efibootmgr | grep "^BootOrder:" | cut -d ':' -f 2 | tr -d ' ' | tr ',' '\n')
        $BootOrderArray = @()
        foreach ($id in $BootOrderIds) {
            $BootOrderArray += (efibootmgr | grep "^Boot${id}" | cut -d' ' -f2-)
        }

        return $BootOrderArray
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Get the computer's next boot entry
 
.DESCRIPTION
Fetch the next boot entry from UEFILABEL
 
.EXAMPLE
Get-ComputerNextBootUEFI
 
.NOTES
General notes
#>

function Get-ComputerNextBootUEFI {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$string
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return (Get-ComputerBootOrderUEFI)[0]
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Know if computer was booted using old legacy BIOS mode or new UEFI.
 
.DESCRIPTION
To make next boot efficient, we need to know in what mode the computer booted to this stage.
This function will tell us that.
If every tests fail, or if we can't determined the boot mode, it default to "BIOS" mode.
 
.EXAMPLE
$bootMode = Get-ComputerBootMode
 
.NOTES
General notes
#>

function Get-ComputerBootMode {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$string
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $bootMode = "BIOS"
        if (Test-DirExist "/sys/firmware/efi") { $bootMode = "UEFI" }

        return $bootMode
    }

    End {
        Write-LeaveFunction
    }
}

function Get-ComputerFirmwareType {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][switch]$Localhost
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Localhost) {
            return Get-ComputerBootMode
        }
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Configure computer to boot on user-asked partition
 
.DESCRIPTION
This function configure the boot flag on the correct partition
 
.PARAMETER Force
Force things
 
.PARAMETER Label
Label of the partition to configure
 
.PARAMETER MountPoint
Mountpoint of the target partition
 
.PARAMETER Disk
Disk device name of the partition
 
.PARAMETER PartNum
Partition number (can be several strings char since nvme disks. e.g. 'p1')
 
.PARAMETER Device
Full device adress like in '/dev/sda1'
 
.NOTES
General notes
#>

function Set-ComputerNextBootBIOS {
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([Boolean])]
    Param (
        # # [switch]$Force,

        # # Label of an UEFI boot entry
        # [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')][string]$UefiLabel = "Windows Boot Manager",

        # # Label of the bootloader entry
        # # This can be used with any other options as the final active partition may contain a bootloader
        # [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTLABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'MOUNTPOINT')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLOADERLABEL')]
        # [string]$BootLoaderLabel, # = "Windows",

        # # Specify bootloader type
        # # specifying it will improve performance
        # # not specifying it will make script to search for all bootloaders and configure them
        # [ValidateSet('all', 'bcd', 'grub2', 'refind', 'syslinux')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLOADERLABEL')][string]$BootLoaderType,

        # # Label of the partition to configure
        # [Alias('Label', 'PartitionLabel', 'Volume')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'PARTLABEL')][string]$PartLabel,

        # # MountPoint of a currently mounted volume or partition
        # [Alias('Letter', 'DriveLetter')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'MOUNTPOINT')][string]$MountPoint,

        # # Disk device name of the partition
        # [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')][string]$Disk,

        # # Partition number (can be several strings char since nvme disks. e.g. 'p1')
        # [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')][string]$PartNum,

        # # Full device address like in '/dev/sda1'
        # [Parameter(Mandatory = $false, ParameterSetName = 'DEVICE')][string]$Device,

        # # Boot PXE using IPv4 stack (only available with UEFI firmware)
        # [Alias('PXE')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv4,

        # # Boot PXE using IPv6 stack (only available with UEFI firmware)
        # [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv6,

        # # If BIOS/UEFI is password-protected, specify it here as a secureString
        # [Parameter(Mandatory = $false)][secureString]$Password

        # Label of the UefiEntry to configure
        [Alias('Efi', 'Uefi')]
        [ArgumentCompleter({
            param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
            $uefi = Get-UEFIBootEntry
            # $entry = $bcd.Keys | Where-Object { $bcd.$_.description -like "$wordToComplete*" }
            # $bcd[$entry].description
            $uefi.label -like "$wordToComplete*"
        })]
        [ValidateScript({
            $uefi = Get-UEFIBootEntry
            # $_ -in ($bcd.Values.description)
            $_ -in ($uefi.label)
        })]
        [Parameter(Mandatory = $true, ParameterSetName = 'UEFILABEL')]
        [string]$UefiLabel,

        # Label of the partition to configure
        # On legacy BIOS, it will activate correct partition
        # On UEFI, it will specify which partition is the EFI partition
        [Alias('PartitionLabel')]
        [Parameter(Mandatory = $true, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'PARTLABEL')]
        [string]$PartLabel,

        # Label of the partition to configure
        # On legacy BIOS, it will activate correct partition
        # On UEFI, it will specify which partition is the EFI partition
        [Alias('PartitionUUID')]
        [Parameter(Mandatory = $true, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'PARTUUID')]
        [string]$PartUUID,

        # Label of the bootloader to boot
        [Parameter(Mandatory = $true, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTLABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTUUID')]
        [string]$BootLoaderLabel,

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

        # Boot PXE using IPv4 stack (only available with UEFI firmware)
        [Alias('PXE')]
        [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv4,

        # Boot PXE using IPv6 stack (only available with UEFI firmware)
        [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv6

        # If BIOS/UEFI is password-protected, specify it here as a secureString
        # [Parameter(Mandatory = $false)][secureString]$Password
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $diskpart = $null
        switch ($PSCmdlet.ParameterSetName) {
            'UEFILABEL' {
                Write-Error "This computer seems to be in legacy BIOS mode, not in UEFI mode."
                return $false
            }
            'PARTLABEL' {
                $diskpart = blkid -t PARTLABEL="$Label" -o device
            }
            'MOUNTPOINT' {
                $diskpart = mount | grep " on $MountPoint " | awk '{ printf $1 }' | head -n 1
            }
            'DISKPART' {
                $diskId = $Disk.Split('/')[-1]
                $d = find /dev -name "$diskId"
                $diskpart = "$d$PartNum"
            }
            'Device' {
                $diskpart = $Device
            }
        }
        if ([string]::IsNullOrEmpty($diskpart)) { return $false }

        $rc = Execute-Command -exe parted -args "-s $diskpart set boot on"
        return $rc
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Configure computer to boot on user-asked partition
 
.DESCRIPTION
This function configure UEFI to next-boot a specified device
 
.NOTES
General notes
#>

function Set-ComputerNextBootUEFI {
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([Boolean])]
    Param (
        # # [switch]$Force,
        # # # Label of an UEFI boot entry to use to configure next boot
        # # [Parameter(Mandatory = $false)][string]$UseUefiLabel = "Klonebot Boot Manager",
        # # Label of an UEFI boot entry
        # [ArgumentCompleter({
        # param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
        # $uefi = Get-UEFIBootEntry
        # # $entry = $bcd.Keys | Where-Object { $bcd.$_.description -like "$wordToComplete*" }
        # # $bcd[$entry].description
        # $uefi.label -like "$wordToComplete*"
        # })]
        # [ValidateScript({
        # $uefi = Get-UEFIBootEntry
        # # $_ -in ($bcd.Values.description)
        # $_ -in ($uefi.label)
        # })]
        # [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')][string]$UefiLabel = "Default Boot Manager",

        # # Label of the bootloader entry
        # # This can be used with any other options as the final active partition may contain a bootloader
        # [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTLABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'MOUNTPOINT')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLOADERLABEL')]
        # [string]$BootLoaderLabel, # = "Windows",

        # # Specify bootloader type
        # # specifying it will improve performance
        # # not specifying it will make script to search for all bootloaders and configure them
        # [ValidateSet('all', 'bcd', 'grub2', 'refind', 'syslinux')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'BOOTLOADERLABEL')][string]$BootLoaderType,

        # # Label of a partition
        # [Alias('Label', 'PartitionLabel')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTLABEL')][string]$PartLabel,
        # # MountPoint of a currently mounted volume or partition
        # [Alias('Volume', 'Letter', 'DriveLetter')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'MOUNTPOINT')][string]$MountPoint,
        # # disk device name
        # [AllowNull]
        # [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')][string]$Disk,
        # # partition number
        # [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')][string]$PartNum,
        # # full device address
        # [Parameter(Mandatory = $false, ParameterSetName = 'DEVICE')][string]$Device,
        # # Boot PXE using IPv4 stack (only available with UEFI firmware)
        # [Alias('PXE')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv4,
        # # Boot PXE using IPv6 stack (only available with UEFI firmware)
        # [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv6,

        # # If BIOS/UEFI is password-protected, specify it here as a secureString
        # [Parameter(Mandatory = $false)][secureString]$Password

        # Label of the UefiEntry to configure
        [Alias('Efi', 'Uefi')]
        [ArgumentCompleter({
            param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
            $uefi = Get-UEFIBootEntry
            # $entry = $bcd.Keys | Where-Object { $bcd.$_.description -like "$wordToComplete*" }
            # $bcd[$entry].description
            $uefi.label -like "$wordToComplete*"
        })]
        [ValidateScript({
            $uefi = Get-UEFIBootEntry
            # $_ -in ($bcd.Values.description)
            $_ -in ($uefi.label)
        })]
        [Parameter(Mandatory = $true, ParameterSetName = 'UEFILABEL')]
        [string]$UefiLabel,

        # Label of the partition to configure
        # On legacy BIOS, it will activate correct partition
        # On UEFI, it will specify which partition is the EFI partition
        [Alias('PartitionLabel')]
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'PARTLABEL')]
        [string]$PartLabel,

        # Label of the partition to configure
        # On legacy BIOS, it will activate correct partition
        # On UEFI, it will specify which partition is the EFI partition
        [Alias('PartitionUUID')]
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $true, ParameterSetName = 'PARTUUID')]
        [string]$PartUUID,

        # Label of the bootloader to boot
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTLABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTUUID')]
        [string]$BootLoaderLabel,

        # Type of the bootloader
        [Alias('BL', 'BootLoader')]
        [ValidateSet('auto', 'bcd', 'grub2', 'refind', 'syslinux')]
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTLABEL')]
        # [Parameter(Mandatory = $false, ParameterSetName = 'PARTUUID')]
        [string]$BootLoaderType = 'auto',

        # Boot PXE using IPv4 stack (only available with UEFI firmware)
        [Alias('PXE')]
        [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv4,

        # Boot PXE using IPv6 stack (only available with UEFI firmware)
        [Parameter(Mandatory = $false, ParameterSetName = 'NETWORK')][switch]$PXEv6

        # If BIOS/UEFI is password-protected, specify it here as a secureString
        # [Parameter(Mandatory = $false)][secureString]$Password
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $bootNum = $null
        switch ($PSCmdlet.ParameterSetName) {
            'UEFILABEL' {
                $bootNum = Get-UEFIBootEntry -UefiLabel $UefiLabel
            }
            # 'MOUNTPOINT' {
            # $diskpart = mount | grep " on $MountPoint " | awk '{ printf $1 }' | head -n 1
            # }
            # 'DISKPART' {
            # $disk = $Disk.Split('/')[-1]
            # $d = find /dev -name "$disk"
            # $diskpart = "$d$PartNum"
            # }
            # 'Device' {
            # $diskpart = $Device
            # }
            'NETWORK' {
                # try a set of values as manufacturer use their own
                if ($PXEv4) {
                    # Dell
                    if ([string]::IsNullOrEmpty($bootnum)) {
                        $bootNum = (Get-UEFIBootEntry -UefiLabel "Onboard NIC(IPV4)").bootnum
                    }
                }
                if ($PXEv6) {
                    # Dell
                    if ([string]::IsNullOrEmpty($bootnum)) {
                        $bootNum = (Get-UEFIBootEntry -UefiLabel "Onboard NIC(IPV6)").bootnum
                    }
                }
                # Dell
                if ([string]::IsNullOrEmpty($bootnum)) {
                    $bootNum = (Get-UEFIBootEntry -UefiLabel "Onboard NIC").bootnum
                }
                # VMware
                if ([string]::IsNullOrEmpty($bootnum)) {
                    $bootNum = (Get-UEFIBootEntry -UefiLabel "EFI Network").bootnum
                }
            }
            default {
                Write-Warning "Parameters '$($PSCmdlet.ParameterSetName)' not implemented yet."
            }
        }

        if ([string]::IsNullOrEmpty($bootNum)) { return $false }
        $rc = Execute-Command -exe efibootmgr -args "--bootnext $bootNum"
        return $rc
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Modify UEFI default boot entry
 
.DESCRIPTION
Long description
 
.EXAMPLE
An example
 
.NOTES
General notes
#>

function Set-ComputerUEFINextBoot {
    [CmdletBinding()]
    [OutputType([Boolean])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][object]$UefiEntry
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $rc = Execute-Command -exe efibootmgr -args "--bootnext $($UefiEntry.bootNum)"
        return $rc
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Fetch a disk/part device name from various source criteria
 
.DESCRIPTION
Search for a full disk/partition device name
 
.EXAMPLE
Get-DiskPartDeviceName -PartUUID a80e3a47-2895-46cf-ba2b-dccbeac8a50b
 
will return "nvme0n1p1" for example on a M.2 PCIe disk
 
.EXAMPLE
Get-DiskPartDeviceName -PartLabel "EFI System Partition"
 
.NOTES
General notes
#>

function Get-DiskPartDeviceName {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # Partition UUID to search for
        [Parameter(Mandatory = $true, ParameterSetName = 'PARTUUID')][string]$PartUUID,
        # Partition Label to search for
        [Parameter(Mandatory = $true, ParameterSetName = 'PARTLABEL')][string]$PartLabel
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $device = $null
        switch ($PSCmdlet.ParameterSetName) {
            'PARTUUID' {
                [array]$blk = (blkid | Select-String "PARTUUID=`"$PartUUID`"") -split " "
                if ($blk[0] -match "^/dev/(?<deviceName>.*):") {
                    $device = $Matches.deviceName
                } else {
                    Write-Error "No device found with partition UUID '$PartUUID'"
                }
            }
            'PARTLABEL' {
                # The regex martch LABEL= and PARTLABEL=
                [array]$blk = (blkid | Select-String "LABEL=`"$Label`"") -split " "
                if ($blk[0] -match "^/dev/(?<deviceName>.*):") {
                    $device = $Matches.deviceName
                } else {
                    Write-Error "No device found with partition label '$Label'"
                }
            }
        }

        return $device
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Get details of an UEFI boot entry
 
.DESCRIPTION
Return UEFI boot entry details as an object
 
.EXAMPLE
Get-UEFIBootEntry -UefiLabel "Windows Boot Manager"
 
.NOTES
General notes
#>

function Get-UEFIBootEntry {
    [CmdletBinding(DefaultParameterSetName = 'ALL')]
    [OutputType([string])]
    Param (
        # Key name to search on
        [Parameter(Mandatory = $false, ParameterSetName = 'KEYVALUE')][string]$Key,
        # Value to find within key
        [Parameter(Mandatory = $false, ParameterSetName = 'KEYVALUE')][string]$Value,
        # Label of an UEFI boot entry
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')][string]$UefiLabel,
        # Show all entries label
        [Parameter(Mandatory = $false, ParameterSetName = 'ALL')][switch]$All
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $uefiEntries = @()
        efibootmgr -v | select-string "^Boot\d" | ForEach-Object {
            [array]$uefiTemp = $_ -split "\t"
            [string]$id = ($uefiTemp[0] -split " ",2)[0] -replace "\*", ""
            [string]$bootnum = $id -replace "\D", ""
            [string]$label = ($uefiTemp[0] -split " ",2)[1]
            [string]$raw = $uefiTemp[1]
            [string]$device = ($raw -split "/")[0]
            if ($raw -match "HD\((?<disknum>\d*),(?<diskformat>\w*),(?<partuuid>.*),.*\)/File\((?<filename>.*)\)") {
                [string]$PartUUID = $Matches.partuuid
                [int]$disknum = $Matches.disknum
                [string]$diskformat = $Matches.diskformat
                [string]$filename = $Matches.filename
            }
            $uefiEntry = @{
                "id" = $id;
                "bootnum" = $bootnum
                "label" = $label
                "description" = $label
                "raw" = $raw
                "device" = $device
                "partUUID" = $PartUUID
                "path" = $filename
                "disknum" = $disknum
                "diskformat" = $diskformat
                "filename" = $filename
            }
            $uefiEntries += $uefiEntry
        }

        switch ($PSCmdlet.ParameterSetName) {
            'UEFILABEL' {
                return ($uefiEntries | Where-Object { $_.label -eq $UefiLabel })
            }
            'KEYVALUE' {
                # $id = ($bcd.keys | Where-Object { $bcd.$_.$Key -eq $Value })
                # return $bcd.$id
                return ($uefiEntries | Where-Object { $_.$Key -eq $Value })
            }
            default {
                return $uefiEntries
            }
        }
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Test if a user (or current user) is admin
 
.DESCRIPTION
This function can take an uid or a username as argument.
 
.EXAMPLE
Test-UserIsAdmin
Test if currently logged on user have admin rights (= is root)
 
.EXAMPLE
Test-UserIsAdmin -username root
Test is user 'root' have admin rights
 
.OUTPUTS
$true is provided user is admin, $false otherwise
#>

function Test-UserIsAdmin {
    [CmdletBinding(DefaultParameterSetName="username")][OutputType([Boolean])]Param (
        [Parameter(ParameterSetName = "username")]
        [Alias("user", "name", "login")]
        [string]$Username = $env:USER,
        [Parameter(ParameterSetName = "id")]
        [Alias("uid", "sid")]
        [string]$id = (id -u)
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'username' {
                return ((id -u $username) -eq 0)
            }
            'id' {
                return ((id -u $id) -eq 0)
            }
            default {
                # unknown parametersetname
                return $false
            }
        }

        return $false
   }

    End {
        Write-LeaveFunction
    }
}

New-Alias -Name userIsAdmin -Value Test-UserIsAdmin -Force
New-Alias -Name isAdmin     -Value Test-UserIsAdmin -Force
New-Alias -Name IAmAdmin    -Value Test-UserIsAdmin -Force
New-Alias -Name AmIAdmin    -Value Test-UserIsAdmin -Force

<#
 
 ######## ### ###### ## ## ###### ###### ## ## ######## ######## ## ## ## ######## ########
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ###### ##### ###### ## ######### ###### ## ## ## ## ## ###### ########
    ## ######### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ###### ## ## ###### ###### ## ## ######## ######## ####### ######## ######## ## ##
 
#>


<#
.SYNOPSIS
Create a new folder in the Operating System's task scheduler
 
.DESCRIPTION
Create a new folder in the Operating System's task scheduler daemon.
 
.PARAMETER FolderName
The name of the folder to create
 
.PARAMETER Root
An optional root folder to be the parent of the folder to create
 
.EXAMPLE
New-PwShFwScheduledTaskFolder -FolderName "MyDaemon"
 
.NOTES
On linux, this function just create an empty file under /etc/cron.d by default
#>

function New-PwShFwScheduledTaskFolder {
    [CmdletBinding()]
    [OutputType([Boolean])]
    [Alias('New-CronTaskFile')]
    Param (
        [Alias('Name')]
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$FolderName,
        [string]$Root = '/etc/cron.d'
    )
    Begin {
        Write-EnterFunction
    }

    Process {
         $ErrorActionPreference = "stop"
        Try {
           $null = New-Item -Path $Root -Name $FolderName -ItemType File
        } Catch {
        } Finally {
            $ErrorActionPreference = "continue"
        }

        # test to return correct value
        if (Test-FileExist "$Root/$FolderName") {
            return $true
        } else {
            return $false
        }
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Create a new scheduled task / cron job
 
.DESCRIPTION
New-PwShFwScheduledTask function is a cross-platform wrapper for Scheduled Task / cron jobs.
It creates a full scheduled task / cron job within one command whatever the underlying OS is.
 
.PARAMETER Folder
Optional Folder name into which to create the task
 
.PARAMETER Name
Name of the task
 
.PARAMETER Command
Command or script to run
 
.PARAMETER Parameters
Arguments to pass to the command
 
.PARAMETER Description
Optional description of the task
 
.PARAMETER Username
Username to use to launch the task
default = root
 
.PARAMETER Minutes
Set the minutes number to trigger job (can be '*' to run every minutes).
Default = '*'
 
.PARAMETER Hour
Set the hour number to trigger job (can be '*' to run every hours).
Default = '*'
 
.PARAMETER DayOfMonth
Set the day of the month number to trigger job (can be '*' to run every days).
Default = '*'
 
.PARAMETER DayOWeek
Set the day of week number to trigger job (can be '*' to run every days of week).
Default = '*'
 
.PARAMETER Month
Set the month number to trigger job (can be '*' to run every months).
Default = '*'
 
.PARAMETER Year
Set the year number to trigger job (can be '*' to run every years).
Default = '*'
 
.PARAMETER EveryMinutes
Equals to -Minute '*'
 
.PARAMETER Hourly
Equals to -Minute 0 -Hours '*'
 
.PARAMETER Daily
Equals to -Minute 0 -Hours 0 -DayOfMonth '*'
 
.PARAMETER Weekly
Equals to -Minute 0 -Hours 0 -DayOfWeek 1 -Week '*'
 
.PARAMETER Monthly
Equals to -Minute 0 -Hours 0 -DayOfMonth 1 -Month '*'
 
.PARAMETER Yearly
Equals to -Minute 0 -Hours 0 -DayOfMonth 1 -Month 1 -Year '*'
 
.PARAMETER AtStartup
Trigger job on system startup
 
.PARAMETER AtLogon
Trigger job on session logon
 
.EXAMPLE
An example
 
.NOTES
General notes
#>

function New-PwShFwScheduledTask {
    [CmdletBinding(DefaultParameterSetName = 'EXACT_TRIGGER')]
    [OutputType([String])]
    Param (
        [string]$Folder,
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Name,
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Command,
        [Parameter(Mandatory = $false, ValueFromPipeLine = $true)][string]$Parameters,
        [string]$Description,
        [string]$Username = $env:USER,
        [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$Minute = '*',
        [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$Hour = '*',
        [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$DayOfMonth = '*',
        [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$DayOfWeek = '*',
        # [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$Week = '*',
        [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$Month = '*',
        [Parameter(ParameterSetName = 'EXACT_TRIGGER')][string]$Year = '*',
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$EveryMinutes,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$Hourly,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$Daily,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$Weekly,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$Monthly,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$Yearly,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$AtStartup,
        [Parameter(ParameterSetName = 'ALIAS_TRIGGER')][switch]$AtLogon
    )
    Begin {
        Write-EnterFunction
        $Filename = $Folder ? "/etc/cron.d/$Folder-$Name" : "/etc/cron.d/$Name"
    }

    Process {
        if ([string]::IsNullOrEmpty($Description)) { $Description = "$Name - $Command $Parameters" }
        $trigger = ""
        switch ($PSCmdlet.ParameterSetName) {
            'EXACT_TRIGGER' {
                $trigger = "$Minute $Hour $DayOfMonth $Month $DayOfWeek"
            }
            'ALIAS_TRIGGER' {
                if ($EveryMinutes)    { $trigger = "* * * * *" }
                if ($Hourly)        { $trigger = "0 * * * *" }
                if ($Daily)            { $trigger = "0 0 * * *" }
                if ($Weekly)        { $trigger = "0 0 * * 0" }
                if ($Monthly)        { $trigger = "0 0 1 * *" }
                if ($Yearly)        { $trigger = "0 0 1 1 *" }
                if ($AtStartup)        { $trigger = "@reboot" }
            }
        }

        $task = @"
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# $Description
$trigger $Username $Command $Parameters
"@

        try {
            $task | Out-File -FilePath $Filename -Encoding utf8
            $rc = $?
        } catch {
            eerror $_
            $rc = $false
        }

        return $rc
    }

    End {
        Write-LeaveFunction
    }
}