From 79e88a9db76f3db56e8bad1b650e5c5707286f6c Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 9 Apr 2025 14:25:39 -0700 Subject: [PATCH] reverted to Dec 1, 2024 --- .../modify-license-type/README.md | 7 +- .../modify-license-type.ps1 | 101 ++++++++++++------ 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/README.md b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/README.md index 66258777..fe527719 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/README.md @@ -38,15 +38,12 @@ The script accepts the following command line parameters: ```PowerShell Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation ``` -> [!IMPORTANT] -> If you are setting License type to "PAYG" in the CSP subscription(s), the subscription resource must have a consent tag enabling perpetual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be added using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). - ## Example 1 -The following command will scan all the subscriptions to which the user has access to, and set the license type to "Paid" on all servers where license type is undefined. +The following command will scan all the subscriptions to which the user has access to, and set the license type to "PAYG" on all servers where license type is undefined. ```PowerShell -.\modify-license-type.ps1 -LicenseType Paid +.\modify-license-type.ps1 -LicenseType PAYG ``` ## Example 2 diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index a14c9611..d6b4159c 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -52,52 +52,82 @@ function ConvertTo-Hashtable { $InputObject ) process { + ## Return null if the input is null. This can happen when calling the function + ## recursively and a property is null if ($null -eq $InputObject) { return $null } - if ($InputObject -is [System.Collections.ICollection]) { + ## Check if the input is an array or collection. If so, we also need to convert + ## those types into hash tables as well. This function will convert all child + ## objects into hash tables (if applicable) + if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { + $collection = @( + foreach ($object in $InputObject) { + ConvertTo-Hashtable -InputObject $object + } + ) + ## Return the array but don't enumerate it because the object may be pretty complex + Write-Output -NoEnumerate $collection + } elseif ($InputObject -is [psobject]) { + ## If the object has properties that need enumeration, cxonvert it to its own hash table and return it $hash = @{} - foreach ($property in $InputObject) { + foreach ($property in $InputObject.PSObject.Properties) { $hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value } $hash } else { + ## If the object isn't an array, collection, or other object, it's already a hash table + ## So just return it. $InputObject } } } -function LoadModule { +# This function checks if the specified module is imported into the session and if not installes and/or imports it +function LoadModule +{ param ( [parameter(Mandatory = $true)][string] $name ) $retVal = $true - if (!(Get-Module -Name $name)) { + if (!(Get-Module -Name $name)) + { $retVal = Get-Module -ListAvailable | Where-Object {$_.Name -eq $name} - if ($retVal) { - try { + if ($retVal) + { + try + { Import-Module $name -ErrorAction SilentlyContinue } - catch { - write-host "The request to load module $($name) failed with the following error:" + catch + { + write-host "The request to lload module $($name) failed with the following error:" write-host $_.Exception.Message $retVal = $false } - } else { + } + else { + + # If module is not imported, not available on disk, but is in online gallery then install and import if (Find-Module -Name $name) { Install-Module -Name $name -Force -Verbose -Scope CurrentUser - try { - Import-Module $name -ErrorAction SilentlyContinue + try + { + Import-Module $name -ErrorAction SilentlyContinue } - catch { + catch + { write-host "The request to load module $($name) failed with the following error:" write-host $_.Exception.Message $retVal = $false } - } else { + } + else { + + # If module is not imported, not available and not in online gallery then abort write-host "Module $($name) not imported, not available and not in online gallery, exiting." EXIT 1 } @@ -107,8 +137,12 @@ function LoadModule { return $retVal } +# +# Suppress warnings +# Update-AzConfig -DisplayBreakingChangeWarning $false +# Load required modules $requiredModules = @( "AzureAD", "Az.Accounts", @@ -117,19 +151,25 @@ $requiredModules = @( ) $requiredModules | Foreach-Object {LoadModule $_} +# Subscriptions to scan + $tenantID = (Get-AzureADTenantDetail).ObjectId if ($SubId -like "*.csv") { $subscriptions = Import-Csv $SubId -}elseif($SubId -ne "") { +}elseif($SubId -ne ""){ $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -TenantID $tenantID -}else { +}else{ $subscriptions = Get-AzSubscription -TenantID $tenantID } + Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --") -foreach ($sub in $subscriptions) { +# Scan arc-enabled servers in each subscription + +foreach ($sub in $subscriptions){ + if ($sub.State -ne "Enabled") {continue} try { @@ -139,23 +179,6 @@ foreach ($sub in $subscriptions) { {continue} } - # Consent tag enforcement on the CSP subscriptions - if ($LicenseType -eq "PAYG") { - $offers = @("MS-AZR-0145P", "MS-AZR-DE-0145P", "MS-AZR-0017G", "MS-AZR-159P", "MS-AZR-USGOV-0145P") - $subscriptionOffers = Get-AzSubscription -SubscriptionId $sub.Id | Select-Object -ExpandProperty OfferId - if ($subscriptionOffers -contains $offers) { - if ($tags.Tags.ContainsKey("SQLPerpetualPaygBilling")) { - if ($tags.Tags["SQLPerpetualPaygBilling"] -ne "Enabled") { - write-host "Error: Subscription $($sub.Id) has an incorrect value $($tags.Tags["SQLPerpetualPaygBilling"]) of the consent tag 'SQLPerpetualPaygBilling' ." - continue - } - } else { - write-host "Error: Subscription $($sub.Id) does not have the consent tag 'SQLPerpetualPaygBilling'." - continue - } - } - } - $query = " resources | where type =~ 'microsoft.hybridcompute/machines/extensions' @@ -180,6 +203,7 @@ foreach ($sub in $subscriptions) { $resources = Search-AzGraph -Query "$($query)" foreach ($r in $resources) { + $setID = @{ MachineName = $r.MachineName Name = $r.extensionName @@ -194,6 +218,7 @@ foreach ($sub in $subscriptions) { $settings = @{} $settings = $r.properties.settings | ConvertTo-Json | ConvertFrom-Json | ConvertTo-Hashtable + # set the license type or update (if -Force). ESU must be disabled to set to LicenseOnly. $LO_Allowed = (!$settings["enableExtendedSecurityUpdates"] -and !$EnableESU) -or ($EnableESU -eq "No") if ($LicenseType) { @@ -210,8 +235,10 @@ foreach ($sub in $subscriptions) { $WriteSettings = $true } } + } + # Enable ESU for qualified license types or disable if ($EnableESU) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($EnableESU -eq "No")) { $settings["enableExtendedSecurityUpdates"] = ($EnableESU -eq "Yes") @@ -222,6 +249,7 @@ foreach ($sub in $subscriptions) { } } + # Enable UsePcoreLicense for qualified license types or disable if ($UsePcoreLicense) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($UsePcoreLicense -eq "No")) { $settings["UsePhysicalCoreLicense"] = @{ @@ -234,14 +262,17 @@ foreach ($sub in $subscriptions) { } } If ($WriteSettings) { + try { - Set-AzConnectedMachineExtension @setID -Settings $settings -NoWait | Out-Null + Set-AzConnectedMachineExtension @setId -Settings $settings -NoWait | Out-Null Write-Host "Updated -- Resource group: [$($r.resourceGroup)], Connected machine: [$($r.MachineName)]" } catch { - write-host "The request to modify the extension object failed with the following error:" + write-host "The request to modify the extenion object failed with the following error:" write-host $_.Exception.Message {continue} } } } } + + \ No newline at end of file