Public/Get-UnifiProductList.ps1

function Get-UnifiProductList {
    [CmdletBinding()]
    param (
        [switch]$Detailed
    )

    function StreamCount {
        [CmdletBinding()]
        param (
            [int]$start,
            $object
        )
        $i=$Start
        $brcount=0
        $Loopbreak=$false
        $InLoop=$false
        while ($loopbreak -eq $false){
            $char=$object[$i]
            if ($char -eq "{"){
                $brcount++
            }
            if ($brcount -gt 0){
                $InLoop=$true
            }
            if ($char -eq "}"){
                $brcount--
            }
            if ($inloop -eq $true){
                if ($brcount -eq 0){
                    $loopbreak=$true
                }
            }
            write-verbose "Char: $char - Count: $i - BR: $brcount $Inloop"
            if ($InLoop -eq $true){
                if ($brcount -eq 0){
                    $loopbreak=$true
                }
            }
            if ($i -ge $object.length) {
                $Loopbreak=$true
            }
            $i++
        }
        $i
    }

    function StreamString {
        param (
            $Start,
            $End,
            $Data
        )
        $RelLength=$End-$Start
        $Data.substring($start,$Rellength)
    }

    # The product list data entry is different under different Unifi controller versions.
    $UnifiVersion=(Get-UnifiStatus).server_version
    $ControllerName=Get-UnifiControllerName

    $URI = "$controller/manage/angular/$ControllerName/js/app.js"
    $WebResults=(Invoke-GetRestAPICall $URI)

    $Webresults | out-file -FilePath "$env:TEMP\Webresults.txt"
    switch ($UnifiVersion){
        # This part contains the regex code to extract the product list data from the javascript code.
        "5.13.32"   {
            $FullRegex='(?<={1:\[function\(e,t,n\)\{t\.exports=\{).*(?=,\{\}\],2:\[function\(e,t,n\))'
        }
    }

    
    $TempData = Get-content "$env:TEMP\webresults.txt"  -raw 
    Remove-Item -Path "$env:TEMP\Webresults.txt"
    [void]($tempData -match $FullRegex)
    $DataToParse=$Matches.0

    $i=0
    $Start=0
    $DeviceData=[System.Collections.ArrayList]@()
    do {
        $EndCount=StreamCount -start $Start -object $DataToParse
        # $Start
        # $Endcount
        if ($endcount -gt $DataToParse.Length){
            $Endcount=$DataToParse.Length
        }
        $String=(StreamString -start $start -end $EndCount -data $DataToParse).replace("`n","")
        if ($string.length -gt 5){
            [void]$DeviceData.Add($string)
        }
        $Start=$EndCount+1
    }
    until ($Endcount -ge $DataToParse.Length)

    if ($Detailed){
        # This object conversion script created by reddit user /u/marsonreddit
        $DeviceList = [System.Collections.Generic.List[psobject]]::new()
        # Apart from an illegal character in your data set, everything after <Device Code>: appear to be valid JSON
        $regex = '(:)(?!["{}\[\]])(?<illegal>[*~@#$%^&*()_+=><?!\/]+\w+[*~@#$%^&*()_+=><?!\/]{0})'
        foreach ($dev in $DeviceData) {
            $FirstColon = $dev.IndexOf(':')
            $code = $dev.Substring(0,$FirstColon)
            $details = $dev.Substring(($FirstColon + 1)) -replace $regex, ('{0}"{1}"' -f '$1', '${illegal}') | ConvertFrom-Json
            [void]$DeviceList.Add(
                [PSCustomObject]@{
                    DeviceCode = $code.replace("`"","")
                    DeviceDetails = $details
                }
            )
        }

        $DeviceList
    }
    else {
        $RegexName='(?<=name:\").*?(?=\")'
        $RegexType='(?<=type:\").*?(?=\")'
        $DeviceDataParsed=[System.Collections.ArrayList]@()
        foreach ($item in $DeviceData){
            $Device=(StreamString -start 0 -end ($Item.indexof(":")) -data $Item).replace("`"","") # A few items have quotes in the device name.
            [void]($item -match $regexName)
            $name=$matches.0
            [void]($item -match $regexType)
            $Type=$matches.0
            $Entry=[PSCustomObject]@{
                Model = $Device
                Type = $Type
                ProductName = $Name
            }
            [void]$DeviceDataParsed.add($Entry)
        }
        $DeviceDataParsed
    }
        <#
        .SYNOPSIS
        Returns information on all device models supported by the controller.

        .DESCRIPTION
        Returns information on all device models supported by the controller. By default, this will return a list of just the model, type and name.
        Use the -Detailed switch to return a list of all information available. This includes items like radio and port information as well as
        physical port layout. The structure of the data is different for each option.

        .PARAMETER Detailed
        Switch to retrieve all availeble model information.
        
        .INPUTS
        None.

        .OUTPUTS
        System.Object.
    #>

}