Merge pull request #1310 from anosov1960/master

Merge activate-pcore-license
This commit is contained in:
Alexander (Sasha) Nosov
2024-06-24 16:38:26 -07:00
committed by GitHub
3 changed files with 286 additions and 0 deletions
@@ -0,0 +1,41 @@
---
services: Azure SQL
platforms: Azure
author: anosov1960
ms.author: sashan
ms.date: 06/24/2024
---
# Overview
This script performes a scheduled activation of a SQL Server p-core license.
# Required permissions
Your RBAC role must include the following permissions:
- Microsoft.AzureArcData/SqlLicenses/read
- Microsoft.AzureArcData/SqlLicenses/write
- Microsoft.Management/managementGroups/read
- Microsoft.Resources/subscriptions/read
- Microsoft.Resources/subscriptions/resourceGroups/read
- Microsoft.Support/supporttickets/write
# Creating a Azure runbook
You can scahedule to run the the command as a runbook. To set it up using Azure Portal, follow these steps.
1. Open a command shell on your device and run this command. It will copy the script to your local folder.
```console
curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md -o activate-pcore-license.ps1
```
2. [Create a new automation account](https://ms.portal.azure.com/#create/Microsoft.AutomationAccount) or open an existing one.
1. Select *Run as accounts* in the **Account Settings** group, open the automatically created *Azure Run As Account* and note or copy the Display Name property.
1. Select *Runbooks* in the **Process automation** group and click on *Import a runbook*, select the file you downloaded in Step 1 and click **Create**.
1. When import is completed, click the *Publish* button.
1. From the runbook blade, click on the *Link to schedule* button and select an existing schedule or create a new one withand spesify the designed launch time.
1. Click on *Parameters and run settings* and specify the following parameters:
- LICENSEID. Put in teh resourec URI
1. Click **OK** to link to the schedule and **OK** again to create the job.
For more information about the runbooks, see the [Runbook tutorial](https://docs.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual-powershell)
@@ -0,0 +1,36 @@
<#
.DESCRIPTION
This runbook activates a SQL Server license using the Managed Identity
The runbook accepts the following parameters:
-LicenseID (The license resource URI)
.NOTES
AUTHOR: Alexander (Sasha) Nosov
LASTEDIT: June 24, 2024
#>
param (
[Parameter (Mandatory= $true)]
[string] $LicenseId,
)
#
# Suppress warnings
#
Update-AzConfig -DisplayBreakingChangeWarning $false
# Logging in to Azure..."
try
{
Connect-AzAccount -Identity
}
catch {
Write-Error -Message $_.Exception
throw $_.Exception
}
$currentLicense = Get-AzResource -ResourceId $LicenseId
$currentLicense.properties.activationState = "Activated"
$currentLicense | Set-AzResource -Force
@@ -0,0 +1,209 @@
param (
[Parameter (Mandatory=$true)]
[string]$AzureSubscriptionId,
[Parameter (Mandatory=$true)]
[string]$AzureResourceGroupUri,
[Parameter (Mandatory=$true)]
[string]$AzureRegion,
[Parameter (Mandatory=$false)]
[string]$SqlServerInstanceName,
[Parameter (Mandatory=$true)]
[string]$SqlServerAdminAccounts,
[Parameter (Mandatory=$true)]
[string]$SqlServerSvcAccount,
[Parameter (Mandatory=$true)]
[string]$SqlServerSvcPassword,
[Parameter (Mandatory=$true)]
[string]$SqlServerVersion,
[Parameter (Mandatory=$true)]
[string]$SqlServerEdition,
[Parameter (Mandatory=$true)]
[string]$SqlServerProductKey,
[Parameter (Mandatory=$true)]
[string]$isoURL
)
# This function checks if the specified module is imported into the session and if not installes and/or imports it
function LoadModule
{
param (
[parameter(Mandatory = $true)][string] $name
)
$retVal = $true
if (!(Get-Module -Name $name))
{
$retVal = Get-Module -ListAvailable | Where-Object {$_.Name -eq $name}
if ($retVal)
{
try
{
Import-Module $name -ErrorAction SilentlyContinue
}
catch
{
write-host "The request to lload module $($name) failed with the following error:"
write-host $_.Exception.Message
$retVal = $false
}
}
else {
# If module is not imported, not available on disk, but is in online gallery then install and import
if (Find-Module -Name $name) {
Install-Module -Name $name -Force -Verbose -Scope CurrentUser
try
{
Import-Module $name -ErrorAction SilentlyContinue
}
catch
{
write-host "The request to lload module $($name) failed with the following error:"
write-host $_.Exception.Message
$retVal = $false
}
}
else {
# If module is not imported, not available and not in online gallery then abort
write-host "Module $($name) not imported, not available and not in online gallery, exiting."
EXIT 1
}
}
}
return $retVal
}
try {
#Step 0: Ensure PS version and load missing Azure modules
#
# Suppress warnings
#
Update-AzConfig -DisplayBreakingChangeWarning $false
# Load required modules
$requiredModules = @(
"AzureAD",
"Az.Accounts",
"Az.ConnectedMachine",
"Az.ResourceGraph"
)
$requiredModules | Foreach-Object {LoadModule $_}
# Step 1: Check if setup.exe is already running and kill it if so
if (Get-Process setup -ErrorAction SilentlyContinue) {
Stop-Process -Name setup -Force
Write-Host "Existing setup.exe process terminated."
}
# Step 2: Log in to Azure
Connect-AzAccount
$subscription = Get-AzSubscription -SubscriptionId $AzureSubscriptionId -ErrorAction SilentlyContinue
if (-not $subscription) {
Write-Error "Azure subscription with ID '$AzureSubscriptionId' does not exist."
exit
}
# Step 2: Block auto-onboarding to Arc by tagging the resource group
$existingResourceGroup = Get-AzResourceGroup -Name $AzureResourceGroupUri -ErrorAction SilentlyContinue
if ($existingResourceGroup) {
Write-Host "Resource group '$AzureResourceGroupUri' exists."
} else {
Write-Error "Resource group '$AzureResourceGroupUri' does not exist."
exit
}
$tags = @{"ArcOnboarding" = "Blocked"}
Set-AzResourceGroup -Name $AzureResourceGroupUri -Tag $tags
# Step 3: Onboard the VM to Azure Arc
$hostName = (Get-WmiObject Win32_ComputerSystem).Name
New-AzConnectedMachine -ResourceGroupName $AzureResourceGroupUri -Name $hostName -Location $AzureRegion
# Step 4: Automatically download installable media
$isoLocation = "C:\download\SQLServer.iso"
if (!(Test-Path -Path $isoLocation)) {
$freeSpace = (Get-PSDrive -Name C).Free
$isoSize = (Invoke-WebRequest -Uri $isoURL -Method Head).Headers.'Content-Length'
if ($freeSpace -gt $isoSize) {
Start-BitsTransfer -Source $isoURL -Destination $isoLocation
} else {
throw "Not enough free space to download the ISO."
}
}
# Step 5: Mount the ISO file as a volume
$volumeInfo = Mount-DiskImage -ImagePath $isoLocation -PassThru | Get-Volume
# Step 6: Run unattended SQL Server setup from the mounted volume
$setupPath = ($volumeInfo.DriveLetter + ":\setup.exe")
$argumentList = "
/q
/ACTION=Install
/FEATURES=SQL
/INSTANCEDIR=C:\SQL
/SQLSYSADMINACCOUNTS='$($SqlServerAdminAccounts)'
/SQLSVCACCOUNT='$($SqlServerSvcAccount)'
/SQLSVCPASSWORD='$($SqlServerSvcPassword)'
/AGTSVCACCOUNT='$($SqlServerSvcAccount)'
/AGTSVCPASSWORD='$($SqlServerSvcPassword)'
/IACCEPTSQLSERVERLICENSETERMS
/PID='$($SqlServerProductKey)'
/Edition='$($SqlServerEdition)'
"
if ($SqlServerInstanceName) {
$argumentList += "/INSTANCENAME='$($SqlServerInstanceName)'"
}
Start-Process -FilePath $setupPath -ArgumentList $argumentList
# Step 7: Install SQL Arc extension with LT=PAYG
$Settings = @{
SqlManagement = @{ IsEnabled = $true };
LicenseType = "PAYG";
enableExtendedSecurityUpdates = $True;
esuLastUpdatedTimestamp = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
}
New-AzConnectedMachineExtension -ResourceGroupName $AzureResourceGroupUri -MachineName $hostName -Name "WindowsAgent.SqlServer" -Publisher "Microsoft.AzureData" -Type "WindowsAgent.SqlServer" -TypeHandlerVersion "1.0" -Settings $settings
# Step 9: Dismount the ISO file after installation
Dismount-DiskImage -ImagePath $isoLocation
# Step 10: Remove the media from the local file system
Remove-Item -Path $isoLocation
# Step 8: Display the status of the Azure resource for Arc-enabled SQL Server
$query = "
resources
| where type =~ 'microsoft.hybridcompute/machines'
| where resourceGroup =~ '$($AzureResourceGroupUri)'
| where properties.detectedProperties.mssqldiscovered == 'true'
| extend machineIdHasSQLServerDiscovered = id
| project name, machineIdHasSQLServerDiscovered, resourceGroup, subscriptionId
| join kind= leftouter (
resources
| where type == 'microsoft.hybridcompute/machines/extensions' | where properties.type in ('WindowsAgent.SqlServer','LinuxAgent.SqlServer')
| extend machineIdHasSQLServerExtensionInstalled = iff(id contains '/extensions/WindowsAgent.SqlServer' or id contains '/extensions/LinuxAgent.SqlServer', substring(id, 0, indexof(id, '/extensions/')), '')
| project Extension_State = properties.provisioningState,
License_Type = properties.settings.LicenseType,
ESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,'enabled','disabled'), ''),
Extension_Version = properties.instanceView.typeHandlerVersion,
machineIdHasSQLServerExtensionInstalled)on $left.machineIdHasSQLServerDiscovered == $right.machineIdHasSQLServerExtensionInstalled
| where isnotempty(machineIdHasSQLServerExtensionInstalled)
| project-away machineIdHasSQLServerDiscovered, machineIdHasSQLServerExtensionInstalled
"
Search-AzGraph -Query "$($query)"
} catch {
Write-Error "An error occurred: $_"
# You can add additional error handling logic here
} finally {
# Cleanup or other actions that should always run
Write-Host "Script execution completed."
}