M365 DownloadLicenseSkuDisplayNames WA

M365SLIC.DownloadLicenseSkuDisplayNames.WA (WriteActionModuleType)

Will attempt to download friendly DisplayNames of M365 License Skus. Will store names in a CSV.

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsM365SL.RunAs.Profile
InputTypeSystem.BaseData

Member Modules:

ID Module Type TypeId RunAs 
WA WriteAction Microsoft.Windows.PowerShellWriteAction Default

Overrideable Parameters:

IDParameterTypeSelector
EventIDFilterstring$Config/EventIDFilter$
OutFilestring$Config/OutFile$
Path_mshtmlstring$Config/Path_mshtml$
TLSVersionstring$Config/TLSVersion$
URLstring$Config/URL$
PoshLibraryPathstring$Config/PoshLibraryPath$
ProbeActionTimeoutSecondsint$Config/ProbeActionTimeoutSeconds$
WriteToEventLogbool$Config/WriteToEventLog$

Source Code:

<WriteActionModuleType ID="M365SLIC.DownloadLicenseSkuDisplayNames.WA" Accessibility="Internal" Batching="false" RunAs="M365SL!M365SL.RunAs.Profile">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="DEFAULT_LIST" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="EventIDFilter" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="OutFile" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="Path_mshtml" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="PoshLibraryPath" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="TLSVersion" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="URL" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="ProbeActionTimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="WorkflowName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="WriteToEventLog" type="xsd:boolean"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="EventIDFilter" Selector="$Config/EventIDFilter$" ParameterType="string"/>
<OverrideableParameter ID="OutFile" Selector="$Config/OutFile$" ParameterType="string"/>
<OverrideableParameter ID="Path_mshtml" Selector="$Config/Path_mshtml$" ParameterType="string"/>
<OverrideableParameter ID="TLSVersion" Selector="$Config/TLSVersion$" ParameterType="string"/>
<OverrideableParameter ID="URL" Selector="$Config/URL$" ParameterType="string"/>
<OverrideableParameter ID="PoshLibraryPath" Selector="$Config/PoshLibraryPath$" ParameterType="string"/>
<OverrideableParameter ID="ProbeActionTimeoutSeconds" Selector="$Config/ProbeActionTimeoutSeconds$" ParameterType="int"/>
<OverrideableParameter ID="WriteToEventLog" Selector="$Config/WriteToEventLog$" ParameterType="bool"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<WriteAction ID="WA" TypeID="Windows!Microsoft.Windows.PowerShellWriteAction">
<ScriptName>M365SLIC.Download-SkuDisplayNames.ps1</ScriptName>
<ScriptBody><Script>&lt;#
Filename: M365SLIC.Download-SkuDisplayNames.ps1
Author: Tyson Paul
Description: Will attempt to download friendly DisplayNames of M365 License Skus. Will store names in a CSV.
Version History:
2020.11.07.1312 - v1
#&gt;

Param (
[string]$DEFAULT_LIST,
[string]$EventIDFilter,
[string]$OutFile = 'C:\Windows\Temp\M365SSM\License\LicenseSkuDisplayNames.csv',
[string]$Path_mshtml = 'C:\Windows\Temp\M365SSM\License\Microsoft.mshtml.dll',
[string]$PoshLibraryPath,
[string]$TLSVersion='1.2',
[string]$URL = 'https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/licensing-service-plan-reference',
[string]$WorkflowName = '&lt;No WorkflowName provided&gt;',
[string]$WriteToEventLog = 'false'
)

[bool]$WriteToEventLog = [System.Convert]::ToBoolean($WriteToEventLog)
[string]$ScriptName = 'M365SLIC.Download-SkuDisplayNames.ps1'

