From cb2e9459ee36466a7ea83d80634702a13c7a2a15 Mon Sep 17 00:00:00 2001 From: anosov1960 Date: Tue, 12 Jan 2021 12:01:56 -0800 Subject: [PATCH] Major rewrite --- samples/manage/azure-hybrid-benefit/README.md | 2 +- .../sql-license-usage-old.ps1 | 392 ------------------ .../sql-license-usage.csv | 2 - 3 files changed, 1 insertion(+), 395 deletions(-) delete mode 100644 samples/manage/azure-hybrid-benefit/sql-license-usage-old.ps1 delete mode 100644 samples/manage/azure-hybrid-benefit/sql-license-usage.csv diff --git a/samples/manage/azure-hybrid-benefit/README.md b/samples/manage/azure-hybrid-benefit/README.md index 313155b3..78685dd5 100644 --- a/samples/manage/azure-hybrid-benefit/README.md +++ b/samples/manage/azure-hybrid-benefit/README.md @@ -8,7 +8,7 @@ ms.date: 1/11/2021 # Overview -This script provided a simple solution to analyze adn track the consolidated utilization of SQL Server licenses by all of the SQL resources in a specific subscription or the entire the account. By default, the script scans all subscriptions the user account has access. Alternatively, you can specify a single subscription or a .CSV file with a list of subscription. The usage report includes the following information for each scanned subscription. +This script provides a simple solution to analyze adn track the consolidated utilization of SQL Server licenses by all of the SQL resources in a specific subscription or the entire the account. By default, the script scans all subscriptions the user account has access. Alternatively, you can specify a single subscription or a .CSV file with a list of subscription. The usage report includes the following information for each scanned subscription. | **Category** | **Description** | |:--|:--| diff --git a/samples/manage/azure-hybrid-benefit/sql-license-usage-old.ps1 b/samples/manage/azure-hybrid-benefit/sql-license-usage-old.ps1 deleted file mode 100644 index 3e990585..00000000 --- a/samples/manage/azure-hybrid-benefit/sql-license-usage-old.ps1 +++ /dev/null @@ -1,392 +0,0 @@ -# ---------------------------------------------------------------------------------- -# -# Copyright Microsoft Corporation -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------------- -# -# Sample script to calculate the consolidated SQL Server license usage by all of the SQL resources in a specific subscription or the entire the account. PowerShell 7$PSverionTable.1 or higher is required. -# -# This script accepts a -SubId parameter to specify a single subscription or a .CSV file with a list of subscription. If omitted, all subsriptions in the account will be scanned. -# To create such a .CSV file, use the following command and then edit to remove the subscriptions you don't want to scan: -# > Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation -# -# The results are saved to a .\sql-license-usage.csv or the database table sql-license-usage if specidied. To save the results in the table, you must provide the following parameters to the script: -# -S [protocol:]server[instance_name][,port] -# -D database_name -# -U user_name -# -P password -# -# NOTE: The script does not calculate usage for Azure SQL resources that use the DTU-based purchasing model -# - -param ([string] $SubId, [string] $S, [string] $U, [string] $P, [string] $D, [Boolean] $UseInRunbook = $False, [Boolean] $UseEC = $False) - -#The following block is required for runbooks only -if ($UseInRunbook){ - # Ensures you do not inherit an AzContext in your runbook - Disable-AzContextAutosave –Scope Process - - $connection = Get-AutomationConnection -Name AzureRunAsConnection - - # Wrap authentication in retry logic for transient network failures - $logonAttempt = 0 - while(!($connectionResult) -and ($logonAttempt -le 10)) - { - $LogonAttempt++ - # Logging in to Azure... - $connectionResult = Connect-AzAccount ` - -ServicePrincipal ` - -Tenant $connection.TenantID ` - -ApplicationId $connection.ApplicationID ` - -CertificateThumbprint $connection.CertificateThumbprint - - Start-Sleep -Seconds 5 - } -} - -# Subscriptions to scan - -if ($SubId -like "*.csv") { - $subscriptions = Import-Csv $args[0] -}elseif($SubId -ne $null){ - $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -}else{ - $subscriptions = Get-AzSubscription -} -$SubId -$subscriptions - -[Boolean] $useDatabase = $PSBoundParameters.ContainsKey("S") -and $PSBoundParameters.ContainsKey("U") -and $PSBoundParameters.ContainsKey("P") -and $PSBoundParameters.ContainsKey("D") - -#Initialize tables and arrays - -if ($useDatabase){ - - #Database setup - - [String] $tableName = "Usage-per-subscription" - [String] $testSQL = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES - WHERE TABLE_SCHEMA = 'dbo' - AND TABLE_NAME = '$tableName'" - [String] $createSQL = "CREATE TABLE [dbo].[$tableName]( - [Date] [date] NOT NULL, - [Time] [time](7) NOT NULL, - [SubscriptionName] [nvarchar](50) NOT NULL, - [SubscriptionID] [nvarchar](50) NOT NULL, - [AHB_EC] [int] NULL, - [PAYG_EC] [int] NULL, - [AHB_STD_vCores] [int] NULL, - [AHB_ENT_vCores] [int] NULL, - [PAYG_STD_vCores] [int] NULL, - [PAYG_ENT_vCores] [int] NULL, - [HADR_STD_vCores] [int] NULL, - [HADR_ENT_vCores] [int] NULL, - [Developer_vCores] [int] NULL, - [Express_vCores] [int] NULL)" - [String] $insertSQL = "INSERT INTO [dbo].[$tableName]( - [Date], - [Time], - [SubscriptionName], - [SubscriptionID], - [AHB_EC], - [PAYG_EC], - [AHB_STD_vCores], - [AHB_ENT_vCores], - [PAYG_STD_vCores], - [PAYG_ENT_vCores], - [HADR_STD_vCores], - [HADR_ENT_vCores], - [Developer_vCores], - [Express_vCores]) - VALUES - ('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}','{13}')" - $propertiesToSplat = @{ - Database = $D - ServerInstance = $S - User = $U - Password = $P - Query = $testSQL - } - - # Create table if does not exist - if ((Invoke-SQLCmd @propertiesToSplat).Column1 -eq 0) { - $propertiesToSplat.Query = $createSQL - Invoke-SQLCmd @propertiesToSplat - } - -}else{ - - #File setup - - [String] $fileName = '.\sql-license-usage.csv' - [System.Collections.ArrayList]$usageTable = @() - $usageTable += ,(@("Date", "Time", "Subscription Name", "Subscription ID", "AHB ECs", "PAYG ECs", "AHB Std vCores", "AHB Ent vCores", "PAYG Std vCores", "PAYG Ent vCores", "HADR Std vCores", "HADR Ent vCores", "Developer vCores", "Express vCores")) -} - -$subtotal = [pscustomobject]@{ahb_std=0; ahb_ent=0; payg_std=0; payg_ent=0; hadr_std=0; hadr_ent=0; developer=0; express=0} -$total = [pscustomobject]@{} -$subtotal.psobject.properties.name | %{$total | Add-Member -MemberType NoteProperty -Name $_ -Value 0} - -#Save the VM SKU table for future use - -$VM_SKUs = Get-AzComputeResourceSku - -Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --") - -# Calculate usage for each subscription - -foreach ($sub in $subscriptions){ - - if ($sub.State -ne "Enabled") {continue} - - try { - Set-AzContext -SubscriptionId $sub.Id - }catch { - write-host "Invalid subscription: " $sub.Id - {continue} - } - - # Reset the subtotals - $subtotal.psobject.properties.name | %{$subtotal.$_ = 0} - - #Get all logical servers - $servers = Get-AzSqlServer - - #Get all SQL database resources in the subscription - $databases = $servers | Get-AzSqlDatabase - - # Process the vCore-based databases - foreach ($db in $databases ){ - if ($db.SkuName -eq "ElasticPool") {continue} - - if ($db.LicenseType -eq "LicenseIncluded") { - if ($db.Edition -eq "BusinessCritical") { - $subtotal.ahb_ent += $db.Capacity - } elseif ($db.Edition -eq "GeneralPurpose") { - $subtotal.ahb_std += $db.Capacity - } - }else{ - if ($db.Edition -eq "BusinessCritical") { - $subtotal.payg_ent += $db.Capacity - } elseif ($db.Edition -eq "GeneralPurpose") { - $subtotal.payg_std += $db.Capacity - } - } - } - - #Get all SQL elastic pool resources in the subscription - $pools = $servers | Get-AzSqlElasticPool - - # Process the vCore-based elastic pools - foreach ($pool in $pools){ - if ($pool.LicenseType -eq "LicenseIncluded") { - if ($pool.Edition -eq "BusinessCritical") { - $subtotal.ahb_ent += $pool.Capacity - } elseif ($pool.Edition -eq "GeneralPurpose") { - $subtotal.ahb_std += $pool.Capacity - } - }else{ - if ($pool.Edition -eq "BusinessCritical") { - $subtotal.payg_ent += $pool.Capacity - } elseif ($pool.Edition -eq "GeneralPurpose") { - $subtotal.payg_std += $pool.Capacity - } - } - } - - #Get all SQL managed instance resources in the subscription - $instances = Get-AzSqlInstance - - # Process the SQL managed instances with License Included and add to VCore count - foreach ($ins in $instances){ - if ($ins.InstancePoolName -eq $null){ - if ($ins.LicenseType -eq "LicenseIncluded") { - if ($ins.Sku.Tier -eq "BusinessCritical") { - $subtotal.ahb_ent += $ins.VCores - } elseif ($ins.Sku.Tier -eq "GeneralPurpose") { - $subtotal.ahb_std += $ins.VCores - } - }else{ - if ($ins.Edition -eq "BusinessCritical") { - $subtotal.payg_ent += $pool.Capacity - } elseif ($ins.Edition -eq "GeneralPurpose") { - $subtotal.payg_std += $ins.Capacity - } - } - } - } - - #Get all instance pool resources in the subscription - $ipools = Get-AzSqlInstancePool - - # Process the instance pools - foreach ($ip in $ipools){ - if ($ip.LicenseType -eq "LicenseIncluded") { - if ($ip.Edition -eq "BusinessCritical") { - $subtotal.ahb_ent += $ip.VCores - } elseif ($ip.Edition -eq "GeneralPurpose") { - $subtotal.ahb_std += $ip.VCores - } - }else{ - if ($ip.Edition -eq "BusinessCritical") { - $subtotal.payg_ent += $ip.Capacity - } elseif ($ip.Edition -eq "GeneralPurpose") { - $subtotal.payg_std += $ip.Capacity - } - } - } - - - #Get all SSIS imtegration runtime resources in the subscription - $ssis_irs = Get-AzResourceGroup | Get-AzDataFactoryV2 | Get-AzDataFactoryV2IntegrationRuntime - - # Get the VM size, match it with the corresponding VCPU count and add to VCore count - foreach ($ssis_ir in $ssis_irs){ - # Select first size and get the VCPus available - $size_info = $VM_SKUs | where { $_.Name -like $ssis_ir.NodeSize} | Select-Object -First 1 - - # Save the VCPU count - $vcpu= $size_info.Capabilities | Where-Object {$_.name -eq "vCPUsAvailable"} - - if ($ssis_ir.State -eq "Started"){ - if ($ssis_ir.LicenseType -like "LicenseIncluded"){ - if ($ssis_ir.Edition -like "Enterprise"){ - $subtotal.ahb_ent += $vcpu.value - }elseif ($ssis_ir.Edition -like "Standard"){ - $subtotal.ahb_std += $vcpu.value - } - }elseif ($data.license -like "BasePrice"){ - if ($ssis_ir.Edition -like "Enterprise"){ - $subtotal.payg_ent += $vcpu.value - }elseif ($ssis_ir.Edition -like "Standard"){ - $subtotal.payg_std += $vcpu.value - }elseif ($ssis_ir.Edition -like "Developer"){ - $subtotal.developer += $vcpu.value - }elseif ($ssis_ir.Edition -like "Express"){ - $subtotal.express += $vcpu.value - } - } - } - } - - - #Get All SQL VMs resources in the subscription - $sql_vms = Get-AzSqlVM - - # Get the VM size, match it with the corresponding VCPU count and add to VCore count - foreach ($sql_vm in $sql_vms){ - $vm = Get-AzVm -Name $sql_vm.Name -ResourceGroupName $sql_vm.ResourceGroupName - $vm_size = $vm.HardwareProfile.VmSize - # Select first size and get the VCPus available - $size_info = $VM_SKUs | where {$_.ResourceType.Contains('virtualMachines') -and $_.Name -like $vm_size} | Select-Object -First 1 - # Save the VCPU count - $vcpu= $size_info.Capabilities | Where-Object {$_.name -eq "vCPUsAvailable"} - - if ($vcpu){ - $data = [pscustomobject]@{vm_resource_uri=$vm.Id;sku=$sql_vm.Sku;license=$sql_vm.LicenseType;size=$vm_size;vcpus=$vcpu.value} - - if ($data.license -like "DR"){ - if ($data.sku -like "Enterprise"){ - $subtotal.hadr_ent += $data.vcpus - }elseif ($data.sku -like "Standard"){ - $subtotal.hadr_std += $data.vcpus - } - }elseif ($data.license -like "AHUB"){ - if ($data.sku -like "Enterprise"){ - $subtotal.ahb_ent += $data.vcpus - }elseif ($data.sku -like "Standard"){ - $subtotal.ahb_std += $data.vcpus - } - }elseif ($data.license -like "PAYG"){ - if ($data.sku -like "Enterprise"){ - $subtotal.payg_ent += $data.vcpus - }elseif ($data.sku -like "Standard"){ - $subtotal.payg_std += $data.vcpus - }elseif ($data.sku -like "Developer"){ - $subtotal.developer += $data.vcpus - }elseif ($data.sku -like "Express"){ - $subtotal.express += $data.vcpus - } - } - } - } - - # Get All VMs hosts in the subscription - $host_groups = Get-AzHostGroup - - # Get the dedicated host size, match it with the corresponding VCPU count and add to VCore count - - foreach ($host_group in $host_groups){ - - $vm_hosts = $host_group | Select-Object -Property @{Name = 'HostGroupName'; Expression = {$_.Name}},@{Name = 'ResourceGroupName'; Expression = {$_.ResourceGroupName}} | Get-AzHost - - foreach ($vm_host in $vm_hosts){ - - $token = (Get-AzAccessToken).Token - $params = @{ - Uri = "https://management.azure.com/subscriptions/" + $sub + - "/resourceGroups/" + $vm_host.ResourceGroupName.ToLower() + - "/providers/Microsoft.Compute/hostGroups/" + $host_group.Name + - "/hosts/" + $vm_host.Name + - "/providers/Microsoft.SoftwarePlan/hybridUseBenefits/SQL_" + $host_group.Name + "_" + $vm_host.Name + "?api-version=2019-06-01-preview" - Headers = @{ 'Authorization' = "Bearer $token" } - Method = 'GET' - ContentType = 'application/json' - } - - $softwarePlan = Invoke-RestMethod @params - if ($softwarePlan.Sku.Name -like "SQL*"){ - $size_info = $VM_SKUs | where {$_.ResourceType.Contains('hostGroups/hosts') -and $_.Name.Contains($vm_host.Sku.Name)} | Select-Object -First 1 - $cores= $size_info.Capabilities | Where-Object {$_.name -eq "Cores"} - $subtotal.ahb_ent += $cores.Value - } - } - } - - # Increment the totals and add subtotals to the usage array - - $subtotal.psobject.properties.name | %{$total.$_ += $subtotal.$_} - - $Date = Get-Date -Format "yyy-MM-dd" - $Time = Get-Date -Format "HH:mm:ss" - if ($includeEC -eq $null){ - $ahb_ec = 0 - $payg_ec = 0 - }else{ - $ahb_ec = ($subtotal.ahb_std + $subtotal.ahb_ent*4) - $payg_ec = ($subtotal.payg_std + $subtotal.payg_ent*4) - } - if ($useDatabase){ - $propertiesToSplat.Query = $insertSQL -f $Date, $Time, $sub.Name, $sub.Id, $ahb_ec, $payg_ec, $subtotal.ahb_std, $subtotal.ahb_ent, $subtotal.payg_std, $subtotal.payg_ent, $subtotal.hadr_std, $subtotal.hadr_ent, $subtotal.developer, $subtotal.express - Invoke-SQLCmd @propertiesToSplat - }else{ - $usageTable += ,(@($Date, $Time, $sub.Name, $sub.Id, $ahb_ec, $payg_ec, $subtotal.ahb_std, $subtotal.ahb_ent, $subtotal.payg_std, $subtotal.payg_ent, $subtotal.hadr_std, $subtotal.hadr_ent, $subtotal.developer, $subtotal.express)) - ($usageTable | %{ $_ -join ','} ) | Write-Host - } -} - -# Add the total numbers to the usage array - -#if ($includeEC -eq $null){ -# $usageTable += ,(@($Date, $Time, "Total", $null, $total.ahb_std, $total.ahb_ent, $total.payg_std, $total.payg_ent, $total.hadr_std, $total.hadr_ent, $total.developer, $total.express)) -#}else{ -# $usageTable += ,(@(($Date, $Time$total, "Total", $null, ($total.ahb_std + $total.ahb_ent*4), ($total.payg_std + $total.payg_ent*4), $total.ahb_std, $total.ahb_ent, $total.payg_std, $total.payg_ent, $total.hadr_std, $total.hadr_ent, $total.developer, $total.express)) -#} - -if ($useDatabase){ - Write-Host ([Environment]::NewLine + "-- Added the usage data to $tableName table --") -}else{ - - # Write usage data to the .csv file - - ($usageTable | %{ $_ -join ','} ) | Out-file -FilePath $fileName -Append - Write-Host ([Environment]::NewLine + "-- Added the usage data to $fileName --") -} \ No newline at end of file diff --git a/samples/manage/azure-hybrid-benefit/sql-license-usage.csv b/samples/manage/azure-hybrid-benefit/sql-license-usage.csv deleted file mode 100644 index bb467516..00000000 --- a/samples/manage/azure-hybrid-benefit/sql-license-usage.csv +++ /dev/null @@ -1,2 +0,0 @@ -Date,Time,Subscription Name,Subscription ID,AHB ECs,PAYG ECs,AHB Std vCores,AHB Ent vCores,PAYG Std vCores,PAYG Ent vCores,HADR Std vCores,HADR Ent vCores,Developer vCores,Express vCores -2020-12-31,13:52:07,geodr_m2_365640,10a238d6-a139-46d0-818d-d091394072b6,0,0,48,17,2,1,0,0,0,0