mirror of
https://github.com/Microsoft/sql-server-samples.git
synced 2025-12-08 14:58:54 +00:00
Merge pull request #1395 from anosov1960/PAYG-transition
Cleaned up and added transcript
This commit is contained in:
@@ -48,14 +48,23 @@ The script accepts the following command line parameters:
|
||||
|`-UsePcoreLicense` | `Yes`, `No` | *Optional*. Enables unlimited virtualization license if the value is "Yes" or disables it if the value is "No". To enable, the license type must be "Paid" or "PAYG"|
|
||||
|`-EnableESU` | `Yes`, `No` | *Optional*. Enables the ESU policy the value is "Yes" or disables it if the value is "No". To enable, the license type must be "Paid" or "PAYG"|
|
||||
|`-Force`| |*Optional*. Forces the change of the license type to the specified value on all installed extensions. If `-Force` is not specified, the `-LicenseType` value is set only if undefined. Ignored if `-LicenseType` is not specified|
|
||||
|`-ExclusionTags`| `{"name":"value","name":"value"}` |*Optional*. If specified, excludes the resources that have this tag assigned.|
|
||||
|`-ExclusionTags`| `{"tag1":"value1","tag2":"value2"}` |*Optional*. If specified, excludes the resources that have these tags assigned.|
|
||||
|`-TenantId`| `tenant_id` |*Optional*. If specified, uses this tenant id to log in. Otherwise, the current context is used.|
|
||||
|`-ReportOnly`| |*Optional*. If true, generates a csv file with the list of resources that are to be modified, but doesn't make the actual change.|
|
||||
|`-UseManagedIdentity`| |*Optional*. If true, logs in both PowerShell and CLI using managed identity. Required to run the script as a runbook.|
|
||||
|
||||
<sup>1</sup>You can create a .csv file using the following command and then edit to remove the subscriptions you don't want to scan.
|
||||
<sup>1</sup>You can generate a .csv file that lists only specific subscriptions. E.g., the following command will include only production subscriptions (exclude dev/test).
|
||||
```PowerShell
|
||||
Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation
|
||||
$tenantId = "<your-tenant-id>"
|
||||
Get-AzSubscription -TenantId $tenantId | Where-Object {
|
||||
$sub = $_
|
||||
$details = Get-AzSubscription -SubscriptionId $sub.Id -TenantId $tenantId
|
||||
if ($details -and $details.ExtendedProperties -and $details.ExtendedProperties.SubscriptionPolicies) {
|
||||
$quotaId = ($details.ExtendedProperties.SubscriptionPolicies | ConvertFrom-Json).quotaId
|
||||
return $quotaId -notmatch 'MSDN|DEV|VS|TEST'
|
||||
}
|
||||
return $false
|
||||
} | Export-Csv .\mysubscriptions.csv -NoTypeInformation
|
||||
```
|
||||
<sup>2</sup>The .csv file must include a column *MachineName*. E.g.:
|
||||
```
|
||||
|
||||
+4
-2
@@ -93,6 +93,7 @@ param (
|
||||
[int] $batchSize = 500
|
||||
)
|
||||
|
||||
Start-Transcript -Path ".\modify-arc-sql-license-type.log"
|
||||
$scriptStartTime = Get-Date
|
||||
Write-Output "Script execution started at: $($scriptStartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
|
||||
|
||||
@@ -139,7 +140,7 @@ function Connect-Azure {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Output "Not connected to Az PowerShell—authenticating..."
|
||||
Write-Output "Not connected to Azure PowerShell. Running Connect-AzAccount..."
|
||||
if ($UseManagedIdentity) {
|
||||
if ($TenantId) {
|
||||
Connect-AzAccount -Identity -Tenant $TenantId | Out-Null
|
||||
@@ -461,4 +462,5 @@ write-Output "Arc SQL Update Script completed"
|
||||
$scriptEndTime = Get-Date
|
||||
$executionDuration = $scriptEndTime - $scriptStartTime
|
||||
Write-Output "Script execution ended at: $($scriptEndTime.ToString('yyyy-MM-dd HH:mm:ss'))"
|
||||
Write-Output "Total execution time: $($executionDuration.ToString('hh\:mm\:ss'))"
|
||||
Write-Output "Total execution time: $($executionDuration.ToString('hh\:mm\:ss'))"
|
||||
Stop-Transcript
|
||||
@@ -32,6 +32,12 @@ This script is designed to help administrators standardize SQL licensing across
|
||||
- SQL Databases & Elastic Pools: Scans individual SQL servers to locate databases and elastic pools with a different license type and updates them accordingly.
|
||||
- SQL Instance Pools: Locates instance pools that require an update.
|
||||
- DataFactory SSIS Integration Runtimes: Checks for integration runtimes with an out-of-date license setting and updates them.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> - SQL Virtual Machines must be in PowerState = "VM running" to be updated
|
||||
> - SQL Managed Instances must be in State = "Ready" to be updated
|
||||
> - DataFactory SSIS Integration Runtimes must be in State = "Stopped" to be updated
|
||||
|
||||
|
||||
# Required Permissions
|
||||
The automation account needs to have the bellow permissions in order to be able to successfully run the Runbook and update all the SQL Server resources license type:
|
||||
@@ -42,7 +48,7 @@ The automation account needs to have the bellow permissions in order to be able
|
||||
1. **Data Factory Contributor**: *Data Factory Contributor role*.
|
||||
1. **Virtual Machine Contributor**: *Virtual Machine Contributor role*.
|
||||
|
||||
A *Subscription Contributor* role has sufficient permissions to mdify any of the above resources.
|
||||
A *Subscription Contributor* role has sufficient permissions to modify any of the above resources.
|
||||
|
||||
# Interactive Reporting
|
||||
|
||||
@@ -59,13 +65,27 @@ The scripts is seamlessly integrated with Azure Authentication. It uses managed
|
||||
|:--|:--|:--|
|
||||
|`-SubId`|`subscription_id` *or* a file_name|Optional: Subscription id or a .csv file with the list of subscriptions<sup>1</sup>. If not specified all subscriptions will be scanned|
|
||||
|`-ResourceGroup` |`resource_group_name`|Optional: Limits the scope to a specific resource group|
|
||||
|`-ResourceName` |`resource_name`|Optional: Limits the scope to resouyrces associated with this name. For SQL Server - updates all databases under the specified server. For SQL Managed Instance - updates the specified instance. For SQL VM - updates the specified VM |
|
||||
|`-ResourceName` |`resource_name`|Optional: Limits the scope to resources associated with this name. For SQL Server - updates all databases under the specified server. For SQL Managed Instance - updates the specified instance. For SQL VM - updates the specified VM |
|
||||
|`-LicenseType` | `LicenseIncluded` (default) or `BasePrice` | Optional: Sets the license type to the specified value |
|
||||
|`-ExclusionTags`| `{"name":"value","name":"value"}` |*Optional*. If specified, excludes the resources that have this tag assigned.|
|
||||
|`-ExclusionTags`| `{"tag1":"value1","tag2":"value2"}` |*Optional*. If specified, excludes the resources that have these tags assigned.|
|
||||
|`-TenantId`| `tenant_id` |*Optional*. If specified, uses this tenant id to log in. Otherwise, the current context is used.|
|
||||
|`-ReportOnly`| |*Optional*. If true, generates a csv file with the list of resources that are to be modified, but doesn't make the actual change.|
|
||||
|`-UseManagedIdentity`| |*Optional*. If true, logs in both PowerShell and CLI using managed identity. Required to run the script as a runbook.|
|
||||
|
||||
<sup>1</sup>You can generate a .csv file that lists only specific subscriptions. E.g., the following command will include only production subscriptions (exclude dev/test).
|
||||
```PowerShell
|
||||
$tenantId = "<your-tenant-id>"
|
||||
Get-AzSubscription -TenantId $tenantId | Where-Object {
|
||||
$sub = $_
|
||||
$details = Get-AzSubscription -SubscriptionId $sub.Id -TenantId $tenantId
|
||||
if ($details -and $details.ExtendedProperties -and $details.ExtendedProperties.SubscriptionPolicies) {
|
||||
$quotaId = ($details.ExtendedProperties.SubscriptionPolicies | ConvertFrom-Json).quotaId
|
||||
return $quotaId -notmatch 'MSDN|DEV|VS|TEST'
|
||||
}
|
||||
return $false
|
||||
} | Export-Csv .\mysubscriptions.csv -NoTypeInformation
|
||||
```
|
||||
|
||||
# Logging & Error Handling
|
||||
|
||||
The script logs key actions to the console and captures error messages using Write-Error. Check the console output for a summary report detailing which resources were updated.
|
||||
|
||||
+50
-29
@@ -74,6 +74,7 @@ param (
|
||||
)
|
||||
|
||||
|
||||
Start-Transcript -Path "$env:TEMP\modify-azure-sql-license-type.log"
|
||||
$scriptStartTime = Get-Date
|
||||
Write-Output "Script execution started at: $($scriptStartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
|
||||
|
||||
@@ -135,7 +136,8 @@ $finalStatus = @()
|
||||
|
||||
# Convert to hashtable explicitly
|
||||
$tagTable = @{}
|
||||
if($null -ne $ExclusionTags){
|
||||
if(
|
||||
$null -ne $ExclusionTags){
|
||||
if($ExclusionTags.GetType().Name -eq "Hashtable"){
|
||||
$tagTable = $ExclusionTags
|
||||
}else{
|
||||
@@ -169,23 +171,23 @@ if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) {
|
||||
$installedModule = Get-InstalledModule -Name Az -ErrorAction SilentlyContinue
|
||||
|
||||
if (-not $installedModule) {
|
||||
Write-Host "Az module not found. Installing latest version..."
|
||||
Write-Output "Az module not found. Installing latest version..."
|
||||
Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force
|
||||
} else {
|
||||
# Get the latest version available in the PSGallery
|
||||
$latestVersion = (Find-Module -Name Az -Repository PSGallery).Version
|
||||
if ($installedModule.Version -lt $latestVersion) {
|
||||
Write-Host "Az module is outdated. Updating to latest version..."
|
||||
Write-Output "Az module is outdated. Updating to latest version..."
|
||||
Update-Module -Name Az -Force
|
||||
} else {
|
||||
Write-Host "Az module is already up to date. No action needed."
|
||||
Write-Output "Az module is already up to date. No action needed."
|
||||
}
|
||||
}
|
||||
|
||||
# Import Az.Accounts with minimum version requirement
|
||||
try {
|
||||
Import-Module Az.Accounts -MinimumVersion 4.2.0 -Force
|
||||
Write-Host "Az.Accounts module imported successfully."
|
||||
Write-Output "Az.Accounts module imported successfully."
|
||||
} catch {
|
||||
Write-Error "Failed to import Az.Accounts: $_"
|
||||
return
|
||||
@@ -194,10 +196,10 @@ try {
|
||||
# Ensure Az.DataFactory is available and import it
|
||||
try {
|
||||
if (-not (Get-Module -ListAvailable -Name Az.DataFactory)) {
|
||||
Write-Host "Az.DataFactory module not found. Installing..."
|
||||
Write-Output "Az.DataFactory module not found. Installing..."
|
||||
Install-Module -Name Az.DataFactory -Scope CurrentUser -Force
|
||||
} else {
|
||||
Write-Host "Az.DataFactory module is already installed."
|
||||
Write-Output "Az.DataFactory module is already installed."
|
||||
}
|
||||
Import-Module Az.DataFactory -Force
|
||||
} catch {
|
||||
@@ -425,6 +427,7 @@ foreach ($sub in $subscriptions) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Add tag filter if specified
|
||||
if ($tagsFilter -and $filterAdded) {
|
||||
$serverQuery += "$tagsFilter"
|
||||
@@ -441,9 +444,10 @@ foreach ($sub in $subscriptions) {
|
||||
# Output the query for debugging
|
||||
Write-Output "SQL Server query: $serverQuery"
|
||||
|
||||
# Get all servers first as a fallback in case the query fails
|
||||
<# Get all servers first as a fallback in case the query fails
|
||||
$allServers = az sql server list -o json | ConvertFrom-Json
|
||||
Write-Output "Found a total of $($allServers.Count) SQL Servers in subscription"
|
||||
#>
|
||||
|
||||
# Now try the filtered query
|
||||
$servers = az sql server list --query "$serverQuery" -o json | ConvertFrom-Json
|
||||
@@ -451,10 +455,11 @@ foreach ($sub in $subscriptions) {
|
||||
# Verify if we got any results
|
||||
if ($null -eq $servers -or $servers.Count -eq 0) {
|
||||
Write-Output "WARNING: No SQL Servers found with the specified filters."
|
||||
Write-Output "Available SQL Servers in subscription:"
|
||||
<# Write-Output "Available SQL Servers in subscription:"
|
||||
$allServers | ForEach-Object {
|
||||
Write-Output " - $($_.name) (Resource Group: $($_.resourceGroup))"
|
||||
}
|
||||
#>
|
||||
|
||||
# Use all servers if no specific resource name was provided
|
||||
if (-not $ResourceName) {
|
||||
@@ -666,31 +671,46 @@ foreach ($sub in $subscriptions) {
|
||||
# --- Section: Update DataFactory SSIS Integration Runtimes ---
|
||||
try {
|
||||
Write-Output "Processing DataFactory SSIS Integration Runtime resources..."
|
||||
Get-AzDataFactoryV2 | Where-Object { $_.ProvisioningState -eq "Succeeded" } | ForEach-Object {
|
||||
Set-AzContext -Subscription $sub.id | Out-Null
|
||||
Get-AzDataFactoryV2 |
|
||||
Where-Object {
|
||||
$_.ProvisioningState -eq "Succeeded" -and
|
||||
($null -eq $ResourceGroup -or $_.ResourceGroupName -eq $ResourceGroup)
|
||||
} |
|
||||
ForEach-Object {
|
||||
$df = $_
|
||||
Get-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $df.ResourceGroupName -DataFactoryName $df.DataFactoryName |
|
||||
$IRs = Get-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $df.ResourceGroupName -DataFactoryName $df.DataFactoryName |
|
||||
Where-Object {
|
||||
$_.Type -eq "Managed" -and
|
||||
$_.State -ne "Starting" -and
|
||||
$_.LicenseType -ne $LicenseType -and
|
||||
($null -eq $ResourceName -or $_.Name -eq $ResourceName)
|
||||
} | ForEach-Object {
|
||||
# Collect data before modification
|
||||
$modifiedResources += [PSCustomObject]@{
|
||||
TenantID = $TenantId
|
||||
SubID = ($_.Id -split '/')[2]
|
||||
ResourceName = $_.Name
|
||||
ResourceType = "Microsoft.DataFactory/factories/integrationRuntimes"
|
||||
Status = $_.State
|
||||
OriginalLicenseType = $_.LicenseType
|
||||
ResourceGroup = $df.ResourceGroupName
|
||||
Location = $df.Location
|
||||
}
|
||||
# Update the license type to $LicenseType.
|
||||
if (-not $ReportOnly) {
|
||||
$result = Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $df.ResourceGroupName -DataFactoryName $df.DataFactoryName -Name $_.Name -LicenseType $LicenseType -Force
|
||||
$finalStatus += $result
|
||||
Write-Host ([Environment]::NewLine + "-- DataFactory '$($df.DataFactoryName)' integration runtime updated to license type $LicenseType")
|
||||
}
|
||||
|
||||
if ($IRs.Count -eq 0) {
|
||||
Write-Output "No matching integration runtimes found."
|
||||
} else {
|
||||
$IRs | ForEach-Object {
|
||||
$modifiedResources += [PSCustomObject]@{
|
||||
TenantID = $TenantId
|
||||
SubID = ($_.Id -split '/')[2]
|
||||
ResourceName = $_.Name
|
||||
ResourceType = "Microsoft.DataFactory/factories/integrationRuntimes"
|
||||
Status = $_.State
|
||||
OriginalLicenseType = $_.LicenseType
|
||||
ResourceGroup = $df.ResourceGroupName
|
||||
Location = $df.Location
|
||||
}
|
||||
|
||||
if (-not $ReportOnly) {
|
||||
if (-not [string]::IsNullOrEmpty($ResourceName) -and $_.State -ne "Stopped") {
|
||||
Write-Output "ADF Integration Service '$($_.Name)' is not in stopped state"
|
||||
} else {
|
||||
$result = Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $df.ResourceGroupName -DataFactoryName $df.DataFactoryName -Name $_.Name -LicenseType $LicenseType -Force
|
||||
$finalStatus += $result
|
||||
Write-Output "-- DataFactory '$($df.DataFactoryName)' integration runtime updated to license type $LicenseType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -728,4 +748,5 @@ Write-Output "Azure SQL Update Script completed"
|
||||
$scriptEndTime = Get-Date
|
||||
$executionDuration = $scriptEndTime - $scriptStartTime
|
||||
Write-Output "Script execution ended at: $($scriptEndTime.ToString('yyyy-MM-dd HH:mm:ss'))"
|
||||
Write-Output "Total execution time: $($executionDuration.ToString('hh\:mm\:ss'))"
|
||||
Write-Output "Total execution time: $($executionDuration.ToString('hh\:mm\:ss'))"
|
||||
Stop-Transcript
|
||||
Reference in New Issue
Block a user