Get-O365SKUsInfos.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#
## Created by: lucas.cueff[at]lucas-cueff.com
#
## released on 01/2021
#
# v1.0.0 : first public release - beta version
# v1.1.0 : beta version - fix IE com object (windows pwsh crash with invoke-webrequest)
# v1.1.1 : last public release - beta version - minor update, replace $host with $psversiontable
#
#'(c) 2020-2021 lucas-cueff.com - Distributed under Artistic Licence 2.0 (https://opensource.org/licenses/artistic-license-2.0).'
<#
    .SYNOPSIS
    Get last Microsoft Office 365 SKU / Service plans info (GUID, String ID, Product Name).
 
    .DESCRIPTION
    Get last Microsoft Office 365 SKU / Service plans info (GUID, String ID, Product Name).
    Resolve SKU and Service Plans from GUID, String ID, Name.
    Get all SKUs that include a Service Plan.
    Cache last catalog from Microsoft locally.
     
    .EXAMPLE
    Get-O365SKUCatalog
    Get last Microsoft Office 365 SKU / Service Plans catalog from Microsoft website and return an array of custom psobjects
 
    .EXAMPLE
    Get-O365SKUinfo
    Get SKU info using a GUID, String ID or Product Name
 
    .EXAMPLE
    Get-O365SKUInfoFromPlan
    Get all SKU and related info including a Service Plan (using GUID, String ID or Plan Name)
 
    .EXAMPLE
    Get-O365Planinfo
    Get Service Plan info using a GUID, String ID or Plan Name
#>

