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 57925a29..d7e6124a 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
@@ -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.|
-1You can create a .csv file using the following command and then edit to remove the subscriptions you don't want to scan.
+1You 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 = ""
+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
```
2The .csv file must include a column *MachineName*. E.g.:
```
diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-arc-sql-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-arc-sql-license-type.ps1
index 26f0c47c..a9e86922 100644
--- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-arc-sql-license-type.ps1
+++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-arc-sql-license-type.ps1
@@ -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'))"
\ No newline at end of file
+Write-Output "Total execution time: $($executionDuration.ToString('hh\:mm\:ss'))"
+Stop-Transcript
\ No newline at end of file
diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md
index 91a3e09e..34aa1dd3 100644
--- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md
+++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md
@@ -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 subscriptions1. 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.|
+1You 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 = ""
+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.
diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-azure-sql-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-azure-sql-license-type.ps1
index 36678760..eac56bfc 100644
--- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-azure-sql-license-type.ps1
+++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-azure-sql-license-type.ps1
@@ -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'))"
\ No newline at end of file
+Write-Output "Total execution time: $($executionDuration.ToString('hh\:mm\:ss'))"
+Stop-Transcript
\ No newline at end of file