1
+ #
2
+ # This script provides a scaleable solution to set or change the license type on all Azure-connected SQL Servers
3
+ # in a specific subscription, a list of subscruiptions or the entire account. By default, it sets the new license
4
+ # type value only on the servers where it is undefined.
5
+ #
6
+ # You can specfy a single subscription to scan, or provide subscriptions as a .CSV file with the list of IDs.
7
+ # If not specified, all subscriptions your role has access to are scanned.
8
+ #
9
+ # The script accepts the following command line parameters:
10
+ #
11
+ # -SubId [subscription_id] | [csv_file_name] (Limit scope to specific subscriptions. Accepts a .csv file with the list of subscriptions)
12
+ # -ResourceGroup [resource_goup] (Limit scope to a specific resoure group)
13
+ # -MachineName [machine_name] (Limit scope to a specific machine)
14
+ # -LicenseType [license_type_value] (Specific LT value)
15
+ # -All (Optional. Set the new license type value only if undefined)
16
+ #
17
+
18
+ param (
19
+ [Parameter (Mandatory = $false )]
20
+ [string ] $SubId ,
21
+ [Parameter (Mandatory = $false )]
22
+ [string ] $ResourceGroup ,
23
+ [Parameter (Mandatory = $false )]
24
+ [string ] $MachineName ,
25
+ [Parameter (Mandatory = $false )]
26
+ [string ] $LicenseType = " Paid" ,
27
+ [Parameter (Mandatory = $false )]
28
+ [boolean ] $All = $false
29
+ )
30
+
31
+ function CheckModule ($m ) {
32
+
33
+ # This function ensures that the specified module is imported into the session
34
+ # If module is already imported - do nothing
35
+
36
+ if (! (Get-Module | Where-Object {$_.Name -eq $m })) {
37
+ # If module is not imported, but available on disk then import
38
+ if (Get-Module - ListAvailable | Where-Object {$_.Name -eq $m }) {
39
+ Import-Module $m
40
+ }
41
+ else {
42
+
43
+ # If module is not imported, not available on disk, but is in online gallery then install and import
44
+ if (Find-Module - Name $m | Where-Object {$_.Name -eq $m }) {
45
+ Install-Module - Name $m - Force - Verbose - Scope CurrentUser
46
+ Import-Module $m
47
+ }
48
+ else {
49
+
50
+ # If module is not imported, not available and not in online gallery then abort
51
+ write-host " Module $m not imported, not available and not in online gallery, exiting."
52
+ EXIT 1
53
+ }
54
+ }
55
+ }
56
+ }
57
+
58
+ function ObjectToHashtable {
59
+ [CmdletBinding ()]
60
+ [OutputType (' hashtable' )]
61
+ param (
62
+ [Parameter (ValueFromPipeline )]
63
+ $InputObject
64
+ )
65
+ process {
66
+ # # Return null if the input is null. This can happen when calling the function
67
+ # # recursively and a property is null
68
+ if ($null -eq $InputObject ) {
69
+ return $null
70
+ }
71
+ # # Check if the input is an array or collection. If so, we also need to convert
72
+ # # those types into hash tables as well. This function will convert all child
73
+ # # objects into hash tables (if applicable)
74
+ if ($InputObject -is [System.Collections.IEnumerable ] -and $InputObject -isnot [string ]) {
75
+ $collection = @ (
76
+ foreach ($object in $InputObject ) {
77
+ ObjectToHashtable - InputObject $object
78
+ }
79
+ )
80
+ # # Return the array but don't enumerate it because the object may be pretty complex
81
+ Write-Output - NoEnumerate $collection
82
+ } elseif ($InputObject -is [psobject ]) {
83
+ # # If the object has properties that need enumeration, cxonvert it to its own hash table and return it
84
+ $hash = @ {}
85
+ foreach ($property in $InputObject.PSObject.Properties ) {
86
+ $hash [$property.Name ] = ObjectToHashtable - InputObject $property.Value
87
+ }
88
+ $hash
89
+ } else {
90
+ # # If the object isn't an array, collection, or other object, it's already a hash table
91
+ # # So just return it.
92
+ $InputObject
93
+ }
94
+ }
95
+ }
96
+
97
+ #
98
+ # Suppress warnings
99
+ #
100
+ Update-AzConfig - DisplayBreakingChangeWarning $false
101
+
102
+ # Load required modules
103
+ $requiredModules = @ (
104
+ " Az.Accounts" ,
105
+ " Az.ConnectedMachine" ,
106
+ " Az.ResourceGraph"
107
+ )
108
+ $requiredModules | Foreach-Object {CheckModule $_ }
109
+
110
+ # Subscriptions to scan
111
+
112
+ if ($SubId -like " *.csv" ) {
113
+ $subscriptions = Import-Csv $SubId
114
+ }elseif ($SubId -ne $null ){
115
+ $subscriptions = [PSCustomObject ]@ {SubscriptionId = $SubId } | Get-AzSubscription
116
+ }else {
117
+ $subscriptions = Get-AzSubscription
118
+ }
119
+
120
+
121
+ Write-Host ([Environment ]::NewLine + " -- Scanning subscriptions --" )
122
+
123
+ # Scan arc-enabled servers in each subscription
124
+
125
+ foreach ($sub in $subscriptions ){
126
+
127
+ if ($sub.State -ne " Enabled" ) {continue }
128
+
129
+ try {
130
+ Set-AzContext - SubscriptionId $sub.Id
131
+ }catch {
132
+ write-host " Invalid subscription: $ ( $sub.Id ) "
133
+ {continue }
134
+ }
135
+
136
+ $query = "
137
+ resources
138
+ | where type =~ 'microsoft.hybridcompute/machines/extensions'
139
+ | extend extensionPublisher = tostring(properties.publisher), extensionType = tostring(properties.type), provisioningState = tostring(properties.provisioningState)
140
+ | where extensionPublisher =~ 'Microsoft.AzureData'
141
+ | where provisioningState =~ 'Succeeded'
142
+ | parse id with * '/providers/Microsoft.HybridCompute/machines/' machineName '/extensions/' *
143
+ | project machineName, extensionName = name, resourceGroup, location, subscriptionId, extensionPublisher, extensionType, properties
144
+ "
145
+
146
+ if ($MachineName ) {$query += " | where machineName =~ '$ ( $MachineName ) '" }
147
+ if ($ResourceGroup ) {$query += " | where resourceGroup =~ '$ ( $ResourceGroup ) '" }
148
+
149
+ $resources = Search-AzGraph - Query " $ ( $query ) | where subscriptionId =~ '$ ( $sub.Id ) '"
150
+ foreach ($r in $resources ) {
151
+
152
+ $setID = @ {
153
+ MachineName = $r.MachineName
154
+ Name = $r.extensionName
155
+ ResourceGroup = $r.resourceGroup
156
+ Location = $r.location
157
+ SubscriptionId = $r.subscriptionId
158
+ Publisher = $r.extensionPublisher
159
+ ExtensionType = $r.extensionType
160
+ }
161
+
162
+ $settings = @ {}
163
+ $settings = $r.properties.settings | ConvertTo-Json | ConvertFrom-Json | ObjectToHashtable
164
+
165
+ if ($settings.ContainsKey (" LicenseType" )) {
166
+ if ($All ) {
167
+ if ($settings [" LicenseType" ] -ne $LicenseType ) {
168
+ $settings [" LicenseType" ] = $LicenseType
169
+ Write-Host " Resource group: [$ ( $r.resourceGroup ) ] Connected machine: [$ ( $r.MachineName ) ] : License type: [$ ( $settings [" LicenseType" ]) ]"
170
+ Set-AzConnectedMachineExtension @setId - Settings $settings - NoWait
171
+ }
172
+ }
173
+ } else {
174
+ $settings [" LicenseType" ] = $LicenseType
175
+ Write-Host " Resource group: [$ ( $r.resourceGroup ) ] Connected machine: [$ ( $r.MachineName ) ] : License type: [$ ( $settings [" LicenseType" ]) ]"
176
+ Set-AzConnectedMachineExtension @setId - Settings $settings
177
+ }
178
+ }
179
+ }
180
+
181
+
0 commit comments