Dictionaries/Computer.Dict.Linux/Computer.Dict.Linux.psm1

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


# function Get-MyInvocation {
# [CmdletBinding()]
# [OutputType([String])]
# Param (
# )
# Begin {
# Write-EnterFunction
# }

# Process {
# $MyInvocation
# }

# End {
# Write-LeaveFunction
# }
# }

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

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

    Process {
        # delete everything after 1st dot to get only hostname (e.g. without domainname)
        return (hostname) -replace "\..*"
    }

    End {
        Write-LeaveFunction
    }
}

function Get-ComputerDomain {
    hostname -d
}

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

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

    End {
        Write-LeaveFunction
    }
}

function Get-ComputerModel {
    [CmdletBinding()]Param (
    )
    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 (
    )
    Begin {
        Write-EnterFunction
    }

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

    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 defaults to "BIOS" mode.
 
    .EXAMPLE
    If (Get-ComputerFirmwareType -eq "UEFI") { # System is running UEFI firmware... }
 
    .EXAMPLE
    Switch (Get-ComputerFirmwareType) {
        "BIOS" { "Legacy BIOS" }
        "UEFI" { "UEFI" }
        Default { "Unknown" }
    }
 
    .OUTPUTS
    string "BIOS" or "UEFI"
 
    .NOTES
    General notes
#>

function Get-ComputerFirmwareType {
    [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
    }
}

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


# Get-NetAdapter is not available on linux

# array of interfaces found
$Script:interfaces = $null

<#
.SYNOPSIS
Gather informations about network interfaces from registry.
 
.DESCRIPTION
Get-NetAdapter is not available on linux. That's why we try to
gather informations from the sysfs. Then we ask 'ip' for layer 3 data
 
.EXAMPLE
$interfaces = Get-ComputerNetAdapter
 
.NOTES
General notes
#>

function Get-ComputerNetAdapter {
    [CmdletBinding()]
    [OutputType([array])]
    Param (
        # [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$string
        # [switch]$Passthru,

        # Force a refresh, do not blindly return cache
        [Alias('Refresh')]
        [switch]$Force
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if (($null -eq $Script:interfaces) -or $Force) {
            $Script:interfaces = @()
            $Path = "/sys/class/net"
            foreach ($item in (Get-ChildItem $Path)) {
                $interface = @{}
                $interface.name = $item.name
                foreach ($subitem in (Get-ChildItem $item.fullname -File)) {
                    $property = $subitem.name
                    try {
                        $interface.$property = (Get-Content $subitem -Raw) -replace "\n"
                    } catch {
                        Write-Warning "Unable to read $property property."
                    }
                }
                # we are missing IP properties.
                # try with 'ip' command
                $output = Execute-Command -exe ip -args "-o -4 addr show dev $($item.name)" -PassThru
                # $regex = "\d: $($item.name)\s+inet (?<cidr>\d+\.\d+\.\d+\.\d+/\d+) brd (?<broadcast>\d+\.\d+\.\d+\.\d+) scope (?<scope>[a-z]+) (dynamic (?<dynamic>[a-z]*))? .*"
                # $regex = "\d: (?<ifname>[a-z0-9]+)\s+inet (?<cidr>\d+\.\d+\.\d+\.\d+/\d+)?(?<ipaddress>\d+\.\d+\.\d+\.\d+)? (brd (?<broadcast>\d+\.\d+\.\d+\.\d+))?(peer (?<peer>\d+\.\d+\.\d+\.\d+/\d+))? scope .*"
                $regex = "\d: $($item.name)\s+inet (?<cidr>\d+\.\d+\.\d+\.\d+/\d+)?(?<ipaddress>\d+\.\d+\.\d+\.\d+)? (brd (?<broadcast>\d+\.\d+\.\d+\.\d+))?(peer (?<peer>\d+\.\d+\.\d+\.\d+/\d+))? scope .*"
                if ($output -match $regex) {
                    $interface.cidr = $Matches.cidr
                    $interface.ipaddress = (($interface.cidr) -split "/")[0]
                    $interface.broadcast = $Matches.broadcast
                    $interface.scope = $Matches.scope
                    $interface.dynamic = $Matches.dynamic
                }
                # Place here properties that we have to make common between all OS's
                $interface.macaddress = $interface.address
                $Script:interfaces += $interface
            }
        }
        return $Script:interfaces
    }

    End {
        Write-LeaveFunction
    }
}

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


<#
.SYNOPSIS
List local disks
 
.DESCRIPTION
Fetch all informations available about local disks. Linux lacks the 'Get-Disk' of the Storage module available on Windows.
 
.EXAMPLE
An example
 
.NOTES
General notes
#>

function Get-ComputerDisk {
    [CmdletBinding(DefaultParameterSetName = "ALL")]
    [OutputType([hashtable])]
    Param (
        # Disk number
        [Parameter(Mandatory = $true, ParameterSetName = 'DISKNUMBER')][string]$DiskNumber,

        # Disk device name (without /dev)
        [Parameter(Mandatory = $true, ParameterSetName = 'DISKNAME')][string]$DiskName,

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

        # Partition of the disk given its ID
        [Alias('UniqueId')]
        [Parameter(Mandatory = $true, ParameterSetName = 'DISKID')][string]$DiskId,

        # Return all $disks
        [Parameter(Mandatory = $false, ParameterSetName = 'ALL')][switch]$All

    )
    Begin {
        Write-EnterFunction
        $disks = ((lsblk --output-all --json --tree) | convertfrom-json).blockdevices | Where-Object { $_.type -eq "disk" }
        # comply with windows code
        foreach ($d in $disks) {
            foreach ($p in $d.children) {
                # foreach <item> is created by reference, not by copy. So we can modify it
                # add IsActive to bootable partition
                if ($p.partflags -eq "0x80") {
                    $p | Add-Member -MemberType NoteProperty -Name IsActive -Value $true
                } else {
                    $p | Add-Member -MemberType NoteProperty -Name IsActive -Value $false
                }
                if ($p.Mountpoints) { $p | Add-Member -MemberType NoteProperty -Name "AccessPaths" -Value $p.Mountpoints }
            }
        }
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'DISKNUMBER' {
                $disks = $disks[$DiskNumber]
            }
            'DISKNAME' {
                $disks = $disks | Where-Object { $_.name -eq $DiskName }
            }
            'DEVICE' {
                $disks = $disks | Where-Object { $_.path -eq $Device }
            }
            'DISKID' {
                $disks = $disks | Where-Object { $_.ptuuid -eq $DiskId }
            }
            default {
            }
        }
        return $disks
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
List local partitions
 
.DESCRIPTION
Fetch all informations available about local partitions. Linux lacks the 'Get-Partition' of the Storage module available on Windows.
 
.EXAMPLE
An example
 
.NOTES
General notes
#>

function Get-ComputerDiskPartition {
    [CmdletBinding(DefaultParameterSetName = "ALL")]
    [OutputType([hashtable])]
    Param (
        # Partition with UUID
        [Alias('UniqueId')]
        [Parameter(Mandatory = $true, ParameterSetName = 'PARTUUID')][string]$PartUUID,

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

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

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

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

        # Mountpoint of a mounted partition
        [Alias('DriveLetter')]
        [Parameter(Mandatory = $true, ParameterSetName = 'MOUNTPOINT')][string]$Mountpoint,

        # Partition of the disk given its ID
        [Parameter(Mandatory = $true, ParameterSetName = 'DISKID')][string]$DiskId,

        # Return all partitions
        [Parameter(Mandatory = $false, ParameterSetName = 'ALL')][switch]$All

    )
    Begin {
        Write-EnterFunction
        $disks = Get-ComputerDisk
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'PARTUUID' {
                $partitions = ($disks.children | Where-Object { $_.partuuid -eq "$PartUUID" })
            }
            'PARTLABEL' {
                $partitions = ($disks.children | Where-Object { $_.label -eq "$PartLabel" })
            }
            'DISKPART' {
                $partitions = ($disks | Where-Object { $_.name -eq $Disk }).children
                if ($PartNumber) {
                    $partitions = ($partitions | Where-Object { $_.name -eq "$Disk$PartNumber" })
                }
            }
            'DEVICE' {
                $partitions = ($disks.children | Where-Object { $_.path -like "$Device*" })
            }
            'MOUNTPOINT' {
                $partitions = ($disks.children | Where-Object { $_.mountpoint -eq "$Mountpoint" })
            }
            'DISKID' {
                $partitions = ($disks.children | Where-Object { $_.ptuuid -eq "$DiskId" })
            }
            default {
                $partitions = $disks.children
            }
        }
        return $partitions
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Mount a partition into running operating system
 
.DESCRIPTION
Mount specified partition
 
.EXAMPLE
An example
 
.NOTES
General notes
 
.OUTPUTS
[string] mountpoint
#>

function Mount-ComputerDiskPartition {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # UUID of the partition to mount
        [Parameter(Mandatory = $true, ParameterSetName = 'PARTUUID')][string]$PartUuid,

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

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

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

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

        # options to pass
        [Parameter(Mandatory = $false)][string]$Options,

        # force mounting to the mountpoint
        [Parameter(Mandatory = $false)][string]$Mountpoint
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'PARTUUID' {
                $partition = Get-ComputerDiskPartition -PartUUID $PartUuid
            }
            'PARTLABEL' {
                $partition = Get-ComputerDiskPartition -PartLabel $PartLabel
            }
            'DISKPART' {
                $partition = Get-ComputerDiskPartition -Disk $Disk -PartNum $PartNum
            }
            'DEVICE' {
                $partition = Get-ComputerDiskPartition -Device $Device
            }
        }
        # partition is already mounted ? return mountpoint
        if ($partition.mountpoint) {
            Write-Debug "Partition $($partition.name) already mounted at '$partition.mountpoint'"
            return $partition.mountpoint
        }
        if (!$Mountpoint) {
            $Mountpoint = "/mnt/$($partition.name)"
        }
        $rc = New-Item $Mountpoint -ItemType Directory -Force
        Write-Debug "Mount partition $($partition.name) in $Mountpoint"
        # options is an array of comma separated values
        $aOptions = $Options -split ","
        switch ($partition.fstype) {
            'ntfs' {
                # probe for mountability
                $rc = Execute-Command -exe ntfs-3g.probe -args "--readwrite $($partition.path)" -AsBool
                rc=$?
                switch (${rc}) {
                    14 {
                        Write-Warning "Windows is hibernating, ntfs-3g will refuse to mount it."
                        Write-Warning "WRN" "We'll try to mount removing hiberfile"
                        # if ${options} is defined, then OPTIONS="${options},ro" else, OPTIONS="ro"
                        $aOptions += "remove_hiberfile"
                    }
                }
                # Make sure the dirty flag is removed. If not, mounting the NTFS partition is impossible.
                $rc = Execute-Command -exe ntfsfix -args "-d $($partition.path)"
                # if ${options} is defined, then OPTIONS="-o ${options}" else, OPTIONS=""
                $rc = Execute-Command -exe ntfs-3g -rags "$($partition.path) $MountPoint $($aOptions -join ",")"
            }
            'crypto_LUKS' {
                $passPhrase = Write-Question -Prompt "Please enter pass-phrase to decypher partition "
                $rc = Execute-Command -exe "cryptsetup" -args "luksOpen /dev/${part} ${part} - <<< ${passPhrase}"
                # if [ -e /dev/mapper/${part} ]; then
                # $mountPoint=$(MountPartition /dev/mapper/${part})
                # return $(true)
                # else
                # CLog "ERR" "${FUNCNAME}(): failed to unlock luks partition /dev/${part}"
                # return $(false)
                # fi
            }
            Default {
                $rc = Execite-Command -exe mount -args "-t auto /dev/${part} $MountPoint $($aOptions -join ",")"
            }
        }
        return $Mountpoint
    }

    End {
        Write-LeaveFunction
    }
}