################################################################
Function Load-Library {
Param (
[string]$PoshLibraryPath
)
$ErrorActionPreference = 'STOP'
If ($PoshLibraryPath ){
ForEach ($Path in $PoshLibraryPath.Split(',') ){
Try {
If (($Path.Length) -AND ($Path -notmatch '^-1$')) {
. $Path
}
} Catch {
Write-Host "Line [$($MyInvocation.ScriptLineNumber )]: Error loading PoshLibrary at path:[$($Path)]. This is likely to cause many other dependent functions to fail. `n`nError data: $($_)`n`n"
}
}
}
$ErrorActionPreference = 'CONTINUE'
}
################################################################

################################################################
############## TESTING ##############
&lt;# #Run this as needed when testing

Function Testing {
$Testing = $true
Get-Item Alias:\_LINE_ -ErrorAction Ignore | Remove-Item -ErrorAction Ignore
$testFile = (Join-path $TestFolder ("PARAMS_$($ScriptName)"))
# Test-Path $testFile
. $testFile
$error.Clear()

}

$TestFolder = 'C:\Test\M365SMP_Dev\License\TestSetup'
If (Test-Path -Path $TestFolder) {
. Testing
}

#&gt;
############## TESTING ##############

LogIt -EventID 9990 -Type $info -Msg "Begin script..." -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
Function Get-WebRequestTable
# https://www.leeholmes.com/blog/2015/01/05/extracting-tables-from-powershells-invoke-webrequest/
{
param(
[Parameter(Mandatory = $true)]
[Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject] $WebRequest,

[Parameter(Mandatory = $true)]
[int] $TableNumber
)

# Create HTML file Object
$HTML = New-Object -Com "HTMLFile"

# Write HTML content according to DOM Level2
$HTML.IHTMLDocument2_write($WebRequest.RawContent)

## Extract the tables out of the web request
$tables = @($HTML.getElementsByTagName('TABLE'))

$table = $tables[$TableNumber]
$titles = @()
$rows = @($table.Rows)
## Go through all of the rows in the table
foreach($row in $rows)
{
$cells = @($row.Cells)

## If we've found a table header, remember its titles
if($cells[0].tagName -eq 'TH')
{
$titles = @($cells | ForEach-Object -Process {
('' + $_.InnerText).Trim()
})
continue
}
## If we haven't found any table headers, make up names "P1", "P2", etc.
if(-not $titles)
{
$titles = @(1..($cells.Count + 2) | ForEach-Object -Process {
"P$_"
})
}
## Now go through the cells in the the row. For each, try to find the
## title that represents that column and create a hashtable mapping those
## titles to content
$resultObject = [Ordered] @{}
for($counter = 0; $counter -lt $cells.Count; $counter++)
{
$title = $titles[$counter]
if(-not $title)
{
continue
}

$resultObject[$title] = ('' + $cells[$counter].InnerText).Trim()
}
## And finally cast that hashtable to a PSCustomObject
[PSCustomObject] $resultObject
}
}

. Load-Library -PoshLibraryPath $PoshLibraryPath
LogIt -EventID 9990 -Type $info -Msg "Begin script..." -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()

$Activity = "attempt to load library at [$($Path_mshtml)] "
# The correct version of this file may or may not already be present on the computer so
# use the version provided in the License MP.
Try {
Add-Type -Path $Path_mshtml -ErrorAction Stop
LogIt -EventID 9992 -Type $info -Msg "Successful $Activity " -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
} Catch {
LogIt -EventID 9995 -Type $warn -Msg "Failed $Activity. " -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
}

# This is where the data file will be stored
$thisTempFolder = (Split-Path $OutFile -Parent)
If (-NOT (Test-Path $thisTempFolder)) {
LogIt -EventID 9995 -Type $warn -Msg "Temp path does not exist: [$($thisTempFolder)]. Creating folder now..." -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
Try {
New-Item -Path $thisTempFolder -ItemType Directory -ErrorAction Stop
} Catch {
LogIt -EventID 9995 -Type $warn -Msg "Failed to create Temp path: [$($thisTempFolder)]. Exiting." -Proceed $true -LINE $(_LINE_); $Error.Clear()
Exit
}
}

