Dictionaries/Dict.Linux/Dict.Linux.psm1

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


<#
.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()]
    [OutputType([Boolean])]
    Param (
        [switch]$Force,
        [Parameter(Mandatory = $true, ParameterSetName = 'LABEL')][string]$Label,
        [Alias('Volume', 'Letter', 'DriveLetter')]
        [Parameter(Mandatory = $true, ParameterSetName = 'MOUNTPOINT')][string]$MountPoint,
        [AllowNull]
        [Parameter(Mandatory = $false, ParameterSetName = 'DISKPART')][string]$Disk,
        [Parameter(Mandatory = $true, ParameterSetName = 'DISKPART')][string]$PartNum,
        [Parameter(Mandatory = $true, ParameterSetName = 'DEVICE')][string]$Device
        )
    Begin {
        Write-EnterFunction
    }

    Process {
        $diskpart = $null
        switch ($PSCmdlet.ParameterSetName) {
            'LABEL' {
                $diskpart = blkid -t PARTLABEL="$Label" -o device
            }
            '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
            }
        }
        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()]
    [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
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')][string]$UefiLabel = "Klonebot Boot Manager",
        # 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
        )
    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
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()]
    [OutputType([Array])]
    Param (
        # Label of an UEFI boot entry
        [Parameter(Mandatory = $false, ParameterSetName = 'UEFILABEL')][string]$UefiLabel
    )
    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
                [string]$path = $Matches.filename
            }
            $uefiEntry = @{
                "id" = $id;
                "bootnum" = $bootnum
                "label" = $label
                "raw" = $raw
                "device" = $device
                "partUUID" = $PartUUID
                "path" = $path
            }
            $uefiEntries += $uefiEntry
        }

        switch ($PSCmdlet.ParameterSetName) {
            'UEFILABEL' {
                return ($uefiEntries | Where-Object { $_.label -eq $UefiLabel })
            }
            default {
                return $uefiEntries
            }
        }
    }

    End {
        Write-LeaveFunction
    }
}

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


<#
.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
    }
}