Skip to content

Commit 1f86cd8

Browse files
authored
Added hyper-link to the original script
1 parent 4c2449e commit 1f86cd8

1 file changed

Lines changed: 4 additions & 295 deletions

File tree

Lines changed: 4 additions & 295 deletions
Original file line numberDiff line numberDiff line change
@@ -1,295 +1,4 @@
1-
#
2-
# This script provides a scaleable solution to set or change the license type and/or enable or disable the ESU policy
3-
# on all Azure-connected SQL Servers in a specified scope.
4-
#
5-
# You can specfy a single subscription to scan, or provide subscriptions as a .CSV file with the list of IDs.
6-
# If not specified, all subscriptions your role has access to are scanned.
7-
#
8-
# The script accepts the following command line parameters:
9-
#.
10-
# -SubId [subscription_id] | [csv_file_name] (Optional. Limits the scope to specific subscriptions. Accepts a .csv file with the list of subscriptions.
11-
# If not specified all subscriptions will be scanned)
12-
# -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group)
13-
# -MachineName [machine_name] (Optional. Limits the scope to a specific machine)
14-
# -LicenseType [license_type_value] (Optional. Sets the license type to the specified value)
15-
# -ConsentToRecurringPAYG [Yes or No] (Optional. Consents to enabling the recurring PAYG billing. LicenseType must be "PAYG". Applies to CSP subscriptions only.
16-
# -UsePcoreLicense [Yes or No] (Optional. Enables unlimited virtualization license if the value is "Yes" or disables it if the value is "No"
17-
# To enable, the license type must be "Paid" or "PAYG"
18-
# -EnableESU [Yes or No] (Optional. Enables the ESU policy if the value is "Yes" or disables it if the value is "No"
19-
# To enable, the license type must be "Paid" or "PAYG"
20-
# -Force (Optional. Forces the chnahge of the license type to the specified value on all installed extensions.
21-
# If Force is not specified, the -LicenseType value is set only if undefined. Ignored if -LicenseType is not specified
22-
#
23-
# This script uses a function ConvertTo-HashTable that was created by Adam Bertram (@adam-bertram).
24-
# The function was originally published on https://4sysops.com/archives/convert-json-to-a-powershell-hash-table/
25-
# and is used here with the author's permission.
26-
#
27-
28-
param (
29-
[Parameter (Mandatory=$false)]
30-
[string] $SubId,
31-
[Parameter (Mandatory= $false)]
32-
[string] $ResourceGroup,
33-
[Parameter (Mandatory= $false)]
34-
[string] $MachineName,
35-
[Parameter (Mandatory= $false)]
36-
[ValidateSet("PAYG","Paid","LicenseOnly", IgnoreCase=$false)]
37-
[string] $LicenseType,
38-
[ValidateSet("Yes","No", IgnoreCase=$false)]
39-
[string] $ConsentToRecurringPAYG,
40-
[Parameter (Mandatory= $false)]
41-
[ValidateSet("Yes","No", IgnoreCase=$false)]
42-
[string] $UsePcoreLicense,
43-
[Parameter (Mandatory= $false)]
44-
[ValidateSet("Yes","No", IgnoreCase=$false)]
45-
[string] $EnableESU,
46-
[Parameter (Mandatory= $false)]
47-
[switch] $Force
48-
)
49-
50-
function ConvertTo-Hashtable {
51-
[CmdletBinding()]
52-
[OutputType('hashtable')]
53-
param (
54-
[Parameter(ValueFromPipeline)]
55-
$InputObject
56-
)
57-
process {
58-
## Return null if the input is null. This can happen when calling the function
59-
## recursively and a property is null
60-
if ($null -eq $InputObject) {
61-
return $null
62-
}
63-
## Check if the input is an array or collection. If so, we also need to convert
64-
## those types into hash tables as well. This function will convert all child
65-
## objects into hash tables (if applicable)
66-
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
67-
$collection = @(
68-
foreach ($object in $InputObject) {
69-
ConvertTo-Hashtable -InputObject $object
70-
}
71-
)
72-
## Return the array but don't enumerate it because the object may be pretty complex
73-
Write-Output -NoEnumerate $collection
74-
} elseif ($InputObject -is [psobject]) {
75-
## If the object has properties that need enumeration, cxonvert it to its own hash table and return it
76-
$hash = @{}
77-
foreach ($property in $InputObject.PSObject.Properties) {
78-
$hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value
79-
}
80-
$hash
81-
} else {
82-
## If the object isn't an array, collection, or other object, it's already a hash table
83-
## So just return it.
84-
$InputObject
85-
}
86-
}
87-
}
88-
89-
# This function checks if the specified module is imported into the session and if not installes and/or imports it
90-
function LoadModule
91-
{
92-
param (
93-
[parameter(Mandatory = $true)][string] $name
94-
)
95-
96-
$retVal = $true
97-
98-
if (!(Get-Module -Name $name))
99-
{
100-
$retVal = Get-Module -ListAvailable | Where-Object {$_.Name -eq $name}
101-
102-
if ($retVal)
103-
{
104-
try
105-
{
106-
Import-Module $name -ErrorAction SilentlyContinue
107-
}
108-
catch
109-
{
110-
write-host "The request to lload module $($name) failed with the following error:"
111-
write-host $_.Exception.Message
112-
$retVal = $false
113-
}
114-
}
115-
else {
116-
117-
# If module is not imported, not available on disk, but is in online gallery then install and import
118-
if (Find-Module -Name $name) {
119-
Install-Module -Name $name -Force -Verbose -Scope CurrentUser
120-
try
121-
{
122-
Import-Module $name -ErrorAction SilentlyContinue
123-
}
124-
catch
125-
{
126-
write-host "The request to load module $($name) failed with the following error:"
127-
write-host $_.Exception.Message
128-
$retVal = $false
129-
}
130-
}
131-
else {
132-
133-
# If module is not imported, not available and not in online gallery then abort
134-
write-host "Module $($name) not imported, not available and not in online gallery, exiting."
135-
EXIT 1
136-
}
137-
}
138-
}
139-
140-
return $retVal
141-
}
142-
143-
#
144-
# Suppress warnings
145-
#
146-
Update-AzConfig -DisplayBreakingChangeWarning $false
147-
148-
# Load required modules
149-
$requiredModules = @(
150-
"AzureAD",
151-
"Az.Accounts",
152-
"Az.ConnectedMachine",
153-
"Az.ResourceGraph"
154-
)
155-
$requiredModules | Foreach-Object {LoadModule $_}
156-
157-
# Subscriptions to scan
158-
159-
$tenantID = (Get-AzureADTenantDetail).ObjectId
160-
161-
if ($SubId -like "*.csv") {
162-
$subscriptions = Import-Csv $SubId
163-
}elseif($SubId -ne ""){
164-
$subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -TenantID $tenantID
165-
}else{
166-
$subscriptions = Get-AzSubscription -TenantID $tenantID
167-
}
168-
169-
170-
Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --")
171-
172-
# Scan arc-enabled servers in each subscription
173-
174-
foreach ($sub in $subscriptions){
175-
176-
if ($sub.State -ne "Enabled") {continue}
177-
178-
try {
179-
Set-AzContext -SubscriptionId $sub.Id -Tenant $tenantID
180-
}catch {
181-
write-host "Invalid subscription: $($sub.Id)"
182-
{continue}
183-
}
184-
185-
$query = "
186-
resources
187-
| where type =~ 'microsoft.hybridcompute/machines/extensions'
188-
| where subscriptionId =~ '$($sub.Id)'
189-
| extend extensionPublisher = tostring(properties.publisher), extensionType = tostring(properties.type), provisioningState = tostring(properties.provisioningState)
190-
| parse id with * '/providers/Microsoft.HybridCompute/machines/' machineName '/extensions/' *
191-
| where extensionPublisher =~ 'Microsoft.AzureData'
192-
| where provisioningState =~ 'Succeeded'
193-
"
194-
195-
if ($ResourceGroup) {
196-
$query += "| where resourceGroup =~ '$($ResourceGroup)'"
197-
}
198-
199-
if ($MachineName) {
200-
$query += "| where machineName =~ '$($MachineName)'"
201-
}
202-
203-
$query += "
204-
| project machineName, extensionName = name, resourceGroup, location, subscriptionId, extensionPublisher, extensionType, properties
205-
"
206-
207-
$resources = Search-AzGraph -Query "$($query)"
208-
foreach ($r in $resources) {
209-
210-
$setID = @{
211-
MachineName = $r.MachineName
212-
Name = $r.extensionName
213-
ResourceGroup = $r.resourceGroup
214-
Location = $r.location
215-
SubscriptionId = $r.subscriptionId
216-
Publisher = $r.extensionPublisher
217-
ExtensionType = $r.extensionType
218-
}
219-
220-
$WriteSettings = $false
221-
$settings = @{}
222-
$settings = $r.properties.settings | ConvertTo-Json | ConvertFrom-Json | ConvertTo-Hashtable
223-
224-
# set the license type or update (if -Force). ESU must be disabled to set to LicenseOnly.
225-
$LO_Allowed = (!$settings["enableExtendedSecurityUpdates"] -and !$EnableESU) -or ($EnableESU -eq "No")
226-
227-
if ($LicenseType) {
228-
if (($LicenseType -eq "LicenseOnly") -and !$LO_Allowed) {
229-
write-host "ESU must be disabled before license type can be set to $($LicenseType)"
230-
} else {
231-
if ($settings.ContainsKey("LicenseType")) {
232-
if ($Force) {
233-
$settings["LicenseType"] = $LicenseType
234-
$WriteSettings = $true
235-
}
236-
} else {
237-
$settings["LicenseType"] = $LicenseType
238-
$WriteSettings = $true
239-
}
240-
}
241-
}
242-
243-
# Enable ESU for qualified license types or disable
244-
if ($EnableESU) {
245-
if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($EnableESU -eq "No")) {
246-
$settings["enableExtendedSecurityUpdates"] = ($EnableESU -eq "Yes")
247-
$settings["esuLastUpdatedTimestamp"] = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
248-
$WriteSettings = $true
249-
} else {
250-
write-host "The configured license type does not support ESUs"
251-
}
252-
}
253-
254-
# Enable UsePcoreLicense for qualified license types or disable
255-
if ($UsePcoreLicense) {
256-
if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($UsePcoreLicense -eq "No")) {
257-
$settings["UsePhysicalCoreLicense"] = @{
258-
"IsApplied" = ($UsePcoreLicense -eq "Yes");
259-
"LastUpdatedTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
260-
}
261-
$WriteSettings = $true
262-
} else {
263-
write-host "The configured license type does not support ESUs"
264-
}
265-
}
266-
267-
# Add or update ConsentToRecurringPAYG setting if applicable
268-
if ($ConsentToRecurringPAYG -eq "Yes") {
269-
$isPayg = ($LicenseType -eq "PAYG") -or ($settings["LicenseType"] -eq "PAYG")
270-
if ($isPayg) {
271-
if (-not $settings.ContainsKey("ConsentToRecurringPAYG") -or -not $settings["ConsentToRecurringPAYG"]["Consented"]) {
272-
$settings["ConsentToRecurringPAYG"] = @{
273-
"Consented" = $true;
274-
"ConsentTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
275-
}
276-
$WriteSettings = $true
277-
}
278-
}
279-
}
280-
281-
If ($WriteSettings) {
282-
283-
try {
284-
Set-AzConnectedMachineExtension @setId -Settings $settings -NoWait | Out-Null
285-
Write-Host "Updated -- Resource group: [$($r.resourceGroup)], Connected machine: [$($r.MachineName)]"
286-
} catch {
287-
write-host "The request to modify the extenion object failed with the following error:"
288-
write-host $_.Exception.Message
289-
{continue}
290-
}
291-
}
292-
}
293-
}
294-
295-
1+
<#
2+
.LINK
3+
https://github.com/microsoft/sql-server-samples/blob/master/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-arc-sql-license-type.ps1
4+
#>

0 commit comments

Comments
 (0)