Get-MacInfo.psm1

#!/usr/bin/env pwsh


## To do:
    #app-sso output
    #SPAudioDataType

function getSPJSONData {
    param (
        [Parameter(Mandatory = $true)][string] $SPDataType
    )

    #get raw json data from system_profiler for $SPDataType. This creates an array of strings
    $SPRawResults = Invoke-Expression -Command "/usr/sbin/system_profiler $SPDataType -detailLevel full -json"
    #convert array to one string
    $SPStringResults = $SPRawResults|Out-String
    #create JSON object from string
    $SPJSONResults = ConvertFrom-Json -InputObject $SPStringResults
    #return JSON object to calling command
    return $SPJSONResults
}

function getSPRawData {
    param (
        [Parameter(Mandatory = $true)][string] $SPDataType
    )

    $SPRawResults = Invoke-Expression -Command "/usr/sbin/system_profiler $SPDataType -detailLevel full"
    return $SPRawResults
}

function Get-MacInfo {
    <#
    .SYNOPSIS
    This is a powershell script for macOS that replicates, or tries to, the "Get-ComputerInfo" command for Windows Powershell

    .DESCRIPTION
    It's not a 1:1 replication, some of it wouldn't make any sense on a Mac. Also, it does check to make sure it's running
    on a mac. This pulls information from a variet of sources, including uname, sysctl, AppleScript, sw_ver, system_profiler,
    and some built-in powershell functions. It shoves it all into an ordered hashtable so there's some coherency in the output.
    If you run the script without any parameters, you get all the items in the hashtable. If you provide one key as a parameter,
    you get the information for that key. You can provide a comma-separated list of keys and you'll get that as a result.

    20221001 added code for Apple Silicon

    Note: the keys labled "Intel Only" don't exist for Apple Silicon.

    Current keys are:
    macOSBuildLabEx
    macOSCurrentVersion
    macOSCurrentBuildNumber
    macOSProductName
    macOSDarwinVersion
    SystemFirmwareVersion
    T2FirmwareVersion (Intel only)
    OSLoaderVersion
    HardwareSerialNumber
    HardwareUUID
    ProvisioningUDID
    HardwareModelName
    HardwareModelID
    HardwareModelNumber (Apple Silicon Only)
    ActivationLockStatus
    CPUArchitecture
    CPUName
    CPUSpeed (Intel Only)
    CPUCount (Intel Only)
    CPUCoreCount (Intel Only)
    CPUTotalCoreCount (Apple Silicon Only)
    CPUPerformanceCoreCount (Apple Silicon Only)
    CPUEfficiencyCoreCount (Apple Silicon Only)
    CPUL2CacheSize (Intel Only)
    CPUBrandString
    L3CacheSize (Intel Only)
    HyperThreadingEnabled (Intel Only)
    RAMAmount
    ApplePayPlatformID
    ApplePaySEID
    ApplePaySystemOSSEID (Apple Silicon Only)
    ApplePayHardware
    ApplePayFirmware
    ApplePayJCOPOSVersion
    ApplePayControllerHardwareVersion
    ApplePayControllerFirmwareVersion
    ApplePayControllerMiddlewareVersion
    BluetoothMAC
    BluetoothChipset
    BluetoothDiscoverable
    BluetoothFirmwareVersion
    BluetoothProductID (Apple Silicon Only)
    BluetoothSupportedServices
    BluetoothTransport
    BluetoothVendorID
    ACCurrentPowerSource
    ACSystemSleepTimer
    ACDiskSleepTImer
    ACDisplaySleepTimer
    ACHibernateMode
    ACLowPowerMode
    ACNetworkOverSleep
    ACWakeOnLan
    ACHighPowerMode (Apple Silicon Only)
    ACSleepOnPowerButton (Apple Silicon Only)
    ACDisplaySleepUsesDim (Intel Only)
    ACWakeOnACChange (Intel Only)
    ACWakeOnClamshellOpen (Intel Only)
    ACChargerConnected
    ACChargerCharging
    ACChargerName
    ACChargerSerialNumber
    ACChargerWatts
    ACChargerManf
    ACChargerID
    ACChargerHWVers
    ACChargerFirmwareVers
    ACChargerFamily
    batteryCurrentPowerSource
    batterySystemSleepTimer
    batteryDiskSleepTimer
    batteryDisplaySleepTimer
    batteryReduceBrightness
    batteryHibernateMode
    batteryLowPowerMode
    batteryNetworkOverSleep
    batteryWakeOnLan
    batteryHighPowerMode (Apple Silicon Only)
    batterySleepOnPowerButton (Apple Silicon Only)
    batteryDisplaySleepUsesDim (Intel Only)
    batteryWakeOnACChange (Intel Only)
    batteryWakeOnClamshellOpen (Intel Only)
    batteryWarningLevel
    batteryFullyCharged
    batteryIsCharging
    batteryChargeLevel
    batteryMaxChargeCapacity (Intel Only)
    batteryCycleCount
    batteryHealth
    batteryHealthMaxCapacity (Apple Silicon Only)
    batterySerialNumber
    batteryDeviceName
    batteryFirmwareVersion
    batteryHardwareRevision
    batteryCellRevision
    batteryManufacturer (Intel Only)
    UPSCurrentPowerSource
    UPSSystemSleepTimer
    UPSAutoRestartOnPowerLoss
    UPSDiskSleepTimer
    UPSDisplaySleepTimer
    UPSNetworkOverSleep
    UPSWakeOnLan
    UPSSleepOnPowerButton (Apple Silicon Only)
    iBridgeBootUUID
    iBridgeFWVersion
    iBridgeModelName
    iBridgeExtraBootPolicies
    iBridgeBootArgsFiltering
    iBridgeKernelCTRR
    iBridgeDEPMDM
    iBridgeUserApprMDM
    iBridgeAllAllKexts
    iBridgeSIPStatus
    iBridgeSSVStatus
    iBridgeSecureBootLvl
    AppMemoryUsedGB
    VMPageFile
    VMSwapInUseGB
    BootDevice
    FileVaultStatus
    SIPStatus
    EFICurrentLanguage
    DSTStatus
    TimeZone
    UTCOffset
    DNSHostName
    LocalHostName
    NetworkServiceList
    CurrentUserName
    CurrentUserUID
    CurrentDateTime
    LastBootDateTime
    Uptime


    .EXAMPLE
    Get-MacInfo by itself gives you all the parameters it can output

    .EXAMPLE
    Get-MacInfo TimeZone gives you the current timezone for the computer

    .EXAMPLE
    Get-MacInfo TimeZone,FileVault status gives you the current timezone and the filevault status for the computer

    .NOTES
    This can be used as a Powershell module or as a standalone script.

    .LINK
    https://github.com/johncwelch/Get-MacInfo
    #>


    #input parameter line, has to be the first executable line in the script
    param ($keys)

    #check to make sure this is running on a mac, if not, print error message and exit
    if (-Not $IsMacOS)
        {
             Write-Output "This Script only runs on macOS, exiting"
             Exit-PSSession
        }

    #since the idea of this is to create a version of Get-Computerinfo for the Mac

    #create the main hashtable that will hold all the values. This will allow for easier retreival of data
    #in a more normal powershell way. Hashtables will work well since we're going to have no repeating keys and allows us to use "normal"
    #dot notation to retrieve values.

    $macInfoHash = [ordered]@{}

    #uname section============================

    #get CPU Architecture
    #we have to do this first so we can account for the CPU differences
    $macInfoCPUArch = Invoke-Expression -Command "/usr/bin/uname -m"
    if ($macInfoCPUArch -eq "x86_64") {
        $isAppleSilicon = $false
    } else {
        $isAppleSilicon = $true
    }

    #we're going to try to mirror the results of the windows version of Get-ComputerInfo as much as possible
    #first get the kernel version as maintDarwinVersion. This is initially a string
    $getMainDarwinVersion = Invoke-Expression -Command "/usr/bin/uname -v"

    #now we want to split the string up into an array so we can build just the elemnts we need
    #use space as the separator
    $darwinVersionSeparator = " "

    #set up our string.split options
    $darwinVersionSplitOptions = [System.StringSplitOptions]::RemoveEmptyEntries

    #create our array of strings
    $mainDarwinVersionArray = $getMainDarwinVersion.Split($darwinVersionSeparator,$darwinVersionSplitOptions)

    #get the kernel version info
    $tempString = $mainDarwinVersionArray[3]
    #since that will end with a colon, strip the last character off the temp string
    $mainDarwinKernelVersion = $tempString.Substring(0,$tempString.Length-1)

    #sw_ver section===============================================================

    #now, let's get some basic higher-level info
    $macInfoOSVersion = Invoke-Expression -Command "/usr/bin/sw_vers -productVersion"
    $macInfoOSBuildNumber = Invoke-Expression -Command "/usr/bin/sw_vers -buildVersion"
    $macInfoOSName = Invoke-Expression -Command "/usr/bin/sw_vers -productName"

    #system_profiler section=========================================================

    ##now, let's get our system_profiler hardware info

    #use getSPJSONData to get a JSON object for SPHardwareDataType
    $SPHardwareTypeData = getSPJSONData -SPDataType "SPHardwareDataType"
    #set up a var that deals with the first two layers of the return
    $SPHardwareTypeInfo = $SPHardwareTypeData[0].SPHardwareDataType[0]

    #Get the raw data so we can more easily get to the things not in JSON output
    $SPHardwareRaw = getSPRawData -SPDataType "SPHardwareDataType"

    ##Apple Silicon Differences
    #Model Number
    #Chip Type: instead of cpu_type:
    #No Processor Speed:
    #No Number of Processors
    #Total Number of Cores: has more info
    #No L2 Cache:
    #No L3 Cache:
    #No HyperThreading Technology:

    ##common SPHardwareType sections

    #Get the OS Loader Version
    $macInfoSMCVersion = $SPHardwareTypeInfo.os_loader_version

    #hardware serial number
    $macInfoHardwareSN = $SPHardwareTypeInfo.serial_number

    #hardware UUID
    $macInfoHardwareUUID = $SPHardwareTypeInfo.platform_UUID

    #provisioning UUID
    $macInfoProvisioningUDID = $SPHardwareTypeInfo.provisioning_UDID

    #activation Lock status
    $macInfoActivationLockStatus = $SPHardwareTypeInfo.activation_lock_status

    #model name
    $macInfoModelName = $SPHardwareTypeInfo.machine_name

    #model Identfier
    $macInfoModelID = $SPHardwareTypeInfo.machine_model

    #RAM size
    $macInfoRAMSize = $SPHardwareTypeInfo.physical_memory

    #Apple Silicon Section
    if($isAppleSilicon) {

        #getthe System Firmware Version
        #this is slightly different on Intel
        $macInfoEFIVersion = $SPHardwareTypeInfo.boot_rom_version

        #model number
        $macInfoModelNumber = $SPHardwareTypeInfo.model_number

        #CPU Model
        $macInfoCPUName = $SPHardwareTypeInfo.chip_type

        #get the core count. We're going to split ito perf and efficiency
        #This is a mess to get because it doesn't show in the JSON output, although to be fair
        #unless the JSON data split it up into total, performance, and efficiency in discrete values
        #the only difference would be we'd not have to run system_profiler again to get the grep'd results

        #get the total number of cores string from $SPHardwareDataRaw
        #this is basically greping the array of strings to find the one we want.
        #this allows us to only need one call to system_profiler for all the non-json data we'll need for SPHardwareDataType
        $macInfoCPUCoreCount = $SPHardwareRaw -match "Total Number of Cores"

        #split on the colon, grab the second element of the array Split(":") creates
        #(with all the good data) and trim leading/trailing whitespace with Trim()
        $macInfoCPUCoreCount = $macInfoCPUCoreCount.Split(":")[1].Trim()

        #list total cores
        $macInfoCPUCoreCountTotal = $macInfoCPUCoreCount.Split(" ")[0]

        #get Perf and efficiency cores

        #strip of total core count and leading parens
        $macInfoCPUCoreCountTemp = $macInfoCPUCoreCount.Split(" (")[1]

        #strip trailing parens from temp
        $macInfoCPUCoreCountTemp = $macInfoCPUCoreCountTemp.Substring(0,$macInfoCPUCoreCountTemp.Length-1)

        #get performance cores
        $macInfoCPUPerformanceCoreCount = $macInfoCPUCoreCountTemp.Split(" and ")[0]

        #get efficiency cores
        $macInfoCPUEfficiencyCoreCount = $macInfoCPUCoreCountTemp.Split(" and ")[1]

    } else {
        #we want to start grabbing items. first we grab the EFI version, aka Boot ROM version. We only want the last part, so
        #we split on the colon, grab the second part [1]
          #trim all the whitespace from [1]
        #this is actually now referred to as the System Firmware Version, so we'll rename that one day
        #get via match from $SPHardwareRaw
        $macInfoEFIRaw = $SPHardwareRaw -match "System Firmware Version"

        #split on the parens and grab the first entry [0] to get rid of the ibridge stuff
          #and get ride of any remaining whitespace
        $macInfoEFIVersion = $macInfoEFIRaw.Split("(")[0].Trim()

        #T2 Firmware Version
        #split on leading parens to get the ibridge version(T2) info
        $macInfoT2FirmwareVersion = $macInfoEFIRaw.Split("(")[1]
        #split on the colon to get just the numbers
        $macInfoT2FirmwareVersion = $macInfoT2FirmwareVersion.Split(":")[1].Trim()
          #get rid of the last ) character
        $macInfoT2FirmwareVersion = $macInfoT2FirmwareVersion.Substring(0,$macInfoT2FirmwareVersion.Length-1)

        #CPU Model
        $macInfoCPUName = $SPHardwareTypeInfo.cpu_type

        #CPU Speed
        $macInfoCPUSpeed = $SPHardwareTypeInfo.current_processor_speed

        #CPU Count
        $macInfoCPUCount = $SPHardwareTypeInfo.packages

        #core count
        $macInfoCPUCoreCount = $SPHardwareTypeInfo.number_processors

        #L2 Cache Size
        $macInfoCPUL2CacheSize = $SPHardwareTypeInfo.l2_cache_core

        #L3 Cache size
        $macInfoL3CacheSize = $SPHardwareTypeInfo.l3_cache

        #hyperthreading status
        #not in json, do with grep
        #get full results
        $macInfoHyperThreadingRaw =  $SPHardwareRaw -match "Hyper-Threading Technology"

        #split at the colon, grab the second element in the array that creates with Split(":")
        #and use Trim() to remove leading trailing whitespace
        $macInfoHyperThreadingEnabled = $macInfoHyperThreadingRaw.Split(":")[1].Trim()
    }

    #apple pay info===============================================================================

    #get JSON applepay data from system profiler
    $SPApplePayData = getSPJSONData -SPDataType "SPSecureElementDataType"
    #we don't need to care about raw here, there's no difference between ray and JSON output
    $SPApplePayInfo = $SPApplePayData[0].SPSecureElementDataType[0]


    #shove into an arraylist, remove all the blank lines
    #[System.Collections.ArrayList]$applePayInfoArrayList = $applePayInfoArrayRaw.Split([Environment]::NewLine,$darwinVersionSplitOptions)

    #remove the first two lines that only say "Apple Pay"
    #$applePayInfoArrayList.RemoveRange(0,2)

    #grab the platform ID line, item[0] split it on the :, grab the second element [1]
    #trim all leading/trailing whitespace from element[1]
    $applePayInfoPlatformID = $SPApplePayInfo.se_plt

    #get the SEID the same way
    $applePayInfoSEID = $SPApplePayInfo.se_id

    #Hardware
    $applePayInfoHardware = $SPApplePayInfo.se_hw

    #firmware
    $applePayInfoFirmware = $SPApplePayInfo.se_fw

    #JCOP OS version
    $applePayInfoJCOPOSVersion = $SPApplePayInfo.se_os_version

    ##Apple Pay Controller Info
        #hardware version
        $applePayControllerHardwareVersion = $SPApplePayInfo.ctl_hw

        #firmware version
        $applePayControllerFirmwareVersion = $SPApplePayInfo.ctl_fw

        #middleWare version
        $applePayControllerMiddlewareVersion = $SPApplePayInfo.ctl_mw

    #get systemOS SEID, this is the only intel/apple silcon difference
    if($isAppleSilicon) {
        #apple Silicon Only
        #system OS SEID
        $applePayInfoSystemOSSEID = $SPApplePayInfo.se_os_id
    }

    #bluetooth info===============================================================================
    #get the applepay info from system profiler
    #Intel doesn't have the product ID

    $SPBlueToothData = getSPJSONData -SPDataType "SPBluetoothDataType"
    $SPBlueToothInfo = $SPBlueToothData[0].SPBluetoothDataType[0].controller_properties

    $blueToothMAC = $SPBlueToothInfo.controller_address

    #get the BT chipset
    $blueToothChipset = $SPBlueToothInfo.controller_chipset

    #get discoverable status
    #we have to do a bit of parsing here. The actual value is "atrrib_on" or "attrib_off"
    #so we split on the "_", then grab the second item in the array created, the actual thing we
    #care about and Trim() any whitespace that may be there
    $blueToothDiscoverable = $SPBlueToothInfo.controller_discoverable.Split("_")[1].Trim()

    #get firmware version
    $bluetoothFirmwareVersion = $SPBlueToothInfo.controller_firmwareVersion

    #supported services end up
    $bluetoothSupportedServicesRaw = $SPBlueToothInfo.controller_supportedServices

    #get transport
    $blueToothTransport = $SPBlueToothInfo.controller_transport

    #get vendor ID
    $blueToothVendorID = $SPBlueToothInfo.controller_vendorID

    #get state ala discoverable status
    $blueToothState = $SPBlueToothInfo.controller_state.Split("_")[1].Trim()

    #start split between Apple Silicon and Intel

    if($isAppleSilicon) {
        #product ID
        $blueToothProductID = $SPBlueToothInfo.controller_productID
    }

    ##for supported services, we only need the inital block in the if statement, all the rest can live outside
    #build an arraylist to contain all the services
    [System.Collections.ArrayList]$bluetoothSupportedServices = @()

    #get the first item
    $bluetoothSupportedServices.Add($bluetoothSupportedServicesRaw.Split("<")[0].Trim())|Out-Null

    #now we get the other half of the string
    $blueToothTemp = $bluetoothSupportedServicesRaw.Split("<")[1].Trim()

    #trim the trailing >
    $blueToothTemp = $blueToothTemp.Substring(0,$blueToothTemp.Length-1)

    #yeet any leading/trailing whitespace
    $blueToothTemp = $blueToothTemp.Trim()

    #create a temp array for the other services
    $blueToothTempArray = $blueToothTemp.Split(" ")

    #add them onto the backend of the arraylist which we can then shove in the hashlist
    foreach($item in $blueToothTempArray){
        $bluetoothSupportedServices.Add($item)|Out-Null
    }

    #Removed the POST test section, it seems to have completely gone away
    #Removed redundancies in the hashtable.

    #SPPowerDataTypeNotes
    #do some checking for AC Charger info
    #Intel has
    ## manufacturer for battery model info
    ## full charge capacity for battery charge info (sppower_battery_max_capacity)
    ## AC Power
    ## Wake on AC Changes
    ## Wake on clamshell open
    ## Display sleep uses Dim
    ## Battery Power
    ## Wake on AC Changes
    ## Wake on clamshell open
    ## Display sleep uses Dim

    #AS has
    ## maximum capacity for battery health info
    ## AC Power
    ## sleep on power button
    ## High Power Mode
    ## Battery Power
    ## sleep on power button
    ## High Power Mode
    ## Reduce Brightness

    #get full output of SPPowerDataType as JSON
    #because of how this works, we'll have to do this as a loop testing section names, AND deal with intel/AS differences
    #oh yey
    $SPPowerTypeData = getSPJSONData -SPDataType "SPPowerDataType"

    #get number of items in the collection, may end up not needing
    #$SPPowerTypeDataCount = $SPPowerTypeData.SPPowerDataType.Count

    #Get list of section names
    $SPPowerTypeNames = $SPPowerTypeData[0].SPPowerDataType._name

    #set up flags to check for battery/UPS
    #every mac always has AC Power, but they don't all have batteries and/or UPS's

    #global flag vars. yes I know, global vars bad, whatevs
    $Global:hasBattery = $false
    $Global:hasUPS = $false

    #we use globals here because scope issues can be tricky and are HARD to manager.
    foreach($entry in $SPPowerTypeNames) {
        #the index is important in doing this, since it may or may not be different. saves some work
        $theIndex = [array]::IndexOf($SPPowerTypeNames,$entry)

        #switch-case to manage this
        switch ($entry) {

            "spbattery_information" {
                #has a battery if this exists, set $hasBattery to true
                $hasBattery = $true
                #get all three battery information items
                #battery Charge Info
                $batteryChargeInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex].sppower_battery_charge_info
                $Global:batteryWarningLevel = $batteryChargeInfo.sppower_battery_at_warn_level
                $Global:batteryFullyCharged = $batteryChargeInfo.sppower_battery_fully_charged
                $Global:batteryIsCharging = $batteryChargeInfo.sppower_battery_is_charging
                $Global:batteryChargeLevel = $batteryChargeInfo.sppower_battery_state_of_charge
                #Intel-only value
                if (!($isAppleSilicon)) {
                    $Global:batteryMaxChargeCapacity = $batteryChargeInfo.sppower_battery_max_capacity
                }

                #battery health info, same for both arch's
                $batteryHealthInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex].sppower_battery_health_info
                $Global:batteryCycleCount = $batteryHealthInfo.sppower_battery_cycle_count
                $Global:batteryHealth = $batteryHealthInfo.sppower_battery_health
                #AS-only value
                if ($isAppleSilicon) {
                    $Global:batteryHealthMaxCapacity = $batteryHealthInfo.sppower_battery_health_maximum_capacity
                }

                #battery model info
                $batteryModelInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex].sppower_battery_model_info
                $Global:batterySerialNumber = $batteryModelInfo.sppower_battery_serial_number
                $Global:batteryDeviceName = $batteryModelInfo.sppower_battery_device_name
                $Global:batteryFirmwareVersion = $batteryModelInfo.sppower_battery_firmware_version
                $Global:batteryHardwareRevision = $batteryModelInfo.sppower_battery_hardware_revision
                $Global:batteryCellRevision = $batteryModelInfo.sppower_battery_cell_revision
                #Intel-Only
                if (!($isAppleSilicon)) {
                    $Global:batteryManufacturer = $batteryModelInfo.sppower_battery_manufacturer
                }
            }

            "sppower_information" {

                #We can always assume AC power exists
                #set up our common stuff
                $ACPowerInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex].'AC Power'
                $Global:ACDiskSleepTimer = $ACPowerInfo.'Disk Sleep Timer'
                $Global:ACDisplaySleepTimer = $ACPowerInfo.'Display Sleep Timer'
                $Global:ACHibernateMode = $ACPowerInfo.'Hibernate Mode'
                $Global:ACLowPowerMode = $ACPowerInfo.LowPowerMode
                $Global:ACNetworkOverSleep = $ACPowerInfo.PrioritizeNetworkReachabilityOverSleep
                $Global:ACSystemSleepTimer = $ACPowerInfo.'System Sleep Timer'
                $Global:ACWakeOnLAN = $ACPowerInfo.'Wake On LAN'

                #test to see if the machine is plugged in or not. IF it is, set the current power source var
                #we set it to null/empty for when we add to the hashtable
                if(!([string]::IsNullOrEmpty($ACPowerInfo.'Current Power Source'))) {
                    $Global:ACCurrentPowerSource = $ACPowerInfo.'Current Power Source'
                } else {
                    $Global:ACCurrentPowerSource = "FALSE"
                }

                #apple Silicon section for AC Power
                if ($isAppleSilicon) {
                    $Global:ACSleepOnPowerButton = $ACPowerInfo.'Sleep On Power Button'
                    $Global:ACHighPowerMode = $ACPowerInfo.HighPowerMode
                } else {
                    $Global:ACDisplaySleepDim = $ACPowerInfo.'Display Sleep Uses Dim'
                    $Global:ACWakeOnACCHange = $ACPowerInfo.'Wake On AC Change'
                    $Global:ACWakeOnClamshellOpen = $ACPowerInfo.'Wake On Clamshell Open'
                }

                #Test for Battery
                $batteryPowerInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex].'Battery Power'

                #if there's a battery (like built in, not in the room)
                if ($null -ne $batteryPowerInfo) {
                    #this is possibly redundant, but since we can't be SURE which will be hit first, this
                    #or the preceding battery info, setting it here too is fine.
                    $hasBattery = $true

                    #test to see if computer is running on battery power
                    if(!([string]::IsNullOrEmpty($batteryPowerInfo.'Current Power Source'))) {
                        $Global:batteryCurrentPowerSource = $batteryPowerInfo.'Current Power Source'
                    } else {
                        $Global:batteryCurrentPowerSource = "FALSE"
                    }

                    #architecture independent stuff
                    $Global:batteryDiskSleepTimer = $batteryPowerInfo.'Disk Sleep Timer'
                    $Global:batteryDisplaySleepTimer = $batteryPowerInfo.'Display Sleep Timer'
                    $Global:batteryHibernateMode = $batteryPowerInfo.'Hibernate Mode'
                    $Global:batteryLowPowerMode = $batteryPowerInfo.LowPowerMode
                    $Global:batteryNetworkOverSleep = $batteryPowerInfo.PrioritizeNetworkReachabilityOverSleep
                    $Global:batteryReduceBrightness = $batteryPowerInfo.ReduceBrightness
                    $Global:batterySystemSleepTimer = $batteryPowerInfo.'System Sleep Timer'
                    $Global:batteryWakeOnLan = $batteryPowerInfo.'Wake On LAN'

                    #Arch-specific stuff
                    if ($isAppleSilicon) {
                        $Global:batteryHighPowerMode = $batteryPowerInfo.HighPowerMode
                        $Global:batterySleepOnPowerButton = $batteryPowerInfo.'Sleep On Power Button'
                    } else {
                        $Global:batteryDisplaySleepUsesDim = $batteryPowerInfo.'Display Sleep Uses Dim'
                        $Global:batteryWakeOnACChange = $batteryPowerInfo.'Wake On AC Change'
                        $Global:batteryWakeOnClamshellOpen = $batteryPowerInfo.'Wake On Clamshell Open'
                    }
                }

                #test for UPS Power. Yes, I know about hwconfig info, but we don't know if this
                #section will process before or after that, so we test it here, where we need it
                $UPSPowerInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex].'UPS Power'

                #UPS power exists
                if ($null -ne $UPSPowerInfo) {

                    #set has UPS flag to true
                    $hasUPS = $true

                    if(!([string]::IsNullOrEmpty($UPSPowerInfo.'Current Power Source'))) {
                        $Global:UPSCurrentPowerSource = $UPSPowerInfo.'Current Power Source'
                    } else {
                        $Global:UPSCurrentPowerSource = "FALSE"
                    }

                    #no idea if there's arch-dependent stuff, so it's all just here
                    $Global:UPSAutoRestartOnPwrLoss = $UPSPowerInfo.'Automatic Restart On Power Loss'
                    $Global:UPSDiskSleepTimer = $UPSPowerInfo.'Disk Sleep Timer'
                    $Global:UPSDisplaySleepTimer = $UPSPowerInfo.'Display Sleep Timer'
                    $Global:UPSNetworkOverSleep = $UPSPowerInfo.PrioritizeNetworkReachabilityOverSleep
                    #assuming this is apple silcon only here too, since it is everywhere else
                    if ($isAppleSilicon) {
                        $Global:UPSSleepOnPowerButton = $UPSPowerInfo.'Sleep On Power Button'
                    }
                    $Global:UPSSystemSleepTimer = $UPSPowerInfo.'System Sleep Timer'
                    $Global:UPSWakeOnLan = $UPSPowerInfo.'Wake On LAN'
                }
            }

            "sppower_hwconfig_information" {
                #has one value: is a UPS installed or not
                #it always exists, so we don't need to set it anywhere else
                $Global:UPSInstalled = $SPPowerTypeData[0].SPPowerDataType[$theIndex].sppower_ups_installed

                #set the flag appropriately.
                if ($UPSInstalled -eq "TRUE") {
                    $hasUPS = $true
                } else {
                    #is this strictly needed? No. Does it avoid potential problems? Yes
                    $hasUPS = $false
                }
            }

            "sppower_ac_charger_information" {
                #like assuming there's always an AC Power Type, we assume there's always some kind of
                #AC charger info. This is different in that we don't have a named property after
                #SPPowerDataType[$theIndex]

                #Also note that depending on the charger the computer is plugged into,
                #much of these may be null. We can check when we build the hash. They're all strings
                #so easy enough
                $ACChargerInfo = $SPPowerTypeData[0].SPPowerDataType[$theIndex]

                #these exist, even when on battery
                $Global:ACChargerConnected = $ACChargerInfo.sppower_battery_charger_connected #false when on battery, use as check
                $Global:ACChargerCharging = $ACChargerInfo.sppower_battery_is_charging #this and connected are only items when not plugged in

                #there doesn't seem to be any architectural difference here, just charger differences
                $Global:ACChargerName = $ACChargerInfo.sppower_ac_charger_name #only for apple chargers
                $Global:ACChargerSerialNumber = $ACChargerInfo.sppower_ac_charger_serial_number #only for apple chargers
                $Global:ACChargerWatts = $ACChargerInfo.sppower_ac_charger_watts
                $Global:ACChargerManf = $ACChargerInfo.sppower_ac_charger_manufacturer #only for apple chargers
                $Global:ACChargerID = $ACChargerInfo.sppower_ac_charger_ID
                $Global:ACChargerHWVers = $ACChargerInfo.sppower_ac_charger_hardware_version #only for apple chargers
                $Global:ACChargerFirmwareVers = $ACChargerInfo.sppower_ac_charger_firmware_version #only for apple chargers
                $Global:ACChargerFamily = $ACChargerInfo.sppower_ac_charger_family #this may be dependent on charger

            }
        }

    }

    ##ibridge Data
    $spiBridgeData = getSPJSONData -SPDataType SPiBridgeDataType
    $spiBridgeDataType = $spiBridgeData.SPiBridgeDataType

    #common types for both intel and AS
    $Global:iBridgeBootUUID = $spiBridgeDataType.ibridge_boot_uuid
    $Global:iBridgeBuild = $spiBridgeDataType.ibridge_build
    #the one intel-unique param
    if (!$isAppleSilicon) {
        $Global:iBridgeModelName = $spiBridgeDataType.ibridge_model_name
    #apple silicon only
    } else {
        $Global:iBridgeExtraBootPolicies = $spiBridgeDataType.ibridge_extra_boot_policies
        $Global:iBridgeSBBootArgs = $spiBridgeDataType.ibridge_sb_boot_args
        $Global:iBridgeSBCtrr = $spiBridgeDataType.ibridge_sb_ctrr
        $Global:iBridgeSBDeviceMDM = $spiBridgeDataType.ibridge_sb_device_mdm
        $Global:iBridgeSBManualMDM = $spiBridgeDataType.ibridge_sb_manual_mdm
        $Global:iBridgeSBOtherKext = $spiBridgeDataType.ibridge_sb_other_kext
        $Global:iBridgeSBSIP = $spiBridgeDataType.ibridge_sb_sip
        $Global:iBridgeSBSSV = $spiBridgeDataType.ibridge_sb_ssv
        $Global:iBridgeSecureBoot = $spiBridgeDataType.ibridge_secure_boot
    }

    #sysctl section===============================================================================
    $macInfoCPUBrand = Invoke-Expression -Command "/usr/sbin/sysctl -n machdep.cpu.brand_string"
    $macInfoVMPageFile = Invoke-Expression -Command "/usr/sbin/sysctl -n vm.swapfileprefix"

    ##get application memory in use. This is calculated by ((vm page size) * (vm page internal count - vm page purgeable count)/1073741824)
    ##to get the memory used in GB. To get this without needing a ton of lines, we're going to directly inject the vm data into the
    ##equation, via invoke-expression to the correct sysctl values. the [Int] parameter coerces that text file returned to an integer value
    ##dividing by 1073741824 converts the number to GB.
    $macInfoAppMemoryUsedGB = (([Int](Invoke-Expression -Command "/usr/sbin/sysctl -n vm.pagesize")) * (([Int](Invoke-Expression -Command "/usr/sbin/sysctl -n vm.page_pageable_internal_count")) - ([Int](Invoke-Expression -Command "/usr/sbin/sysctl -n vm.page_purgeable_count"))))/1073741824

    ##now, we trim this down to four decimal places (just in case it's less than a GB, we get a useful number that way)
    $macInfoAppMemoryUsedGB = "{0:N4}" -f $macInfoAppMemoryUsedGB

    ##next is current swap usage. Again, this is going to come from sysctl, specifically vm.swapusage. That reports in M as a string,
    ##so we first grab the data from sysctl and split each entry into its own item in an array by splitting on spaces
    $macInfoVMSwapUsed = (Invoke-Expression -Command "/usr/sbin/sysctl -n vm.swapusage").Split(" ",[System.StringSplitOptions]::RemoveEmptyEntries)

    ##next, the value we want is the 6th entry in the array. that's a string that ends in "M", so we want to trim that "M" from the
    ##end via "TrimEnd("M"), which makes the string able to be coerced into a decimal via [Decimal], then we divide by 1024
    ##to convert the data in MB to GB (we're trying to stick with GB in this where possible), and finally, we limit the decimal
    ##to four decimal places "{0,N4}" -f at the front end. Again, we use four decimal places in case there's less than a GB of swap used.

    $macInfoVMSwapUsed = "{0:N4}" -f (([Decimal]($macInfoVMSwapUsed[5].TrimEnd("M")))/1024)

    #other section================================================================================

    #get boot device
    $macInfoBootDevice = Invoke-Expression -Command "/usr/sbin/bless --info --getboot"

    #get the current language
    $macInfoEFILanguage = (Get-Culture).DisplayName

    #get DST status
    $macInfoDSTStatus = (Get-Date).IsDaylightSavingTime()

    #get timezone
    $macInfoTimeZone = (Get-TimeZone).Id

    #get UTC offset
    $macInfoUTCOffset = (Get-TimeZone).BaseUTCOffset

    ##filevault status
    #changed this to allow for multiline entries that can happen, all we care about for this is if FV is on
    $macInfoFileVaultTemp = Invoke-Expression -Command "/usr/bin/fdesetup status"
    #shove into array because multiline
    $macInfoFileVaultStatusArray = $macInfoFileVaultTemp.Split([Environment]::NewLine,$darwinVersionSplitOptions)
    #get last word of return of first line of array which has on/off
     #and trim trailing period
    $macInfoFileVaultStatus = $macInfoFileVaultStatusArray[0].Split(" ")[-1].TrimEnd(".")

    #DNS host name
    $macInfoDNSHostNameTest = Invoke-Expression -Command "/usr/sbin/scutil --get HostName"
    #we want to test for null or empty so we can have a default value just in case
    if([string]::IsNullOrEmpty($macInfoDNSHostNameTest)) {
        $macInfoDNSHostName = "Hostname: Not Set"
    } else {
        $macInfoDNSHostName = $macInfoDNSHostNameTest
    }

    ##local machine name
    $macInfoLocalHostName = Invoke-Expression -Command "/usr/sbin/scutil --get ComputerName"

    #get a list of network services. This takes a few steps. First, get the list and put it into an array
    ##this does a lot of things. It runs the networksetup - listallnetworkservices, then splits that output into an array,
    ##one entry per line and removes blank lines
    #set it up as an arraylist
    [System.Collections.ArrayList]$macInfoNICList = @()

    #grab the NIC list and shove them into the array list
    $macInfoNICList = (Invoke-Expression -Command "/usr/sbin/networksetup -listallnetworkservices").Split([Environment]::NewLine,[System.StringSplitOptions]::RemoveEmptyEntries)

    ##now we remove the first line, which is unnecessary for our needs
    ##and yes, i know this is not technically a nic list, but it will work for our needs
    ##and it grabs services that don't have ports that -listallhardwareports would have, like iPhone USB
    $macInfoNICList.RemoveAt(0)


    #using powershell -> bash -> applescript
    #get current user name
    $macInfoShortUserName = Invoke-Expression -Command '/usr/bin/osascript -e "get short user name of (system info)"'

    #get current user UID
    $macInfoUID = Invoke-Expression -Command '/usr/bin/osascript -e "get user ID of (system info)"'

    #get current date and time
    $macInfoCurrentDate = Get-Date

    #get last boot time
    ##run who -b, but split on a space since you only get back a single line.
    $macInfoLastBoot = (Invoke-Expression -Command "/usr/bin/who -b").Split(" ",[System.StringSplitOptions]::RemoveEmptyEntries)
    ##remove the first two entries, since those aren't of use here
    $macInfoLastBoot = $macInfoLastBoot[2..($macInfoLastBoot.length - 1)]
    ##convert it from an array back to a single line text string with the things we want
    $macInfoLastBoot = $macInfoLastBoot -join ' '

    #get uptime since
    ##first, get the raw uptime
    $macInfoUptime = Get-Uptime
    ## now pull out days.hours:minutes:seconds
    $macInfoUptime = $macInfoUptime -join " "

    ##Get SIP status, split on : to make array
    $csrutilOutput = (Invoke-Expression -Command "/usr/bin/csrutil status").Split(":")
    #remove the leading space in the status
    $csrutilStatus = $csrutilOutput[1].Trim()
    #remove the trailing period
    $csrutilStatus = $csrutilStatus.Substring(0,$csrutilStatus.Length-1)

    ##hashtable build, we deal with arch versions inline. It's not harder to read
    ##and gets rid of a LOT of duplication.

    ##the reason for the ever-increasing spaces in the blank lines is to avoid duplication of "names"
    ##which are no-nos for hashtables.

    $macInfoHash.Add("macOSBuildLabEx", $mainDarwinKernelVersion)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("macOSCurrentVersion", $macInfoOSVersion)
    $macInfoHash.Add("macOSCurrentBuildNumber", $macInfoOSBuildNumber)
    $macInfoHash.Add("macOSProductName", $macInfoOSName)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("macOSDarwinVersion", $mainDarwinKernelVersion)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("SystemFirmwareVersion", $macInfoEFIVersion)
    if (!($isAppleSilicon)) {
        $macInfoHash.Add("T2FirmwareVersion", $macInfoT2FirmwareVersion) #intel only
    }
    $macInfoHash.Add("OSLoaderVersion", $macInfoSMCVersion)
    $macInfoHash.Add("HardwareSerialNumber", $macInfoHardwareSN)
    $macInfoHash.Add("HardwareUUID", $macInfoHardwareUUID)
    $macInfoHash.Add("ProvisioningUDID",$macInfoProvisioningUDID)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("HardwareModelName", $macInfoModelName)
    $macInfoHash.Add("HardwareModelID", $macInfoModelID)
    if ($isAppleSilicon) {
        $macInfoHash.Add("HardwareModelNumber", $macInfoModelNumber) #apple silicon only
    }
    $macInfoHash.Add("ActivationLockStatus", $macInfoActivationLockStatus)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("CPUArchitecture", $macInfoCPUArch)
    $macInfoHash.Add("CPUName" , $macInfoCPUName)
    $macInfoHash.Add("CPUBrandString", $macInfoCPUBrand)
    $macInfoHash.Add("RAMAmount", $macInfoRAMSize)
    if ($isAppleSilicon) {
        $macInfoHash.Add("CPUTotalCoreCount", $macInfoCPUCoreCountTotal) #apple silicon only
        $macInfoHash.Add("CPUPerformanceCoreCount", $macInfoCPUPerformanceCoreCount) #apple silicon only
        $macInfoHash.Add("CPUEfficiencyCoreCount", $macInfoCPUEfficiencyCoreCount) #apple silicon only
    } else {
        $macInfoHash.Add("CPUSpeed", $macInfoCPUSpeed) #Intel Only
        $macInfoHash.Add("CPUCount", $macInfoCPUCount) #Intel Only
        $macInfoHash.Add("CPUCoreCount", $macInfoCPUCoreCount) #Intel Only
        $macInfoHash.Add("CPUL2CacheSize", $macInfoCPUL2CacheSize) #Intel Only
        $macInfoHash.Add("L3CacheSize", $macInfoL3CacheSize) #Intel Only
        $macInfoHash.Add("HyperThreadingEnabled", $macInfoHyperThreadingEnabled) #Intel Only
    }
    $macInfoHash.Add(" "," ")

    $macInfoHash.Add("ApplePayPlatformID", $applePayInfoPlatformID)
    $macInfoHash.Add("ApplePaySEID", $applePayInfoSEID)
    if ($isAppleSilicon) {
        $macInfoHash.Add("ApplePaySystemOSSEID", $applePayInfoSystemOSSEID)#apple silicon only
    }
    $macInfoHash.Add("ApplePayHardware", $applePayInfoHardware)
    $macInfoHash.Add("ApplePayFirmware", $applePayInfoFirmware)
    $macInfoHash.Add("ApplePayJCOPOSVersion", $applePayInfoJCOPOSVersion)
    $macInfoHash.Add("ApplePayControllerHardwareVersion", $applePayControllerHardwareVersion)
    $macInfoHash.Add("ApplePayControllerFirmwareVersion", $applePayControllerFirmwareVersion)
    $macInfoHash.Add("ApplePayControllerMiddlewareVersion", $applePayControllerMiddlewareVersion)
    $macInfoHash.Add(" "," ")

    $macInfoHash.Add("BluetoothMAC",$blueToothMAC)
    $macInfoHash.Add("BluetoothChipset",$blueToothChipset)
    $macInfoHash.Add("BluetoothDiscoverable",$blueToothDiscoverable)
    $macInfoHash.Add("BluetoothState",$blueToothState)
    $macInfoHash.Add("BluetoothFirmwareVersion",$bluetoothFirmwareVersion)
    if ($isAppleSilicon) {
        $macInfoHash.Add("BluetoothProductID", $blueToothProductID) #apple silicon only
    }
    $macInfoHash.Add("BluetoothSupportedServices",$bluetoothSupportedServices)
    $macInfoHash.Add("BluetoothTransport",$blueToothTransport)
    $macInfoHash.Add("BluetoothVendorID",$blueToothVendorID)
    $macInfoHash.Add(" "," ")

    #more common elements. The order matters
    $macInfoHash.Add("AppMemoryUsedGB", $macInfoAppMemoryUsedGB)
    $macInfoHash.Add("VMPageFile", $macInfoVMPageFile)
    $macInfoHash.Add("VMSwapInUseGB", $macInfoVMSwapUsed)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("BootDevice", $macInfoBootDevice)
    $macInfoHash.Add("FileVaultStatus", $macInfoFileVaultStatus)
    $macInfoHash.Add("SIPStatus", $csrutilStatus)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("EFICurrentLanguage", $macInfoEFILanguage)
    $macInfoHash.Add("DSTStatus", $macInfoDSTStatus)
    $macInfoHash.Add("TimeZone", $macInfoTimeZone)
    $macInfoHash.Add("UTCOffset", $macInfoUTCOffset)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("DNSHostName", $macInfoDNSHostName)
    $macInfoHash.Add("LocalHostName", $macInfoLocalHostName)
    $macInfoHash.Add("NetworkServiceList", $macInfoNICList)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("CurrentUserName", $macInfoShortUserName)
    $macInfoHash.Add("CurrentUserUID", $macInfoUID)
    $macInfoHash.Add(" "," ")
    $macInfoHash.Add("CurrentDateTime", $macInfoCurrentDate)
    $macInfoHash.Add("LastBootDateTime", $macInfoLastBoot)
    $macInfoHash.Add("Uptime", $macInfoUptime)
    $macInfoHash.Add(" "," ")

    ##Power Info
    #AC Power first, that's always there
    $macInfoHash.Add("ACCurrentPowerSource",$ACCurrentPowerSource)
    $macInfoHash.Add("ACSystemSleepTimer",$ACSystemSleepTimer)
    $macInfoHash.Add("ACDiskSleepTImer",$ACDiskSleepTimer)
    $macInfoHash.Add("ACDisplaySleepTimer",$ACDisplaySleepTimer)
    $macInfoHash.Add("ACHibernateMode",$ACHibernateMode)
    $macInfoHash.Add("ACLowPowerMode",$ACLowPowerMode)
    $macInfoHash.Add("ACNetworkOverSleep",$ACNetworkOverSleep)
    $macInfoHash.Add("ACWakeOnLan",$ACWakeOnLAN)
    #apple silicon info
    if ($isAppleSilicon) {
        $macInfoHash.Add("ACHighPowerMode",$ACHighPowerMode)
        $macInfoHash.Add("ACSleepOnPowerButton",$ACSleepOnPowerButton)
    } else {
        #intel info
        $macInfoHash.Add("ACDisplaySleepUsesDim",$ACDisplaySleepDim)
        $macInfoHash.Add("ACWakeOnACChange",$ACWakeOnACCHange)
        $macInfoHash.Add("ACWakeOnClamshellOpen",$ACWakeOnClamshellOpen)
    }
    #add a blank line to make reading easier
    $macInfoHash.Add(" "," ")

    #put in the AC Charger info here, there's some logic to it
    $macInfoHash.Add("ACChargerConnected",$ACChargerConnected)
    $macInfoHash.Add("ACChargerCharging",$ACChargerCharging)
    #the rest of this is variable AF, and there's not a great way to test for it other
    #than if statements or a switch case. Which I'll do if I get complaints
    $macInfoHash.Add("ACChargerName",$ACChargerName)
    $macInfoHash.Add("ACChargerSerialNumber",$ACChargerSerialNumber)
    $macInfoHash.Add("ACChargerWatts",$ACChargerWatts)
    $macInfoHash.Add("ACChargerManf",$ACChargerManf)
    $macInfoHash.Add("ACChargerID",$ACChargerID)
    $macInfoHash.Add("ACChargerHWVers",$ACChargerHWVers)
    $macInfoHash.Add("ACChargerFirmwareVers",$ACChargerFirmwareVers)
    $macInfoHash.Add("ACChargerFamily",$ACChargerFamily)
    $macInfoHash.Add(" "," ")

    #if we have a battery, add that
    if ($hasBattery) {
        $macInfoHash.Add("batteryCurrentPowerSource",$batteryCurrentPowerSource)
        $macInfoHash.Add("batterySystemSleepTimer",$batterySystemSleepTimer)
        $macInfoHash.Add("batteryDiskSleepTimer",$batteryDiskSleepTimer)
        $macInfoHash.Add("batteryDisplaySleepTimer",$batteryDisplaySleepTimer)
        $macInfoHash.Add("batteryReduceBrightness",$batteryReduceBrightness)
        $macInfoHash.Add("batteryHibernateMode",$batteryHibernateMode)
        $macInfoHash.Add("batteryLowPowerMode",$batteryLowPowerMode)
        $macInfoHash.Add("batteryNetworkOverSleep",$batteryNetworkOverSleep)
        $macInfoHash.Add("batteryWakeOnLan",$batteryWakeOnLan)
        #apple silicon info
        if ($isAppleSilicon) {
            $macInfoHash.Add("batteryHighPowerMode",$batteryHighPowerMode)
            $macInfoHash.Add("batterySleepOnPowerButton",$batterySleepOnPowerButton)
        } else {
            #intel info
            $macInfoHash.Add("batteryDisplaySleepUsesDim",$batteryDisplaySleepUsesDim)
            $macInfoHash.Add("batteryWakeOnACChange",$batteryWakeOnACChange)
            $macInfoHash.Add("batteryWakeOnClamshellOpen",$batteryWakeOnClamshellOpen)
        }
        #more white space
        $macInfoHash.Add(" "," ")

        $macInfoHash.Add("batteryWarningLevel",$batteryWarningLevel)
        $macInfoHash.Add("batteryFullyCharged",$batteryFullyCharged)
        $macInfoHash.Add("batteryIsCharging",$batteryIsCharging)
        $macInfoHash.Add("batteryChargeLevel",$batteryChargeLevel)
        if (!($isAppleSilicon)) {
            $macInfoHash.Add("batteryMaxChargeCapacity",$batteryMaxChargeCapacity) #intel only
        }
        $macInfoHash.Add(" "," ")

        $macInfoHash.Add("batteryCycleCount",$batteryCycleCount)
        $macInfoHash.Add("batteryHealth",$batteryHealth)
        if ($isAppleSilicon) {
            $macInfoHash.Add("batteryHealthMaxCapacity",$batteryHealthMaxCapacity) #apple silicon only
        }
        $macInfoHash.Add(" "," ")

        $macInfoHash.Add("batterySerialNumber",$batterySerialNumber)
        $macInfoHash.Add("batteryDeviceName",$batteryDeviceName)
        $macInfoHash.Add("batteryFirmwareVersion",$batteryFirmwareVersion)
        $macInfoHash.Add("batteryHardwareRevision",$batteryHardwareRevision)
        $macInfoHash.Add("batteryCellRevision",$batteryCellRevision)
        if (!($isAppleSilicon)) {
            $macInfoHash.Add("batteryManufacturer",$batteryManufacturer) #intel Only
        }
        $macInfoHash.Add(" "," ")
    }

    #if we have a UPS, add that
    #note we add the hardware config regardless, this is just for the UPS-specific info
    $macInfoHash.Add("UPSInstalled",$UPSInstalled)
    $macInfoHash.Add(" "," ")
    if ($hasUPS) {
        $macInfoHash.Add("UPSCurrentPowerSource",$UPSCurrentPowerSource)
        $macInfoHash.Add("UPSSystemSleepTimer",$UPSSystemSleepTimer)
        $macInfoHash.Add("UPSAutoRestartOnPowerLoss",$UPSAutoRestartOnPwrLoss)
        $macInfoHash.Add("UPSDiskSleepTimer",$UPSDiskSleepTimer)
        $macInfoHash.Add("UPSDisplaySleepTimer",$UPSDisplaySleepTimer)
        $macInfoHash.Add("UPSNetworkOverSleep",$UPSNetworkOverSleep)
        $macInfoHash.Add("UPSWakeOnLan",$UPSWakeOnLan)
        if ($isAppleSilicon) {
            $macInfoHash.Add("UPSSleepOnPowerButton",$UPSSleepOnPowerButton) #apple silicon only
        }
        $macInfoHash.Add(" "," ")
    }

    #ibridge additions
    $macInfoHash.Add("iBridgeBootUUID",$iBridgeBootUUID)
    $macInfoHash.Add("iBridgeFWVersion",$iBridgeBuild)
    #split out intel & AS
    if (!$isAppleSilicon) {
        $macInfoHash.Add("iBridgeModelName",$iBridgeModelName)
    } else {
        $macInfoHash.Add("iBridgeExtraBootPolicies",$iBridgeExtraBootPolicies)
        $macInfoHash.Add("iBridgeBootArgsFiltering",$iBridgeSBBootArgs)
        $macInfoHash.Add("iBridgeKernelCTRR",$iBridgeSBCtrr)
        $macInfoHash.Add("iBridgeDEPMDM",$iBridgeSBDeviceMDM)
        $macInfoHash.Add("iBridgeUserApprMDM",$iBridgeSBManualMDM)
        $macInfoHash.Add("iBridgeAllAllKexts",$iBridgeSBOtherKext)
        $macInfoHash.Add("iBridgeSIPStatus",$iBridgeSBSIP)
        $macInfoHash.Add("iBridgeSSVStatus",$iBridgeSBSSV)
        $macInfoHash.Add("iBridgeSecureBootLvl",$iBridgeSecureBoot)
    }
    $macInfoHash.Add(" "," ")

    #so we want the hashtable to be filled before we even care about what the person asked for. This is lazy as hell, to be sure, but,
    #it ensures that no matter what the parameter asks for, it will work. Also really, the entire thing takes just over a second to run,
    #even on a ten-year-old macbook pro.

    #so here, we're checking to see if there's no input parameters, which means display the entire hashtable. We're not formatting it,
    #the default is fine.

    #if there are input parameters, we use the -f formatting operator to create two columns labled "Name", and "Value", setting the first one
    #to 30 characters, which gives us some space as our longest key is only about 24 characters in width, and the value column to 100 characters
    #both columns are lef-aligned.

    #I did try to use -format table, but it didn't work out

    if ($null -eq $keys) {
        $macInfoHash
        Exit-PSSession
    }
    else {
        "{0,-30}{1,-100}" -f "Name","Value"
        "{0,-30}{1,-100}" -f "----","-----"
        foreach ($key in $keys) {
             $theValue = $macInfoHash.$key
             "{0,-30}{1,-100}" -f $key,$theValue
        }
    }
}

