Skip to content

Commit e1bb09d

Browse files
authored
Merge pull request #204 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 505a784 + 65707c3 commit e1bb09d

File tree

3 files changed

+88
-27
lines changed

3 files changed

+88
-27
lines changed

Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,43 @@ function Get-CIPPAzDataTableEntity {
1212

1313
$Results = Get-AzDataTableEntity @PSBoundParameters
1414
$mergedResults = @{}
15+
$rootEntities = @{} # Keyed by "$PartitionKey|$RowKey"
1516

16-
# First pass: Collect all parts and complete entities
1717
foreach ($entity in $Results) {
18-
if ($entity.OriginalEntityId) {
19-
$entityId = $entity.OriginalEntityId
20-
$partitionKey = $entity.PartitionKey
21-
if (-not $mergedResults.ContainsKey($partitionKey)) {
22-
$mergedResults[$partitionKey] = @{}
23-
}
24-
if (-not $mergedResults[$partitionKey].ContainsKey($entityId)) {
25-
$mergedResults[$partitionKey][$entityId] = @{
26-
Parts = [System.Collections.Generic.List[object]]::new()
27-
}
28-
}
29-
$mergedResults[$partitionKey][$entityId]['Parts'].Add($entity)
30-
} else {
31-
$partitionKey = $entity.PartitionKey
32-
if (-not $mergedResults.ContainsKey($partitionKey)) {
33-
$mergedResults[$partitionKey] = @{}
34-
}
35-
$mergedResults[$partitionKey][$entity.RowKey] = @{
18+
$partitionKey = $entity.PartitionKey
19+
$rowKey = $entity.RowKey
20+
$hasOriginalId = $entity.PSObject.Properties.Match('OriginalEntityId') -and $entity.OriginalEntityId
21+
22+
if (-not $mergedResults.ContainsKey($partitionKey)) {
23+
$mergedResults[$partitionKey] = @{}
24+
}
25+
26+
if (-not $hasOriginalId) {
27+
# It's a standalone root row
28+
$rootEntities["$partitionKey|$rowKey"] = $true
29+
$mergedResults[$partitionKey][$rowKey] = @{
3630
Entity = $entity
3731
Parts = [System.Collections.Generic.List[object]]::new()
3832
}
33+
continue
34+
}
35+
36+
# It's a part of something else
37+
$entityId = $entity.OriginalEntityId
38+
39+
# Check if this entity's target has a "real" base
40+
if ($rootEntities.ContainsKey("$partitionKey|$entityId")) {
41+
# Root row exists → skip merging this part
42+
continue
43+
}
44+
45+
# Merge it as a part
46+
if (-not $mergedResults[$partitionKey].ContainsKey($entityId)) {
47+
$mergedResults[$partitionKey][$entityId] = @{
48+
Parts = [System.Collections.Generic.List[object]]::new()
49+
}
3950
}
51+
$mergedResults[$partitionKey][$entityId]['Parts'].Add($entity)
4052
}
4153

4254
$finalResults = [System.Collections.Generic.List[object]]::new()

Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ function New-CIPPAlertTemplate {
3131
if ($InputObject -eq 'sherwebmig') {
3232
$DataHTML = ($Data | ConvertTo-Html | Out-String).Replace('<table>', ' <table class="table-modern">')
3333
$IntroText = "<p>The following licenses have not yet been found at Sherweb, and are expiring within 7 days:</p>$dataHTML"
34+
if ($data.SherwebMig -like '*buy*') {
35+
$introText = "<p>The following licenses have not yet been found at Sherweb, and are expiring within 7 days. We have started the process to automatically buy these licenses:</p>$dataHTML"
36+
}
37+
}
38+
if ($InputObject -eq 'sherwebmigfailcancel') {
39+
$DataHTML = ($Data | ConvertTo-Html | Out-String).Replace('<table>', ' <table class="table-modern">')
40+
$IntroText = "<p>The following licenses have not been cancelled due to an API error at the old provider:</p>$dataHTML"
41+
}
42+
if ($InputObject -eq 'sherwebmigBuyFail') {
43+
$DataHTML = ($Data | ConvertTo-Html | Out-String).Replace('<table>', ' <table class="table-modern">')
44+
$IntroText = "<p>The following licenses have not been bought as we could not find a correctly matching license. Please login and buy the license:</p>$dataHTML"
3445
}
3546
if ($InputObject -eq 'table') {
3647
#data can be a array of strings or a string, if it is, we need to convert it to an object so it shows up nicely, that object will have one header: message.

Modules/CippExtensions/Public/Sherweb/Test-SherwebMigrationAccounts.ps1

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ function Test-SherwebMigrationAccounts {
77
$Table = Get-CIPPTable -TableName Extensionsconfig
88
$Config = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).Sherweb
99
#First get a list of all subscribed skus for this tenant, that are in the transfer window.
10-
$Licenses = (Get-CIPPLicenseOverview -TenantFilter $TenantFilter) | ForEach-Object { $_.terminfo = ($_.terminfo | ConvertFrom-Json -ErrorAction SilentlyContinue) ; $_ } | Where-Object { $_.terminfo -ne $null -and $_.terminfo.TransferWindow -LE 78 }
10+
$Licenses = (Get-CIPPLicenseOverview -TenantFilter $TenantFilter) | ForEach-Object { $_.terminfo = ($_.terminfo | ConvertFrom-Json -ErrorAction SilentlyContinue) ; $_ } | Where-Object { $_.terminfo -ne $null -and $_.terminfo.TransferWindow -LE 7 }
1111

1212
#now check if this exact count of licenses is available at Sherweb, if not, we need to migrate them.
1313
$SherwebLicenses = Get-SherwebCurrentSubscription -TenantFilter $TenantFilter
1414
$LicencesToMigrate = foreach ($License in $Licenses) {
1515
foreach ($termInfo in $License.terminfo) {
16-
$matchedSherweb = $SherwebLicenses | Where-Object { $_.quantity -eq 3 -and $_.commitmentTerm.termEndDate -eq $termInfo.NextLifecycle }
16+
$matchedSherweb = $SherwebLicenses | Where-Object { $_.quantity -eq $termInfo.TotalLicenses -and $_.commitmentTerm.termEndDate -eq $termInfo.NextLifecycle }
1717
if (-not $matchedSherweb) {
1818
[PSCustomObject]@{
1919
LicenseName = ($Licenses | Where-Object { $_.skuId -eq $License.skuId }).license
@@ -31,19 +31,57 @@ function Test-SherwebMigrationAccounts {
3131

3232
switch -wildcard ($config.migrationMethods) {
3333
'*notify*' {
34+
$Subject = "Sherweb Migration: $($TenantFilter) - $($LicencesToMigrate.Count) licenses to migrate"
3435
$HTMLContent = New-CIPPAlertTemplate -Data $LicencesToMigrate -Format 'html' -InputObject 'sherwebmig'
3536
$JSONContent = New-CIPPAlertTemplate -Data $LicencesToMigrate -Format 'json' -InputObject 'sherwebmig'
3637
Send-CIPPAlert -Type 'email' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $tenant -APIName 'Alerts'
3738
Send-CIPPAlert -Type 'psa' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $standardsTenant -APIName 'Alerts'
3839
Send-CIPPAlert -Type 'webhook' -JSONContent $JSONContent -TenantFilter $Tenant -APIName 'Alerts'
3940
}
40-
'buyAndNotify' {
41-
#Buy the licenses at Sherweb using the matching CSV.
41+
'*buy*' {
42+
try {
43+
$PotentialLicenses = Get-SherwebCatalog -TenantFilter $TenantFilter | Where-Object { $_.microsoftSkuId -in $LicencesToMigrate.SkuId -and $_.sku -like "*$($Config.migrateToLicense)" }
44+
if (!$PotentialLicenses) {
45+
throw 'cannot buy new license: no matching license found in catalog'
46+
} else {
47+
$PotentialLicenses | ForEach-Object {
48+
Set-SherwebSubscription -TenantFilter $TenantFilter -SKU $PotentialLicenses.sku -Quantity $LicencesToMigrate.TotalLicensesAtUnknownCSP
49+
}
50+
}
51+
} catch {
52+
$Subject = "Sherweb Migration: $($TenantFilter) - Failed to buy licenses."
53+
$HTMLContent = New-CIPPAlertTemplate -Data $LicencesToMigrate -Format 'html' -InputObject 'sherwebmigBuyFail'
54+
$JSONContent = New-CIPPAlertTemplate -Data $LicencesToMigrate -Format 'json' -InputObject 'sherwebmigBuyFail'
55+
Send-CIPPAlert -Type 'email' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $tenant -APIName 'Alerts'
56+
Send-CIPPAlert -Type 'psa' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $standardsTenant -APIName 'Alerts'
57+
Send-CIPPAlert -Type 'webhook' -JSONContent $JSONContent -TenantFilter $Tenant -APIName 'Alerts'
58+
}
59+
4260
}
43-
'buyAndCancel' {
44-
#Create HTML report for this tenant. Send to webhook/notifications/etc
45-
#Buy the licenses at Sherweb using the matching CSV.
46-
#Cancel the licenses in old vendor.
61+
'*Cancel' {
62+
try {
63+
$tenantid = (Get-Tenants -TenantFilter $TenantFilter).customerId
64+
$paxBody = @{
65+
client_id = $Config.paxclientId
66+
client_secret = $Config.paxclientSecret
67+
audience = 'https://api.pax8.com'
68+
grant_type = 'client_credentials'
69+
}
70+
$Token = Invoke-RestMethod -Uri 'https://api.pax8.com/v1/token' -Method POST -Headers $headers -ContentType 'application/json' -Body $paxBody
71+
$headers = @{ Authorization = "Bearer $($Token.access_token)" }
72+
$cancelSubList = Invoke-RestMethod -Uri "https://api.pax8.com/v1/subscriptions?page=0&size=10&status=Active&companyId=$($tenantid)" -Method GET -Headers $headers | Where-Object -Property productId -In $LicencesToMigrate.SkuId
73+
$cancelSubList | ForEach-Object {
74+
$response = Invoke-RestMethod -Uri "https://api.pax8.com/v1/subscriptions/$($_.subscriptionId)" -Method DELETE -Headers $headers -ContentType 'application/json' -Body ($body | ConvertTo-Json)
75+
}
76+
77+
} catch {
78+
$Subject = 'Sherweb Migration: Pax Migration failed'
79+
$HTMLContent = New-CIPPAlertTemplate -Data $LicencesToMigrate -Format 'html' -InputObject 'sherwebmigfailpax'
80+
$JSONContent = New-CIPPAlertTemplate -Data $LicencesToMigrate -Format 'json' -InputObject 'sherwebmigfailpax'
81+
Send-CIPPAlert -Type 'email' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $tenant -APIName 'Alerts'
82+
Send-CIPPAlert -Type 'psa' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $standardsTenant -APIName 'Alerts'
83+
Send-CIPPAlert -Type 'webhook' -JSONContent $JSONContent -TenantFilter $Tenant -APIName 'Alerts'
84+
}
4785
}
4886

4987
}

0 commit comments

Comments
 (0)