|
| 1 | +# |
| 2 | +# This script provides a scalable method to switch the license type to pay-as-you-go (aka LicenseIncluded) for all SQL resources in a specific subscription or the entire tenant. By default, the script scans |
| 3 | +# all subscriptions the user account has access. Alternatively, you can specify a single subscription or a .CSV file |
| 4 | +# with a list of subscription. The usage report includes the list of resources that have been affected by the change. |
| 5 | +# |
| 6 | +# The following resources are in scope for the license utilization analysis: |
| 7 | +# - Azure SQL databases (vCore-based purchasing model only) |
| 8 | +# - Azure SQL elastic pools (vCore-based purchasing model only) |
| 9 | +# - Azure SQL managed instances |
| 10 | +# - Azure SQL instance pools |
| 11 | +# - Azure Data Factory SSIS integration runtimes |
| 12 | +# - SQL Servers in Azure virtual machines |
| 13 | +# |
| 14 | +# The script accepts the following command line parameters: |
| 15 | +# |
| 16 | +# -SubId [subscription_id] | [csv_file_name] (Accepts a .csv file with the list of subscriptions) |
| 17 | +# -Cred [credential_object] (Required to save data to the database) |
| 18 | +# -FilePath [csv_file_name] (Required to save data in a .csv format. Ignored if database parameters are specified) |
| 19 | +# |
| 20 | + |
| 21 | +param ( |
| 22 | + [Parameter (Mandatory= $false)] |
| 23 | + [string] $SubId, |
| 24 | + [Parameter (Mandatory= $false)] |
| 25 | + [PSCredential] $Cred, |
| 26 | + [Parameter (Mandatory= $false)] |
| 27 | + [string] $FilePath |
| 28 | +) |
| 29 | + |
| 30 | +function CheckModule ($m) { |
| 31 | + |
| 32 | + # This function ensures that the specified module is imported into the session |
| 33 | + # If module is already imported - do nothing |
| 34 | + |
| 35 | + if (!(Get-Module | Where-Object {$_.Name -eq $m})) { |
| 36 | + # If module is not imported, but available on disk then import |
| 37 | + if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { |
| 38 | + Import-Module $m |
| 39 | + } |
| 40 | + else { |
| 41 | + |
| 42 | + # If module is not imported, not available on disk, but is in online gallery then install and import |
| 43 | + if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { |
| 44 | + Install-Module -Name $m -Force -Verbose -Scope CurrentUser |
| 45 | + Import-Module $m |
| 46 | + } |
| 47 | + else { |
| 48 | + |
| 49 | + # If module is not imported, not available and not in online gallery then abort |
| 50 | + write-host "Module $m not imported, not available and not in online gallery, exiting." |
| 51 | + EXIT 1 |
| 52 | + } |
| 53 | + } |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +# |
| 58 | +# Suppress warnings |
| 59 | +# |
| 60 | +Update-AzConfig -DisplayBreakingChangeWarning $false |
| 61 | + |
| 62 | +$requiredModules = @( |
| 63 | + "Az.Accounts", |
| 64 | + "Az.Compute", |
| 65 | + "Az.DataFactory", |
| 66 | + "Az.Resources", |
| 67 | + "Az.Sql", |
| 68 | + "Az.SqlVirtualMachine" |
| 69 | +) |
| 70 | +$requiredModules | Foreach-Object {CheckModule $_} |
| 71 | + |
| 72 | +# Subscriptions to scan |
| 73 | + |
| 74 | +if ($SubId -like "*.csv") { |
| 75 | + $subscriptions = Import-Csv $SubId |
| 76 | +}elseif($SubId -ne $null){ |
| 77 | + $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription |
| 78 | +}else{ |
| 79 | + $subscriptions = Get-AzSubscription |
| 80 | +} |
| 81 | + |
| 82 | +#Log file setup |
| 83 | +if (!$PSBoundParameters.ContainsKey("FilePath")) { |
| 84 | + $FilePath = '.\sql-change-log.csv' |
| 85 | +} |
| 86 | + |
| 87 | +Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --") |
| 88 | + |
| 89 | +# Calculate usage for each subscription |
| 90 | + |
| 91 | +foreach ($sub in $subscriptions){ |
| 92 | + |
| 93 | + if ($sub.State -ne "Enabled") {continue} |
| 94 | + |
| 95 | + try { |
| 96 | + Set-AzContext -SubscriptionId $sub.Id |
| 97 | + }catch { |
| 98 | + write-host "Invalid subscription: " $sub.Id |
| 99 | + {continue} |
| 100 | + } |
| 101 | + |
| 102 | + # Get all resource groups in the subscription |
| 103 | + $rgs = Get-AzResourceGroup |
| 104 | + |
| 105 | + # Get all logical servers |
| 106 | + $servers = Get-AzSqlServer |
| 107 | + |
| 108 | + # Scan all vCore-based SQL database resources in the subscription |
| 109 | + $servers | Get-AzSqlDatabase | Where-Object { $_.SkuName -ne "ElasticPool" -and $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { |
| 110 | + if ($_.LicenseType -ne "LicenseIncluded") { |
| 111 | + Set-AzSqlDatabase -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -DatabaseName $_.DatabaseName -LicenseType "LicenseIncluded" |
| 112 | + Write-Host ([Environment]::NewLine + "-- Database $_.DatabaseName is set to \"LicenseIncluded\"") |
| 113 | + } |
| 114 | + } |
| 115 | + [system.gc]::Collect() |
| 116 | + |
| 117 | + # Scan all vCore-based SQL elastic pool resources in the subscription |
| 118 | + $servers | Get-AzSqlElasticPool | Where-Object { $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { |
| 119 | + if ($_.LicenseType -ne "LicenseIncluded") { |
| 120 | + Set-AzSqlElasticPool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -ElasticPoolName $_.ElasticPoolName -LicenseType "LicenseIncluded" |
| 121 | + Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to \"LicenseIncluded\"") |
| 122 | + } |
| 123 | + } |
| 124 | + [system.gc]::Collect() |
| 125 | + |
| 126 | + # Scan all SQL managed instance resources in the subscription |
| 127 | + Get-AzSqlInstance | Where-Object { $_.InstancePoolName -eq $null } | ForEach-Object { |
| 128 | + if ($_.LicenseType -ne "LicenseIncluded") { |
| 129 | + Set-AzSqlInstance -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType "LicenseIncluded" |
| 130 | + Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to \"LicenseIncluded\"") |
| 131 | + } |
| 132 | + } |
| 133 | + [system.gc]::Collect() |
| 134 | + |
| 135 | + # Scan all instance pool resources in the subscription |
| 136 | + Get-AzSqlInstancePool | Foreach-Object { |
| 137 | + if ($_.LicenseType -ne "LicenseIncluded") { |
| 138 | + Set-AzSqlInstancePool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType "LicenseIncluded" |
| 139 | + Write-Host ([Environment]::NewLine + "-- InstancePool $_.InstanceName is set to \"LicenseIncluded\"") |
| 140 | + } |
| 141 | + } |
| 142 | + [system.gc]::Collect() |
| 143 | + |
| 144 | + # Scan all SSIS imtegration runtime resources in the subscription |
| 145 | + $rgs | Get-AzDataFactoryV2 | Get-AzDataFactoryV2IntegrationRuntime | Where-Object { $_.State -eq "Started" -and $_.NodeSize -ne $null } | ForEach-Object { |
| 146 | + if ($_.LicenseType -ne "LicenseIncluded") { |
| 147 | + # Set the license type to "LicenseIncluded" |
| 148 | + Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType "LicenseIncluded" |
| 149 | + Write-Host ([Environment]::NewLine + "-- DataFactory $_.DataFactoryName is set to \"LicenseIncluded\"") |
| 150 | + } |
| 151 | + } |
| 152 | + [system.gc]::Collect() |
| 153 | + |
| 154 | + # Scan all SQL VMs in the subscription |
| 155 | + $rgs | Get-AzVM | Where-Object { $_.StorageProfile.ImageReference.Offer -like "*sql*" -and $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { |
| 156 | + $vmName = $_.Name |
| 157 | + $resourceGroupName = $_.ResourceGroupName |
| 158 | + |
| 159 | + # Get the SQL configuration for the VM |
| 160 | + $sqlConfig = Get-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" |
| 161 | + |
| 162 | + if ($sqlConfig -ne $null) { |
| 163 | + $licenseType = $sqlConfig.Settings.LicenseType |
| 164 | + |
| 165 | + if ($licenseType -ne "LicenseIncluded") { |
| 166 | + # Set the license type to "LicenseIncluded" |
| 167 | + Set-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" -Publisher "Microsoft.SqlServer.Management" -ExtensionType "SqlIaaSAgent" -TypeHandlerVersion "1.5" -Settings @{ "LicenseType" = "LicenseIncluded" } |
| 168 | + Write-Host ([Environment]::NewLine + "-- SQL VM $vmName is set to \"LicenseIncluded\"") |
| 169 | + } |
| 170 | + |
| 171 | + } |
| 172 | + } |
| 173 | + [system.gc]::Collect() |
| 174 | +} |
0 commit comments