Export-ModuleMember -Function Get-MacInfo


# SIG # Begin signature block
# MIIMgAYJKoZIhvcNAQcCoIIMcTCCDG0CAQMxDTALBglghkgBZQMEAgEwewYKKwYB
# BAGCNwIBBKBtBGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC+w4dAgNCnWQp1
# Zs5LDqWRYdwbgof80dNxdAarPC7lCaCCCaswggQEMIIC7KADAgECAggYeqmowpYh
# DDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUg
# SW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAU
# BgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMTIwMjAxMjIxMjE1WhcNMjcwMjAxMjIx
# MjE1WjB5MS0wKwYDVQQDDCREZXZlbG9wZXIgSUQgQ2VydGlmaWNhdGlvbiBBdXRo
# b3JpdHkxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMw
# EQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAIl2TwZbmkHupSMrAqNf13M/wDWwi4QKPwYkf6eVP+tP
# DpOvtA7QyD7lbRizH+iJR7/XCQjk/1aYKRXnlJ25NaMKzbTA4eJg9MrsKXhFaWlg
# a1+KkvyeI+Y6wiKzMU8cuvK2NFlC7rCpAgMYkQS2s3guMx+ARQ1Fb7sOWlt/OufY
# CNcLDjJt+4Y25GyrxBGKcIQmqp9E0fG4xnuUF5tI9wtYFrojxZ8VOX7KXcMyXw/g
# Un9A6r6sCGSVW8kanOWAyh9qRBxsPsSwJh8d7HuvXqBqPUepWBIxPyB2KG0dHLDC
# ThFpJovL1tARgslOD/FWdNDZCEtmeKKrrKfi0kyHWckCAwEAAaOBpjCBozAdBgNV
# HQ4EFgQUVxftos/cfJihEOD8voctLPLjF1QwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
# HSMEGDAWgBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAuBgNVHR8EJzAlMCOgIaAfhh1o
# dHRwOi8vY3JsLmFwcGxlLmNvbS9yb290LmNybDAOBgNVHQ8BAf8EBAMCAYYwEAYK
# KoZIhvdjZAYCBgQCBQAwDQYJKoZIhvcNAQELBQADggEBAEI5dGuh3MakjzcqjLMd
# CkS8lSx/vFm4rGH7B5CSMrnUvzvBUDlqRHSi7FsfcOWq3UtsHCNxLV/RxZO+7puK
# cGWCnRbjGhAXiS2ozf0MeFhJDCh/M+4Aehu0dqy2tbtP36gbncgZl0oLVmcvwj62
# s8SDOvB3bXTELiNR7pqlA29g9KVIpwbCu1riHx9GRX7kl/UnELcgInJvctrGUHXF
# PSWPXaMA6Z82jEg5j7M76pCALpWaYPR4zvQOClM+ovpP2B6uhJWNMrxWTYnpeBjg
# rJpCunpGG4Siic4U6IjRWIv2rlbELAUqRa8L2UupAg80rIjHYVWJRMkncwfuguVO
# 9XAwggWfMIIEh6ADAgECAggGHmabX9eOKjANBgkqhkiG9w0BAQsFADB5MS0wKwYD
# VQQDDCREZXZlbG9wZXIgSUQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJjAkBgNV
# BAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBs
# ZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0yMDA5MTYwMzU4MzBaFw0yNTA5MTcwMzU4
# MzBaMIGNMRowGAYKCZImiZPyLGQBAQwKNzk2NDg4Vkc5NTE4MDYGA1UEAwwvRGV2
# ZWxvcGVyIElEIEluc3RhbGxlcjogSm9obiBXZWxjaCAoNzk2NDg4Vkc5NSkxEzAR
# BgNVBAsMCjc5NjQ4OFZHOTUxEzARBgNVBAoMCkpvaG4gV2VsY2gxCzAJBgNVBAYT
# AlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0uP+x8FCIpcy4DJ
# xqWRX3Pdtr55nnka0f22c7Ko+IAC//91iQxQLuz8fqbe4b3pEyemzfDB0GSVyhnY
# AYLVYMjVaUamr2j7apX8M3QxIcxrlHAJte1Mo+ntsQic4+syz5HZm87ew4R/52T3
# zzvtsjaKRIfy0VT35E9T4zVhpq3vdJkUCuQrHrXljxXhOEzJrJ9XllDDJ2QmYZc0
# K29YE9pVPFiZxkbf5xmtx1CZhiUulCI0ypnj7dGxLJxRtJhsFChzeSflkOBtn9H/
# RVuBjb0DaRib/mEK7FCbYgEbcIL5QcO3pUlIyghXaQoZsNaViszg7Xzfdh16efby
# y+JLaQIDAQABo4ICFDCCAhAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRXF+2i
# z9x8mKEQ4Py+hy0s8uMXVDBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUHMAGGJGh0
# dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtZGV2aWQwNzCCAR0GA1UdIASCARQw
# ggEQMIIBDAYJKoZIhvdjZAUBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNl
# IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
# YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
# b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
# Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8v
# d3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wFwYDVR0lAQH/BA0w
# CwYJKoZIhvdjZAQNMB0GA1UdDgQWBBRdVgk/6FL+2RJDsLeMey31Hn+TBzAOBgNV
# HQ8BAf8EBAMCB4AwHwYKKoZIhvdjZAYBIQQRDA8yMDE5MDIwNjAwMDAwMFowEwYK
# KoZIhvdjZAYBDgEB/wQCBQAwDQYJKoZIhvcNAQELBQADggEBAHdfmGHh7XOchb/f
# reKxq4raNtrvb7DXJaubBNSwCjI9GhmoAJIQvqtAHSSt4CHsffoekPkWRWaJKgbk
# +UTCZLMy712KfWtRcaSNNzOp+5euXkEsrCurBm/Piua+ezeQWt6RzGNM86bOa34W
# 4r6jdYm8ta9ql4So07Z4kz3y5QN7fI20B8kG5JFPeN88pZFLUejGwUpshXFO+gbk
# GrojkwbpFuRAsiEZ1ngeqtObaO8BRKHahciFNpuTXk1I0o0XBZ2JmCUWzx3a6T4u
# fME1heNtNLRptGYMtZXH4tboV39Wf5lgHc4KR85Mbw52srsRU22NE8JWAvgFp/Qz
# qX5rmVIxggIrMIICJwIBATCBhTB5MS0wKwYDVQQDDCREZXZlbG9wZXIgSUQgQ2Vy
# dGlmaWNhdGlvbiBBdXRob3JpdHkxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRp
# b24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUwII
# Bh5mm1/XjiowCwYJYIZIAWUDBAIBoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
# ARUwLwYJKoZIhvcNAQkEMSIEIO3+qdTpxr/RS3JdlW1bhEeCAD6jiULffHpAUrR6
# oaU+MAsGCSqGSIb3DQEBAQSCAQAb8Z9a0CA/qATzbifp7lK+OHKIOlKgdDp7qYUY
# rOQRaPn5dIhD1siM8yzu+//zPnbjK6l/We+nDKRnMWKRt3bwVGjnYtnRwHKf8pA5
# 0jaYe2kt09fcCunNtoMYZUnuQh0kOVrCermjza6ATCp2sm9AE63wgFFsWjsIetXZ
# y8fIGyOHL7mAtQ8xYv1AgFZa6/+XtHmIci0mVYc0obRu4OxWewGAtQRAE+z4eE+N
# 8Q1ysoAoBEOgJ1GwjXD9hcPsfYcOAJ4a2U6TpWAHkrTw7glvsRuszjO4ADDwXmXw
# aa6MkeFdZEwhueWbbFLo4r1I1Tm+zBcWIW70gNHgGPU6h6ry
# SIG # End signature block