function Convert-HTMLTableToArray {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory = $true)]
            $HTMLObject,
        [Parameter(Mandatory = $true)]
            [int]$TableNumber
    )
    process {
        $tables = @($HTMLObject.getElementsByTagName("TABLE"))
        $table = $tables[$TableNumber]
        $titles = @()
        $rows = @($table.Rows)
        foreach($row in $rows) {
            $cells = @($row.Cells)
            if($cells[0].tagName -eq "TH"){
                $titles = @($cells | foreach-object { ("" + $_.InnerText).Trim() })
                continue
            }
            if (!($titles)) {
                $titles = @(1..($cells.Count + 2) | foreach-object { "P$_" })
            }
            $resultObject = [Ordered] @{}
            for($counter = 0; $counter -lt $cells.Count; $counter++) {
                $title = $titles[$counter]
                if(!($title)) { continue }
                $resultObject[$title] = ("" + $cells[$counter].InnerText).Trim()
            }
            [PSCustomObject]$resultObject
        }
    }
}
function Get-O365SKUCatalog {
<#
    .SYNOPSIS
    Get last Microsoft Office 365 SKU / Service Plans information from Microsoft Website
 
    .DESCRIPTION
    Get last Microsoft Office 365 SKU / Service Plans information from Microsoft Website
    Downloaded from https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference
     
    .PARAMETER ServicePlansInfoAsStrings
    -ServicePlansInfoAsStrings [switch]
    add a new property 'Service plans included as strings' so the object could be easily exported to an external file like a CSV file.
 
    .PARAMETER AsGlobalVariable
    -AsGlobalVariable [switch]
    save objets into global variable O365SKUsInfos
         
    .OUTPUTS
       TypeName : pscustomobject
         
    .EXAMPLE
    Get-O365SKUCatalog
    Get all MS O365 SKUs / Service Plans info
     
    .EXAMPLE
    Get-O365SKUCatalog -AsGlobalVariable
    Get all MS O365 SKUs / Service Plans info and save psobjets to $global:O365SKUsInfos
#>

    [cmdletbinding()]
    param(
        [parameter(Mandatory=$false)]
            [switch]$ServicePlansInfoAsStrings,
        [parameter(Mandatory=$false)]
            [switch]$AsGlobalVariable
    )
    process {
        #$script:URICatalog = "https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference"
        $script:URICatalog = "https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/active-directory/enterprise-users/licensing-service-plan-reference.md"
        $script:tempfile = [System.IO.Path]::GetTempFileName()
        write-verbose "Microsoft O365 SKU catalog URL : $($script:URICatalog)"
        write-verbose "Temporary html file : $($script:tempfile)"
        try {
            $request = Invoke-WebRequest -Uri $script:URICatalog -OutFile $script:tempfile -UseBasicParsing
        } catch {
            throw "Microsoft O365 SKU online catalog $($script:URICatalog) is not available. Please check your network / internet connexion."
        }
        if (!(test-path $script:tempfile)) {
            throw "not able to dowload licensing-service-plan-reference HTML content to $($script:tempfile)"
        } else {
            write-verbose "Temporary html file $($script:tempfile) created successfully"
        }
        $htmlcontent = get-content -Raw -Path $script:tempfile
        try {
            $htmlobj = New-Object -ComObject "HTMLFile"
        } catch {
            throw "not able to create HTMLFile com object"
        }
        try {
            if ($PSVersionTable.PSVersion.Major -gt 5) {
                $encodedhtmlcontent = [System.Text.Encoding]::Unicode.GetBytes($htmlcontent)
                $htmlobj.write($encodedhtmlcontent)
            } else {
                $htmlobj.IHTMLDocument2_write($htmlcontent)
            }
        }
        catch {
            throw "not able to create Com HTML object from temporary file $($script:tempfile)"
        }
        if ($htmlobj) {
            $skuinfo = Convert-HTMLTableToArray -HTMLObject $htmlobj -TableNumber 1
        }
        $skuinfo
        foreach ($sku in $skuinfo) {
            if ($sku.'Service plans included') {
                $tmpserviceplan = $sku.'Service plans included'.split("`n")
                $tmpserviceplanname = $sku.'Service plans included (friendly names)'.split("`n")
                $resultserviceplan = @()
                for ($i=0;$i -le ($tmpserviceplan.count -1);$i++) {
                    $tmpstringid = ($tmpserviceplan[$i]).substring(0,$tmpserviceplan[$i].length - 39)
                    $tmpguid = ($tmpserviceplan[$i]).substring($tmpstringid.length,$tmpserviceplan[$i].length - $tmpstringid.length)
                    $tmpplanname = ($tmpserviceplanname[$i]).substring(0,$tmpserviceplanname[$i].length - 39)
                    $resultserviceplan += [PSCustomObject]@{
                        'String ID' = $tmpstringid.replace(" ","")
                        'GUID' = ((($tmpguid.replace("(","")).replace(")","")).replace(" ","")).replace("`r","")
                        'Plan Name' = if (($tmpplanname.substring($tmpplanname.length - 1,1)) -eq " ") {
                            $tmpplanname.substring(0, $tmpplanname.length - 1)
                        } else {
                            $tmpplanname
                        }
                    }
                }
                if ($ServicePlansInfoAsStrings.IsPresent) {
                    $sku | Add-Member -NotePropertyName "Service plans included as strings" -NotePropertyValue $sku.'Service plans included'
                }
                $sku.'Service plans included' = $resultserviceplan
                $sku.PSObject.Properties.Remove('Service plans included (friendly names)')
            }
        }
        if ($AsGlobalVariable.IsPresent) {
            $global:O365SKUsInfos = $skuinfo
            write-verbose -message "Global Variable O365SKUsInfos set with SKUs Infos"
        }
        return $skuinfo
    } 
}
function Get-O365SKUinfo {
<#
    .SYNOPSIS
    Get last Microsoft Office 365 SKU information from Microsoft Website.
 
    .DESCRIPTION
    Get last Microsoft Office 365 SKU information from Microsoft Website.
    Downloaded from https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference
    You can search the SKU info based on its GUID, String ID or Product Name
     
    .PARAMETER GUID
    -GUID [GUID]
    search a SKU using its GUID
 
    .PARAMETER StringID
    -StringID [string]
    search a SKU using its StringID
 
    .PARAMETER ProductName
    -ProductName [string]
    search a SKU using its Product Name
         
    .OUTPUTS
       TypeName : pscustomobject
         
    .EXAMPLE
    Get-O365SKUinfo -GUID 8f0c5670-4e56-4892-b06d-91c085d7004f
    Get SKU info based on GUID 8f0c5670-4e56-4892-b06d-91c085d7004f
     
    .EXAMPLE
    Get-O365SKUinfo -ProductName "Microsoft 365 F1"
    Get SKU info of "Microsoft 365 F1"
#>

    [cmdletbinding()]
    param(
        [parameter(Mandatory=$false)]
            [guid]$GUID,
        [parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
            [string]$StringID,
        [parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
            [string]$ProductName
    )
    process {
        if (!($global:O365SKUsInfos)) {
            Get-O365SKUCatalog -AsGlobalVariable | out-null
        }
        if ($GUID) {
            $global:O365SKUsInfos | Where-Object {$_.GUID -eq $GUID}
        } elseif ($StringID) {
            $global:O365SKUsInfos | Where-Object {$_.'String ID' -eq $StringID}
        } elseif ($ProductName) {
            $global:O365SKUsInfos | Where-Object {$_.'Product Name' -eq $ProductName}
        } else {
            throw "please use GUID or StringID or ProductName parameters"
        }
    }
}
function Get-O365SKUInfoFromPlan {
<#
    .SYNOPSIS
    Get last Microsoft Office 365 SKU information that included a specific Service Plan.
 
    .DESCRIPTION
    Get last Microsoft Office 365 SKU information that included a specific Service Plan.
    Downloaded from https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference
    You can search the Service Plan info based on its GUID, String ID or Plan Name
     
    .PARAMETER GUID
    -GUID [GUID]
    search a SP using its GUID
 
    .PARAMETER StringID
    -StringID [string]
    search a SP using its StringID
 
    .PARAMETER PlanName
    -PlanName [string]
    search a SP using its Plan Name
         
    .OUTPUTS
       TypeName : pscustomobject
         
    .EXAMPLE
    Get-O365SKUInfoFromPlan -GUID 41781fb2-bc02-4b7c-bd55-b576c07bb09d
    Get all SKU including Service Plan GUID 41781fb2-bc02-4b7c-bd55-b576c07bb09d
     
    .EXAMPLE
    Get-O365SKUInfoFromPlan -PlanName "AZURE ACTIVE DIRECTORY PREMIUM P1"
    Get all SKU including Service Plan "AZURE ACTIVE DIRECTORY PREMIUM P1"
#>

    [cmdletbinding()]
    param(
        [parameter(Mandatory=$false)]
            [guid]$GUID,
        [parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
            [string]$StringID,
        [parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
            [string]$PlanName
    )
    process {
        if (!($global:O365SKUsInfos)) {
            Get-O365SKUCatalog -AsGlobalVariable | out-null
        }
        if ($GUID) {
            $global:O365SKUsInfos | Where-Object {$_.'Service plans included'.GUID -contains $GUID}
        } elseif ($StringID) {
            $global:O365SKUsInfos | Where-Object {$_.'Service plans included'.'String ID' -contains $StringID}
        } elseif ($PlanName) {
            $global:O365SKUsInfos | Where-Object {$_.'Service plans included'.'Plan Name' -contains $PlanName}
        } else {
            throw "please use GUID or StringID or PlanName parameters"
        }
    }
}
function Get-O365Planinfo {
<#
    .SYNOPSIS
    Get last Microsoft Office 365 Service Plan information from Microsoft Website.
 
    .DESCRIPTION
    Get last Microsoft Office 365 Service Plan information from Microsoft Website.
    Downloaded from https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference
    You can search the Service Plan info based on its GUID, String ID or Plan Name
     
    .PARAMETER GUID
    -GUID [GUID]
    search a SP using its GUID
 
    .PARAMETER StringID
    -StringID [string]
    search a SP using its StringID
 
    .PARAMETER PlanName
    -PlanName [string]
    search a SP using its Plan Name
         
    .OUTPUTS
       TypeName : pscustomobject
         
    .EXAMPLE
    Get-O365Planinfo -GUID 41781fb2-bc02-4b7c-bd55-b576c07bb09d
    Get Service Plan info based on GUID 41781fb2-bc02-4b7c-bd55-b576c07bb09d
     
    .EXAMPLE
    Get-O365Planinfo -PlanName "AZURE ACTIVE DIRECTORY PREMIUM P1"
    Get Service Plan info of "AZURE ACTIVE DIRECTORY PREMIUM P1"
#>

    [cmdletbinding()]
    param(
        [parameter(Mandatory=$false)]
            [guid]$GUID,
        [parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
            [string]$StringID,
        [parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
            [string]$PlanName
    )
    process {
        if (!($global:O365SKUsInfos)) {
            Get-O365SKUCatalog -AsGlobalVariable | out-null
        }
        if ($GUID) {
            ($global:O365SKUsInfos | Where-Object {$_.'Service plans included'.GUID -contains $GUID})[0].'Service plans included' | Where-Object {$_.GUID -eq $GUID}
        } elseif ($StringID) {
            ($global:O365SKUsInfos | Where-Object {$_.'Service plans included'.'String ID' -contains $StringID})[0].'Service plans included' | Where-Object {$_.'String ID' -eq $StringID}
        } elseif ($PlanName) {
            ($global:O365SKUsInfos | Where-Object {$_.'Service plans included'.'Plan Name' -contains $PlanName})[0].'Service plans included' | Where-Object {$_.'Plan Name' -eq $PlanName}
        } else {
            throw "please use GUID or StringID or PlanName parameters"
        }
    }
}

Export-ModuleMember -Function Get-O365SKUCatalog, Get-O365SKUinfo, Get-O365SKUInfoFromPlan, Get-O365Planinfo