Dictionaries/Dict.Unix.Linux/Dict.Unix.Linux.psm1

<#

    .SYNOPSIS
    Dictionnary of Linux functions

    .DESCRIPTION

    .NOTES
        Author: Charles-Antoine Degennes <cadegenn@gmail.com>
        Version: 0.0.1
        Changelog:
            2018.02.07, DCA - inital version
        Manifest created with command line:
        New-ModuleManifest PwSh.Linux.psd1 -RootModule PwSh.Linux.psm1 -ModuleVersion "0.0.1" -Author "Charles-Antoine Degennes <cadegenn@gmail.com>"

#>


$env:LANGUAGE = "en_US"

<#

  ###### ####### ## ## ######## ## ## ######## ######## ########
 ## ## ## ## ### ### ## ## ## ## ## ## ## ##
 ## ## ## #### #### ## ## ## ## ## ## ## ##
 ## ## ## ## ### ## ######## ## ## ## ###### ########
 ## ## ## ## ## ## ## ## ## ## ## ##
 ## ## ## ## ## ## ## ## ## ## ## ## ##
  ###### ####### ## ## ## ####### ## ######## ## ##

#>


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

    Process {
        $dirExist = dirExist -Path /sys/firmware/efi
        if ($dirExist) {
            return "UEFI"
        } else {
            return "BIOS"
        }
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-ComputerArch {
    [CmdletBinding()][OutputType([System.String])]Param (
        [switch]$localhost
    )
    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        # 'lm' is the 64-bit flag on Intel CPUs
        grep -q -w 'lm' /proc/cpuinfo
        $rc = $?
        switch ($rc) {
            False {
                return 'x86'
            }
            True {
                return 'x64'
            }
            else {
                return 'unknown'
            }
        }
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

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

    Process {
        if ($Localhost) {
            if (Test-UserIsAdmin) {
                if (FileExist "/sys/devices/virtual/dmi/id/product_serial") {
                    $serial = Get-Content /sys/devices/virtual/dmi/id/product_serial
                }
            } else {
                ewarn "You need to be admin to get computer serial number"
                $serial = $null
            }
        }

        return $serial
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

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

    Process {
        if ($Localhost) {
            if (FileExist "/sys/devices/virtual/dmi/id/bios_vendor") {
                $manufacturer = Get-Content /sys/devices/virtual/dmi/id/bios_vendor
            }
        }

        return $manufacturer
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

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

    Process {
        if ($Localhost) {
            if (FileExist "/sys/devices/virtual/dmi/id/product_name") {
                $model = Get-Content /sys/devices/virtual/dmi/id/product_name
            }
        }

        return $model
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

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

    Process {
        if ($Localhost) {
            if (FileExist "/sys/devices/virtual/dmi/id/bios_version") {
                $version = Get-Content /sys/devices/virtual/dmi/id/bios_version
            }
        }

        return $version
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-ComputerEthernet {
    [CmdletBinding()]Param (
        [switch]$localhost,
        [ValidateSet('Index', 'Name')]
        [string]$ListAvailable = 'Index'
    )
    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        if ($Localhost) {
            switch ($ListAvailable) {
                'Index' {
                    # ip -o addr show | cut -d':' -f1 | sort | uniq
                    # ip -o link show | cut -d':' -f1 | sort | uniq
                    Get-ChildItem /sys/class/net | ForEach-Object { Get-Content $_/ifindex}
                }
                'Name' {
                    # ip -o addr show | awk '{print $2}' | sort | uniq
                    # (ip -o link show | awk -F':' '{print $2}' | sort | uniq).Trim()
                    (Get-ChildItem -Path /sys/class/net).Name
                }
            }
        }
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-ComputerDisks {
    [CmdletBinding()]Param (
        [switch]$localhost,
        [ValidateSet('Index', 'Name')]
        [string]$ListAvailable = 'Index'
    )
    Begin {
        Write-PwShFwOSEnterFunction
        $precedence = @('nvme', 'sd', 'hd')
    }

    Process {
        if ($Localhost) {
            foreach ($p in $precedence) {
                switch ($ListAvailable) {
                    'Index' {
                        # ip -o addr show | cut -d':' -f1 | sort | uniq
                        # ip -o link show | cut -d':' -f1 | sort | uniq
                        lsblk -d -n -o NAME | grep "^$p" | sort | uniq | grep -n "." | awk -F':' '{print $1}'
                    }
                    'Name' {
                        # ip -o addr show | awk '{print $2}' | sort | uniq
                        # (ip -o link show | awk -F':' '{print $2}' | sort | uniq).Trim()
                        lsblk -d -n -o NAME | grep "^$p" | sort | uniq
                    }
                }
            }
        }
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

<#

 ######## ######## ## ## ######## ######## ## ## ######## ########
 ## ## ## ## ## ## ## ### ## ## ##
 ## ## ## ## ## ## ## #### ## ## ##
 ###### ## ######### ###### ######## ## ## ## ###### ##
 ## ## ## ## ## ## ## ## #### ## ##
 ## ## ## ## ## ## ## ## ### ## ##
 ######## ## ## ## ######## ## ## ## ## ######## ##

#>




function Get-EthIndex {
    [CmdletBinding()]Param(
        [Parameter(ValueFromPipeLine = $true)]
        [string]$AdapterName = "",
        [ValidateSet('IPv4', 'IPv6')]
        [string]$Family = 'IPv4'
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($Family) {
            'IPv4' {
                # $inet = "inet"
            }
            'IPv6' {
                # $inet = "inet6"
            }
        }

        # $value = ip -o -f $inet addr show $AdapterName | cut -d':' -f1
        # return $value
        Get-Content -Raw /sys/class/net/$AdapterName/ifindex
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthName {
    [CmdletBinding()]Param(
        [Parameter(ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,
        [ValidateSet('IPv4', 'IPv6')]
        [string]$Family = 'IPv4'
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($Family) {
            'IPv4' {
                # $inet = "inet"
            }
            'IPv6' {
                # $inet = "inet6"
            }
        }

        # $value = ip -o -f $inet addr show | grep $("^" + $AdapterIndex + ":") | awk '{print $2}'
        # return $value
        Get-ChildItem /sys/class/net | ForEach-Object {
            $i = Get-Content $_/ifindex
            if ($i -eq $AdapterIndex) {
                # Split-Path -leaf $_
                $_.Name
            }
        }
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthMacAddress {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo"
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }

        # $value = ifconfig $AdapterName | grep "HWaddr" | awk '{print $5}'
        # return $value
        Get-Content /sys/class/net/$AdapterName/address
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthLinkStatus {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )][OutputType([System.Boolean])]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 1,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo"
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }

        if (fileExist "/sys/class/net/$AdapterName/carrier") {
            try {
                [int]$status = [int](Get-Content -Raw /sys/class/net/$AdapterName/carrier -ErrorAction SilentlyContinue)
                if ($status -eq 0) { return $false }
                if ($status -eq 1) { return $true }
            } catch {
                return $false
            }
        } else {
            return $false
        }
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

<#
.SYNOPSIS
Get network adapter speed

.DESCRIPTION
Ask OS for network adapter speed

.PARAMETER AdapterIndex
Adapter index

.PARAMETER AdapterName
Adapter name

.EXAMPLE
Get-EthSpeed -AdapterIndex 0

.EXAMPLE
Get-EthSpeed -AdapterName Ethernet0

.OUTPUTS
[uint32] return link speed in bytes per seconds

.NOTES
General notes
#>


function Get-EthSpeed {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo"
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }

        [int]$value = [int](Get-Content -Raw /sys/class/net/$AdapterName/speed -ErrorAction SilentlyContinue)

        return $value
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthIPAddress {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo",

        [ValidateSet('IPv4', 'IPv6')]
        [string]$Family = 'IPv4'
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($Family) {
            'IPv4' {
                $inet = "inet"
            }
            'IPv6' {
                $inet = "inet6"
            }
        }
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }

        $value = ip -o -f $inet address show $AdapterName | grep "scope global" | awk '{print $4}' | cut -d'/' -f1
        # Write-PwShFwOSDevel "value = $value"

        return $value
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthNetMask {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo",

        [ValidateSet('IPv4', 'IPv6')]
        [string]$Family = 'IPv4'
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }
        switch ($Family) {
            'IPv4' {
                $inet = "inet"
                $mask = ip -o -f $inet address show $AdapterName | awk '{print $4}' | cut -d'/' -f2
                $value = ConvertTo-Mask -MaskLength $mask
            }
            'IPv6' {
                $inet = "inet6"
                ewarn("Module Indented.Net.IP does not provides IPv6 calculator yet !!")
            }
        }

        return $value
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthBroadcast {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )][OutputType([String])]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo",

        [ValidateSet('IPv4', 'IPv6')]
        [string]$Family = 'IPv4'
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }
        $ip = Get-EthIPAddress -AdapterName $AdapterName -Family $Family
        $mask = Get-EthNetMask -AdapterName $AdapterName -Family $Family

        switch ($Family) {
            'IPv4' {
                if ([string]::IsNullOrEmpty($ip)) { return "255.255.255.255" }
                if ([string]::IsNullOrEmpty($mask)) { return "255.255.255.255" }
                $value = Get-BroadcastAddress -IPAddress $ip -SubnetMask $mask
            }
            'IPv6' {
                ewarn("Module Indented.Net.IP does not provides IPv6 calculator yet !!")
            }
        }

        return $value
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-EthGateway {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )]Param(
        # Parameter help description
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$AdapterIndex = 0,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$AdapterName = "lo",

        [ValidateSet('IPv4', 'IPv6')]
        [string]$Family = 'IPv4'
    )

    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $AdapterName = Get-EthName -AdapterIndex $AdapterIndex
            }
            'NAME' {
            }
        }

        switch ($Family) {
            'IPv4' {
                $value = ip -f inet route | grep "^default " | grep $AdapterName | awk '{print $3}'
                break
            }
            'IPv6' {
                $value = ip -f inet6 route | grep "^default " | grep $AdapterName | awk '{print $3}'
                break
            }
        }

        return $value
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

<#

 ######## #### ###### ## ## ######
 ## ## ## ## ## ## ## ## ##
 ## ## ## ## ## ## ##
 ## ## ## ###### ##### ######
 ## ## ## ## ## ## ##
 ## ## ## ## ## ## ## ## ##
 ######## #### ###### ## ## ######

#>


function Get-DiskInfos {
    [CmdletBinding(
        DefaultParameterSetName="INDEX"
    )]Param(
        [switch]$localhost,
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$DiskIndex,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$DiskName
    )
    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                $DiskName = lsblk -d -n -o NAME | sort | uniq | grep -n '.' | grep "^${DiskIndex}:" | cut -d':' -f2
            }
            'NAME' {
            }
        }

        if ($DiskName -match '^/dev/') {
            $device = $DiskName
        } else {
            $device = "/dev/$DiskName"
        }
        lsblk -d -O $device -J | ConvertFrom-Json
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}

function Get-ComputerDisks2 {
    [CmdletBinding(
        DefaultParameterSetName="ALL"
    )]Param(
        [switch]$localhost,
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$Index,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$Name,

        [Parameter(ParameterSetName="ALL")]
        [switch]$All
    )

    Begin {
        $disks = @()
        $i = 0
        # precedence tell the order search precedence of the type of disk. It aims to mimic BIOS / UEFI discovery order
        $precedence = @('nvme', 'sd', 'hd')
        $list = lsblk -d -n -o NAME | sort | uniq
    }

    Process {
        ForEach ($p in $precedence) {
            # echo "$p"
            ForEach ($d in ($list | Where-Object { $_ -match "^$p" })) {
                # echo " $d"
                # $disks[$i] = $d
                # $i++
                $device = "/dev/$d"
                $lsblk = $null
                # TODO Use the -J option of lsblk to output as a json object. e.g. lsblk -d -O -P $device -J
                # TODO then convert it to a real object like $obj = lsblk -d -O -P $device -J | ConvertFrom-Json -With -Options (remeber to trim values)
                $lsblk = New-HashtableFromCommand -Command "lsblk -d -O -P $device | sed -e 's/\`" \([A-Z]\)/\`"\n\1/g'" -sep:'='
                $parted = $null
                $parted = New-HashtableFromCommand -Command "parted -s $device print" -sep:":"
                $disk = $null
                # $disk = [PSCustomObject]@{
                # Index = $i++
                # Name = $d
                # serial = $lsblk.serial
                # uuid = $lsblk.uuid
                # manufacturer = $lsblk.vendor
                # model = $lsblk.model
                # PhysicalSectorSize = $lsblk."phy-sec"
                # size = ($lsblk.size.replace(',','.') + "B")/1 | Convert-Size -From Bytes -To Bytes -Precision 0
                # PartitionStyle = ""
                # DriveType = ""
                # }
                $disk = @{}
                $disk.Index = $i++
                $disk.Name = $d
                $disk.serial = $lsblk.serial
                $disk.uuid = $lsblk.uuid
                $disk.manufacturer = $lsblk.vendor
                $disk.model = $lsblk.model
                $disk.PhysicalSectorSize = $lsblk."phy-sec"
                $disk.size = ($lsblk.size.replace(',','.') + "B")/1 | Convert-Size -From Bytes -To Bytes -Precision 0
                $disk.PartitionStyle = $parted."partition table"
                $disk.DriveType = ""
                # switch ($parted."partition table") {
                # 'msdos' {
                # $disk.PartitionStyle = "MBR"
                # }
                # 'gpt' {
                # $disk.PartitionStyle = "GPT"
                # }
                # }
                switch ($lsblk.hotplug) {
                    0 {
                        $disk.DriveType = 'Fixed'
                    }
                    1 {
                        $disk.DriveType = 'Removable'
                    }
                }
                $disks += $disk
            }
        }

        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                return $disks[$Index]
            }
            'NAME' {
                $Index = ($disks | Where-Object { $_.Name -eq $Name }).Index
                if ($null -ne $Index) {
                    return $disks[$Index]
                } else {
                    return
                }
            }
            'ALL' {
                return $disks
            }
        }
    }

    End {

    }
}

<#
.SYNOPSIS
Short description

.DESCRIPTION
Long description

.PARAMETER diskIndex
Parameter description

.PARAMETER Index
Parameter description

.PARAMETER Name
Parameter description

.PARAMETER All
Parameter description

.EXAMPLE
$parts = Get-ComputerDiskParts

.EXAMPLE
$parts = Get-ComputerDiskParts -diskIndex 0

.EXAMPLE
$parts = Get-ComputerDiskParts diskIndex 0 -Index 1

.NOTES
General notes

.OUTPUTS
2 Dimensional array (or Jagged Array in powershel lexic) if listing all partitions of all disks
1 dimensional array if listing all partitions of 1 disk
object if requesting 1 particular partition on 1 disk

#>

function Get-ComputerDiskParts {
    [CmdletBinding(
        DefaultParameterSetName="ALL"
    )][OutputType([Array])]Param(
        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [Parameter(ParameterSetName="ALL",ValueFromPipeLine = $true)]
        [int]$diskIndex = $null,

        [Parameter(ParameterSetName="INDEX",ValueFromPipeLine = $true)]
        [int]$Index,

        [Parameter(ParameterSetName="NAME",ValueFromPipeLine = $true)]
        [string]$Name,

        [Parameter(ParameterSetName="ALL")]
        [switch]$All
    )

    Begin {
        $allParts = @()
        # precedence tell the order search precedence of the type of disk. It aims to mimic BIOS / UEFI discovery order
        $disks = Get-ComputerDisks
    }

    Process {
        ForEach ($d in $disks) {
            # $d
            # part number start at 1
            $i = 1
            # create part#0 to make 1st partition array index = 1
            $parts = @()
            $parts += $d
            $obj = lsblk -n -O -J $("/dev/" + $d.Name) | ConvertFrom-Json
            # $obj
            # $obj.blockdevices[0].children
            ForEach ($p in $obj.blockdevices[0].children) {
                $part = @{}
                $part.Index = $i++
                $part.Name = $p.name
                $part.Label = $p.Label
                $part.uuid = $p.uuid
                # TODO primary ? logical ? extended ?
                $part.Type = ""
                $part.partTypeId = $p.parttype
                $part.fileSystem = $p.fstype
                $part.MountPoint = $p.mountpoint
                # TODO boot flag
                $part.boot = $false
                # $part.size = ($p.size.replace(',','.') + "B")/1 | Convert-Size -From Bytes -To Bytes -Precision 0
                $part.size = df --output=source,size,avail $("/dev/" + $d.Name) | tail -n -1 | awk '{print $2}' | Convert-Size -From KB -To Bytes -Precision 0
                $part.free = df --output=source,size,avail $("/dev/" + $d.Name) | tail -n -1 | awk '{print $3}' | Convert-Size -From KB -To Bytes -Precision 0
                # $parts[$d.Index] = @()
                $parts += @($part)
                # $parts[$d.Index] += $part
                # $parts += $part
                # $part
            }
            $allParts += ,@($parts)
        }
        # $parts

        switch ($PSCmdlet.ParameterSetName) {
            'INDEX' {
                if ($diskIndex -ne $null -and $Index -ne $null) {
                    return $allParts[$diskIndex][$Index]
                }
                if ($diskIndex -ne $null) {
                    return $allParts[$diskIndex]
                }
                return
            }
            'NAME' {
            }
            'ALL' {
                # $diskIndex
                if ($diskIndex -ne $null) {
                    return $allParts[$diskIndex]
                }
                return $allParts
            }
        }
    }

    End {

    }
}

<#

    ### ######## ###### ## ## #### ## ## ######## ######
   ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  ## ## ## ## ## ## ## ## ## ## ## ##
 ## ## ######## ## ######### ## ## ## ###### ######
 ######### ## ## ## ## ## ## ## ## ## ##
 ## ## ## ## ## ## ## ## ## ## ## ## ## ##
 ## ## ## ## ###### ## ## #### ### ######## ######

#>


<#
.SYNOPSIS
Uncompress a cabinet file.

.DESCRIPTION
Uncompress a cabinet file using windows's 'expand' binary.

.PARAMETER filename
Filename of the cabinet to expand.

.PARAMETER options
Options to pass to 'expand'

.PARAMETER files
Pattern of files to extract from cabinet. If not specified, extract all files.

.PARAMETER destination
Destination folder

.NOTES
This function is a skeleton from Dict.OS module. If you see this help, it means this function
is not yet implemented for the OS you are running.
#>

function Expand-Cabinet {
    [CmdletBinding()][OutputType([System.Boolean])]Param (
        [Parameter(Mandatory = $true,ValueFromPipeLine = $true)][string]$filename,
        [parameter()][string]$options,
        [parameter()][string]$files,
        [parameter()][string]$destination
    )
    Begin {
        Write-PwShFwOSEnterFunction
    }

    Process {
        if (!fileExist($filename)) {
            Write-Error "$filename not found."
            return $false
        }

        if ($files) {
            $options = "-F " + $files
        }
        Execute-Command -exe cabextract -args "$options $files $destination"
        return $?
    }

    End {
        Write-PwShFwOSLeaveFunction
    }
}