$message = "Setting TLS version to: [$($TLSVersion)]... "
LogIt -EventID 9992 -Type $info -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
. Set-TLS -TLSVersion $TLSVersion

# Attempt to get Displaynames from online Docs site
LogIt -EventID 9992 -Type $info -Msg "Will attempt to retrieve DisplayNames from URL: [$($URL)]... " -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
Try {
# Use basic parsing because otherwise LocalSystem security context may cause problems
$WebRequest = Invoke-WebRequest $URL -UseBasicParsing -ErrorAction Stop
$message = "Successfully retrieved DisplayNames from URL: [$($URL)]."
LogIt -EventID 9992 -Type $info -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
} Catch {
$message = "Failed to get display names from URL: [$($URL)]."
LogIt -EventID 9992 -Type $warn -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
}

$Remediation = "Please use the LicenseSku Addendum management pack task to distribute displaynames file to Watcher Nodes."
$Activity = "attempt to parse Displaynames from Docs site HTML object"
LogIt -EventID 9992 -Type $info -Msg "Will $($Activity) " -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
Try {
$Table = Get-WebRequestTable $WebRequest -TableNumber 0
$message = "Successful $($Activity)."
LogIt -EventID 9992 -Type $info -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
} Catch {
$message = "Failed $($Activity). $($Remediation)"
LogIt -EventID 9992 -Type $warn -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
}


# Write data from online source if it was successfully retrieved.
$message = "Will attempt to write DisplayName CSV data to file: [$($OutFile)]..."
LogIt -EventID 9992 -Type $info -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
If ($Table.Count){
Try {
$Table | Select-Object @{Name='skuPartNumber';Expression={$_."String ID"} },@{Name='DisplayName';Expression={$_."Product Name"}} | Export-Csv -Path $OutFile -Force -NoTypeInformation -Encoding UTF8 -ErrorAction Stop
$message = "Success writing DisplayName CSV data to file: [$($OutFile)]. "
LogIt -EventID 9992 -Type $info -Msg $message -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
} Catch {
$message = "Failed to write DisplayNames CSV data to file: [$($OutFile)]. $($Remediation) Exiting."
LogIt -EventID 9995 -Type $warn -Msg $message -Proceed $true -LINE $(_LINE_); $Error.Clear()
}
}
Else {
$message = "No 'Table' data exists from URL. Will NOT write 'default' DisplayName CSV data to file: [$($OutFile)]. $($Remediation)"
LogIt -EventID 9992 -Type $warn -Msg $message -Proceed $true -LINE $(_LINE_); $Error.Clear()
}
LogIt -EventID 9991 -Type $info -Msg "End script." -Proceed $WriteToEventLog -LINE $(_LINE_); $Error.Clear()
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>DEFAULT_LIST</Name>
<Value>$Config/DEFAULT_LIST$</Value>
</Parameter>
<Parameter>
<Name>EventIDFilter</Name>
<Value>$Config/EventIDFilter$</Value>
</Parameter>
<Parameter>
<Name>OutFile</Name>
<Value>$Config/OutFile$</Value>
</Parameter>
<Parameter>
<Name>Path_mshtml</Name>
<Value>$Config/Path_mshtml$</Value>
</Parameter>
<Parameter>
<Name>PoshLibraryPath</Name>
<Value>$FileResource[Name='Res.M365SLIC.M365Library.ps1.Resource']/Path$,$Config/PoshLibraryPath$</Value>
</Parameter>
<Parameter>
<Name>TLSVersion</Name>
<Value>$Config/TLSVersion$</Value>
</Parameter>
<Parameter>
<Name>URL</Name>
<Value>$Config/URL$</Value>
</Parameter>
<Parameter>
<Name>WorkflowName</Name>
<Value>$Config/WorkflowName$</Value>
</Parameter>
<Parameter>
<Name>WriteToEventLog</Name>
<Value>$Config/WriteToEventLog$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/ProbeActionTimeoutSeconds$</TimeoutSeconds>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="WA"/>
</Composition>
</Composite>
</ModuleImplementation>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>