Libraries/OS.Macos/OS.Macos.psm1

$Script:NS = (get-item $PSCommandPath).basename

<#
    .SYNOPSIS
    Get the distribution of the OS
#>

function Get-OSDistrib {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root = "/"
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return "macOS"
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSIdentity {
    [CmdletBinding()]Param (
        [switch]$Online,
        [string]$Root = "/"
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) { $Root = '' }
        $osid = ([xml](Get-Content "$Root/System/Library/CoreServices/SystemVersion.plist") | convertfrom-plist)
        # $osid += ([xml](Get-Content "$Root/System/Library/CoreServices/Finder.app/Contents/Info.plist") | convertfrom-plist)
        # edevel($osid | convertto-json)
        return $osid
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSCodename {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root,
        [AllowNull()][AllowEmptyString()][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'ONLINE' {
                $ReleaseId = OS.Macos\Get-OSReleaseID -Online
                break
            }
            'ROOT' {
                $ReleaseId = OS.Macos\Get-OSReleaseID -Root $Root
                break
            }
            'OBJECT' {
                break
            }
        }
        # edevel("ReleaseId = $ReleaseId")
        $value = Get-OSCodenameFromVersion -ReleaseId $ReleaseId

        return $value
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSCodenameFromVersion {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(Mandatory = $true, Position = 1)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch -wildcard ($ReleaseId) {
            '10.*' {
                return Get-MacOSXCodeName -ReleaseId $ReleaseId
            }
            default { return $ReleaseId }
        }
        return $null
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSProductnameFromVersion {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(Mandatory = $true, Position = 1)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch  ($ReleaseId) {
            '10.0'  { $productname =  "Mac OS X" }
            '10.1'  { $productname =  "Mac OS X" }
            '10.2'  { $productname =  "Mac OS X" }
            '10.3'  { $productname =  "Mac OS X" }
            '10.4'  { $productname =  "Mac OS X" }
            '10.5'  { $productname =  "Mac OS X" }
            '10.6'  { $productname =  "Mac OS X" }
            '10.7'  { $productname =  "Mac OS X" }
            '10.8'  { $productname =  "OS X" }
            '10.9'  { $productname =  "OS X" }
            '10.10' { $productname =  "OS X" }
            '10.11' { $productname =  "OS X" }
            '10.12' { $productname =  "macOS" }
            '10.13' { $productname =  "macOS" }
            '10.14' { $productname =  "macOS" }
            '10.15' { $productname =  "macOS" }
            default { $productname =  "MacOS" }
        }
        return $productname
    }

    End {
        Write-LeaveFunction
    }
}

function Get-MacOSXCodeName {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(Mandatory = $true, Position = 1)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch  ($ReleaseId) {
            '10.0'  { return "Cheetah" }
            '10.1'  { return "Puma" }
            '10.2'  { return "Jaguar" }
            '10.3'  { return "Panther" }
            '10.4'  { return "Tiger" }
            '10.5'  { return "Leopard" }
            '10.6'  { return "Snow Leopard" }
            '10.7'  { return "Lion" }
            '10.8'  { return "Mountain Lion" }
            '10.9'  { return "Mavericks" }
            '10.10' { return "Yosemite" }
            '10.11' { return "El Capitan" }
            '10.12' { return "Sierra" }
            '10.13' { return "High Sierra" }
            '10.14' { return "Mojave" }
            '10.15' { return "Catalina" }
            default { return $ReleaseId }
        }
        return $null
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSLongCodename {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root,
        [AllowNull()][AllowEmptyString()][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'ONLINE' {
                $ReleaseId = OS.Macos\Get-OSReleaseID -Online
                break
            }
            'ROOT' {
                $ReleaseId = OS.Macos\Get-OSReleaseID -Root $Root
                break
            }
            'OBJECT' {
                break
            }
        }
        # edevel("ReleaseId = $ReleaseId")
        $productname = OS.MacOS\Get-OSProductnameFromVersion -ReleaseId $ReleaseId
        $codename = OS.MacOS\Get-OSCodenameFromVersion -ReleaseId $ReleaseId

        return "$productname $codename"
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSProductName {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root,
        [Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName){
            'ONLINE' {
                $osIdentity = OS.Macos\Get-OSIdentity -Online
                $ReleaseId = $osIdentity.ProductVersion
            }
            'ROOT' {
                $osIdentity = OS.Macos\Get-OSIdentity -Root $Root
                $ReleaseId = $osIdentity.ProductVersion
            }
            'OBJECT' {
            }
        }
        # edevel("ReleaseId = $ReleaseId")
        $productname = OS.MacOS\Get-OSProductnameFromVersion -ReleaseId $ReleaseId
        $codename = OS.MacOS\Get-OSCodenameFromVersion -ReleaseId $ReleaseId

        return "$productname $ReleaseId $codename"
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSKernelVersion {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root = "/"
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) {
            $rc = Get-Command system_profiler -ErrorAction SilentlyContinue
            if ($null -ne $rc) {
                return (((system_profiler SPSoftwareDataType) -replace ":", "=" | ConvertFrom-StringData -ErrorAction SilentlyContinue).'Kernel Version' -split ' ')[1]
            }
        }
        return $null
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Get macOS architecture
 
.DESCRIPTION
 
 
.PARAMETER Online
Specify you want to get the archtiecture of the running OS. It is equivalent of specifying -Root /
 
.PARAMETER Root
Specify to inquire the OS located at the specified mountpoint
 
.EXAMPLE
Get-OSArch -Online
 
.EXAMPLE
Get-OSArch -Root /mnt/sda3
 
.NOTES
 
#>


function Get-OSArch {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root = "/"
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) { $Root = '' }
        return "x64"
    }

    End {
        Write-LeaveFunction
    }
}

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

    Process {
        $Root = $Root.Trim('/')
        $wkFiles = @{}
        if (FileExist ("$Root/System/Library/Kernels/kernel")) {
            $wkFiles.Add('kernel', "$Root/System/Library/Kernels/kernel")
        }
        return $wkFiles
    }

    End {
        Write-LeaveFunction
    }
}

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

    Process {
        $Root = $Root.Trim('/')
        $wkFolders = @{}
        if (DirExist ("$Root/private/etc")) {
            $wkFolders.Add('etc', "$Root/private/etc")
            # $wkFolders.Add('ProgramData', "$Root/etc")
        }
        if (DirExist ("$Root/bin")) {
            $wkFolders.Add('bin', "$Root/bin")
            $wkFolders.Add('bin-x86', "$Root/bin")
            $wkFolders.Add('bin-x64', "$Root/bin")
            $wkFolders.Add('ProgramFiles', "$Root/bin")
            $wkFolders.Add('ProgramFiles-x86', "$Root/bin")
            $wkFolders.Add('ProgramFiles-x64', "$Root/bin")
        }
        if (DirExist ("$Root/sbin")) {
            $wkFolders.Add('sbin', "$Root/sbin")
            $wkFolders.Add('sbin-x64', "$Root/sbin")
            $wkFolders.Add('System-x86', "$Root/sbin")
            $wkFolders.Add('System-x64', "$Root/sbin")
        }
        if (DirExist ("$Root/private/var/lib")) {
            $wkFolders.Add('var', "$Root/private/var/lib")
            $wkFolders.Add('ProgramData', "$Root/private/var/lib")
        }
        if (DirExist ("$Root/private/var/log")) {
            $wkFolders.Add('log', "$Root/private/var/log")
        }
        return $wkFolders
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSPackages {
    [CmdletBinding()][OutputType([Hashtable])]Param (
        [switch]$Online,
        [string]$Root = "/"
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) { $Root = '' }
        # $aPackages = @()
        $hPackages = @{}
        $infosPlist = Get-Childitem -Path "$Root/Applications/" -Filter "Info.plist" -Recurse -Depth 3
        $infosPlist += Get-Childitem -Path "$Root/System/Library/CoreServices/*.App" -Filter "Info.plist" -Recurse -Depth 3
        foreach ($info in $infosPlist) {
            Write-Devel "Processing $($info.fullname)"
            $app = $null
            try {
                $app = [xml](Get-Content -Raw $info.fullname) | ConvertFrom-PList
            } catch {
                if ($Online) {
                    $app = [xml](plutil -convert xml1 -o - $info.fullname) | ConvertFrom-PList
                } else {
                    ewarn "Unable to read $($info.fullname). It is probably a binary .plist"
                }
            }
            if ($null -ne $app) {
                $key = $app.CFBundleName
                # $key = (get-item $info.DirectoryName).Parent.name
                # # try to get consistent data accross platforms
                # $app.name = (get-item $info.DirectoryName).Parent.name -replace ".App$", ""
                $app.Name = $app.CFBundleName
                $app.DisplayName = $app.CFBundleName
                Write-Debug "Found application $($app.DisplayName)"
                # try to handle fancy version numbers
                $keys = $app.Keys
                foreach ($k in $keys) {
                    switch -wildcard ($k) {
                        "*Version*" {
                            $app."Raw$k" = $app.$k
                            $app.$k = [system.version]($app.$k | ConvertTo-VersionNumber)
                        }
                    }
                }
                $app.filename = $info.fullname
                if ($hPackages.ContainsKey($key)) {
                    ewarn "Application conflict ! while processing $($info.fullname)"
                    ewarn ("Application '$($app.CFBundleName)' already added by " + $hPackages."$key".filename)
                } else {
                    Write-Devel "Add package $($oPackage.Package) to hashtable"
                    $hPackages.Add($key, $app)
                    Write-Devel "Package added"
                }
            }
        }
        return ($hPackages | Sort-HashTable)
        # return $hPackages
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSReleaseId {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root,
        [Alias('Version')][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$CurrentVersion
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName){
            'ONLINE' {
                $version = OS.Macos\Get-OSVersion -Online
            }
            'ROOT' {
                $version = OS.Macos\Get-OSVersion -Root $Root
            }
            'OBJECT' {
                $version = $CurrentVersion
            }
        }
        if ($Version -match "^[0-9]*.[0-9]*") {
            return $matches[0]
        } else {
            return $null
        }
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSVersion {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName){
            'ONLINE' {
                $osIdentity = OS.Macos\Get-OSIdentity -Online
                $version = $osIdentity.ProductVersion
            }
            'ROOT' {
                $osIdentity = OS.Macos\Get-OSIdentity -Root $Root
                $version = $osIdentity.ProductVersion
            }
        }

        return [system.version]$version
   }

    End {
        Write-LeaveFunction
    }
}