o365Skus.psm1

<#
    ===========================================================================
     Created with: PowerShell ISE
     Created on: 11/28/2020 1:52 AM
     Created by: DataTraveler1
     Organization:
     Filename: o365Skus.psd1
     -------------------------------------------------------------------------
     Module Manifest
    -------------------------------------------------------------------------
     Module Name: o365Skus
    ===========================================================================
#>


<#
  .SYNOPSIS
  Fetches the list of Office 365 SKUs with string ID and friendly name.
 
  .DESCRIPTION
  Parses the content of "https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference"
  into a array. Note: This page stopped being updated by Microsoft in September of 2020. A new source for this information is needed.
 
  .INPUTS
  None.
 
  .OUTPUTS
  [array]
 
  .EXAMPLE
  Get-o365ProductSKUs
#>


function Get-o365ProductSKUs
{
    [OutputType([array])]
    [CmdletBinding()]
    $text_info = (Get-Culture).TextInfo
    $global:ProgressPreference = 'SilentlyContinue'
    Try
    {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    }
    Catch
    {
        [string]$error_message = $Error | Select-Object -First 1 | Select-Object -ExpandProperty Exception
        Write-Host "Unable to set security to Tls12 due to [$error_message]. Exiting."
    }
    [System.Management.Automation.CommandInfo]$check_command = Get-Command -Name "Invoke-WebRequest"
    If ($check_command.Name -ne "Invoke-WebRequest")
    {
        Write-Host "Error! Somehow the Invoke-WebRequest cmdlet is not available? Exiting."
        Exit
    }
    [string]$url = "https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference"
    [hashtable]$parameters = @{ }
    $parameters.Add("UseBasicParsing", $true)
    $parameters.Add("Uri", $url)
    $Error.Clear()
    Try
    {
        [Microsoft.PowerShell.Commands.WebResponseObject]$html_content = Invoke-WebRequest @parameters
    }
    Catch
    {
        [string]$error_message = $Error | Select-Object -First 1 | Select-Object -ExpandProperty Exception
        Write-Host "Unable to invoke web request due to [$error_message]. Exiting."
        Exit
    }
    $ProgressPreference = 'Continue'
    [int]$html_content_status_code = $html_content.StatusCode
    If ($html_content_status_code -ne 200)
    {
        Write-Host "Error! Did not receive code 200 (success) from Invoke-WebRequest. Please check into this."
        Exit
    }
    [string]$html_content_raw = $html_content.RawContent
    If ($html_content_raw.Length -eq 0)
    {
        Write-Host "Error! Somehow the HTML content is empty. Please check into this."
        Exit
    }
    If ($html_content_raw -notlike "*<tbody>*" -or $html_content_raw -notlike "*</tbody>*")
    {
        Write-host "Error! Somehow the HTML does not contain the expected content. Exiting."
        Exit
    }
    $Error.Clear()
    Try
    {
        [int]$start_index = $html_content_raw.IndexOf("<tbody>")
        [int]$end_index = $html_content_raw.IndexOf("</tbody>") + 8
        [string]$html_content_edited = $html_content_raw[$start_index .. $end_index] -join '' -replace '<td></td>'
    }
    Catch
    {
        [string]$error_message = $Error | Select-Object -First 1 | Select-Object -ExpandProperty Exception | Select-Object -ExpandProperty Message
        Write-Host "Error! Unable to format the HTML content due to [$error_message]"
    }
    Try
    {
        [xml]$html_xml = [xml]$html_content_edited
    }
    Catch
    {
        Write-Host "Error! Unable to convert the filtered HTML content into a valid XML object. Exiting."
        Exit
    }
    [array]$initial_product_array = $html_xml | Select-Object -ExpandProperty tbody | Select-Object -ExpandProperty tr
    [int]$initial_product_array_count = $initial_product_array.Count
    If ($initial_product_array_count -eq 0)
    {
        Write-Host "Error! Somehow there are 0 products in the product array. Something must be wrong. Exiting."
        Exit
    }
    [array]$product_list = ForEach ($product in $initial_product_array)
    {
        [array]$product_expanded = $product | Select-Object -ExpandProperty td
        [string]$product_name_raw = $product_expanded | Select-Object -First 1
        [string]$product_name = ($text_info.ToTitleCase($product_name_raw.ToLower())) -replace "`t", " "
        [string]$product_string_id = $product_expanded | Select-Object -Skip 1 -First 1
        [string]$product_guid = $product_expanded | Select-Object -Skip 2 -First 1
        If ($product_guid.length -ne 36)
        {
            Write-Host "Error! Somehow the product GUID for [$product_name] was not 36 characters in length. There must be a problem. Exiting."
            Exit
        }
        ElseIf ($product_string_id -like "* *")
        {
            Write-Host "Error! Somehow the product string ID contains spaces. This should never happen. There must be a problem. Exiting."
            Exit
        }
        ElseIf ($product_name.Length -eq 0)
        {
            Write-Host "Error! Somehow the product name is 0 characters in length. This should never happen. There must be a problem. Exiting."
            Exit
        }
        [PSCustomObject]@{ Product_GUID = $product_guid; Product_String_ID = $product_string_id; Product_Name = $product_name; }
    }
    Return $product_list
}