From 09647386dd192e93eae2cd3c5675b7880a5953d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 04:13:26 +0000 Subject: [PATCH 001/159] Bump ejs Bumps [ejs](https://github.com/mde/ejs) from 3.1.8 to 3.1.10. - [Release notes](https://github.com/mde/ejs/releases) - [Commits](https://github.com/mde/ejs/compare/v3.1.8...v3.1.10) --- updated-dependencies: - dependency-name: ejs dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../SqlDbEdgeDemo.Web/ClientApp/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 76a6dc205f..5dc1f9f1f1 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -4937,9 +4937,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "ejs": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", - "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "requires": { "jake": "^10.8.5" } From 5bfe458854f8a80b22efad2b71590e13857a0bdd Mon Sep 17 00:00:00 2001 From: Alex Talarico <3521183+getalex@users.noreply.github.com> Date: Wed, 15 May 2024 21:36:18 -0400 Subject: [PATCH 002/159] Updated logging logic and format to CSV (ssrs_migration.rss) Added header to generated CSV log file enhancements to logging output generated, color scheme updates. --- .../ssrs-migration-rss/ssrs_migration.rss | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss b/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss index ac67503709..49164e10af 100644 --- a/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss +++ b/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss @@ -75,7 +75,7 @@ Private policies As Policy() = Nothing Private srcSiteUrl As String = Nothing Private snkSiteUrl As String = Nothing -Private logFilePath As String = "MigrationLog.txt" +Private logFilePath As String = "MigrationLog.csv" '''''''''''''''''''''''''''''''''''''''''''''' Sub Main() @@ -241,8 +241,8 @@ Sub Main() RsSnk.CreateFolder(folderName, parentFolder, Nothing) Catch er As Exception If (er.Message.Contains("Microsoft.ReportingServices.Diagnostics.Utilities.ItemAlreadyExistsException")) - Console.ForegroundColor = ConsoleColor.Yellow - Console.WriteLine("Folder already exists.") + Console.ForegroundColor = ConsoleColor.Gray + Console.WriteLine("Folder already exists: " + folderName) Console.ResetColor() Else Throw ' Unknown Exception @@ -478,7 +478,7 @@ Function MigrateDataSource(srcItem As CatalogItem) As CatalogItem Console.WriteLine(warningMsg) Console.ResetColor() - LogErrorToFile("CATALOGITEM", "Warning", warningMsg) + LogErrorToFile("CATALOGITEM", "Warning: " + result.Path, warningMsg) End If @@ -567,7 +567,7 @@ Function MigrateCatalogItem(srcItem As CatalogItem) As CatalogItem Console.WriteLine(warningMsg) Console.ResetColor() - LogErrorToFile("CATALOGITEM", "Warning", warningMsg) + LogErrorToFile("CATALOGITEM", "Warning: " + result.TypeName, warningMsg) End If End If Next @@ -742,7 +742,7 @@ Sub MigrateReportSubscriptions(snkReport As CatalogItem, srcReport As CatalogIte Console.Write(description) If Not dataRetrievalPlan Is Nothing And TypeOf dataRetrievalPlan.Item Is DataSourceReference Then Dim item As DataSourceReference = dataRetrievalPlan.Item - Dim ref As String = GetSnkPath(item.Reference) + Dim ref As String = GetSnkPathRef(item.Reference) item.Reference = ref End If RsSnk.CreateDataDrivenSubscription(snkReport.Path, extensionSettings, dataRetrievalPlan, description, eventType, GetMatchData(matchData, RsSnk), parameters) @@ -756,7 +756,7 @@ Sub MigrateReportSubscriptions(snkReport As CatalogItem, srcReport As CatalogIte Console.WriteLine(warningMsg) Console.ResetColor() - LogErrorToFile("SUBSCRIPTIONS", "Warning", warningMsg) + LogErrorToFile("SUBSCRIPTIONS", "Warning: " + snkReport.Path, warningMsg) End If End If @@ -795,9 +795,9 @@ Sub MigrateReportSubscriptions(snkReport As CatalogItem, srcReport As CatalogIte Console.WriteLine(warningMsg) Console.ResetColor() - LogErrorToFile("SUBSCRIPTIONS", "Warning", warningMsg) + LogErrorToFile("SUBSCRIPTIONS", "Warning: " + snkReport.Path, warningMsg) - End If + End If Next Catch ex As Exception @@ -990,10 +990,19 @@ End Sub 'Helper function to link snk reference with relative paths Function GetSnkPathRef(srcPath As String) As String - Dim snkPath = srcPath - If srcSiteUrl isNot Nothing - snkPath = srcPath.Remove(0, srcSiteUrl.LastIndexOf("/")) - End If + Dim snkPath = srcPath + + If Not SrcIsNative Then + 'SharePoint integrated mode, will assume /sites server relative URL delimeter + If srcSiteUrl isNot Nothing + Dim delimeter = "/sites/" + snkPath = srcPath.Remove(0, srcSiteUrl.IndexOf(delimeter) + delimeter.Length-1) + End If + Else + 'Treat path reference like other scenarios if not intergated mode + snkPath = GetSnkPath(srcPath) + End If + Return snkPath End Function @@ -1189,12 +1198,18 @@ Sub LogErrorToFile(source As String, errItem as String, message As String) Dim writer as StreamWriter Try + Dim fileExists As Boolean = Not File.Exists(logFilePath) OrElse New FileInfo(logFilePath).Length = 0 + ' Create a StreamWriter object writer = New StreamWriter(logFilePath, True) + If fileExists Then + writer.WriteLine("DateTime, Source, ErrorItem, ErrorMessage") + End If + ' Format log message with timestamp Dim timeStamp As String = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") - Dim formattedMessage as String = String.Format("{0}, {1}, {2}, ""{3}""", timeStamp, source, errItem, message.Replace(Environment.NewLine, "")) + Dim formattedMessage as String = String.Format("{0}, {1}, {2}, ""{3}""", timeStamp, source, errItem, message.Replace(Environment.NewLine, " ")) ' Write the log entry to file writer.WriteLine(formattedMessage) From ca425596f3df435ff2e669f9ef477f053090ce6f Mon Sep 17 00:00:00 2001 From: Monem Date: Sat, 18 May 2024 01:13:59 +0300 Subject: [PATCH 003/159] fix wwi-ssis package file: "DailyETLMain.dtsx" --- .../wwi-ssis/wwi-ssis/DailyETLMain.dtsx | 6253 ++++++++++++++++- 1 file changed, 6252 insertions(+), 1 deletion(-) diff --git a/samples/databases/wide-world-importers/wwi-ssis/wwi-ssis/DailyETLMain.dtsx b/samples/databases/wide-world-importers/wwi-ssis/wwi-ssis/DailyETLMain.dtsx index e3a97158cd..796d73cf74 100644 --- a/samples/databases/wide-world-importers/wwi-ssis/wwi-ssis/DailyETLMain.dtsx +++ b/samples/databases/wide-world-importers/wwi-ssis/wwi-ssis/DailyETLMain.dtsx @@ -6829,4 +6829,6255 @@ WITH RESULT SETS WITH RESULT SETS ( ( - [WWI Stock Item ID] int, \ No newline at end of file + [WWI Stock Item ID] int, + [Stock Item] nvarchar(100), + Color nvarchar(20), + [Selling Package] nvarchar(50), + [Buying Package] nvarchar(50), + Brand nvarchar(50), + Size nvarchar(20), + [Lead Time Days] int, + [Quantity Per Outer] int, + [Is Chiller Stock] bit, + Barcode nvarchar(50), + [Tax Rate] decimal(18,3), + [Unit Price] decimal(18,2), + [Recommended Retail Price] decimal(18,2), + [Typical Weight Per Unit] decimal(18,3), + Photo varbinary(max), + [Valid From] datetime2(7), + [Valid To] datetime2(7) + ) +); + + 1252 + false + 2 + "@LastCutoff:Input",{60BD9010-4784-49A6-8FF2-340D7AB3B70D};"@NewCutoff:Input",{B96D08A3-EC4E-45C1-8E78-526920753C6B}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + [Integration].[StockItem_Staging] + + + 1252 + false + 3 + false + false + CHECK_CONSTRAINTS + 2147483647 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + EXEC Integration.GetSupplierUpdates ?, ? +WITH RESULT SETS +( + ( + [WWI Supplier ID] int, + Supplier nvarchar(100), + Category nvarchar(50), + [Primary Contact] nvarchar(50), + [Supplier Reference] nvarchar(20), + [Payment Days] int, + [Postal Code] nvarchar(10), + [Valid From] datetime2(7), + [Valid To] datetime2(7) + ) +); + + 1252 + false + 2 + "@LastCutoff:Input",{60BD9010-4784-49A6-8FF2-340D7AB3B70D};"@NewCutoff:Input",{B96D08A3-EC4E-45C1-8E78-526920753C6B}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + [Integration].[Supplier_Staging] + + + 1252 + false + 3 + false + false + CHECK_CONSTRAINTS + 2147483647 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + EXEC Integration.GetTransactionUpdates ?, ? +WITH RESULT SETS +( + ( + [Date Key] date, + [WWI Customer Transaction ID] int, + [WWI Supplier Transaction ID] int, + [WWI Invoice ID] int, + [WWI Purchase Order ID] int, + [Supplier Invoice Number] nvarchar(20), + [Total Excluding Tax] decimal(18,2), + [Tax Amount] decimal(18,2), + [Total Including Tax] decimal(18,2), + [Outstanding Balance] decimal(18,2), + [Is Finalized] bit, + [WWI Customer ID] int, + [WWI Bill To Customer ID] int, + [WWI Supplier ID] int, + [WWI Transaction Type ID] int, + [WWI Payment Method ID] int, + [Last Modified When] datetime2(7) + ) +); + + 1252 + false + 2 + "@LastCutoff:Input",{60BD9010-4784-49A6-8FF2-340D7AB3B70D};"@NewCutoff:Input",{B96D08A3-EC4E-45C1-8E78-526920753C6B}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + [Integration].[Transaction_Staging] + + + 1252 + false + 3 + false + false + CHECK_CONSTRAINTS + 2147483647 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + EXEC Integration.GetTransactionTypeUpdates ?, ? +WITH RESULT SETS +( + ( + [WWI Transaction Type ID] int, + [Transaction Type] nvarchar(50), + [Valid From] datetime2(7), + [Valid To] datetime2(7) + ) +); + + 1252 + false + 2 + "@LastCutoff:Input",{60BD9010-4784-49A6-8FF2-340D7AB3B70D};"@NewCutoff:Input",{B96D08A3-EC4E-45C1-8E78-526920753C6B}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + [Integration].[TransactionType_Staging] + + + 1252 + false + 3 + false + false + CHECK_CONSTRAINTS + 2147483647 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataSourceViewID + + + TableInfoObjectType + Table + + + +]]> + \ No newline at end of file From b0967ce536e49ca472aafb898e89c6133b1565da Mon Sep 17 00:00:00 2001 From: WilliamDAssafMSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Tue, 21 May 2024 15:51:44 -0700 Subject: [PATCH 004/159] 20240521 ML extensibility --- samples/extensibility/Install-MLModels.ps1 | 565 ++++++++++++++++++ .../9.2.1/Install-PyForMLS.ps1 | 128 ++++ .../9.3/Install-PyForMLS.ps1 | 323 ++++++++++ samples/extensibility/TutorialDB.bak | Bin 0 -> 431104 bytes 4 files changed, 1016 insertions(+) create mode 100644 samples/extensibility/Install-MLModels.ps1 create mode 100644 samples/extensibility/Microsoft Python packages/9.2.1/Install-PyForMLS.ps1 create mode 100644 samples/extensibility/Microsoft Python packages/9.3/Install-PyForMLS.ps1 create mode 100644 samples/extensibility/TutorialDB.bak diff --git a/samples/extensibility/Install-MLModels.ps1 b/samples/extensibility/Install-MLModels.ps1 new file mode 100644 index 0000000000..a77ecbf1fb --- /dev/null +++ b/samples/extensibility/Install-MLModels.ps1 @@ -0,0 +1,565 @@ +# +# Install-MLModels.ps1 +# Copyright (C) Microsoft. All rights reserved. +# + +# See: https://learn.microsoft.com/sql/machine-learning/install/sql-pretrained-models-install + +# Verify script is being run with elevated privileges +if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) +{ + Write-Error "This script must be run as Administrator" + Exit 1 +} + +class SqlInstance +{ + static $Languages = @{` + 'R' = @{` + 'ModelsPath' = 'library\MicrosoftML\mxLibs\x64';` + 'SharedKey' = 'sql_shared_mr';` + 'DllName' = 'MR';` + 'ConfigNode' = 'mrs' };` + 'Python' = @{` + 'ModelsPath' = 'Lib\site-packages\microsoftml\mxLibs';` + 'SharedKey' = 'sql_shared_mpy';` + 'DllName' = 'MPY';` + 'ConfigNode' = 'mpy' }} + + [bool]$IsShared + [Version]$MlmVersion + [Version]$MlsVersion + [string]$Name + [string]$RootPath + [string]$RSetupPath + [string]$SqlVersion + + # + # Returns SqlInstance or $null if an error occurred + # + [SqlInstance] static Create($isShared, $instanceName, $sqlVersion) + { + $sqlInstance = [SqlInstance]::new() + + $sqlInstance.IsShared = $isShared + $sqlInstance.Name = $instanceName + $sqlInstance.SqlVersion = $sqlVersion + $sqlVersionName = ConvertSqlVersionToName( $sqlVersion ) + + if( [string]::IsNullOrEmpty($sqlVersionName) ){ + Write-Warning "Sql name not found: instance name= $($instanceName), sql version=$($sqlVersion)" + return $null + } + + if ($sqlInstance.IsShared) + { + $found = $false + foreach ($language in [SqlInstance]::Languages.Values) + { + $sharedRegPath = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$sqlVersion\$($language.SharedKey)" + $sharedKey = Get-ItemProperty -Path $sharedRegPath -ErrorAction "Ignore" + + if ($sharedKey -ne $null) + { + $sqlInstance.RootPath = (Get-Item($sharedKey.Path)).Parent.FullName + $sqlInstance.RSetupPath = "$($sqlInstance.RootPath)\Setup Bootstrap\{0}\x64\RSetup.exe" -f $sqlVersionName + $found = $true + break + } + } + if(!$found) + { + return $null + } + } + else + { + $setupRegPath = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceName\Setup" + $sqlInstance.RootPath = (Get-Item (Get-ItemProperty -Path $setupRegPath -ErrorAction "Ignore").SQLPath).Parent.FullName + $sqlInstance.RSetupPath = "{0}{1}\x64\RSetup.exe" -f` + (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$sqlVersion\Bootstrap" -ErrorAction "Ignore").BootstrapDir,` + $sqlVersionName + } + + # Set MLS version + try + { + $bindingPath = Join-Path $sqlInstance.GetLanguageFolder("R") ".sqlbindr.ini" + + if ((Test-Path $bindingPath) -and ((Get-Item -Force $bindingPath).Length -gt 0)) + { + $sqlInstance.MlsVersion = Get-Content $bindingPath + $sqlInstance.RSetupPath = Join-Path (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\R Server').Path "Setup\rsetup.exe" + } + else + { + # Get MLS version from XML resource + foreach ($language in [SqlInstance]::Languages.Values) + { + $dllName = if ($sqlInstance.IsShared) {"S$($language.DllName)Dll"} else {"I$($language.DllName)Dll"} + $dllPath = if ($sqlInstance.IsShared) {"Shared\$dllName.dll"} else {"MSSQL\Binn\$dllName.dll"} + $dllPath = Join-Path $sqlInstance.RootPath $dllPath + + if (Test-Path $dllPath) + { + $assembly = [System.Reflection.Assembly]::LoadFrom($dllPath) + $doc = New-Object System.Xml.XmlDocument + $doc.Load($assembly.GetManifestResourceStream("$dllName.$dllName.xml")) + $sqlInstance.MlsVersion = $doc.SelectSingleNode("/ConfigurationData/$($language.ConfigNode)").InnerText + break + } + } + } + } + catch + { + # Ignore exceptions + } + + # check RSetup.exe exists + if (($sqlInstance.RSetupPath -eq $null) -or !(Test-Path -Path $sqlInstance.RSetupPath -PathType Leaf)) + { + Write-Warning "RSetup.exe not found for instance name= $($instanceName), sql version=$($sqlVersion)" + return $null + } + + # Map MLS version to MLM version + if ($sqlInstance.MlsVersion.ToString(3) -eq "9.2.0") + { + $sqlInstance.MlmVersion = "9.2.0.24" + } + elseif ($sqlInstance.MlsVersion.ToString(3) -eq "9.2.1"` + -or $sqlInstance.MlsVersion.ToString(3) -eq "9.3.0"` + -or $sqlInstance.MlsVersion.ToString(3) -eq "9.4.1"` + -or $sqlInstance.MlsVersion.ToString(3) -eq "9.4.7") + { + $sqlInstance.MlmVersion = $sqlInstance.MlsVersion.ToString(3) + } + else + { + $sqlInstance.MlmVersion = $sqlInstance.MlsVersion + } + + return $sqlInstance + } + + + [string] GetLanguageFolder($language) + { + $languageFolder = $null + + if ([SqlInstance]::Languages.ContainsKey($language)) + { + if ($this.IsShared) + { + $languageFolder = Join-Path $this.RootPath "$($language)_SERVER".ToUpper() + } + else + { + $languageFolder = Join-Path $this.RootPath "$($language)_SERVICES".ToUpper() + } + } + + return $languageFolder + } +} + +# +# Retursn sql version name or $null if name was not found +# +function ConvertSqlVersionToName($sqlVersion) +{ + $sqlVersionName = $null + + foreach ($sqlKey in (Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$sqlVersion" -ErrorAction "Ignore").PSChildName) + { + try + { + if ($sqlKey -imatch "^SQL(Server)?\d+$") + { + $sqlVersionName = $sqlKey + break + } + #example: SQL2019CTP3.0 + if ($sqlKey -imatch "^SQL?\d{4}CTP\d+.\d+$") + { + $sqlVersionName = $sqlKey + break + } + } + catch + { + # Ignore exceptions + } + } + + return $sqlVersionName +} + +# +# Returns number of instances found and hash table with successfully parsed instances +# +function GetSqlInstances() +{ + $sqlInstances = @{} + + # Handle shared installs + foreach ($sqlVersion in (Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' -ErrorAction "Ignore").PSChildName) + { + try + { + $name = ConvertSqlVersionToName($sqlVersion) + if( ![string]::IsNullOrEmpty($name)) + { + $sqlInstance = [SqlInstance]::Create($true, "SHARED_{0}" -f $name.ToUpper(), $sqlVersion) + + if ( ($sqlInstance -ne $null) -and ($sqlInstance.MlmVersion -ne $null)) + { + $sqlInstances[$sqlInstance.Name] = $sqlInstance + } + } + } + catch + { + # Ignore exceptions + } + } + + # Handle per-instance installs + foreach ($sqlKey in (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL" -ErrorAction "Ignore").PSObject.Properties) + { + try + { + $versionRegPath = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$($sqlKey.Value)\MSSQLServer\CurrentVersion" + $sqlVersion = (Get-ItemProperty -Path $versionRegPath -ErrorAction "Ignore").CurrentVersion -replace '^(\d+)\.(\d).*', '${1}0' + + if( ![string]::IsNullOrEmpty($sqlVersion) ) + { + $sqlInstance = [SqlInstance]::Create($false, $sqlKey.Value, $sqlVersion) + + if (($sqlInstance -ne $null) -and ($sqlInstance.MlmVersion -ne $null)) + { + $sqlInstances[$sqlKey.Name] = $sqlInstance + } + } + } + catch + { + # Ignore exceptions + } + } + + return $sqlInstances +} + +# Handle command-line arguments +if ($Args -ne $null -and $Args.Length -gt 0) +{ + $sqlInstances = GetSqlInstances + + if( $sqlInstances.Count -eq 0){ + Write-Host "INFO: no SQL Server instances identified for model installation" + Exit 1 + } + + # Handle all instances + foreach ($arg in $Args) + { + if ($sqlInstances.ContainsKey($arg)) + { + $sqlInstance = $sqlInstances[$arg] + + Write-Host "INFO: processing instance $($sqlInstance.Name)" + + foreach ($language in [SqlInstance]::Languages.Keys) + { + $languageFolder = $sqlInstance.GetLanguageFolder($language) + if (Test-Path $languageFolder) + { + $modelsPath = [SqlInstance]::Languages[$language].ModelsPath + $installDir = Join-Path $languageFolder $modelsPath + $rsetupArgs = "/component MLM /version $($sqlInstance.MlmVersion) /language 1033 /destdir `"$installDir`"" + + # Verify models version + Write-Host "`tVerifying $language models [$($sqlInstance.MlmVersion)]" + &$sqlInstance.RSetupPath "/checkurl $rsetupArgs" 2>&1 > $null + if ($lastexitcode -eq -1 -or $lastexitcode -eq 2) + { + Write-Warning "MLS version $($sqlInstance.MlmVersion) not supported" + break + } + elseif ($lastexitcode -gt 10000) + { + Write-Warning "Error downloading models [https://go.microsoft.com/fwlink/?LinkId=$lastexitcode&clcid=1033]" + break + } + elseif ($lastexitcode -ne 0) + { + Write-Warning "rsetup.exe exited with $lastexitcode" + break + } + + # Download models, if not already cached + &$sqlInstance.RSetupPath "/checkcache $rsetupArgs" 2>&1 > $null + if ($lastexitcode -ne 0) + { + Write-Host "`tDownloading $language models [$Env:TEMP]" + &$sqlInstance.RSetupPath "/download $rsetupArgs" 2>&1 > $null + + if ($lastexitcode -gt 10000) + { + Write-Warning "Error downloading models [https://go.microsoft.com/fwlink/?LinkId=$lastexitcode&clcid=1033]" + break + } + if ($lastexitcode -ne 0) + { + Write-Warning "rsetup.exe exited with $lastexitcode" + break + } + } + + # Install models + Write-Host "`tInstalling $language models [$installDir]" + &$sqlInstance.RSetupPath "/install $rsetupArgs" 2>&1 > $null + if ($lastexitcode -eq 0) + { + Write-Host "SUCCESS installed $language for $($sqlInstance.Name)" + } + else + { + Write-Warning "rsetup.exe failed and exited with $lastexitcode for $language and $($sqlInstance.Name)" + break + } + } + } + } + else + { + Write-Warning "$($arg): invalid instance" + } + } +} +else +{ + Write-Host + Write-Host "USAGE: Install-MLModels.ps1 [ ...]" + + $sqlInstances = GetSqlInstances + + if( $sqlInstances.Count -eq 0) + { + Write-Host "NOTE: no SQL Server instances identified for model installation" + Exit 1 + } + + Write-Host + Write-Host "Available instances:" + + # Display available instances + foreach ($instanceName in $sqlInstances.Keys | Sort-Object) + { + $sqlInstance = $sqlInstances[$instanceName] + Write-Host + Write-Host "`tInstance=$($instanceName)" + Write-Host "`tIsShared=$($sqlInstance.IsShared)" + Write-Host "`tMlmVersion=$($sqlInstance.MlmVersion)" + Write-Host "`tMlsVersion=$($sqlInstance.MlsVersion)" + Write-Host "`tRootPath=$($sqlInstance.RootPath)" + Write-Host "`tRSetupPath=$($sqlInstance.RSetupPath)" + Write-Host "`tSqlVersion=$($sqlInstance.SqlVersion)" + Write-Host "`tSqlVersionName=$(ConvertSqlVersionToName($sqlInstance.SqlVersion))" + } +} + +# SIG # Begin signature block +# MIIjigYJKoZIhvcNAQcCoIIjezCCI3cCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCOTihGgHRUMJIw +# J5dFR3HXpebAuyRhtn6jmFBEPnttOKCCDYUwggYDMIID66ADAgECAhMzAAABUptA +# n1BWmXWIAAAAAAFSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD +# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p +# bmcgUENBIDIwMTEwHhcNMTkwNTAyMjEzNzQ2WhcNMjAwNTAyMjEzNzQ2WjB0MQsw +# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u +# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +# AQCxp4nT9qfu9O10iJyewYXHlN+WEh79Noor9nhM6enUNbCbhX9vS+8c/3eIVazS +# YnVBTqLzW7xWN1bCcItDbsEzKEE2BswSun7J9xCaLwcGHKFr+qWUlz7hh9RcmjYS +# kOGNybOfrgj3sm0DStoK8ljwEyUVeRfMHx9E/7Ca/OEq2cXBT3L0fVnlEkfal310 +# EFCLDo2BrE35NGRjG+/nnZiqKqEh5lWNk33JV8/I0fIcUKrLEmUGrv0CgC7w2cjm +# bBhBIJ+0KzSnSWingXol/3iUdBBy4QQNH767kYGunJeY08RjHMIgjJCdAoEM+2mX +# v1phaV7j+M3dNzZ/cdsz3oDfAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE +# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU3f8Aw1sW72WcJ2bo/QSYGzVrRYcw +# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh +# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1NDEzNjAfBgNVHSMEGDAW +# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v +# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw +# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov +# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx +# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB +# AJTwROaHvogXgixWjyjvLfiRgqI2QK8GoG23eqAgNjX7V/WdUWBbs0aIC3k49cd0 +# zdq+JJImixcX6UOTpz2LZPFSh23l0/Mo35wG7JXUxgO0U+5drbQht5xoMl1n7/TQ +# 4iKcmAYSAPxTq5lFnoV2+fAeljVA7O43szjs7LR09D0wFHwzZco/iE8Hlakl23ZT +# 7FnB5AfU2hwfv87y3q3a5qFiugSykILpK0/vqnlEVB0KAdQVzYULQ/U4eFEjnis3 +# Js9UrAvtIhIs26445Rj3UP6U4GgOjgQonlRA+mDlsh78wFSGbASIvK+fkONUhvj8 +# B8ZHNn4TFfnct+a0ZueY4f6aRPxr8beNSUKn7QW/FQmn422bE7KfnqWncsH7vbNh +# G929prVHPsaa7J22i9wyHj7m0oATXJ+YjfyoEAtd5/NyIYaE4Uu0j1EhuYUo5VaJ +# JnMaTER0qX8+/YZRWrFN/heps41XNVjiAawpbAa0fUa3R9RNBjPiBnM0gvNPorM4 +# dsV2VJ8GluIQOrJlOvuCrOYDGirGnadOmQ21wPBoGFCWpK56PxzliKsy5NNmAXcE +# x7Qb9vUjY1WlYtrdwOXTpxN4slzIht69BaZlLIjLVWwqIfuNrhHKNDM9K+v7vgrI +# bf7l5/665g0gjQCDCN6Q5sxuttTAEKtJeS/pkpI+DbZ/MIIHejCCBWKgAwIBAgIK +# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV +# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv +# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm +# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw +# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE +# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD +# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG +# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la +# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc +# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D +# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ +# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk +# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 +# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd +# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL +# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd +# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 +# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS +# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI +# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL +# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD +# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv +# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf +# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 +# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf +# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF +# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h +# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA +# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn +# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 +# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b +# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ +# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy +# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp +# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi +# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb +# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS +# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL +# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX +# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFVswghVXAgEBMIGVMH4x +# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt +# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p +# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAFSm0CfUFaZdYgAAAAA +# AVIwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw +# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIG3G +# 7RvsqFwz7WY6U4HOPqdKK3BPgFwYBSdAqzbXoj3uMEIGCisGAQQBgjcCAQwxNDAy +# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j +# b20wDQYJKoZIhvcNAQEBBQAEggEAGyMo1lNn2g9GCbLVrzD8KtHpnboaxDtKsqdu +# gIV6UjEl376n/D7+8zivlU+eSb1/H5hrorYzss2c0DJaZQG3wVjHzBuB/gmQHTig +# RYTLqb9fYqmzIaPt0hPFyRDSRU0vbicr8b8bmIC2BSPZdkwAWWvXfgTtsoa+ay8N +# G4DqDUJsGOkVLpPHQe0ixaH58OGRdFeQVN7XCDI5N+nM1V9LdxEy9HjCwNn8UBcE +# NjDz9R+nUCqIfdwdcAiEuChu2iCIljSGI2WC9cnsE/fJSit2s7blZ9+tMwR9A9Ds +# KsjD358pOzVBUQxFb9T+oaSBHxOeK7wdIK9LimSHzr75zkbxGKGCEuUwghLhBgor +# BgEEAYI3AwMBMYIS0TCCEs0GCSqGSIb3DQEHAqCCEr4wghK6AgEDMQ8wDQYJYIZI +# AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE +# WQoDATAxMA0GCWCGSAFlAwQCAQUABCDVLWm2KCM2EapNQd+shZsDvjT3+xGk9ZHM +# X7U16MZmPwIGXPEIIccdGBMyMDE5MDcxNjIzNTEwNy40MTFaMASAAgH0oIHQpIHN +# MIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQx +# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z +# b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMg +# VFNTIEVTTjpFMDQxLTRCRUUtRkE3RTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt +# U3RhbXAgc2VydmljZaCCDjwwggTxMIID2aADAgECAhMzAAAA1p5lgY4NGKM7AAAA +# AADWMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo +# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y +# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw +# MB4XDTE4MDgyMzIwMjY0OVoXDTE5MTEyMzIwMjY0OVowgcoxCzAJBgNVBAYTAlVT +# MQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z +# b2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVy +# YXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkUwNDEtNEJF +# RS1GQTdFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBzZXJ2aWNlMIIB +# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1c/AXoWbAgfvaGmvL/sJ4BCI +# UKntNpiAOe5phUnhNPuCPMQDYTo+DAc1fctJaTqds4EBHniBT95Rm6fa1ejs3AsP +# k7xUbBkjxmC1PAM7g3UEaPLDW8CZfmvx8A0UvkOUBuWkqvqjFrVawUX/hGbmJSC2 +# ljjsprizJmgSfjWnTHkdAj+yhiVeYcAehNOMsp1R6ctphRDwE+Kfj9sAarA3jxHV +# OjG7WxQvIBXDgYSezQUEtX80U/HnMTLi+tD3W0CAvfX72jOfpQp9fUg8Jh8WiGzl +# l02sNhicmM3gV4K4kPCaTNVjZyh8kcyi765Ofd3IJJUg3NDxoPIGADjWOjTbiQID +# AQABo4IBGzCCARcwHQYDVR0OBBYEFGdUMJPgSTEafvZOFxynETg3j4j4MB8GA1Ud +# IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0 +# dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0 +# YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG +# Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB +# XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH +# AwgwDQYJKoZIhvcNAQELBQADggEBAE/ShYCJm+Wlw+CRtcUt/ma3+rn0rliEPXG2 +# cBw3faMZjaJTfs3S9WPw8jVsYggVBu9exGJigWimWxY/9DR+p21tB+XwG8iTQfiw +# ACWKiLGjDu4DfwhX54v/yCAVTsAi+bxFolbivR067fz0NHwuZAubqdt4a3K2+Ahn +# 8csAJmFzkF+c8tLTgKFuit0zpnBIIZc591NOoK6vYSn+Be0rtgJhjeFeiZB2hpHo +# CvDt62eyXLJs6JIleKNXEcGhNjpMlT6bG5+r2VXvx0EscTTaAVYwoE6L83VAgNAa +# Eh/k+1zum8IbVNyes5I3/t4WPUWFx8R6Mjfi+2uWKdCGQI+8Jr8wggZxMIIEWaAD +# AgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET +# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV +# TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBD +# ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3 +# MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw +# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x +# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkq +# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWl +# CgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/Fg +# iIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeR +# X4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/Xcf +# PfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogI +# Neh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB +# 5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvF +# M2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP +# BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE +# MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv +# Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF +# BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w +# a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8E +# gZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5t +# aWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcC +# AjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUA +# bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Pr +# psz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOM +# zPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCv +# OA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v +# /rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99 +# lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1kl +# D3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQ +# Hm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30 +# uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp +# 25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HS +# xVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi6 +# 2jbb01+P3nSISRKhggLOMIICNwIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMx +# CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv +# ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh +# dGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046RTA0MS00QkVF +# LUZBN0UxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIHNlcnZpY2WiIwoB +# ATAHBgUrDgMCGgMVAA9UX0q/L+thMJX0rozPt72QIBXRoIGDMIGApH4wfDELMAkG +# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx +# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z +# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDg2NPEMCIY +# DzIwMTkwNzE3MDY1MjUyWhgPMjAxOTA3MTgwNjUyNTJaMHcwPQYKKwYBBAGEWQoE +# ATEvMC0wCgIFAODY08QCAQAwCgIBAAICIjQCAf8wBwIBAAICEYQwCgIFAODaJUQC +# AQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEK +# MAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQBlNpEdpWGf/B83X8hAVPxRTgW4 +# 0prA9h6EG/xUWfp2c40h4vr0I2ee2oPbLNa9PTdTPO0deSBDcwM/J1lV7XV/5TgI +# AxLLJgfSHdaIrZmiV38CZyd2vCQP6beG2TydK/aHkZpIApUQY54kQyB9X4QW5uPh +# lis3qUZwulqZ4VaICjGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD +# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w +# IFBDQSAyMDEwAhMzAAAA1p5lgY4NGKM7AAAAAADWMA0GCWCGSAFlAwQCAQUAoIIB +# SjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIP5z +# azPb5aBR/KZQlipF+nKTJNp041jk7Yld+TnbBe99MIH6BgsqhkiG9w0BCRACLzGB +# 6jCB5zCB5DCBvQQgDKcXGy85Pqmxmt5kRTcsOqGjceOxduVb/tGYJy6USM4wgZgw +# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE +# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD +# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAANaeZYGODRij +# OwAAAAAA1jAiBCBsua44ho7AmDyDQPtF5fHr6CZ0JRmATzJfI/y++JB4GzANBgkq +# hkiG9w0BAQsFAASCAQCBHgNjNO2+pFexw7gNQkDtrTM/I0APnvHsVOXLFSVTSj5P +# HMrq+jR+IBnm8WCP9rRij/XZ2d/yM//JAzajALNk0mX2G6xuJx56xX8r2Q6Xvns3 +# a2v6a31u2bA+jaBWUK5089uIoLARpDOIlibuY0HSWavr0TntPL4c9oj5ZrWGVHDf +# m36zM9J4wobjmzCjQBTBCtik3TZ1QPIpGErjEV6MyRP3cEDFBg6TLK11IPVpE0YE +# N/aAHifwolmj9n5vqnMiWgKhiN7C7uIbOo0ytbeYu2dzRzIQvwuyWsgy5RJYkpkp +# UUHb1YVGyl3yhOqan9rU68Qiza/tgULbBhXYn68L +# SIG # End signature block \ No newline at end of file diff --git a/samples/extensibility/Microsoft Python packages/9.2.1/Install-PyForMLS.ps1 b/samples/extensibility/Microsoft Python packages/9.2.1/Install-PyForMLS.ps1 new file mode 100644 index 0000000000..5738ed5d40 --- /dev/null +++ b/samples/extensibility/Microsoft Python packages/9.2.1/Install-PyForMLS.ps1 @@ -0,0 +1,128 @@ +# +# Install-PyForMLS.ps1 +# Copyright (C) Microsoft. All rights reserved. +# + +# See: https://learn.microsoft.com/sql/machine-learning/python/setup-python-client-tools-sql + +# Command-line parameters +param +( + [string]$InstallFolder = "$Env:ProgramFiles\Microsoft\PyForMLS", + [string]$CacheFolder = $Env:Temp, + [string]$JupyterShortcut = "$Env:ProgramData\Microsoft\Windows\Start Menu\Jupyter Notebook for Microsoft Machine Learning Server.lnk" +) + +# Verify script is being run with elevated privileges +if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) +{ + Write-Error "This script must be run as Administrator" + Exit 1 +} + +# Product version to install +$productVersion = '9.2.1.0' + +# Default language to install (en-us) +$productLcid = '1033' + +# Component names and their corresponding fwlink IDs +$components = @{ 'SPO' = '852723'; 'SPS' = '852726'; } + +# Helper function which outputs the specified message to the console and prepends the current date and time +function WriteMessage($message) +{ + Write-Host ("[{0}] {1}" -f (Get-Date -format u), $message) +} + +# Helper function which generates a fwlink for the specified component +function GenerateFwlink($componentName) +{ + return 'https://go.microsoft.com/fwlink/?LinkId={0}&clcid={1}' -f $components[$componentName], $productLcid +} + +# Helper function which generates the absolute CAB path of the specified component +function GenerateCabPath($componentName) +{ + return "{0}\{1}_{2}_1033.cab" -f $cacheFolder, $componentName, $productVersion +} + +# Helper function which returns true if the specified CAB file is found in the cache +function IsCachedCabValid($cabFile, $cabUrl) +{ + $isValid = $false + + # Does CAB file exist? + if (Test-Path $cabFile) + { + # Retrieve headers from CAB URL + $response = Invoke-WebRequest -Method Head -Uri $cabUrl + + # Compare last modified date of cached file against the remote file + if ([datetime](Get-ItemProperty -Path $cabFile).LastWriteTime -ge $response.Headers['Last-Modified']) + { + WriteMessage "Cached $cabFile is up-to-date" + $isValid = $true + } + else + { + WriteMessage "Cached $cabFile is expired" + $isValid = $false + } + } + else + { + WriteMessage "$cabFile not found in cache" + $isValid = $false + } + + return $isValid +} + +WriteMessage "Starting installation" + +# Create install folder, if necessary +if (-not (Test-Path $installFolder)) +{ + WriteMessage "Creating install folder $installFolder" + New-Item -ItemType directory -Path $installFolder > $null +} + +# Download the CAB file for each component +foreach ($componentName in $components.Keys) +{ + $cabUrl = GenerateFwlink($componentName) + $cabFile = GenerateCabPath($componentName) + + # Download CAB file, if necessary + if (-not (IsCachedCabValid $cabFile $cabUrl)) + { + WriteMessage "Downloading $cabUrl to $cabFile" + Invoke-WebRequest -Uri $cabUrl -OutFile $cabFile + } +} + +# Extract the contents of each CAB file +foreach ($componentName in $components.Keys) +{ + $cabFile = GenerateCabPath($componentName) + + # Extract all files using the built-in expand.exe tool + WriteMessage "Extracting $cabFile to $installFolder (this may take several minutes)" + &"$Env:WinDir\System32\expand.exe" $cabFile -F:* $installFolder > $null +} + +# Create shortcut +WriteMessage "Creating shortcut $jupyterShortcut" +$shell = New-Object -comObject WScript.Shell +$shortcut = $shell.CreateShortcut($jupyterShortcut) +$shortcut.TargetPath = "$installFolder\Scripts\jupyter-notebook.exe" +$shortcut.Arguments = "--notebook-dir `"$installFolder\samples`"" +$shortcut.Save() + +# Force shortcut to launch as admin +$bytes = [System.IO.File]::ReadAllBytes($jupyterShortcut) +$bytes[0x15] = $bytes[0x15] -bor 0x20 +[System.IO.File]::WriteAllBytes($JupyterShortcut, $bytes) + +WriteMessage "Installation complete" diff --git a/samples/extensibility/Microsoft Python packages/9.3/Install-PyForMLS.ps1 b/samples/extensibility/Microsoft Python packages/9.3/Install-PyForMLS.ps1 new file mode 100644 index 0000000000..ed22aebdd5 --- /dev/null +++ b/samples/extensibility/Microsoft Python packages/9.3/Install-PyForMLS.ps1 @@ -0,0 +1,323 @@ +# +# Install-PyForMLS.ps1 +# Copyright (C) Microsoft. All rights reserved. +# + +# See: https://learn.microsoft.com/sql/machine-learning/python/setup-python-client-tools-sql + +# Command-line parameters +param +( + [string]$InstallFolder = "$Env:ProgramFiles\Microsoft\PyForMLS", + [string]$CacheFolder = $Env:Temp, + [string]$JupyterShortcut = "$Env:ProgramData\Microsoft\Windows\Start Menu\Jupyter Notebook for Microsoft Machine Learning Server.lnk" +) + +# Verify script is being run with elevated privileges +if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) +{ + Write-Error "This script must be run as Administrator" + Exit 1 +} + +# Product version to install +$productVersion = '9.3.0.0' + +# Default language to install (en-us) +$productLcid = '1033' + +# Component names and their corresponding fwlink IDs +$components = @{ 'SPO' = '859054'; 'SPS' = '859056'; } + +# Helper function which outputs the specified message to the console and prepends the current date and time +function WriteMessage($message) +{ + Write-Host ("[{0}] {1}" -f (Get-Date -format u), $message) +} + +# Helper function which generates a fwlink for the specified component +function GenerateFwlink($componentName) +{ + return 'https://go.microsoft.com/fwlink/?LinkId={0}&clcid={1}' -f $components[$componentName], $productLcid +} + +# Helper function which generates the absolute CAB path of the specified component +function GenerateCabPath($componentName) +{ + return "{0}\{1}_{2}_1033.cab" -f $cacheFolder, $componentName, $productVersion +} + +# Helper function which returns true if the specified CAB file is found in the cache +function IsCachedCabValid($cabFile, $cabUrl) +{ + $isValid = $false + + # Does CAB file exist? + if (Test-Path $cabFile) + { + # Retrieve headers from CAB URL + $response = Invoke-WebRequest -Method Head -Uri $cabUrl + + # Compare last modified date of cached file against the remote file + if ([datetime](Get-ItemProperty -Path $cabFile).LastWriteTime -ge $response.Headers['Last-Modified']) + { + WriteMessage "Cached $cabFile is up-to-date" + $isValid = $true + } + else + { + WriteMessage "Cached $cabFile is expired" + $isValid = $false + } + } + else + { + WriteMessage "$cabFile not found in cache" + $isValid = $false + } + + return $isValid +} + +WriteMessage "Starting installation" + +# Create install folder, if necessary +if (-not (Test-Path $installFolder)) +{ + WriteMessage "Creating install folder $installFolder" + New-Item -ItemType directory -Path $installFolder > $null +} + +# Download the CAB file for each component +foreach ($componentName in $components.Keys) +{ + $cabUrl = GenerateFwlink($componentName) + $cabFile = GenerateCabPath($componentName) + + # Download CAB file, if necessary + if (-not (IsCachedCabValid $cabFile $cabUrl)) + { + WriteMessage "Downloading $cabUrl to $cabFile" + Invoke-WebRequest -Uri $cabUrl -OutFile $cabFile + } +} + +# Extract the contents of each CAB file +foreach ($componentName in $components.Keys) +{ + $cabFile = GenerateCabPath($componentName) + + # Extract all files using the built-in expand.exe tool + WriteMessage "Extracting $cabFile to $installFolder (this may take several minutes)" + &"$Env:WinDir\System32\expand.exe" $cabFile -F:* $installFolder > $null +} + +# Create shortcut +WriteMessage "Creating shortcut $jupyterShortcut" +$shell = New-Object -comObject WScript.Shell +$shortcut = $shell.CreateShortcut($jupyterShortcut) +$shortcut.TargetPath = "$installFolder\Scripts\jupyter-notebook.exe" +$shortcut.Arguments = "--notebook-dir `"$installFolder\samples`"" +$shortcut.Save() + +# Force shortcut to launch as admin +$bytes = [System.IO.File]::ReadAllBytes($jupyterShortcut) +$bytes[0x15] = $bytes[0x15] -bor 0x20 +[System.IO.File]::WriteAllBytes($JupyterShortcut, $bytes) + +WriteMessage "Installation complete" + +# SIG # Begin signature block +# MIIj7gYJKoZIhvcNAQcCoIIj3zCCI9sCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCcQAtZ7Zu4h+GZ +# d5+6oKbm+wLBylyrt7Epkx69JtzklaCCDYMwggYBMIID6aADAgECAhMzAAAAxOmJ +# +HqBUOn/AAAAAADEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD +# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p +# bmcgUENBIDIwMTEwHhcNMTcwODExMjAyMDI0WhcNMTgwODExMjAyMDI0WjB0MQsw +# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u +# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +# AQCIirgkwwePmoB5FfwmYPxyiCz69KOXiJZGt6PLX4kvOjMuHpF4+nypH4IBtXrL +# GrwDykbrxZn3+wQd8oUK/yJuofJnPcUnGOUoH/UElEFj7OO6FYztE5o13jhwVG87 +# 7K1FCTBJwb6PMJkMy3bJ93OVFnfRi7uUxwiFIO0eqDXxccLgdABLitLckevWeP6N +# +q1giD29uR+uYpe/xYSxkK7WryvTVPs12s1xkuYe/+xxa8t/CHZ04BBRSNTxAMhI +# TKMHNeVZDf18nMjmWuOF9daaDx+OpuSEF8HWyp8dAcf9SKcTkjOXIUgy+MIkogCy +# vlPKg24pW4HvOG6A87vsEwvrAgMBAAGjggGAMIIBfDAfBgNVHSUEGDAWBgorBgEE +# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUy9ZihM9gOer/Z8Jc0si7q7fDE5gw +# UgYDVR0RBEswSaRHMEUxDTALBgNVBAsTBE1PUFIxNDAyBgNVBAUTKzIzMDAxMitj +# ODA0YjVlYS00OWI0LTQyMzgtODM2Mi1kODUxZmEyMjU0ZmMwHwYDVR0jBBgwFoAU +# SG5k5VAF04KqFzc3IrVtqMp1ApUwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL3d3 +# dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljQ29kU2lnUENBMjAxMV8yMDEx +# LTA3LTA4LmNybDBhBggrBgEFBQcBAQRVMFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93 +# d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljQ29kU2lnUENBMjAxMV8y +# MDExLTA3LTA4LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQAG +# Fh/bV8JQyCNPolF41+34/c291cDx+RtW7VPIaUcF1cTL7OL8mVuVXxE4KMAFRRPg +# mnmIvGar27vrAlUjtz0jeEFtrvjxAFqUmYoczAmV0JocRDCppRbHukdb9Ss0i5+P +# WDfDThyvIsoQzdiCEKk18K4iyI8kpoGL3ycc5GYdiT4u/1cDTcFug6Ay67SzL1BW +# XQaxFYzIHWO3cwzj1nomDyqWRacygz6WPldJdyOJ/rEQx4rlCBVRxStaMVs5apao +# pIhrlihv8cSu6r1FF8xiToG1VBpHjpilbcBuJ8b4Jx/I7SCpC7HxzgualOJqnWmD +# oTbXbSD+hdX/w7iXNgn+PRTBmBSpwIbM74LBq1UkQxi1SIV4htD50p0/GdkUieeN +# n2gkiGg7qceATibnCCFMY/2ckxVNM7VWYE/XSrk4jv8u3bFfpENryXjPsbtrj4Ns +# h3Kq6qX7n90a1jn8ZMltPgjlfIOxrbyjunvPllakeljLEkdi0iHv/DzEMQv3Lz5k +# pTdvYFA/t0SQT6ALi75+WPbHZ4dh256YxMiMy29H4cAulO2x9rAwbexqSajplnbI +# vQjE/jv1rnM3BrJWzxnUu/WUyocc8oBqAU+2G4Fzs9NbIj86WBjfiO5nxEmnL9wl +# iz1e0Ow0RJEdvJEMdoI+78TYLaEEAo5I+e/dAs8DojCCB3owggVioAMCAQICCmEO +# kNIAAAAAAAMwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv +# ZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmlj +# YXRlIEF1dGhvcml0eSAyMDExMB4XDTExMDcwODIwNTkwOVoXDTI2MDcwODIxMDkw +# OVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT +# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UE +# AxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTCCAiIwDQYJKoZIhvcN +# AQEBBQADggIPADCCAgoCggIBAKvw+nIQHC6t2G6qghBNNLrytlghn0IbKmvpWlCq +# uAY4GgRJun/DDB7dN2vGEtgL8DjCmQawyDnVARQxQtOJDXlkh36UYCRsr55JnOlo +# XtLfm1OyCizDr9mpK656Ca/XllnKYBoF6WZ26DJSJhIv56sIUM+zRLdd2MQuA3Wr +# aPPLbfM6XKEW9Ea64DhkrG5kNXimoGMPLdNAk/jj3gcN1Vx5pUkp5w2+oBN3vpQ9 +# 7/vjK1oQH01WKKJ6cuASOrdJXtjt7UORg9l7snuGG9k+sYxd6IlPhBryoS9Z5JA7 +# La4zWMW3Pv4y07MDPbGyr5I4ftKdgCz1TlaRITUlwzluZH9TupwPrRkjhMv0ugOG +# jfdf8NBSv4yUh7zAIXQlXxgotswnKDglmDlKNs98sZKuHCOnqWbsYR9q4ShJnV+I +# 4iVd0yFLPlLEtVc/JAPw0XpbL9Uj43BdD1FGd7P4AOG8rAKCX9vAFbO9G9RVS+c5 +# oQ/pI0m8GLhEfEXkwcNyeuBy5yTfv0aZxe/CHFfbg43sTUkwp6uO3+xbn6/83bBm +# 4sGXgXvt1u1L50kppxMopqd9Z4DmimJ4X7IvhNdXnFy/dygo8e1twyiPLI9AN0/B +# 4YVEicQJTMXUpUMvdJX3bvh4IFgsE11glZo+TzOE2rCIF96eTvSWsLxGoGyY0uDW +# iIwLAgMBAAGjggHtMIIB6TAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUSG5k +# 5VAF04KqFzc3IrVtqMp1ApUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYD +# VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUci06AjGQQ7kU +# BU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybC5taWNyb3Nv +# ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAz +# XzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cu +# bWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAz +# XzIyLmNydDCBnwYDVR0gBIGXMIGUMIGRBgkrBgEEAYI3LgMwgYMwPwYIKwYBBQUH +# AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvZG9jcy9wcmltYXJ5 +# Y3BzLmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBwAG8AbABpAGMA +# eQBfAHMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAZ/KG +# pZjgVHkaLtPYdGcimwuWEeFjkplCln3SeQyQwWVfLiw++MNy0W2D/r4/6ArKO79H +# qaPzadtjvyI1pZddZYSQfYtGUFXYDJJ80hpLHPM8QotS0LD9a+M+By4pm+Y9G6XU +# tR13lDni6WTJRD14eiPzE32mkHSDjfTLJgJGKsKKELukqQUMm+1o+mgulaAqPypr +# WEljHwlpblqYluSD9MCP80Yr3vw70L01724lruWvJ+3Q3fMOr5kol5hNDj0L8giJ +# 1h/DMhji8MUtzluetEk5CsYKwsatruWy2dsViFFFWDgycScaf7H0J/jeLDogaZiy +# WYlobm+nt3TDQAUGpgEqKD6CPxNNZgvAs0314Y9/HG8VfUWnduVAKmWjw11SYobD +# HWM2l4bf2vP48hahmifhzaWX0O5dY0HjWwechz4GdwbRBrF1HxS+YWG18NzGGwS+ +# 30HHDiju3mUv7Jf2oVyW2ADWoUa9WfOXpQlLSBCZgB/QACnFsZulP0V3HjXG0qKi +# n3p6IvpIlR+r+0cjgPWe+L9rt0uX4ut1eBrs6jeZeRhL/9azI2h15q/6/IvrC4Dq +# aTuv/DDtBEyO3991bWORPdGdVk5Pv4BXIqF4ETIheu9BCrE/+6jMpF3BoYibV3FW +# TkhFwELJm3ZbCoBIa/15n8G9bW1qyVJzEw16UM0xghXBMIIVvQIBATCBlTB+MQsw +# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u +# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNy +# b3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAAxOmJ+HqBUOn/AAAAAADE +# MA0GCWCGSAFlAwQCAQUAoIGwMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG +# CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBFICAp +# M2j0TOGgkpBNkVd+X/ZevrIdRG1Kc4YxAZ0uLjBEBgorBgEEAYI3AgEMMTYwNKAU +# gBIATQBpAGMAcgBvAHMAbwBmAHShHIAaaHR0cHM6Ly93d3cubWljcm9zb2Z0LmNv +# bSAwDQYJKoZIhvcNAQEBBQAEggEAX4lloFuwEEraoxJFk/wnE107hYIp7veGKPhB +# Fd7aUOll/FY7emZeZ7Dbz2b1qbV6DmKboiSNRfqgfB0F3dMVUiBVtvtRdw5MAUqx +# o/PKCD82KDZudLvcOkXDZLgfQSe2EKsrme96HFJ7D+s/vrGACewiixNXsZ7MMJ/K +# pKwJF7kqD5/W7V+QzpgaYa9qYG4Iomrybua7VEeGhUg4islCHIwvX0naAAPY11gZ +# ubZFGnC+w11dl1lQ1IzNga6Kxl857DygTiJIV7ODUP8eCELDCTgIUj3PXq04hTzn +# mW1hzCBoqCTYinYSDZjVyg6mFxQUMIlp4w/210hSKivxCA8o0aGCE0kwghNFBgor +# BgEEAYI3AwMBMYITNTCCEzEGCSqGSIb3DQEHAqCCEyIwghMeAgEDMQ8wDQYJYIZI +# AWUDBAIBBQAwggE8BgsqhkiG9w0BCRABBKCCASsEggEnMIIBIwIBAQYKKwYBBAGE +# WQoDATAxMA0GCWCGSAFlAwQCAQUABCBz8XcAnPXHLROng3eOI0UaWfW0nM5svgvd +# BWnWX9tULAIGWwMpKo8OGBMyMDE4MDUyNDIwMDA1NS44NDRaMAcCAQGAAgPnoIG4 +# pIG1MIGyMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE +# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMQwwCgYD +# VQQLEwNBT0MxJzAlBgNVBAsTHm5DaXBoZXIgRFNFIEVTTjo4NDNELTM3RjYtRjEw +# NDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCDs0wggZx +# MIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQG +# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG +# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg +# Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVa +# Fw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n +# dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y +# YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIB +# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mU +# a3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZ +# sTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4Yy +# hB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQ +# YrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDa +# TgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQID +# AQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDz +# Q3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQE +# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQ +# W9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNv +# bS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBa +# BggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0 +# LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNV +# HSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDov +# L3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggr +# BgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQA +# ZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2d +# o6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GC +# RBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZ +# eUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8y +# Sif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOc +# o6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz3 +# 9L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSY +# Ighh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvY +# grRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98is +# TtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8 +# l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzV +# s341Hgi62jbb01+P3nSISRIwggTZMIIDwaADAgECAhMzAAAAqVRw2XnAhGXiAAAA +# AACpMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo +# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y +# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw +# MB4XDTE2MDkwNzE3NTY1M1oXDTE4MDkwNzE3NTY1M1owgbIxCzAJBgNVBAYTAlVT +# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK +# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDDAKBgNVBAsTA0FPQzEnMCUGA1UECxMe +# bkNpcGhlciBEU0UgRVNOOjg0M0QtMzdGNi1GMTA0MSUwIwYDVQQDExxNaWNyb3Nv +# ZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +# CgKCAQEArJSFGKblVtOd3wNnLtuYkUePlYlyTZp08zRA3msRp9THkn4O/581On+n +# ZIxxm2HFGVk+lF2RL07A7cFAbicHkdTlrPYePM5QEVMnaITS0makH24deymLJuMJ +# rnTnTPyfg7dGDdsVqQ37V/ezmxDeDBykTRrDliRGNimQXN4dR9aXP0KNB/+oLyeO +# 6xIQsUdC9wS9OTbExbvA7La8joGcyd2yQDw9o+sbvTB1/lsFcx0UMRHU8Dq/7NET +# 3kTJxP5I4VfELngIFX7zRQY2Sba1/VgdEd2IZANCEDnvrlMWRhFbXH0SWndIdnAp +# YSEak1OcImlunLR5eo5MOIQVGWxfoQIDAQABo4IBGzCCARcwHQYDVR0OBBYEFA/V +# Qfu78530vklS2ow3V85kD/N9MB8GA1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2ha +# hW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9w +# a2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggr +# BgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNv +# bS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB +# /wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBAAiZ +# GKUHiy9yJHUsjiCEAv0Koa8O4bAyEYaqxYYgnbvoRDuVzLU654tGpRPTjCAbqDpX +# HBX3c22NC7IHRW6GRXYkRrp0TPE2b1KdtuTklIzJKauJqr5ygtO6m1WroII54Bku +# 2BGtRYkDS8Av4gCeuHuH28rXdbguBLSMkzeKHiZE5NlBZY7RQrleExC8GWd1u86E +# qekfjnvPG5S4OV1tV1nsCn7G1pUNO+f6iC9WrFUEUHJnP7IAA8OOwvw+yJWr4NRn +# tqY0bbRgCLJCid5/YNpYIbzTjDgyU/IKzNvfJLcA65NKPwl6NDtLwHNralKEU6Gb +# BERZYUKtcvBAwG78mrKhggN3MIICXwIBATCB4qGBuKSBtTCBsjELMAkGA1UEBhMC +# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV +# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQL +# Ex5uQ2lwaGVyIERTRSBFU046ODQzRC0zN0Y2LUYxMDQxJTAjBgNVBAMTHE1pY3Jv +# c29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiJQoBATAJBgUrDgMCGgUAAxUAXTq/Vr3h +# DynKcg5k93U7eBoi6/SggcEwgb6kgbswgbgxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv +# ZnQgQ29ycG9yYXRpb24xDDAKBgNVBAsTA0FPQzEnMCUGA1UECxMebkNpcGhlciBO +# VFMgRVNOOjI2NjUtNEMzRi1DNURFMSswKQYDVQQDEyJNaWNyb3NvZnQgVGltZSBT +# b3VyY2UgTWFzdGVyIENsb2NrMA0GCSqGSIb3DQEBBQUAAgUA3rEC7DAiGA8yMDE4 +# MDUyNDA5MjI1MloYDzIwMTgwNTI1MDkyMjUyWjB3MD0GCisGAQQBhFkKBAExLzAt +# MAoCBQDesQLsAgEAMAoCAQACAhmJAgH/MAcCAQACAhmrMAoCBQDeslRsAgEAMDYG +# CisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwGgCjAIAgEAAgMegJihCjAIAgEA +# AgMehIAwDQYJKoZIhvcNAQEFBQADggEBACCC4U8Xw3EV8c3XIrkUGCA5fOqq33GG +# gvCw8gXTlTglImU6Z5JbrziEP+02wW6RN/uvuWpfu+ErTvN5E7vxxj5Og/IFWmif +# swF/N40pWeTJU1fyvo4BVYHygLyRpnGFCEeXT4sjXQSa1YLoaFcamTG/r7vt9W1s +# nvJUfyW5KMX8xlnivFKM65RUYHZ1/zB/fA9K9MQtIFU0Jr3jYwCd0JVcnuysaN66 +# aU2EnpsoiTYmBL138s4hM7cK5vymzofp0eYVTd/83PP8H2ZTRGEm9sOglOewtNMs +# fHwkpm7cZxPF5fsbxxYUGwM/mCl89dBGsdU+vjlIaiovX8yJKHUznnkxggL1MIIC +# 8QIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G +# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYw +# JAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAKlUcNl5 +# wIRl4gAAAAAAqTANBglghkgBZQMEAgEFAKCCATIwGgYJKoZIhvcNAQkDMQ0GCyqG +# SIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCDEz3JAIekNn0Gtr62/eNmLmZoYbCcR +# rmhTOaiTywyovDCB4gYLKoZIhvcNAQkQAgwxgdIwgc8wgcwwgbEEFF06v1a94Q8p +# ynIOZPd1O3gaIuv0MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh +# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD +# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw +# MTACEzMAAACpVHDZecCEZeIAAAAAAKkwFgQUsmMPwmVuSiBbNg4ZDFfesXTSyM8w +# DQYJKoZIhvcNAQELBQAEggEAgVub0c34ntVQ3x1wpzKcQgN+UswIw5fkKgkAjKNK +# 4dRCJpcja9P15d3t72KA/dJOoGBNagloOyewROaGSaoKjBKzBsSEX9ADdAFicYgW +# Oywr8cfChXdrwZNRHlOAcZV0G1TGWtaY5/Hb46KS2WZamBeraQ7+eqGsIoYrQyl5 +# quKcDvd+Msa8NQelc/ypudesYKUnE+96RIvJACR2CD99aYq22uWgXX75q9RgcUuE +# PNCIfqdw36oeC6bz9/fHCORlfPMnzZYebJE7rw7utrg7m6SnL5dLQM2v3OnFwccq +# jSE2VAQNJk/Z3FZnpXquy5pNbtuNcd3sYki5+d0OV4fcpQ== +# SIG # End signature block diff --git a/samples/extensibility/TutorialDB.bak b/samples/extensibility/TutorialDB.bak new file mode 100644 index 0000000000000000000000000000000000000000..91da5416932bf2f5a78be427b3187bbbedda3e6e GIT binary patch literal 431104 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 !vyC#$()YTz{mlwZL0B}U4$-~%(s0kHh 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͟}M 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�*qR6gcnSSeu!{KhKy{`u}U#BEDBhz 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�^J)QsD>LQUv+6z7 zML^it?6~#WTwC))-A6tIhI9|c$i3%j5Wp6taudp29xISA&E0Mdf^IM7*9J?k=mY*C z$3|uuQAWXrnb>1_ENq<4wB{+)x*f2+;uS~`vQwr< zSrVLs0uv%X1ftB?3ibZ$K!H$!e0OeM5V8``gDexy_W~m$n{!QRA~D=Z-QMlOx2m-U z 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�O>>iLbk0FU=B8jMb^LO`Xp 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

rOf~C(| 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

Y+jxcfcjbI{%u9dPQ&J1uUfc%9BRC>O62HZ&(% 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

=c?!^Scu9dn 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 Sxpw}#Nq?{Vcm7{?1pWiGFa8|> literal 0 HcmV?d00001 From 6aa81f36a7c8edaeebb344f67337572a52aa9adf Mon Sep 17 00:00:00 2001 From: "Masha Thomas (MSFT)" <32783170+MashaMSFT@users.noreply.github.com> Date: Wed, 22 May 2024 11:29:19 -0700 Subject: [PATCH 005/159] Add files via upload --- samples/manage/sql-vm-throttling-analysis.ps1 | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 samples/manage/sql-vm-throttling-analysis.ps1 diff --git a/samples/manage/sql-vm-throttling-analysis.ps1 b/samples/manage/sql-vm-throttling-analysis.ps1 new file mode 100644 index 0000000000..5a6539296e --- /dev/null +++ b/samples/manage/sql-vm-throttling-analysis.ps1 @@ -0,0 +1,186 @@ +# Prompt user for details +$subscriptionId = Read-Host "Enter Subscription ID" +$resourceGroup = Read-Host "Enter Resource Group Name" +$vmName = Read-Host "Enter VM Name" + +# Set resource details +$resourceType = "Microsoft.Compute/virtualMachines" +$resourceId = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/$resourceType/$vmName" + +# Get Azure access token +$accessToken = az account get-access-token --query accessToken -o tsv + +# Function to invoke Azure Monitor Metrics API +function Get-Metrics { + [CmdletBinding()] + param ( + [string]$accessToken, + [string]$resourceId, + [string]$metricNames, + [string]$apiVersion = "2023-10-01" + ) + try { + $startTime = (Get-Date).AddHours(-24).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $endTime = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $timespan = "$startTime/$endTime" + Write-Verbose "Evaluating timespan: $timespan" + $uri = "https://management.azure.com$resourceId/providers/Microsoft.Insights/metrics?api-version=$apiVersion&metricnames=$metricNames&aggregation=maximum&interval=PT1M×pan=$timespan" + $headers = @{ "Authorization" = "Bearer $accessToken"; "Content-Type" = "application/json" } + + $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get + if ($response) { + Write-Verbose "API response successfully retrieved." + return $response + } else { + Write-Error "No response from API." + } + } catch { + Write-Error "Error retrieving metrics: $_" + } +} + +# Function to check if Data Disk Latency data is violating thresholds +function Check-Latency { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [Object]$metrics, + + [Parameter()] + [int]$latencyThreshold = 500, + + [Parameter()] + [int]$consecutiveCount = 5 + ) + $violationTimes = @() + foreach ($metric in $metrics.value) { + if ($metric.name.value -eq "Data Disk Latency") { + $count = 0 + foreach ($dataPoint in $metric.timeseries[0].data) { + if ($dataPoint.maximum -gt $latencyThreshold) { + $count++ + if ($count -ge $consecutiveCount) { + $violationTimes += $dataPoint.timeStamp + $count = 0 # Reset count after recording a violation + } + } else { + $count = 0 # Reset count if the sequence is broken + } + } + } + } + if ($violationTimes.Count -gt 0) { + Write-Verbose "Latency violations detected." + return @{ "Flag" = $true; "Times" = $violationTimes } + } else { + Write-Verbose "No latency violations detected." + return @{ "Flag" = $false } + } +} + +# Function to check metrics other than Latency and evaluate if they are throttled +function Check-OtherMetricsThrottled { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [Object]$metrics, + + [Parameter()] + [int]$PercentageThreshold = 90, + + [Parameter()] + [int]$consecutiveCount = 5 + ) + $violatedMetrics = @() + foreach ($metric in $metrics.value) { + $count = 0 + foreach ($dataPoint in $metric.timeseries[0].data) { + if ($dataPoint.maximum -gt $PercentageThreshold) { + $count++ + if ($count -ge $consecutiveCount) { + $violatedMetrics += @{ "Metric" = $metric.name.localizedValue; "Time" = $dataPoint.timeStamp; "Value" = $dataPoint.maximum } + break + } + } else { + $count = 0 + } + } + } + if ($violatedMetrics.Count -gt 0) { + Write-Verbose "Other metrics violations detected." + } else { + Write-Verbose "No other metrics violations detected." + } + return $violatedMetrics +} + +# Function to compare the times for Latency Metric & other Throttled Metrics. Logs Violations with Values & Timestamps +function CompareTimes { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [Hashtable]$latencyResult, + + [Parameter(Mandatory = $true)] + [Array]$otherMetrics + ) + foreach ($metric in $otherMetrics) { + $otherDateTime = [DateTime]$metric["Time"] + $isWithinFiveMinutes = $false + $closestLatencyTime = $null + $closestTimeDifference = [int]::MaxValue + + foreach ($latencyTime in $latencyResult.Times) { + $latencyDateTime = [DateTime]$latencyTime + $timeDifference = [Math]::Abs(($otherDateTime - $latencyDateTime).TotalMinutes) + + if ($timeDifference -le 5) { + $isWithinFiveMinutes = $true + if ($timeDifference -lt $closestTimeDifference) { + $closestTimeDifference = $timeDifference + $closestLatencyTime = $latencyTime + } + } + } + + if ($isWithinFiveMinutes) { + if ($otherDateTime -lt $closestLatencyTime) { + Write-Host "`n $($metric["Metric"]) limit was hit before latency spiked at $closestLatencyTime with value $($metric["Value"]). `n" + } else { + Write-Host "`n $($metric["Metric"]) hit its limit with value $($metric["Value"]) at $($metric["Time"])." + Write-Host "Latency spiked at $closestLatencyTime before $($metric["Metric"]) hit its limit `n" + } + } else { + Write-Host "`n Metric: $($metric["Metric"]) exceeded its threshold with a value of $($metric["Value"]) at $($metric["Time"]), but this was not within 5 minutes of any latency spikes." + } + } +} + +# Prompt user for latency threshold +$latencyThreshold = Read-Host "Enter Latency Threshold (default is 500)" +if (-not [int]::TryParse($latencyThreshold, [ref]0)) { + $latencyThreshold = 500 # Use default if invalid input + Write-Host "No valid input provided. Using Default 500ms for disk latency threshold" +} + +# Main Logic Execution: +$latencyMetrics = Get-Metrics -accessToken $accessToken -resourceId $resourceId -metricNames "Data Disk Latency" +$latencyResult = Check-Latency -metrics $latencyMetrics -latencyThreshold $latencyThreshold + +if ($latencyResult.Flag) { + + # Only if Latency is flagged we will check for other metrics. If no disk latency is experienced, machine is likely not throttled but only at high consumption + Write-Verbose "Checking the following metrics: Data Disk Bandwidth Consumed Percentage,Data Disk IOPS Consumed Percentage,VM Cached Bandwidth Consumed Percentage,VM Cached IOPS Consumed Percentage,VM Uncached Bandwidth Consumed Percentage,VM Uncached IOPS Consumed Percentage" + + $DiskVMMetrics = Get-Metrics -accessToken $accessToken -resourceId $resourceId -metricNames "Data Disk Bandwidth Consumed Percentage,Data Disk IOPS Consumed Percentage,VM Cached Bandwidth Consumed Percentage,VM Cached IOPS Consumed Percentage,VM Uncached Bandwidth Consumed Percentage,VM Uncached IOPS Consumed Percentage" + + $additionalMetrics = Check-OtherMetricsThrottled -metrics $DiskVMMetrics + + if ($additionalMetrics.Count -gt 0) { + CompareTimes $latencyResult $additionalMetrics + } else { + Write-Host "No metrics violations detected besides latency." + } +} else { + Write-Host "No latency issues detected." +} From 308136be11e7614304b10f740575afab90182cfe Mon Sep 17 00:00:00 2001 From: "Masha Thomas (MSFT)" <32783170+MashaMSFT@users.noreply.github.com> Date: Wed, 22 May 2024 11:35:17 -0700 Subject: [PATCH 006/159] Update and rename sql-vm-throttling-analysis.ps1 to sql-vm-io-analysis.ps1 updating name --- .../{sql-vm-throttling-analysis.ps1 => sql-vm-io-analysis.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename samples/manage/{sql-vm-throttling-analysis.ps1 => sql-vm-io-analysis.ps1} (100%) diff --git a/samples/manage/sql-vm-throttling-analysis.ps1 b/samples/manage/sql-vm-io-analysis.ps1 similarity index 100% rename from samples/manage/sql-vm-throttling-analysis.ps1 rename to samples/manage/sql-vm-io-analysis.ps1 From f9eb783e6077a9fdb936ffb341abf8a19214a5b0 Mon Sep 17 00:00:00 2001 From: "Masha Thomas (MSFT)" <32783170+MashaMSFT@users.noreply.github.com> Date: Wed, 22 May 2024 12:16:20 -0700 Subject: [PATCH 007/159] Update sql-vm-io-analysis.ps1 --- samples/manage/sql-vm-io-analysis.ps1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/samples/manage/sql-vm-io-analysis.ps1 b/samples/manage/sql-vm-io-analysis.ps1 index 5a6539296e..9f0195255a 100644 --- a/samples/manage/sql-vm-io-analysis.ps1 +++ b/samples/manage/sql-vm-io-analysis.ps1 @@ -1,7 +1,7 @@ -# Prompt user for details -$subscriptionId = Read-Host "Enter Subscription ID" -$resourceGroup = Read-Host "Enter Resource Group Name" -$vmName = Read-Host "Enter VM Name" +# Enter parameters +$subscriptionId = Read-Host "" +$resourceGroup = Read-Host "" +$vmName = Read-Host "" # Set resource details $resourceType = "Microsoft.Compute/virtualMachines" @@ -10,7 +10,7 @@ $resourceId = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/prov # Get Azure access token $accessToken = az account get-access-token --query accessToken -o tsv -# Function to invoke Azure Monitor Metrics API +# Invoke Azure Monitor Metrics API function Get-Metrics { [CmdletBinding()] param ( @@ -39,7 +39,7 @@ function Get-Metrics { } } -# Function to check if Data Disk Latency data is violating thresholds +# Check if data disk latency violates thresholds function Check-Latency { [CmdletBinding()] param ( @@ -78,7 +78,7 @@ function Check-Latency { } } -# Function to check metrics other than Latency and evaluate if they are throttled +# Check metrics other than latency to evaluate for throttling function Check-OtherMetricsThrottled { [CmdletBinding()] param ( @@ -114,7 +114,7 @@ function Check-OtherMetricsThrottled { return $violatedMetrics } -# Function to compare the times for Latency Metric & other Throttled Metrics. Logs Violations with Values & Timestamps +# Compare times for latency & other throttled metrics. Logs the volations with values & timestamps function CompareTimes { [CmdletBinding()] param ( @@ -163,13 +163,13 @@ if (-not [int]::TryParse($latencyThreshold, [ref]0)) { Write-Host "No valid input provided. Using Default 500ms for disk latency threshold" } -# Main Logic Execution: +# Execute main logic $latencyMetrics = Get-Metrics -accessToken $accessToken -resourceId $resourceId -metricNames "Data Disk Latency" $latencyResult = Check-Latency -metrics $latencyMetrics -latencyThreshold $latencyThreshold if ($latencyResult.Flag) { - # Only if Latency is flagged we will check for other metrics. If no disk latency is experienced, machine is likely not throttled but only at high consumption + # If latency is flagged, check for other metrics. If there is no disk latency, machine is likely not throttled but only at high consumption Write-Verbose "Checking the following metrics: Data Disk Bandwidth Consumed Percentage,Data Disk IOPS Consumed Percentage,VM Cached Bandwidth Consumed Percentage,VM Cached IOPS Consumed Percentage,VM Uncached Bandwidth Consumed Percentage,VM Uncached IOPS Consumed Percentage" $DiskVMMetrics = Get-Metrics -accessToken $accessToken -resourceId $resourceId -metricNames "Data Disk Bandwidth Consumed Percentage,Data Disk IOPS Consumed Percentage,VM Cached Bandwidth Consumed Percentage,VM Cached IOPS Consumed Percentage,VM Uncached Bandwidth Consumed Percentage,VM Uncached IOPS Consumed Percentage" From d80560971d22949c42a1ce8fac72708952de10ad Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Thu, 23 May 2024 14:39:25 +0200 Subject: [PATCH 008/159] Initial commit for README.md --- .../manage/polybase/external-table/README.md | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 samples/manage/polybase/external-table/README.md diff --git a/samples/manage/polybase/external-table/README.md b/samples/manage/polybase/external-table/README.md new file mode 100644 index 0000000000..412fb4ae98 --- /dev/null +++ b/samples/manage/polybase/external-table/README.md @@ -0,0 +1,109 @@ + +![](https://github.com/microsoft/sql-server-samples/blob/master/media/solutions-microsoft-logo-small.png) + +# Handling Update Statistics Error on External Tables in SQL Server + +This sample describes an option to update statistics on SQL Server PolyBase external tables! + +## Background + +In the process of configuring a maintenance plan for a SQL Server database with external tables and external data sources for PolyBase queries, an error occurred during the update statistics task. + +## Problem Encountered + +While attempting to update statistics on an external table, the following error message was encountered: + +```sql +UPDATE STATISTICS [dbo].[ExternalTableName] WITH FULLSCAN, COLUMNS + +Message 46519, level 16, state 22 + +The object Update Statistics isn't supported on External Table +``` + +### Contents + +[About this sample](#about-this-sample)
+[Before you begin](#before-you-begin)
+[Case history](#case-history)
+[Resolution steps](#resolution-steps)
+[Further considerations](#further-considerations)
+[Outcome](#outcome)
+[Disclaimers](#disclaimers)
+[Related links](#related-links)
+ + + +## About this sample + +- **Applies to:** SQL Server 2017 (or higher) +- **Key features:** Update statistics +- **Workload:** No workload related to this sample +- **Programming Language:** T-SQL +- **Authors:** [Sergio Govoni](https://www.linkedin.com/in/sgovoni/) | [Microsoft MVP Profile](https://mvp.microsoft.com/mvp/profile/c7b770c0-3c9a-e411-93f2-9cb65495d3c4) | [Blog](https://segovoni.medium.com/) | [GitHub](https://github.com/segovoni) | [Twitter](https://twitter.com/segovoni) + + + +## Before you begin + +To run this example, the following basic concepts are required. + +[SQL Server PolyBase](https://learn.microsoft.com/sql/relational-databases/polybase/polybase-guide?WT.mc_id=DP-MVP-4029181) enables your SQL Server instance to query data with T-SQL directly from SQL Server, Oracle, Teradata, MongoDB, Hadoop clusters, Cosmos DB, and S3-compatible object storage without separately installing client connection software. If you are new to PolyBase, you can find initial information in this article: [Polybase for beginners](https://techcommunity.microsoft.com/t5/sql-server-support-blog/polybase-for-beginners/ba-p/1075336). + + + +## Case history + +Upon investigation, it became apparent that SQL Server does not support the direct updating of statistics on external tables, as documented in the [CREATE STATISTICS documentation page](https://learn.microsoft.com/sql/t-sql/statements/create-statistics-transact-sql?WT.mc_id=DP-MVP-4029181#limitations-and-restrictions). + + + +## Resolution steps + +1. Understanding the Limitation: + +Referring to the documentation page, it explicitly states, "Updating statistics is not supported on external tables. To update statistics on an external table, drop and re-create the statistics." + +2. Available Solutions: + +Option 1: Ignore External Tables: +This option is not feasible for maintenance plans managed by SQL Server Management Studio, necessitating third-party solutions. + +Option 2: Drop and Recreate Statistics: +Employ a stored procedure, `sp_drop_create_stats_external_table`, to generate T-SQL statements for dropping and creating statistics on external tables. This procedure supports statistics on multiple columns. + +3. Implementation Guide: + +- Execute `sp_drop_create_stats_external_table` to generate T-SQL statements +- Execute DROP STATISTICS statements before the maintenance statistics task +- Execute CREATE STATISTICS statements after the maintenance statistics task +- Implement robust error handling during the maintenance plan execution +- Validate the presence of statistics on the external table upon completion + + + +## Further considerations + +- When dealing with large external tables, consider the performance implications of using default sampling versus full scan options +- Note that external tables utilizing DELIMITEDTEXT, CSV, PARQUET, or DELTA as data types only support statistics for one column per CREATE STATISTICS command + + + +## Outcome + +By integrating the `sp_drop_create_stats_external_table` stored procedure into the maintenance plan, developers can effectively manage statistics on external tables within SQL Server databases, ensuring optimal performance and reliability. + +From the maintenance plan prospective, CREATE and DROP STATISTICS statements can be stored on a temporary table or working table and executed separately. DROP STATISTICS statements can be executed before the maintenance statistics task and afterward the CREATE STATISTICS statements. Pay attention to the error handling during the maintenance plan because, at the end of the maintenance, statistics have to be in place on the external table. The output of the stored procedure cannot be missed. + + + +## Disclaimers + +This code sample is provided for demonstration and educational purposes only. It is recommended to use it with caution and fully understand its implications before applying it in a production environment. The provided code may not fully reflect the best development or security practices and may require adjustments to meet specific project requirements. The author disclaims any liability for any damages resulting from the use or interpretation of this material. + + + +## Related Links + + +For more information, see these articles... \ No newline at end of file From b03edd99d03b977bce7104f557b5ed649051e1b7 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Thu, 23 May 2024 15:01:05 +0200 Subject: [PATCH 009/159] Cosmetic care on README.md --- .../manage/polybase/external-table/README.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/samples/manage/polybase/external-table/README.md b/samples/manage/polybase/external-table/README.md index 412fb4ae98..1e8e3ea477 100644 --- a/samples/manage/polybase/external-table/README.md +++ b/samples/manage/polybase/external-table/README.md @@ -1,9 +1,9 @@ ![](https://github.com/microsoft/sql-server-samples/blob/master/media/solutions-microsoft-logo-small.png) -# Handling Update Statistics Error on External Tables in SQL Server +# Handling UPDATE STATISTICS error on SQL Server PolyBase external tables -This sample describes an option to update statistics on SQL Server PolyBase external tables! +This sample describes an option to update statistics on SQL Server PolyBase external tables. ## Background @@ -37,7 +37,7 @@ The object Update Statistics isn't supported on External Table ## About this sample - **Applies to:** SQL Server 2017 (or higher) -- **Key features:** Update statistics +- **Key features:** UPDATE STATISTICS - **Workload:** No workload related to this sample - **Programming Language:** T-SQL - **Authors:** [Sergio Govoni](https://www.linkedin.com/in/sgovoni/) | [Microsoft MVP Profile](https://mvp.microsoft.com/mvp/profile/c7b770c0-3c9a-e411-93f2-9cb65495d3c4) | [Blog](https://segovoni.medium.com/) | [GitHub](https://github.com/segovoni) | [Twitter](https://twitter.com/segovoni) @@ -60,19 +60,19 @@ Upon investigation, it became apparent that SQL Server does not support the dire ## Resolution steps -1. Understanding the Limitation: +### Understanding the Limitation Referring to the documentation page, it explicitly states, "Updating statistics is not supported on external tables. To update statistics on an external table, drop and re-create the statistics." -2. Available Solutions: +### Available Solutions -Option 1: Ignore External Tables: -This option is not feasible for maintenance plans managed by SQL Server Management Studio, necessitating third-party solutions. +* Option 1: Ignore External Tables: + * This option is not feasible for maintenance plans managed by SQL Server Management Studio, necessitating third-party solutions. -Option 2: Drop and Recreate Statistics: -Employ a stored procedure, `sp_drop_create_stats_external_table`, to generate T-SQL statements for dropping and creating statistics on external tables. This procedure supports statistics on multiple columns. +* Option 2: Drop and Recreate Statistics: + * Employ a stored procedure, `sp_drop_create_stats_external_table`, to generate T-SQL statements for dropping and creating statistics on external tables. This procedure supports statistics on multiple columns. -3. Implementation Guide: +### Implementation Guide - Execute `sp_drop_create_stats_external_table` to generate T-SQL statements - Execute DROP STATISTICS statements before the maintenance statistics task @@ -106,4 +106,4 @@ This code sample is provided for demonstration and educational purposes only. It ## Related Links -For more information, see these articles... \ No newline at end of file +For more information, see these articles... From 1c11b10d600a3ed74319180a5b3f19e32b581ada Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Thu, 23 May 2024 15:08:53 +0200 Subject: [PATCH 010/159] Add related links --- samples/manage/polybase/external-table/README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/samples/manage/polybase/external-table/README.md b/samples/manage/polybase/external-table/README.md index 1e8e3ea477..c8c49f51b8 100644 --- a/samples/manage/polybase/external-table/README.md +++ b/samples/manage/polybase/external-table/README.md @@ -9,7 +9,7 @@ This sample describes an option to update statistics on SQL Server PolyBase exte In the process of configuring a maintenance plan for a SQL Server database with external tables and external data sources for PolyBase queries, an error occurred during the update statistics task. -## Problem Encountered +## Problem encountered While attempting to update statistics on an external table, the following error message was encountered: @@ -60,11 +60,11 @@ Upon investigation, it became apparent that SQL Server does not support the dire ## Resolution steps -### Understanding the Limitation +### Understanding the limitation Referring to the documentation page, it explicitly states, "Updating statistics is not supported on external tables. To update statistics on an external table, drop and re-create the statistics." -### Available Solutions +### Available solutions * Option 1: Ignore External Tables: * This option is not feasible for maintenance plans managed by SQL Server Management Studio, necessitating third-party solutions. @@ -72,7 +72,7 @@ Referring to the documentation page, it explicitly states, "Updating statistics * Option 2: Drop and Recreate Statistics: * Employ a stored procedure, `sp_drop_create_stats_external_table`, to generate T-SQL statements for dropping and creating statistics on external tables. This procedure supports statistics on multiple columns. -### Implementation Guide +### Implementation guide - Execute `sp_drop_create_stats_external_table` to generate T-SQL statements - Execute DROP STATISTICS statements before the maintenance statistics task @@ -103,7 +103,11 @@ This code sample is provided for demonstration and educational purposes only. It -## Related Links +## Related links -For more information, see these articles... +For more information, see these articles: + +- [Data virtualization with PolyBase in SQL Server](https://learn.microsoft.com/sql/relational-databases/polybase/polybase-guide?WT.mc_id=DP-MVP-4029181) +- [UPDATE STATISTICS (Transact-SQL)](https://learn.microsoft.com/sql/t-sql/statements/update-statistics-transact-sql?WT.mc_id=DP-MVP-4029181) +- [External tables: Why create statistics?](https://learn.microsoft.com/answers/questions/978155/external-tables-why-create-statistics?WT.mc_id=DP-MVP-4029181) From e299b4b35830d1ce9d301ce00c304059fe9eec53 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Thu, 23 May 2024 15:24:57 +0200 Subject: [PATCH 011/159] Initial commit sp_drop_create_stats_external_table --- .../sp-drop-create-stats-external-table.sql | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 samples/manage/polybase/external-table/source/sp-drop-create-stats-external-table.sql diff --git a/samples/manage/polybase/external-table/source/sp-drop-create-stats-external-table.sql b/samples/manage/polybase/external-table/source/sp-drop-create-stats-external-table.sql new file mode 100644 index 0000000000..d937266f52 --- /dev/null +++ b/samples/manage/polybase/external-table/source/sp-drop-create-stats-external-table.sql @@ -0,0 +1,213 @@ +------------------------------------------------------------------------ +-- Project: sp_drop_create_stats_external_table -- +-- -- +-- The stored procedure is able to generate all the -- +-- T-SQL statements for drop and create statistics -- +-- defined on SQL Server external tables in your -- +-- database! -- +-- -- +-- File: Stored procedure implementation -- +-- Author: Sergio Govoni https://www.linkedin.com/in/sgovoni/ -- +-- Notes: -- -- +------------------------------------------------------------------------ + + +IF OBJECT_ID('dbo.sp_drop_create_stats_external_table', 'P') IS NOT NULL + DROP PROCEDURE dbo.sp_drop_create_stats_external_table; +GO + +CREATE PROCEDURE dbo.sp_drop_create_stats_external_table +AS BEGIN + /* + Author: Sergio Govoni https://www.linkedin.com/in/sgovoni/ + Version: 1.0 + License: MIT License + */ + + DECLARE + -- Output table + @DropCreateSQLCmd TABLE + ( + ID INTEGER IDENTITY(1, 1) NOT NULL + ,SchemaName SYSNAME NOT NULL + ,TableName SYSNAME NOT NULL + ,ObjectType SYSNAME NOT NULL + ,OperationType NCHAR(1) NOT NULL + ,SQLCmd NVARCHAR(1024) NOT NULL + ); + + -- Generate CREATE STATISTICS statements + WITH StatCreate AS + ( + SELECT + 'A' AS RowType + ,T.[object_id] + ,T.stats_id + ,T.StatLevel + ,T.KeyOrdinal + ,T.SchemaName + ,T.TableName + ,CAST('CREATE ' + + 'STATISTICS [' + TRIM(T.StatsName) + + '] ON [' + TRIM(T.SchemaName) + + '].[' + TRIM(T.TableName) + + '] ( ' AS VARCHAR(MAX)) AS SQLCmd + FROM + ( + SELECT + DISTINCT + stat.[object_id] + ,stat.stats_id + ,CAST(0 AS INTEGER) AS StatLevel + ,CAST(0 AS INTEGER) AS KeyOrdinal + ,stat.name AS StatsName + ,sch.name AS SchemaName + ,obj.name AS TableName + FROM + sys.stats_columns AS statc + JOIN + sys.stats AS stat ON ((stat.stats_id = statc.stats_id) + AND (stat.[object_id] = statc.[object_id])) + JOIN + sys.objects AS obj ON statc.[object_id] = obj.[object_id] + JOIN + sys.external_tables external_tab ON ((external_tab.[object_id] = obj.[object_id]) + AND (external_tab.[schema_id] = obj.[schema_id])) + JOIN + sys.columns AS col ON ((col.column_id = statc.column_id) + AND (col.[object_id] = statc.[object_id])) + JOIN + sys.schemas AS sch ON obj.[schema_id] = sch.[schema_id] + WHERE + ((stat.auto_created = 1) OR (stat.user_created = 1)) + AND (obj.type = 'U') + ) AS T + + UNION ALL + + SELECT + 'R' AS RowType + ,statcol.[object_id] + ,statcol.stats_id + ,CAST(S.StatLevel + 1 AS INTEGER) AS IdxLevel + ,CAST(statcol.stats_column_id AS INTEGER) AS KeyOrdinal + ,S.SchemaName + ,S.TableName + ,CAST(S.SQLCmd + CASE(statcol.stats_column_id) WHEN 1 THEN '' ELSE ',' END + + '[' + TRIM(col.name) + + '] ' AS VARCHAR(MAX)) AS SQLCmd + FROM + StatCreate AS S + JOIN + sys.stats_columns AS statcol ON ((statcol.[object_id] = S.[object_id]) + AND (statcol.stats_id = S.stats_id)) + JOIN + sys.columns AS col ON ((col.column_id = statcol.column_id) + AND (col.[object_id] = statcol.[object_id])) + WHERE + (statcol.stats_column_id = (S.KeyOrdinal + 1)) + ), + StatCreateGroup AS + ( + SELECT + MAX(S.KeyOrdinal) AS MaxKeyOrdinal + ,S.[object_id] + ,S.stats_id + FROM + StatCreate AS S + JOIN + sys.objects AS O ON O.[object_id] = S.[object_id] + WHERE + (S.RowType = 'R') + GROUP BY + S.[object_id] + ,S.stats_id + ) + INSERT INTO @DropCreateSQLCmd + ( + SchemaName + ,TableName + ,ObjectType + ,OperationType + ,SQLCmd + ) + SELECT + StatCreate.SchemaName + ,StatCreate.TableName + ,'STATS' AS ObjecType + ,'C' AS OperationType + ,StatCreate.SQLCmd + ') WITH FULLSCAN;' AS SQLCmd + FROM + StatCreateGroup + JOIN + StatCreate ON ((StatCreate.[object_id] = StatCreateGroup.[object_id]) + AND (StatCreate.stats_id = StatCreateGroup.stats_id)) + AND (StatCreate.KeyOrdinal = StatCreateGroup.MaxKeyOrdinal); + + -- Generate DROP STATISTICS statements + WITH StatsDrop AS + ( + SELECT + T.SchemaName + ,T.TableName + ,'STATS' AS ObjectType + ,'D' AS OperationType + ,'DROP STATISTICS [' + + TRIM(SchemaName) + '].[' + + TRIM(TableName) + '].[' + + TRIM(StatisticName) + '];' AS SQLCmd + + FROM ( + SELECT + sch.[Name] as SchemaName + ,obj.[Name] as TableName + ,stat.[Name] as StatisticName + FROM + sys.stats AS stat + INNER JOIN + sys.objects AS obj ON stat.[object_id] = obj.[object_id] + INNER JOIN + sys.external_tables external_tab ON ((external_tab.[object_id] = obj.[object_id]) + AND (external_tab.[schema_id] = obj.[schema_id])) + INNER JOIN + sys.schemas AS sch ON obj.[schema_id] = sch.[schema_id] + WHERE + ((stat.auto_created = 1) OR (stat.user_created = 1)) + AND (obj.type = 'U') + ) AS T + ) + INSERT INTO @DropCreateSQLCmd + ( + SchemaName + ,TableName + ,ObjectType + ,OperationType + ,SQLCmd + ) + SELECT + SchemaName + ,TableName + ,ObjectType + ,OperationType + ,SQLCmd + FROM + StatsDrop; + + SELECT + ID + ,SchemaName + ,TableName + ,ObjectType + ,OperationType + ,SQLCmd + FROM + @DropCreateSQLCmd; + + RETURN; +END; +GO + +/* +EXEC dbo.sp_drop_create_stats_external_table; +GO +*/ \ No newline at end of file From 7bcef17abe61886fe44ab02fc314dc927cef43fc Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Thu, 23 May 2024 15:43:55 +0200 Subject: [PATCH 012/159] Add link to SP source code --- samples/manage/polybase/external-table/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/polybase/external-table/README.md b/samples/manage/polybase/external-table/README.md index c8c49f51b8..79e03bb56d 100644 --- a/samples/manage/polybase/external-table/README.md +++ b/samples/manage/polybase/external-table/README.md @@ -70,7 +70,7 @@ Referring to the documentation page, it explicitly states, "Updating statistics * This option is not feasible for maintenance plans managed by SQL Server Management Studio, necessitating third-party solutions. * Option 2: Drop and Recreate Statistics: - * Employ a stored procedure, `sp_drop_create_stats_external_table`, to generate T-SQL statements for dropping and creating statistics on external tables. This procedure supports statistics on multiple columns. + * Employ a stored procedure, [sp_drop_create_stats_external_table](https://github.com/microsoft/sql-server-samples/tree/master/samples/manage/polybase/external-table/source/sp-drop-create-stats-external-table.sql), to generate T-SQL statements for dropping and creating statistics on external tables. This procedure supports statistics on multiple columns. ### Implementation guide From e37dd54657d26b7c2bf703bab23a5adc5d22b9db Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Thu, 23 May 2024 16:01:20 +0200 Subject: [PATCH 013/159] Add link to new sample on database management --- samples/manage/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/manage/README.md b/samples/manage/README.md index 0a24ac8f4d..adf3291c21 100644 --- a/samples/manage/README.md +++ b/samples/manage/README.md @@ -17,3 +17,6 @@ This Solution Quick Start provides a solution for a Software-as-a-Solution (SaaS ## Windows Containers This includes samples for setting up mssql-server in Windows Containers. Currently it only includes a link to the separately maintained [mssql-docker](https://github.com/Microsoft/mssql-docker/blob/master/windows/README.md) instructions. + +## Handling UPDATE STATISTICS error on SQL Server PolyBase external tables +[This sample](https://github.com/microsoft/sql-server-samples/tree/master/samples/manage/polybase/external-table/README.md) describes an option to update statistics on SQL Server PolyBase external tables. From 60edf5f39297ef4c3c130c8eb68ac4b472072100 Mon Sep 17 00:00:00 2001 From: Sergio Govoni Date: Fri, 24 May 2024 15:01:19 +0200 Subject: [PATCH 014/159] Update the sample title --- samples/manage/README.md | 2 +- samples/manage/polybase/external-table/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/README.md b/samples/manage/README.md index adf3291c21..477015372a 100644 --- a/samples/manage/README.md +++ b/samples/manage/README.md @@ -18,5 +18,5 @@ This Solution Quick Start provides a solution for a Software-as-a-Solution (SaaS ## Windows Containers This includes samples for setting up mssql-server in Windows Containers. Currently it only includes a link to the separately maintained [mssql-docker](https://github.com/Microsoft/mssql-docker/blob/master/windows/README.md) instructions. -## Handling UPDATE STATISTICS error on SQL Server PolyBase external tables +## Handling UPDATE STATISTICS on SQL Server PolyBase external tables [This sample](https://github.com/microsoft/sql-server-samples/tree/master/samples/manage/polybase/external-table/README.md) describes an option to update statistics on SQL Server PolyBase external tables. diff --git a/samples/manage/polybase/external-table/README.md b/samples/manage/polybase/external-table/README.md index 79e03bb56d..670b1c228d 100644 --- a/samples/manage/polybase/external-table/README.md +++ b/samples/manage/polybase/external-table/README.md @@ -1,7 +1,7 @@ ![](https://github.com/microsoft/sql-server-samples/blob/master/media/solutions-microsoft-logo-small.png) -# Handling UPDATE STATISTICS error on SQL Server PolyBase external tables +# Handling UPDATE STATISTICS on SQL Server PolyBase external tables This sample describes an option to update statistics on SQL Server PolyBase external tables. From 0354d1b31e0346794d6880fb08e38bfb22e9fda8 Mon Sep 17 00:00:00 2001 From: Mehul Chamria <64285622+MehulChamria@users.noreply.github.com> Date: Tue, 28 May 2024 14:46:42 +0100 Subject: [PATCH 015/159] Update delegateSubnet.ps1 Spell Check --- .../delegate-subnet/delegateSubnet.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-sql-db-managed-instance/delegate-subnet/delegateSubnet.ps1 b/samples/manage/azure-sql-db-managed-instance/delegate-subnet/delegateSubnet.ps1 index e3010da16a..529a35307a 100644 --- a/samples/manage/azure-sql-db-managed-instance/delegate-subnet/delegateSubnet.ps1 +++ b/samples/manage/azure-sql-db-managed-instance/delegate-subnet/delegateSubnet.ps1 @@ -17,7 +17,7 @@ function VerifyPSVersion { Write-Host "PowerShell version verified." -ForegroundColor Green } else { - Write-Host "You need to install PowerShell version 5.1 or heigher." -ForegroundColor Red + Write-Host "You need to install PowerShell version 5.1 or higher." -ForegroundColor Red Break; } } @@ -26,7 +26,7 @@ function VerifyPSVersion { Write-Host "PowerShell version verified." -ForegroundColor Green } else { - Write-Host "You need to install PowerShell version 6.0 or heigher." -ForegroundColor Red + Write-Host "You need to install PowerShell version 6.0 or higher." -ForegroundColor Red Break; } } From 71800f0f534c025ef2ded11d08a442948de66997 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 18:19:03 +0200 Subject: [PATCH 016/159] Replace the legacy Standard SKU with VpnGw1 --- .../attach-vpn-gateway/azuredeploy.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json index fa4e4dd0b2..d116af3552 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json @@ -74,8 +74,8 @@ } ], "sku": { - "name": "Standard", - "tier": "Standard" + "name": "VpnGw1", + "tier": "VpnGw1" }, "gatewayType": "Vpn", "vpnType": "RouteBased", From a457465b274caed883d3e8fcdd0f5413c56bd5a1 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 18:28:29 +0200 Subject: [PATCH 017/159] Set the SKU for public IP addys to Standard --- .../attach-vpn-gateway/azuredeploy.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json index d116af3552..f5525a9244 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json @@ -47,7 +47,8 @@ "name": "[variables('gatewayPublicIpAddressName')]", "location": "[parameters('location')]", "properties": { - "publicIPAllocationMethod": "Dynamic" + "publicIPAllocationMethod": "Dynamic", + "Sku": "Standard" } }, { From ee46d852510dc2afee43e4120c8ec9453c5e46c1 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 18:32:48 +0200 Subject: [PATCH 018/159] Fix syntax --- .../attach-vpn-gateway/azuredeploy.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json index f5525a9244..2f0bd1259b 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json @@ -46,9 +46,9 @@ "type": "Microsoft.Network/publicIPAddresses", "name": "[variables('gatewayPublicIpAddressName')]", "location": "[parameters('location')]", + "Sku": "Standard", "properties": { - "publicIPAllocationMethod": "Dynamic", - "Sku": "Standard" + "publicIPAllocationMethod": "Dynamic" } }, { From 71edf6096ff0b5713f4ac323ce276dbc8d648f3c Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 18:36:48 +0200 Subject: [PATCH 019/159] Fix syntax fix --- .../attach-vpn-gateway/azuredeploy.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json index 2f0bd1259b..b04c15e41f 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json @@ -46,7 +46,9 @@ "type": "Microsoft.Network/publicIPAddresses", "name": "[variables('gatewayPublicIpAddressName')]", "location": "[parameters('location')]", - "Sku": "Standard", + "sku": { + "name": "Standard" + }, "properties": { "publicIPAllocationMethod": "Dynamic" } From eb4279fb9205a287cbe27837b74e48ffcb259ec2 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 18:43:26 +0200 Subject: [PATCH 020/159] Avoid Dynamic allocation --- .../attach-vpn-gateway/azuredeploy.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json index b04c15e41f..d785c1d268 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json @@ -50,7 +50,8 @@ "name": "Standard" }, "properties": { - "publicIPAllocationMethod": "Dynamic" + "publicIPAllocationMethod": "Static", + "publicIPAddressVersion": "IPv4" } }, { From 9f1440613fcb96325913d0a64fc88fff3456a136 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 18:49:54 +0200 Subject: [PATCH 021/159] Increase GW subnet size to account for ZR --- .../attach-vpn-gateway/attachVPNGateway.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 index aa66caa0ec..d289bf3136 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 @@ -239,7 +239,7 @@ $gatewaySubnetName = "GatewaySubnet" If ($false -eq $subnets.Contains($gatewaySubnetName)) { Write-Host "$gatewaySubnetName is not one of the subnets in $subnets" -ForegroundColor Yellow - $gatewaySubnetPrefix = CalculateNextAddressPrefix $virtualNetwork 28 + $gatewaySubnetPrefix = CalculateNextAddressPrefix $virtualNetwork 27 Write-Host "Creating subnet $gatewaySubnetName ($gatewaySubnetPrefix) in the virtual network ..." -ForegroundColor Green $virtualNetwork.AddressSpace.AddressPrefixes.Add($gatewaySubnetPrefix) From d181e237b8dbbdff3d48808105e61b2e456ce256 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 29 May 2024 11:20:45 -0700 Subject: [PATCH 022/159] initial draft --- .../install-payg-sql-server.ps1 | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 new file mode 100644 index 0000000000..51a6298ca9 --- /dev/null +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -0,0 +1,88 @@ +param ( + [string]$AzureSubscriptionId, + [string]$AzureResourceGroupUri, + [string]$location, + [string]$SqlServerInstanceName, + [string]$SqlServerAdminAccount, + [string]$SqlServerAdminPassword, + [string]$SqlServerVersion, + [string]$SqlServerEdition, + [string]$SqlServerProductKey, + [string]$SqlServerCU = "latest", + [string]$isoURL # URL to the ISO file +) + +try { + # Step 0: 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 1: Log in to Azure + az login + $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 + } + az group update --name $AzureResourceGroupUri --tags "ArcOnboarding=Blocked" + + + + # Step 3: Onboard the VM to Azure Arc + $hostName = (Get-WmiObject Win32_ComputerSystem).Name + + az arc connectedmachine create --resource-group $AzureResourceGroupUri --name $hostName --location $location + + # Step 4: Install SQL Arc extension with LT=PAYG + az connectedmachine extension create --machine-name $hostName --resource-group $AzureResourceGroupUri --name "WindowsAgent.SqlServer" --type "WindowsAgent.SqlServer" --publisher "Microsoft.AzureData" --settings '{"LicenseType":"PAYG", "SqlManagement": {"IsEnabled":true}}' + + + # Step 5: Automatically download installable media + $localPath = "C:\path\to\download\SQLServer.iso" + $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 $localPath + } else { + throw "Not enough free space to download the ISO." + } + + + # Step 6: Mount the ISO file as a volume + $volumeInfo = Mount-DiskImage -ImagePath $localPath -PassThru | Get-Volume + + # Step 7: Run unattended SQL Server setup from the mounted volume + $setupPath = ($volumeInfo.DriveLetter + ":\setup.exe") + Start-Process -FilePath $setupPath -ArgumentList "/q /ACTION=Install /INSTANCENAME=$SqlServerInstanceName /FEATURES=SQL /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS=$SqlServerAdminAccount /SQLSVCACCOUNT=$SqlServerAdminAccount /SQLSVCPASSWORD=$SqlServerAdminPassword /AGTSVCACCOUNT=$SqlServerAdminAccount /AGTSVCPASSWORD=$SqlServerAdminPassword /IACCEPTSQLSERVERLICENSETERMS /PID=$SqlServerProductKey /SQLSERVERUPDATE=$SqlServerCU" + + # Step 8: Dismount the ISO file after installation + Dismount-DiskImage -ImagePath $localPath + + # Step 9: Remove the media from the local file system + Remove-Item -Path $localPath + + # Step 10: Display the status of the Azure resource + az resource show --ids $AzureResourceGroupUri + + # Step 11: Verify the presence of the Arc-enabled SQL Server + az sql arc list --resource-group $AzureResourceGroupUri +} 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." +} From 673feb11478ded8f3333b00a8b187109c5d798ea Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 29 May 2024 12:20:15 -0700 Subject: [PATCH 023/159] progress --- .../install-payg-sql-server.ps1 | 121 +++++++++++++++--- 1 file changed, 104 insertions(+), 17 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 51a6298ca9..77d4501e70 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -1,25 +1,114 @@ param ( + [Parameter (Mandatory=$true)] [string]$AzureSubscriptionId, + [Parameter (Mandatory=$true)] [string]$AzureResourceGroupUri, + [Parameter (Mandatory=$true)] [string]$location, + [Parameter (Mandatory=$false)] [string]$SqlServerInstanceName, + [Parameter (Mandatory=$true)] [string]$SqlServerAdminAccount, + [Parameter (Mandatory=$true)] [string]$SqlServerAdminPassword, + [Parameter (Mandatory=$true)] [string]$SqlServerVersion, + [Parameter (Mandatory=$true)] [string]$SqlServerEdition, + [Parameter (Mandatory=$true)] [string]$SqlServerProductKey, + [Parameter (Mandatory=$false)] [string]$SqlServerCU = "latest", - [string]$isoURL # URL to the ISO file + [Parameter (Mandatory=$false)] + [string]$isoLocation = "C:\download\SQLServer.iso" ) +# 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: Check if setup.exe is already running and kill it if so + # ISO URL for each version + $isoURL @{ + 2012 = ""; + 2014 = ""; + 2016 = ""; + 2019 = ""; + 2022 = "https://download.microsoft.com/download/7/c/1/7c14e92e-bdcb-4f89-b7cf-93543e7112d1/SQLServer2019-x64-ENU-Dev.iso" + } + + #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 1: Log in to Azure + # Step 2: Log in to Azure az login $subscription = Get-AzSubscription -SubscriptionId $AzureSubscriptionId -ErrorAction SilentlyContinue if (-not $subscription) { @@ -38,8 +127,6 @@ try { } az group update --name $AzureResourceGroupUri --tags "ArcOnboarding=Blocked" - - # Step 3: Onboard the VM to Azure Arc $hostName = (Get-WmiObject Win32_ComputerSystem).Name @@ -50,29 +137,29 @@ try { # Step 5: Automatically download installable media - $localPath = "C:\path\to\download\SQLServer.iso" - $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 $localPath - } else { - throw "Not enough free space to download the ISO." + + if (!(Test-Path -Path $isoLocation)) { + $freeSpace = (Get-PSDrive -Name C).Free + $isoSize = (Invoke-WebRequest -Uri $isoURL[$SqlServerVersion] -Method Head).Headers.'Content-Length' + if ($freeSpace -gt $isoSize) { + Start-BitsTransfer -Source $isoURL[$SqlServerVersion] -Destination $isoLocation + } else { + throw "Not enough free space to download the ISO." + } } - # Step 6: Mount the ISO file as a volume - $volumeInfo = Mount-DiskImage -ImagePath $localPath -PassThru | Get-Volume + $volumeInfo = Mount-DiskImage -ImagePath $isoLocation -PassThru | Get-Volume # Step 7: Run unattended SQL Server setup from the mounted volume $setupPath = ($volumeInfo.DriveLetter + ":\setup.exe") Start-Process -FilePath $setupPath -ArgumentList "/q /ACTION=Install /INSTANCENAME=$SqlServerInstanceName /FEATURES=SQL /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS=$SqlServerAdminAccount /SQLSVCACCOUNT=$SqlServerAdminAccount /SQLSVCPASSWORD=$SqlServerAdminPassword /AGTSVCACCOUNT=$SqlServerAdminAccount /AGTSVCPASSWORD=$SqlServerAdminPassword /IACCEPTSQLSERVERLICENSETERMS /PID=$SqlServerProductKey /SQLSERVERUPDATE=$SqlServerCU" # Step 8: Dismount the ISO file after installation - Dismount-DiskImage -ImagePath $localPath + Dismount-DiskImage -ImagePath $isoLocation # Step 9: Remove the media from the local file system - Remove-Item -Path $localPath + Remove-Item -Path $isoLocation # Step 10: Display the status of the Azure resource az resource show --ids $AzureResourceGroupUri From e3c50e23bd93f69a888336bd3255d8b0c0381c81 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 21:39:34 +0200 Subject: [PATCH 024/159] Adjust GW subnet's starting addr space per suffix size --- .../attach-vpn-gateway/attachVPNGateway.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 index d289bf3136..d05a78d343 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 @@ -162,7 +162,10 @@ function CalculateNextAddressPrefix { $startIPAddress = $endIPAddress } } - $startIPAddress += 1 + # round up to the next possible start for the given suffix size + $suffixLength = 32 - $prefixLength + $startIPAddress = (($startIPAddress -shr $suffixLength) + 1) -shl $suffixLength + # convert and return $addressPrefixResult = (ConvertUInt32ToIPAddress $startIPAddress) + "/" + $prefixLength Write-Host "Using address prefix $addressPrefixResult." -ForegroundColor Green return $addressPrefixResult From 3177256e4dd6867d679f18932e7c5b1183c83141 Mon Sep 17 00:00:00 2001 From: Zoran Rilak <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 29 May 2024 21:53:36 +0200 Subject: [PATCH 025/159] Don't skip blocks if suffix size fits --- .../attach-vpn-gateway/attachVPNGateway.ps1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 index d05a78d343..aedf2e4d30 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 @@ -162,9 +162,12 @@ function CalculateNextAddressPrefix { $startIPAddress = $endIPAddress } } - # round up to the next possible start for the given suffix size - $suffixLength = 32 - $prefixLength - $startIPAddress = (($startIPAddress -shr $suffixLength) + 1) -shl $suffixLength + $startIPAddress += 1 + # if crossing a block boundary, round to the next possible start for the given suffix size + if (($startIPAddress -shr $prefixLength) -ne 0) { + $suffixLength = 32 - $prefixLength + $startIPAddress = (($startIPAddress -shr $suffixLength) + 1) -shl $suffixLength + } # convert and return $addressPrefixResult = (ConvertUInt32ToIPAddress $startIPAddress) + "/" + $prefixLength Write-Host "Using address prefix $addressPrefixResult." -ForegroundColor Green From 2c2c4c09be511e9321cbd1f19fdfdfb19ecbadc6 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 29 May 2024 13:00:21 -0700 Subject: [PATCH 026/159] Added isoURL --- .../install-payg-sql-server.ps1 | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 77d4501e70..2794a959fd 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -17,6 +17,8 @@ param ( [string]$SqlServerEdition, [Parameter (Mandatory=$true)] [string]$SqlServerProductKey, + [Parameter (Mandatory=$true)] + [string]$isoURL, [Parameter (Mandatory=$false)] [string]$SqlServerCU = "latest", [Parameter (Mandatory=$false)] @@ -78,14 +80,6 @@ function LoadModule } try { - # ISO URL for each version - $isoURL @{ - 2012 = ""; - 2014 = ""; - 2016 = ""; - 2019 = ""; - 2022 = "https://download.microsoft.com/download/7/c/1/7c14e92e-bdcb-4f89-b7cf-93543e7112d1/SQLServer2019-x64-ENU-Dev.iso" - } #Step 0: Ensure PS version and load missing Azure modules # @@ -140,9 +134,9 @@ try { if (!(Test-Path -Path $isoLocation)) { $freeSpace = (Get-PSDrive -Name C).Free - $isoSize = (Invoke-WebRequest -Uri $isoURL[$SqlServerVersion] -Method Head).Headers.'Content-Length' + $isoSize = (Invoke-WebRequest -Uri $isoURL -Method Head).Headers.'Content-Length' if ($freeSpace -gt $isoSize) { - Start-BitsTransfer -Source $isoURL[$SqlServerVersion] -Destination $isoLocation + Start-BitsTransfer -Source $isoURL -Destination $isoLocation } else { throw "Not enough free space to download the ISO." } From 370587b66e801eb900f26ee278a1ef416a3c9c10 Mon Sep 17 00:00:00 2001 From: zoran-rilak-msft <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Thu, 30 May 2024 11:52:01 +0200 Subject: [PATCH 027/159] Fix the boundary crossing check --- .../attach-vpn-gateway/attachVPNGateway.ps1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 index aedf2e4d30..cc5aff0de9 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/attachVPNGateway.ps1 @@ -164,9 +164,12 @@ function CalculateNextAddressPrefix { } $startIPAddress += 1 # if crossing a block boundary, round to the next possible start for the given suffix size - if (($startIPAddress -shr $prefixLength) -ne 0) { - $suffixLength = 32 - $prefixLength - $startIPAddress = (($startIPAddress -shr $suffixLength) + 1) -shl $suffixLength + $suffixLength = 32 - $prefixLength + $mask = (1 -shl $suffixLength) - 1 + if (($startIPAddress -band $mask) -ne $startIPAddress) { + $x = $startIPAddress -shr $suffixLength + $x += 1 + $startIPAddress = $x -shl $suffixLength } # convert and return $addressPrefixResult = (ConvertUInt32ToIPAddress $startIPAddress) + "/" + $prefixLength From 2b4156619d9537fd7c38b758d6369b8fb1837aeb Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 6 Jun 2024 11:31:50 -0700 Subject: [PATCH 028/159] replaced az with PS, added verification KQL --- .../install-payg-sql-server.ps1 | 55 +++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 2794a959fd..c4f06b96b5 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -103,7 +103,7 @@ try { } # Step 2: Log in to Azure - az login + Connect-AzAccount $subscription = Get-AzSubscription -SubscriptionId $AzureSubscriptionId -ErrorAction SilentlyContinue if (-not $subscription) { Write-Error "Azure subscription with ID '$AzureSubscriptionId' does not exist." @@ -119,18 +119,15 @@ try { Write-Error "Resource group '$AzureResourceGroupUri' does not exist." exit } - az group update --name $AzureResourceGroupUri --tags "ArcOnboarding=Blocked" + $tags = @{"ArcOnboarding" = "Blocked"} + Set-AzResourceGroup -Name $AzureResourceGroupUri -Tag $tags # Step 3: Onboard the VM to Azure Arc $hostName = (Get-WmiObject Win32_ComputerSystem).Name - az arc connectedmachine create --resource-group $AzureResourceGroupUri --name $hostName --location $location + New-AzConnectedMachine -ResourceGroupName $AzureResourceGroupUri -Name $hostName -Location $location - # Step 4: Install SQL Arc extension with LT=PAYG - az connectedmachine extension create --machine-name $hostName --resource-group $AzureResourceGroupUri --name "WindowsAgent.SqlServer" --type "WindowsAgent.SqlServer" --publisher "Microsoft.AzureData" --settings '{"LicenseType":"PAYG", "SqlManagement": {"IsEnabled":true}}' - - - # Step 5: Automatically download installable media + # Step 4: Automatically download installable media if (!(Test-Path -Path $isoLocation)) { $freeSpace = (Get-PSDrive -Name C).Free @@ -142,24 +139,50 @@ try { } } - # Step 6: Mount the ISO file as a volume + # Step 5: Mount the ISO file as a volume $volumeInfo = Mount-DiskImage -ImagePath $isoLocation -PassThru | Get-Volume - # Step 7: Run unattended SQL Server setup from the mounted volume + # Step 6: Run unattended SQL Server setup from the mounted volume $setupPath = ($volumeInfo.DriveLetter + ":\setup.exe") Start-Process -FilePath $setupPath -ArgumentList "/q /ACTION=Install /INSTANCENAME=$SqlServerInstanceName /FEATURES=SQL /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS=$SqlServerAdminAccount /SQLSVCACCOUNT=$SqlServerAdminAccount /SQLSVCPASSWORD=$SqlServerAdminPassword /AGTSVCACCOUNT=$SqlServerAdminAccount /AGTSVCPASSWORD=$SqlServerAdminPassword /IACCEPTSQLSERVERLICENSETERMS /PID=$SqlServerProductKey /SQLSERVERUPDATE=$SqlServerCU" - # Step 8: Dismount the ISO file after installation + # 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 9: Remove the media from the local file system + # Step 10: Remove the media from the local file system Remove-Item -Path $isoLocation - # Step 10: Display the status of the Azure resource - az resource show --ids $AzureResourceGroupUri + # 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)" - # Step 11: Verify the presence of the Arc-enabled SQL Server - az sql arc list --resource-group $AzureResourceGroupUri } catch { Write-Error "An error occurred: $_" # You can add additional error handling logic here From fa3f5134959d60a43ba0f39ea6ee3075e47969af Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 6 Jun 2024 15:14:38 -0700 Subject: [PATCH 029/159] Added edition to setup --- .../install-payg-sql-server.ps1 | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index c4f06b96b5..3193cb812b 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -144,7 +144,23 @@ try { # Step 6: Run unattended SQL Server setup from the mounted volume $setupPath = ($volumeInfo.DriveLetter + ":\setup.exe") - Start-Process -FilePath $setupPath -ArgumentList "/q /ACTION=Install /INSTANCENAME=$SqlServerInstanceName /FEATURES=SQL /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS=$SqlServerAdminAccount /SQLSVCACCOUNT=$SqlServerAdminAccount /SQLSVCPASSWORD=$SqlServerAdminPassword /AGTSVCACCOUNT=$SqlServerAdminAccount /AGTSVCPASSWORD=$SqlServerAdminPassword /IACCEPTSQLSERVERLICENSETERMS /PID=$SqlServerProductKey /SQLSERVERUPDATE=$SqlServerCU" + $argumentList = " + /q + /ACTION=Install + /INSTANCENAME='$($SqlServerInstanceName)' + /FEATURES=SQL + /INSTANCEDIR=C:\SQL + /SQLSYSADMINACCOUNTS='$($SqlServerAdminAccount)' + /SQLSVCACCOUNT='$($SqlServerAdminAccount)' + /SQLSVCPASSWORD='$($SqlServerAdminPassword)' + /AGTSVCACCOUNT='$($SqlServerAdminAccount)' + /AGTSVCPASSWORD='$($SqlServerAdminPassword)' + /IACCEPTSQLSERVERLICENSETERMS + /PID='$($SqlServerProductKey)' + /SQLSERVERUPDATE='$($SqlServerCU)' + /Edition='$($SqlServerEdition)' + " + Start-Process -FilePath $setupPath -ArgumentList $argumentList # Step 7: Install SQL Arc extension with LT=PAYG $Settings = @{ @@ -164,18 +180,18 @@ try { # Step 8: Display the status of the Azure resource for Arc-enabled SQL Server $query = " resources - | where type =~ "microsoft.hybridcompute/machines" + | where type =~ 'microsoft.hybridcompute/machines' | where resourceGroup =~ '$($AzureResourceGroupUri)' - | where properties.detectedProperties.mssqldiscovered == "true" + | 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/")), "") + | 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"), ""), + 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) From 3f479bbfbb2ef6105e5d3b1ec8d0475d73d16878 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 6 Jun 2024 15:23:21 -0700 Subject: [PATCH 030/159] Fixed azure region --- .../install-payg-sql-server.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 3193cb812b..801cedb34d 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -4,7 +4,7 @@ param ( [Parameter (Mandatory=$true)] [string]$AzureResourceGroupUri, [Parameter (Mandatory=$true)] - [string]$location, + [string]$AzureRegion, [Parameter (Mandatory=$false)] [string]$SqlServerInstanceName, [Parameter (Mandatory=$true)] @@ -20,9 +20,8 @@ param ( [Parameter (Mandatory=$true)] [string]$isoURL, [Parameter (Mandatory=$false)] - [string]$SqlServerCU = "latest", - [Parameter (Mandatory=$false)] - [string]$isoLocation = "C:\download\SQLServer.iso" + [string]$SqlServerCU = "latest" + ) # This function checks if the specified module is imported into the session and if not installes and/or imports it @@ -125,10 +124,11 @@ try { # Step 3: Onboard the VM to Azure Arc $hostName = (Get-WmiObject Win32_ComputerSystem).Name - New-AzConnectedMachine -ResourceGroupName $AzureResourceGroupUri -Name $hostName -Location $location + 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' From 0e2ae65786e724cb6fd6d9c20d22cf22c7aec145 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 6 Jun 2024 15:45:26 -0700 Subject: [PATCH 031/159] added svc account --- .../install-payg-sql-server.ps1 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 801cedb34d..25242f59eb 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -12,6 +12,10 @@ param ( [Parameter (Mandatory=$true)] [string]$SqlServerAdminPassword, [Parameter (Mandatory=$true)] + [string]$SqlServerSvcAccount, + [Parameter (Mandatory=$true)] + [string]$SqlServerSvcPassword, + [Parameter (Mandatory=$true)] [string]$SqlServerVersion, [Parameter (Mandatory=$true)] [string]$SqlServerEdition, @@ -151,10 +155,11 @@ try { /FEATURES=SQL /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS='$($SqlServerAdminAccount)' - /SQLSVCACCOUNT='$($SqlServerAdminAccount)' - /SQLSVCPASSWORD='$($SqlServerAdminPassword)' - /AGTSVCACCOUNT='$($SqlServerAdminAccount)' - /AGTSVCPASSWORD='$($SqlServerAdminPassword)' + /SAPWD='$($SqlServerAdminPassword)' + /SQLSVCACCOUNT='$($SqlServerSvcAccount)' + /SQLSVCPASSWORD='$($SqlServerSvcPassword)' + /AGTSVCACCOUNT='$($SqlServerSvcAccount)' + /AGTSVCPASSWORD='$($SqlServerSvcPassword)' /IACCEPTSQLSERVERLICENSETERMS /PID='$($SqlServerProductKey)' /SQLSERVERUPDATE='$($SqlServerCU)' From a698ca951dd991d2526ed2d336c7ea6999d72e54 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 6 Jun 2024 15:48:32 -0700 Subject: [PATCH 032/159] removed SA password --- .../install-payg-sql-server/install-payg-sql-server.ps1 | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 25242f59eb..447012b64f 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -8,9 +8,7 @@ param ( [Parameter (Mandatory=$false)] [string]$SqlServerInstanceName, [Parameter (Mandatory=$true)] - [string]$SqlServerAdminAccount, - [Parameter (Mandatory=$true)] - [string]$SqlServerAdminPassword, + [string]$SqlServerAdminAccounts, [Parameter (Mandatory=$true)] [string]$SqlServerSvcAccount, [Parameter (Mandatory=$true)] @@ -154,8 +152,7 @@ try { /INSTANCENAME='$($SqlServerInstanceName)' /FEATURES=SQL /INSTANCEDIR=C:\SQL - /SQLSYSADMINACCOUNTS='$($SqlServerAdminAccount)' - /SAPWD='$($SqlServerAdminPassword)' + /SQLSYSADMINACCOUNTS='$($SqlServerAdminAccounts)' /SQLSVCACCOUNT='$($SqlServerSvcAccount)' /SQLSVCPASSWORD='$($SqlServerSvcPassword)' /AGTSVCACCOUNT='$($SqlServerSvcAccount)' From d440166ac5ffe66b3873c2c4426ab5aae8b2d750 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 7 Jun 2024 23:35:17 +0000 Subject: [PATCH 033/159] adding connection test script --- .../troubleshooting/test-connectivity.ps1 | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 samples/features/azure-arc/troubleshooting/test-connectivity.ps1 diff --git a/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 b/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 new file mode 100644 index 0000000000..185384fe6d --- /dev/null +++ b/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 @@ -0,0 +1,64 @@ +#This script repeatedly probes all regions for connectivity to the Azure Arc data services/Arc-enabled SQL Server endpoints for telemetry and the data processing service. +#The script will output the status of the connectivity to the console. +#The script will run indefinitely until stopped by the user. +#The script will iterate through all regions in the $regions array. +#The list of regions are updated as of June 7,2024 to reflect all publicly available, supported Azure regions for Arc-enabled SQL Server. + +$regions = @( + "East US", + "East US 2", + "West US 2", + "West US 3", + "Central US", + "North Central US", + "South Central US", + "West Central US", + "Canada Central", + "Canada East", + "UK South", + "UK West", + "France Central", + "West Europe", + "North Europe", + "Switzerland North", + "Central India", + "Brazil South", + "South Africa North", + "UAE North", + "Japan East", + "Korea Central", + "Southeast Asia", + "Australia East", + "Sweden Central", + "Norway East" +) + +$regions = $regions | ForEach-Object { $_.Replace(" ", "") } + +do{ + $regions | ForEach-Object { + $dps_url = "dataprocessingservice.$_.arcdataservices.com" + $ti_url = "telemetry.$_.arcdataservices.com" + try{ + $dps_result = (Invoke-WebRequest -Uri $dps_url -Method Get).StatusCode + }catch{ + $dps_result = $_.Exception.Message + } + try{ + $ti_result = (Invoke-WebRequest -Uri $ti_url -Method Get).StatusCode + if($ti_result -contains "401"){ #As of now, the telemetry endpoint returns unauthorized status code if accessing in an unauthenticated way. Since this is a connectivity test script, a 401 response is good enough to establish availability and connectivity. + $ti_result = "Expected" + } + }catch{ + if($_.Exception.Message -like "*401*"){ + $ti_result = "Expected" + } + else { + $ti_result = $_.Exception.Message + } + + } + Write-Host $dps_result $ti_result " :: $_" + } + Write-Host "============================================" +} while($true) From 4580a3702834fa8342a621832b16e1d141d23ba1 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Sat, 8 Jun 2024 03:24:39 +0000 Subject: [PATCH 034/159] format better and show response time --- .../troubleshooting/test-connectivity.ps1 | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 b/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 index 185384fe6d..965990923a 100644 --- a/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 +++ b/samples/features/azure-arc/troubleshooting/test-connectivity.ps1 @@ -40,15 +40,13 @@ do{ $dps_url = "dataprocessingservice.$_.arcdataservices.com" $ti_url = "telemetry.$_.arcdataservices.com" try{ - $dps_result = (Invoke-WebRequest -Uri $dps_url -Method Get).StatusCode + $dps_response_time = Measure-Command { $response = Invoke-WebRequest -Uri $dps_url -Method Get } + $dps_result = ($response).StatusCode }catch{ $dps_result = $_.Exception.Message } try{ - $ti_result = (Invoke-WebRequest -Uri $ti_url -Method Get).StatusCode - if($ti_result -contains "401"){ #As of now, the telemetry endpoint returns unauthorized status code if accessing in an unauthenticated way. Since this is a connectivity test script, a 401 response is good enough to establish availability and connectivity. - $ti_result = "Expected" - } + $ti_response_time = Measure-Command { $response = Invoke-WebRequest -Uri $ti_url -Method Get -SkipHttpErrorCheck } }catch{ if($_.Exception.Message -like "*401*"){ $ti_result = "Expected" @@ -56,9 +54,17 @@ do{ else { $ti_result = $_.Exception.Message } - } - Write-Host $dps_result $ti_result " :: $_" + if ($ti_response_time.TotalSeconds -gt 3 -or $dps_response_time.TotalSeconds -gt 3 -or $dps_result -ne 200 -or $ti_result -ne "Expected") { + Write-Host $dps_result "($dps_response_time) " $ti_result " ($ti_response_time) :: $_" -ForegroundColor Red + } + elseif ($ti_response_time.TotalSeconds -gt 1 -or $dps_response_time.TotalSeconds -gt 1) { + Write-Host $dps_result "($dps_response_time) " $ti_result " ($ti_response_time) :: $_" -ForegroundColor Yellow + } + else + { + Write-Host $dps_result "($dps_response_time) " $ti_result " ($ti_response_time) :: $_" + } } - Write-Host "============================================" -} while($true) + Write-Host "=====================================================================" +} while($true) \ No newline at end of file From d5aed9df004de10183255bb007445d516db93d96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:58:28 +0000 Subject: [PATCH 035/159] Bump com.azure:azure-identity Bumps [com.azure:azure-identity](https://github.com/Azure/azure-sdk-for-java) from 1.0.4 to 1.12.2. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-sdk-bom_1.0.4...azure-identity_1.12.2) --- updated-dependencies: - dependency-name: com.azure:azure-identity dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../java/Unix-based/AzureSqlHibernateSample/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlHibernateSample/pom.xml b/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlHibernateSample/pom.xml index 563c34af82..ac8bec2711 100644 --- a/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlHibernateSample/pom.xml +++ b/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlHibernateSample/pom.xml @@ -50,7 +50,7 @@ com.azure azure-identity - 1.0.4 + 1.12.2 org.slf4j From a337e16a26bd6c0bc86fe5205c7af708948f4ba0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:40:34 +0000 Subject: [PATCH 036/159] Bump Azure.Identity Bumps [Azure.Identity](https://github.com/Azure/azure-sdk-for-net) from 1.11.0 to 1.11.4. - [Release notes](https://github.com/Azure/azure-sdk-for-net/releases) - [Commits](https://github.com/Azure/azure-sdk-for-net/compare/Azure.Identity_1.11.0...Azure.Identity_1.11.4) --- updated-dependencies: - dependency-name: Azure.Identity dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../features/security/ledger/source/ContosoHR/ContosoHR.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/features/security/ledger/source/ContosoHR/ContosoHR.csproj b/samples/features/security/ledger/source/ContosoHR/ContosoHR.csproj index 99e6ed6546..9be5ac6bb6 100644 --- a/samples/features/security/ledger/source/ContosoHR/ContosoHR.csproj +++ b/samples/features/security/ledger/source/ContosoHR/ContosoHR.csproj @@ -43,7 +43,7 @@ - + From bfcc39ab0eb64be4e1c208871a2f2b3f2cf63b38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:46:50 +0000 Subject: [PATCH 037/159] Bump azure-identity Bumps [azure-identity](https://github.com/Azure/azure-sdk-for-python) from 1.6.0 to 1.16.1. - [Release notes](https://github.com/Azure/azure-sdk-for-python/releases) - [Changelog](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/esrp_release.md) - [Commits](https://github.com/Azure/azure-sdk-for-python/compare/azure-identity_1.6.0...azure-identity_1.16.1) --- updated-dependencies: - dependency-name: azure-identity dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../kms_plugin_app/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt index 2b367a6821..7105f927bc 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt @@ -2,5 +2,5 @@ pycrypto==2.6.1 pycryptodome==3.19.1 cryptography==41.0.4 hvac==0.10.11 -azure-identity==1.6.0 +azure-identity==1.16.1 azure-keyvault-keys==4.3.1 From 7873626aa6f1cb49a62128fd35a7378daa3f195b Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 10:01:36 -0700 Subject: [PATCH 038/159] Removed /SQLSERVERUPDATE --- .../install-payg-sql-server.ps1 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 447012b64f..6ff5d8f1f8 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -20,10 +20,7 @@ param ( [Parameter (Mandatory=$true)] [string]$SqlServerProductKey, [Parameter (Mandatory=$true)] - [string]$isoURL, - [Parameter (Mandatory=$false)] - [string]$SqlServerCU = "latest" - + [string]$isoURL ) # This function checks if the specified module is imported into the session and if not installes and/or imports it @@ -149,7 +146,6 @@ try { $argumentList = " /q /ACTION=Install - /INSTANCENAME='$($SqlServerInstanceName)' /FEATURES=SQL /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS='$($SqlServerAdminAccounts)' @@ -159,9 +155,12 @@ try { /AGTSVCPASSWORD='$($SqlServerSvcPassword)' /IACCEPTSQLSERVERLICENSETERMS /PID='$($SqlServerProductKey)' - /SQLSERVERUPDATE='$($SqlServerCU)' /Edition='$($SqlServerEdition)' " + if ($SqlServerInstanceName) { + $argumentList += "/INSTANCENAME='$($SqlServerInstanceName)'" + } + Start-Process -FilePath $setupPath -ArgumentList $argumentList # Step 7: Install SQL Arc extension with LT=PAYG From 01a8300e869e1b87b23a865becbd13d93d3a6c06 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 17:26:46 -0700 Subject: [PATCH 039/159] added activate license script --- .../activate-pcore-license/README.md | 86 +++++++++++++++++++ .../activate-pcore-license.md | 83 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md create mode 100644 samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md new file mode 100644 index 0000000000..c44992d0d7 --- /dev/null +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -0,0 +1,86 @@ +--- +services: Azure SQL +platforms: Azure +author: anosov1960 +ms.author: sashan +ms.date: 06/12/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 + +# Launching the script + +The script accepts the following command line parameters: + +| **Parameter**                                         | **Value**                                                                       | **Description** | +|:--|:--|:--| +|-licenseId| License resource URI | +|-UseInRunbook| \$True or \$False (default) | Optional: must be $True when executed as a Runbook| + + +## Example + +The following command activate the license + +```PowerShell +.\activate-pcore-license.ps1 -licenseID +``` + +# Running the script using Cloud Shell + +To run the script in the Cloud Shell, use the following steps: + +1. Launch the [Cloud Shell](https://shell.azure.com/). For details, read [PowerShell in Cloud Shell](https://aka.ms/pscloudshell/docs). + +2. Upload the script to the shell using the following command: + + ```console + curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-hybrid-benefit/sql-license-usage.ps1 -o sql-license-usage.ps1 + ``` + +3. Run the script with a set of parameters that reflect your desired configuration. + + ```console + .\activate-pcore-license.ps1 -licenseID + ``` + +> [!NOTE] +> - To paste the commands into the shell, use `Ctrl-Shift-V` on Windows or `Cmd-v` on MacOS. +> - The `curl` command will copy the script directly to the home folder associated with your Cloud Shell session. + +# Running the script as 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-hybrid-benefit/sql-license-usage.ps1 -o sql-license-usage.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. You must add this user to all the target subscriptions with at least a *Reader* access role. To collect the Unregistered vCores, the user must be at least a *Contributor*. See [Role assignment portal](https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal) for the instructions about role assignments. +1. Select *Credentials* in the **Shared resources** group and create a credential object with the database username and password. The script will use these to connect to the specified database to save the license utilization data. +1. Select *Modules* in the **Shared resources** group and make sure your automation account have the following PowerShell modules installed. If not, add them from the Gallery. + - Az.Accounts + - Az.Resources +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 with the desired frequency of runs and the expiration time. +1. Click on *Parameters and run settings* and specify the following parameters: + - LICENSEID. Put in teh resourec URI + - USEINRUNBOOKS. Select True to activate the logic that authenticates the runbook using the *Azure Run As Account*. +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) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md new file mode 100644 index 0000000000..81d274ab7c --- /dev/null +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -0,0 +1,83 @@ +# +# This script performes a scheduled activation of a SQL Server p-core license. +# +# The script accepts the following command line parameters: +# +# -licenseID (The specific resource URI) +# + +param ( + [Parameter (Mandatory= $true)] + [string] $licenseId, + [Parameter (Mandatory= $false)] + [string] $UseInRunbook = $true +) + +function CheckModule ($m) { + + # This function ensures that the specified module is imported into the session + # If module is already imported - do nothing + + if (!(Get-Module | Where-Object {$_.Name -eq $m})) { + # If module is not imported, but available on disk then import + if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { + Import-Module $m + } + else { + + # If module is not imported, not available on disk, but is in online gallery then install and import + if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { + Install-Module -Name $m -Force -Verbose -Scope CurrentUser + Import-Module $m + } + else { + + # If module is not imported, not available and not in online gallery then abort + write-host "Module $m not imported, not available and not in online gallery, exiting." + EXIT 1 + } + } + } +} + +# +# Suppress warnings +# +Update-AzConfig -DisplayBreakingChangeWarning $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 + } +}else{ + # Ensure that the required modules are imported + # In Runbooks these modules must be added to the automation account manually + + $requiredModules = @( + "Az.Accounts", + "Az.Resources" + ) + $requiredModules | Foreach-Object {CheckModule $_} +} + +$newActivationState = "Activated" +Set-AzResource -ResourceId $licenseId -PropertyObject @{"properties.activationState" = $newActivationState} -Force + From 6713bef69a67768caed15d567ae4a4d2b6595bf9 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 17:47:02 -0700 Subject: [PATCH 040/159] fixed URL --- .../activate-pcore-license/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index c44992d0d7..f20a639674 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -67,7 +67,7 @@ You can scahedule to run the the command as a runbook. To set it up using Azure 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-hybrid-benefit/sql-license-usage.ps1 -o sql-license-usage.ps1 +curl https://raw.githubusercontent.com/anosov1960/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. You must add this user to all the target subscriptions with at least a *Reader* access role. To collect the Unregistered vCores, the user must be at least a *Contributor*. See [Role assignment portal](https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal) for the instructions about role assignments. From deccf74d928dea1de3366a3956482629cacb4bf6 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 18:00:04 -0700 Subject: [PATCH 041/159] Fixed URL --- .../activate-pcore-license/README.md | 8 ++++---- .../activate-pcore-license/activate-pcore-license.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index f20a639674..1ba9cf28b6 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -27,7 +27,7 @@ The script accepts the following command line parameters: | **Parameter**                                         | **Value**                                                                       | **Description** | |:--|:--|:--| -|-licenseId| License resource URI | +|-LicenseId| License resource URI | |-UseInRunbook| \$True or \$False (default) | Optional: must be $True when executed as a Runbook| @@ -36,7 +36,7 @@ The script accepts the following command line parameters: The following command activate the license ```PowerShell -.\activate-pcore-license.ps1 -licenseID +.\activate-pcore-license.ps1 -LicenseID ``` # Running the script using Cloud Shell @@ -48,13 +48,13 @@ To run the script in the Cloud Shell, use the following steps: 2. Upload the script to the shell using the following command: ```console - curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-hybrid-benefit/sql-license-usage.ps1 -o sql-license-usage.ps1 + curl https://raw.githubusercontent.com/anosov1960/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md -o activate-pcore-license.ps1 ``` 3. Run the script with a set of parameters that reflect your desired configuration. ```console - .\activate-pcore-license.ps1 -licenseID + .\activate-pcore-license.ps1 -licenseID ``` > [!NOTE] diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 81d274ab7c..34ca0399b1 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -8,7 +8,7 @@ param ( [Parameter (Mandatory= $true)] - [string] $licenseId, + [string] $LicenseId, [Parameter (Mandatory= $false)] [string] $UseInRunbook = $true ) @@ -79,5 +79,5 @@ if ($UseInRunbook){ } $newActivationState = "Activated" -Set-AzResource -ResourceId $licenseId -PropertyObject @{"properties.activationState" = $newActivationState} -Force +Set-AzResource -ResourceId $LicenseId -PropertyObject @{"properties.activationState" = $newActivationState} -Force From e0eb733357ccc3e12a896f30976fd68d435670c7 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 18:02:52 -0700 Subject: [PATCH 042/159] Added instructions --- .../activate-pcore-license/activate-pcore-license.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 34ca0399b1..10be86a193 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -3,7 +3,8 @@ # # The script accepts the following command line parameters: # -# -licenseID (The specific resource URI) +# -LicenseID (The specific resource URI) +# -UseInRunbook (True to use Azure Runbook) # param ( From a776aecadf8952f329002d4914756d6f6a7874d0 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 18:07:19 -0700 Subject: [PATCH 043/159] Temp change default --- .../activate-pcore-license/activate-pcore-license.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 10be86a193..6000ac8b99 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -11,7 +11,7 @@ param ( [Parameter (Mandatory= $true)] [string] $LicenseId, [Parameter (Mandatory= $false)] - [string] $UseInRunbook = $true + [string] $UseInRunbook = $false ) function CheckModule ($m) { From a58f6f5d11e1f8b757fed270e156fffdb31e62a6 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 20:23:00 -0700 Subject: [PATCH 044/159] Fixed logic --- .../activate-pcore-license/activate-pcore-license.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 6000ac8b99..2b4ea2e1fc 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -79,6 +79,7 @@ if ($UseInRunbook){ $requiredModules | Foreach-Object {CheckModule $_} } -$newActivationState = "Activated" -Set-AzResource -ResourceId $LicenseId -PropertyObject @{"properties.activationState" = $newActivationState} -Force +$currentLicense = Get-AzResource -ResourceId $LicenseId +$currentLicense.properties.activationState = "Activated" +$currentLicense | Set-AzResource -Force From 01020de8cb281bb1fd4280f5de2643fdd06f3429 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 23:37:15 -0700 Subject: [PATCH 045/159] Fix parameters --- .../activate-pcore-license/README.md | 6 +----- .../activate-pcore-license/activate-pcore-license.md | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index 1ba9cf28b6..edc77eeb9b 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -70,11 +70,7 @@ You can scahedule to run the the command as a runbook. To set it up using Azure curl https://raw.githubusercontent.com/anosov1960/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. You must add this user to all the target subscriptions with at least a *Reader* access role. To collect the Unregistered vCores, the user must be at least a *Contributor*. See [Role assignment portal](https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal) for the instructions about role assignments. -1. Select *Credentials* in the **Shared resources** group and create a credential object with the database username and password. The script will use these to connect to the specified database to save the license utilization data. -1. Select *Modules* in the **Shared resources** group and make sure your automation account have the following PowerShell modules installed. If not, add them from the Gallery. - - Az.Accounts - - Az.Resources +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 with the desired frequency of runs and the expiration time. diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 2b4ea2e1fc..5d40020170 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -10,8 +10,8 @@ param ( [Parameter (Mandatory= $true)] [string] $LicenseId, - [Parameter (Mandatory= $false)] - [string] $UseInRunbook = $false + [Parameter (Mandatory= $true)] + [string] $UseInRunbook ) function CheckModule ($m) { From 58a15954a2bdc1f9eaf05303c485e8c177a33330 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 12 Jun 2024 23:41:11 -0700 Subject: [PATCH 046/159] Fix type --- .../activate-pcore-license/activate-pcore-license.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 5d40020170..35ca9ccb83 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -11,7 +11,7 @@ param ( [Parameter (Mandatory= $true)] [string] $LicenseId, [Parameter (Mandatory= $true)] - [string] $UseInRunbook + [bool] $UseInRunbook ) function CheckModule ($m) { From 5070d5ec75109df03d093b9056ca9813376874e9 Mon Sep 17 00:00:00 2001 From: soradotwav Date: Thu, 13 Jun 2024 14:08:21 -0700 Subject: [PATCH 047/159] Added original v_backup files --- samples/features/sqlvdi/{ => include}/vdi.h | 714 ++++++++------- .../features/sqlvdi/{ => include}/vdierror.h | 0 .../features/sqlvdi/{ => include}/vdiguid.h | 23 +- samples/features/sqlvdi/mprocess/mprocess.cpp | 648 ++++++++++++++ samples/features/sqlvdi/mprocess/mprocess.dsp | 100 +++ samples/features/sqlvdi/mprocess/mprocess.dsw | 29 + samples/features/sqlvdi/mthread/mthread.cpp | 600 +++++++++++++ samples/features/sqlvdi/mthread/mthread.dsp | 100 +++ samples/features/sqlvdi/mthread/mthread.dsw | 29 + samples/features/sqlvdi/osimple/osimple.cpp | 659 ++++++++++++++ samples/features/sqlvdi/osimple/osimple.dsp | 100 +++ samples/features/sqlvdi/osimple/osimple.dsw | 29 + samples/features/sqlvdi/simple/simple.cpp | 348 ++++++++ samples/features/sqlvdi/simple/simple.dsp | 100 +++ samples/features/sqlvdi/simple/simple.dsw | 29 + samples/features/sqlvdi/snapshot/snapshot.cpp | 828 ++++++++++++++++++ samples/features/sqlvdi/snapshot/snapshot.dsp | 100 +++ samples/features/sqlvdi/snapshot/snapshot.dsw | 29 + 18 files changed, 4101 insertions(+), 364 deletions(-) rename samples/features/sqlvdi/{ => include}/vdi.h (74%) rename samples/features/sqlvdi/{ => include}/vdierror.h (100%) rename samples/features/sqlvdi/{ => include}/vdiguid.h (83%) create mode 100644 samples/features/sqlvdi/mprocess/mprocess.cpp create mode 100644 samples/features/sqlvdi/mprocess/mprocess.dsp create mode 100644 samples/features/sqlvdi/mprocess/mprocess.dsw create mode 100644 samples/features/sqlvdi/mthread/mthread.cpp create mode 100644 samples/features/sqlvdi/mthread/mthread.dsp create mode 100644 samples/features/sqlvdi/mthread/mthread.dsw create mode 100644 samples/features/sqlvdi/osimple/osimple.cpp create mode 100644 samples/features/sqlvdi/osimple/osimple.dsp create mode 100644 samples/features/sqlvdi/osimple/osimple.dsw create mode 100644 samples/features/sqlvdi/simple/simple.cpp create mode 100644 samples/features/sqlvdi/simple/simple.dsp create mode 100644 samples/features/sqlvdi/simple/simple.dsw create mode 100644 samples/features/sqlvdi/snapshot/snapshot.cpp create mode 100644 samples/features/sqlvdi/snapshot/snapshot.dsp create mode 100644 samples/features/sqlvdi/snapshot/snapshot.dsw diff --git a/samples/features/sqlvdi/vdi.h b/samples/features/sqlvdi/include/vdi.h similarity index 74% rename from samples/features/sqlvdi/vdi.h rename to samples/features/sqlvdi/include/vdi.h index 97404b79e3..e7e6f56c93 100644 --- a/samples/features/sqlvdi/vdi.h +++ b/samples/features/sqlvdi/include/vdi.h @@ -3,17 +3,25 @@ /* this ALWAYS GENERATED file contains the definitions for the interfaces */ - /* File created by MIDL compiler version 7.00.0555 */ -/* at Tue Oct 12 14:51:44 2010 + /* File created by MIDL compiler version 7.00.0408 */ +/* at Tue Sep 28 18:18:04 2004 */ - +/* Compiler settings for vdi.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) #pragma warning( disable: 4049 ) /* more than 64k source lines */ /* verify that the version is high enough to compile this file*/ #ifndef __REQUIRED_RPCNDR_H_VERSION__ -#define __REQUIRED_RPCNDR_H_VERSION__ 440 +#define __REQUIRED_RPCNDR_H_VERSION__ 475 #endif #include "rpc.h" @@ -35,7 +43,7 @@ #pragma once #endif -/* Forward Declarations */ +/* Forward Declarations */ #ifndef __IClientVirtualDevice_FWD_DEFINED__ #define __IClientVirtualDevice_FWD_DEFINED__ @@ -78,11 +86,13 @@ typedef interface IServerVirtualDeviceSet2 IServerVirtualDeviceSet2; #ifdef __cplusplus extern "C"{ -#endif +#endif +void * __RPC_USER MIDL_user_allocate(size_t); +void __RPC_USER MIDL_user_free( void * ); -/* interface __MIDL_itf_vdi_0000_0000 */ -/* [local] */ +/* interface __MIDL_itf_vdi_0000 */ +/* [local] */ #pragma pack(push, _vdi_h_) @@ -115,10 +125,8 @@ enum VDFeatures VDF_SnapshotPrepare = 0x400, VDF_EnumFrozenFiles = 0x800, VDF_VSSWriter = 0x1000, - VDF_RequestComplete = 0x2000, VDF_WriteMedia = 0x10000, VDF_ReadMedia = 0x20000, - VDF_CompleteEnabled = 0x40000, VDF_LatchStats = 0x80000000, VDF_LikePipe = 0, VDF_LikeTape = ( ( ( ( ( VDF_FileMarks | VDF_Removable ) | VDF_Rewind ) | VDF_Position ) | VDF_SkipBlocks ) | VDF_ReversePosition ) , @@ -142,15 +150,13 @@ enum VDCommands VDC_MountSnapshot = ( VDC_Snapshot + 1 ) , VDC_PrepareToFreeze = ( VDC_MountSnapshot + 1 ) , VDC_FileInfoBegin = ( VDC_PrepareToFreeze + 1 ) , - VDC_FileInfoEnd = ( VDC_FileInfoBegin + 1 ) , - VDC_GetError = (VDC_FileInfoEnd + 1), - VDC_Complete = (VDC_GetError + 1) + VDC_FileInfoEnd = ( VDC_FileInfoBegin + 1 ) } ; enum VDWhence { VDC_Beginning = 0, VDC_Current = ( VDC_Beginning + 1 ) , - VDC_End = ( VDC_Current + 1 ) + VDC_End = ( VDC_Current + 1 ) } ; struct VDC_Command { @@ -161,66 +167,65 @@ struct VDC_Command } ; -extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_0000_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_0000_v0_0_s_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_v0_0_s_ifspec; #ifndef __IClientVirtualDevice_INTERFACE_DEFINED__ #define __IClientVirtualDevice_INTERFACE_DEFINED__ /* interface IClientVirtualDevice */ -/* [object][uuid] */ +/* [object][uuid] */ EXTERN_C const IID IID_IClientVirtualDevice; #if defined(__cplusplus) && !defined(CINTERFACE) - + MIDL_INTERFACE("40700424-0080-11d2-851f-00c04fc21759") IClientVirtualDevice : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE GetCommand( + virtual HRESULT STDMETHODCALLTYPE GetCommand( /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDC_Command **ppCmd) = 0; - - virtual HRESULT STDMETHODCALLTYPE CompleteCommand( + + virtual HRESULT STDMETHODCALLTYPE CompleteCommand( /* [in] */ struct VDC_Command *pCmd, /* [in] */ DWORD dwCompletionCode, /* [in] */ DWORD dwBytesTransferred, /* [in] */ DWORDLONG dwlPosition) = 0; - + }; - + #else /* C style interface */ typedef struct IClientVirtualDeviceVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IClientVirtualDevice * This, /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - __RPC__deref_out void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( + /* [iid_is][out] */ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( IClientVirtualDevice * This); - - ULONG ( STDMETHODCALLTYPE *Release )( + + ULONG ( STDMETHODCALLTYPE *Release )( IClientVirtualDevice * This); - - HRESULT ( STDMETHODCALLTYPE *GetCommand )( + + HRESULT ( STDMETHODCALLTYPE *GetCommand )( IClientVirtualDevice * This, /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDC_Command **ppCmd); - - HRESULT ( STDMETHODCALLTYPE *CompleteCommand )( + + HRESULT ( STDMETHODCALLTYPE *CompleteCommand )( IClientVirtualDevice * This, /* [in] */ struct VDC_Command *pCmd, /* [in] */ DWORD dwCompletionCode, /* [in] */ DWORD dwBytesTransferred, /* [in] */ DWORDLONG dwlPosition); - + END_INTERFACE } IClientVirtualDeviceVtbl; @@ -229,26 +234,26 @@ EXTERN_C const IID IID_IClientVirtualDevice; CONST_VTBL struct IClientVirtualDeviceVtbl *lpVtbl; }; - + #ifdef COBJMACROS #define IClientVirtualDevice_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IClientVirtualDevice_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) + ( (This)->lpVtbl -> AddRef(This) ) #define IClientVirtualDevice_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) + ( (This)->lpVtbl -> Release(This) ) #define IClientVirtualDevice_GetCommand(This,dwTimeOut,ppCmd) \ - ( (This)->lpVtbl -> GetCommand(This,dwTimeOut,ppCmd) ) + ( (This)->lpVtbl -> GetCommand(This,dwTimeOut,ppCmd) ) #define IClientVirtualDevice_CompleteCommand(This,pCmd,dwCompletionCode,dwBytesTransferred,dwlPosition) \ - ( (This)->lpVtbl -> CompleteCommand(This,pCmd,dwCompletionCode,dwBytesTransferred,dwlPosition) ) + ( (This)->lpVtbl -> CompleteCommand(This,pCmd,dwCompletionCode,dwBytesTransferred,dwlPosition) ) #endif /* COBJMACROS */ @@ -257,7 +262,7 @@ EXTERN_C const IID IID_IClientVirtualDevice; -HRESULT STDMETHODCALLTYPE IClientVirtualDevice_GetCommand_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDevice_GetCommand_Proxy( IClientVirtualDevice * This, /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDC_Command **ppCmd); @@ -270,7 +275,7 @@ void __RPC_STUB IClientVirtualDevice_GetCommand_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDevice_CompleteCommand_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDevice_CompleteCommand_Proxy( IClientVirtualDevice * This, /* [in] */ struct VDC_Command *pCmd, /* [in] */ DWORD dwCompletionCode, @@ -293,99 +298,98 @@ void __RPC_STUB IClientVirtualDevice_CompleteCommand_Stub( #define __IClientVirtualDeviceSet_INTERFACE_DEFINED__ /* interface IClientVirtualDeviceSet */ -/* [object][uuid] */ +/* [object][uuid] */ EXTERN_C const IID IID_IClientVirtualDeviceSet; #if defined(__cplusplus) && !defined(CINTERFACE) - + MIDL_INTERFACE("40700425-0080-11d2-851f-00c04fc21759") IClientVirtualDeviceSet : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE Create( + virtual HRESULT STDMETHODCALLTYPE Create( /* [in] */ LPCWSTR lpName, /* [in] */ struct VDConfig *pCfg) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetConfiguration( + + virtual HRESULT STDMETHODCALLTYPE GetConfiguration( /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDConfig *pCfg) = 0; - - virtual HRESULT STDMETHODCALLTYPE OpenDevice( + + virtual HRESULT STDMETHODCALLTYPE OpenDevice( /* [in] */ LPCWSTR lpName, /* [out] */ IClientVirtualDevice **ppVirtualDevice) = 0; - + virtual HRESULT STDMETHODCALLTYPE Close( void) = 0; - + virtual HRESULT STDMETHODCALLTYPE SignalAbort( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE OpenInSecondary( + + virtual HRESULT STDMETHODCALLTYPE OpenInSecondary( /* [in] */ LPCWSTR lpSetName) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetBufferHandle( + + virtual HRESULT STDMETHODCALLTYPE GetBufferHandle( /* [in] */ BYTE *pBuffer, /* [out] */ DWORD *pBufferHandle) = 0; - - virtual HRESULT STDMETHODCALLTYPE MapBufferHandle( + + virtual HRESULT STDMETHODCALLTYPE MapBufferHandle( /* [in] */ DWORD dwBuffer, /* [out] */ BYTE **ppBuffer) = 0; - + }; - + #else /* C style interface */ typedef struct IClientVirtualDeviceSetVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IClientVirtualDeviceSet * This, /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - __RPC__deref_out void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( + /* [iid_is][out] */ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( IClientVirtualDeviceSet * This); - - ULONG ( STDMETHODCALLTYPE *Release )( + + ULONG ( STDMETHODCALLTYPE *Release )( IClientVirtualDeviceSet * This); - - HRESULT ( STDMETHODCALLTYPE *Create )( + + HRESULT ( STDMETHODCALLTYPE *Create )( IClientVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName, /* [in] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( IClientVirtualDeviceSet * This, /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *OpenDevice )( + + HRESULT ( STDMETHODCALLTYPE *OpenDevice )( IClientVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName, /* [out] */ IClientVirtualDevice **ppVirtualDevice); - - HRESULT ( STDMETHODCALLTYPE *Close )( + + HRESULT ( STDMETHODCALLTYPE *Close )( IClientVirtualDeviceSet * This); - - HRESULT ( STDMETHODCALLTYPE *SignalAbort )( + + HRESULT ( STDMETHODCALLTYPE *SignalAbort )( IClientVirtualDeviceSet * This); - - HRESULT ( STDMETHODCALLTYPE *OpenInSecondary )( + + HRESULT ( STDMETHODCALLTYPE *OpenInSecondary )( IClientVirtualDeviceSet * This, /* [in] */ LPCWSTR lpSetName); - - HRESULT ( STDMETHODCALLTYPE *GetBufferHandle )( + + HRESULT ( STDMETHODCALLTYPE *GetBufferHandle )( IClientVirtualDeviceSet * This, /* [in] */ BYTE *pBuffer, /* [out] */ DWORD *pBufferHandle); - - HRESULT ( STDMETHODCALLTYPE *MapBufferHandle )( + + HRESULT ( STDMETHODCALLTYPE *MapBufferHandle )( IClientVirtualDeviceSet * This, /* [in] */ DWORD dwBuffer, /* [out] */ BYTE **ppBuffer); - + END_INTERFACE } IClientVirtualDeviceSetVtbl; @@ -394,44 +398,44 @@ EXTERN_C const IID IID_IClientVirtualDeviceSet; CONST_VTBL struct IClientVirtualDeviceSetVtbl *lpVtbl; }; - + #ifdef COBJMACROS #define IClientVirtualDeviceSet_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IClientVirtualDeviceSet_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) + ( (This)->lpVtbl -> AddRef(This) ) #define IClientVirtualDeviceSet_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) + ( (This)->lpVtbl -> Release(This) ) #define IClientVirtualDeviceSet_Create(This,lpName,pCfg) \ - ( (This)->lpVtbl -> Create(This,lpName,pCfg) ) + ( (This)->lpVtbl -> Create(This,lpName,pCfg) ) #define IClientVirtualDeviceSet_GetConfiguration(This,dwTimeOut,pCfg) \ - ( (This)->lpVtbl -> GetConfiguration(This,dwTimeOut,pCfg) ) + ( (This)->lpVtbl -> GetConfiguration(This,dwTimeOut,pCfg) ) #define IClientVirtualDeviceSet_OpenDevice(This,lpName,ppVirtualDevice) \ - ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) + ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) #define IClientVirtualDeviceSet_Close(This) \ - ( (This)->lpVtbl -> Close(This) ) + ( (This)->lpVtbl -> Close(This) ) #define IClientVirtualDeviceSet_SignalAbort(This) \ - ( (This)->lpVtbl -> SignalAbort(This) ) + ( (This)->lpVtbl -> SignalAbort(This) ) #define IClientVirtualDeviceSet_OpenInSecondary(This,lpSetName) \ - ( (This)->lpVtbl -> OpenInSecondary(This,lpSetName) ) + ( (This)->lpVtbl -> OpenInSecondary(This,lpSetName) ) #define IClientVirtualDeviceSet_GetBufferHandle(This,pBuffer,pBufferHandle) \ - ( (This)->lpVtbl -> GetBufferHandle(This,pBuffer,pBufferHandle) ) + ( (This)->lpVtbl -> GetBufferHandle(This,pBuffer,pBufferHandle) ) #define IClientVirtualDeviceSet_MapBufferHandle(This,dwBuffer,ppBuffer) \ - ( (This)->lpVtbl -> MapBufferHandle(This,dwBuffer,ppBuffer) ) + ( (This)->lpVtbl -> MapBufferHandle(This,dwBuffer,ppBuffer) ) #endif /* COBJMACROS */ @@ -440,7 +444,7 @@ EXTERN_C const IID IID_IClientVirtualDeviceSet; -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_Create_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_Create_Proxy( IClientVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName, /* [in] */ struct VDConfig *pCfg); @@ -453,7 +457,7 @@ void __RPC_STUB IClientVirtualDeviceSet_Create_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_GetConfiguration_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_GetConfiguration_Proxy( IClientVirtualDeviceSet * This, /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDConfig *pCfg); @@ -466,7 +470,7 @@ void __RPC_STUB IClientVirtualDeviceSet_GetConfiguration_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_OpenDevice_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_OpenDevice_Proxy( IClientVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName, /* [out] */ IClientVirtualDevice **ppVirtualDevice); @@ -479,7 +483,7 @@ void __RPC_STUB IClientVirtualDeviceSet_OpenDevice_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_Close_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_Close_Proxy( IClientVirtualDeviceSet * This); @@ -490,7 +494,7 @@ void __RPC_STUB IClientVirtualDeviceSet_Close_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_SignalAbort_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_SignalAbort_Proxy( IClientVirtualDeviceSet * This); @@ -501,7 +505,7 @@ void __RPC_STUB IClientVirtualDeviceSet_SignalAbort_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_OpenInSecondary_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_OpenInSecondary_Proxy( IClientVirtualDeviceSet * This, /* [in] */ LPCWSTR lpSetName); @@ -513,7 +517,7 @@ void __RPC_STUB IClientVirtualDeviceSet_OpenInSecondary_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_GetBufferHandle_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_GetBufferHandle_Proxy( IClientVirtualDeviceSet * This, /* [in] */ BYTE *pBuffer, /* [out] */ DWORD *pBufferHandle); @@ -526,7 +530,7 @@ void __RPC_STUB IClientVirtualDeviceSet_GetBufferHandle_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_MapBufferHandle_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet_MapBufferHandle_Proxy( IClientVirtualDeviceSet * This, /* [in] */ DWORD dwBuffer, /* [out] */ BYTE **ppBuffer); @@ -547,92 +551,91 @@ void __RPC_STUB IClientVirtualDeviceSet_MapBufferHandle_Stub( #define __IClientVirtualDeviceSet2_INTERFACE_DEFINED__ /* interface IClientVirtualDeviceSet2 */ -/* [object][uuid] */ +/* [object][uuid] */ EXTERN_C const IID IID_IClientVirtualDeviceSet2; #if defined(__cplusplus) && !defined(CINTERFACE) - + MIDL_INTERFACE("d0e6eb07-7a62-11d2-8573-00c04fc21759") IClientVirtualDeviceSet2 : public IClientVirtualDeviceSet { public: - virtual HRESULT STDMETHODCALLTYPE CreateEx( + virtual HRESULT STDMETHODCALLTYPE CreateEx( /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpName, /* [in] */ struct VDConfig *pCfg) = 0; - - virtual HRESULT STDMETHODCALLTYPE OpenInSecondaryEx( + + virtual HRESULT STDMETHODCALLTYPE OpenInSecondaryEx( /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpSetName) = 0; - + }; - + #else /* C style interface */ typedef struct IClientVirtualDeviceSet2Vtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IClientVirtualDeviceSet2 * This, /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - __RPC__deref_out void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( + /* [iid_is][out] */ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( IClientVirtualDeviceSet2 * This); - - ULONG ( STDMETHODCALLTYPE *Release )( + + ULONG ( STDMETHODCALLTYPE *Release )( IClientVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *Create )( + + HRESULT ( STDMETHODCALLTYPE *Create )( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpName, /* [in] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( IClientVirtualDeviceSet2 * This, /* [in] */ DWORD dwTimeOut, /* [out] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *OpenDevice )( + + HRESULT ( STDMETHODCALLTYPE *OpenDevice )( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpName, /* [out] */ IClientVirtualDevice **ppVirtualDevice); - - HRESULT ( STDMETHODCALLTYPE *Close )( + + HRESULT ( STDMETHODCALLTYPE *Close )( IClientVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *SignalAbort )( + + HRESULT ( STDMETHODCALLTYPE *SignalAbort )( IClientVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *OpenInSecondary )( + + HRESULT ( STDMETHODCALLTYPE *OpenInSecondary )( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpSetName); - - HRESULT ( STDMETHODCALLTYPE *GetBufferHandle )( + + HRESULT ( STDMETHODCALLTYPE *GetBufferHandle )( IClientVirtualDeviceSet2 * This, /* [in] */ BYTE *pBuffer, /* [out] */ DWORD *pBufferHandle); - - HRESULT ( STDMETHODCALLTYPE *MapBufferHandle )( + + HRESULT ( STDMETHODCALLTYPE *MapBufferHandle )( IClientVirtualDeviceSet2 * This, /* [in] */ DWORD dwBuffer, /* [out] */ BYTE **ppBuffer); - - HRESULT ( STDMETHODCALLTYPE *CreateEx )( + + HRESULT ( STDMETHODCALLTYPE *CreateEx )( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpName, /* [in] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *OpenInSecondaryEx )( + + HRESULT ( STDMETHODCALLTYPE *OpenInSecondaryEx )( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpSetName); - + END_INTERFACE } IClientVirtualDeviceSet2Vtbl; @@ -641,51 +644,51 @@ EXTERN_C const IID IID_IClientVirtualDeviceSet2; CONST_VTBL struct IClientVirtualDeviceSet2Vtbl *lpVtbl; }; - + #ifdef COBJMACROS #define IClientVirtualDeviceSet2_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IClientVirtualDeviceSet2_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) + ( (This)->lpVtbl -> AddRef(This) ) #define IClientVirtualDeviceSet2_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) + ( (This)->lpVtbl -> Release(This) ) #define IClientVirtualDeviceSet2_Create(This,lpName,pCfg) \ - ( (This)->lpVtbl -> Create(This,lpName,pCfg) ) + ( (This)->lpVtbl -> Create(This,lpName,pCfg) ) #define IClientVirtualDeviceSet2_GetConfiguration(This,dwTimeOut,pCfg) \ - ( (This)->lpVtbl -> GetConfiguration(This,dwTimeOut,pCfg) ) + ( (This)->lpVtbl -> GetConfiguration(This,dwTimeOut,pCfg) ) #define IClientVirtualDeviceSet2_OpenDevice(This,lpName,ppVirtualDevice) \ - ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) + ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) #define IClientVirtualDeviceSet2_Close(This) \ - ( (This)->lpVtbl -> Close(This) ) + ( (This)->lpVtbl -> Close(This) ) #define IClientVirtualDeviceSet2_SignalAbort(This) \ - ( (This)->lpVtbl -> SignalAbort(This) ) + ( (This)->lpVtbl -> SignalAbort(This) ) #define IClientVirtualDeviceSet2_OpenInSecondary(This,lpSetName) \ - ( (This)->lpVtbl -> OpenInSecondary(This,lpSetName) ) + ( (This)->lpVtbl -> OpenInSecondary(This,lpSetName) ) #define IClientVirtualDeviceSet2_GetBufferHandle(This,pBuffer,pBufferHandle) \ - ( (This)->lpVtbl -> GetBufferHandle(This,pBuffer,pBufferHandle) ) + ( (This)->lpVtbl -> GetBufferHandle(This,pBuffer,pBufferHandle) ) #define IClientVirtualDeviceSet2_MapBufferHandle(This,dwBuffer,ppBuffer) \ - ( (This)->lpVtbl -> MapBufferHandle(This,dwBuffer,ppBuffer) ) + ( (This)->lpVtbl -> MapBufferHandle(This,dwBuffer,ppBuffer) ) #define IClientVirtualDeviceSet2_CreateEx(This,lpInstanceName,lpName,pCfg) \ - ( (This)->lpVtbl -> CreateEx(This,lpInstanceName,lpName,pCfg) ) + ( (This)->lpVtbl -> CreateEx(This,lpInstanceName,lpName,pCfg) ) #define IClientVirtualDeviceSet2_OpenInSecondaryEx(This,lpInstanceName,lpSetName) \ - ( (This)->lpVtbl -> OpenInSecondaryEx(This,lpInstanceName,lpSetName) ) + ( (This)->lpVtbl -> OpenInSecondaryEx(This,lpInstanceName,lpSetName) ) #endif /* COBJMACROS */ @@ -694,7 +697,7 @@ EXTERN_C const IID IID_IClientVirtualDeviceSet2; -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet2_CreateEx_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet2_CreateEx_Proxy( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpName, @@ -708,7 +711,7 @@ void __RPC_STUB IClientVirtualDeviceSet2_CreateEx_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet2_OpenInSecondaryEx_Proxy( +HRESULT STDMETHODCALLTYPE IClientVirtualDeviceSet2_OpenInSecondaryEx_Proxy( IClientVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpSetName); @@ -725,8 +728,8 @@ void __RPC_STUB IClientVirtualDeviceSet2_OpenInSecondaryEx_Stub( #endif /* __IClientVirtualDeviceSet2_INTERFACE_DEFINED__ */ -/* interface __MIDL_itf_vdi_0000_0003 */ -/* [local] */ +/* interface __MIDL_itf_vdi_0011 */ +/* [local] */ struct VDS_Command { @@ -742,56 +745,55 @@ struct VDS_Command } ; -extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_0003_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_0003_v0_0_s_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_vdi_0011_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_vdi_0011_v0_0_s_ifspec; #ifndef __IServerVirtualDevice_INTERFACE_DEFINED__ #define __IServerVirtualDevice_INTERFACE_DEFINED__ /* interface IServerVirtualDevice */ -/* [object][uuid] */ +/* [object][uuid] */ EXTERN_C const IID IID_IServerVirtualDevice; #if defined(__cplusplus) && !defined(CINTERFACE) - + MIDL_INTERFACE("b5e7a131-a7bd-11d1-84c2-00c04fc21759") IServerVirtualDevice : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE SendCommand( + virtual HRESULT STDMETHODCALLTYPE SendCommand( /* [in] */ struct VDS_Command *pCmd) = 0; - + virtual HRESULT STDMETHODCALLTYPE CloseDevice( void) = 0; - + }; - + #else /* C style interface */ typedef struct IServerVirtualDeviceVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IServerVirtualDevice * This, /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - __RPC__deref_out void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( + /* [iid_is][out] */ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( IServerVirtualDevice * This); - - ULONG ( STDMETHODCALLTYPE *Release )( + + ULONG ( STDMETHODCALLTYPE *Release )( IServerVirtualDevice * This); - - HRESULT ( STDMETHODCALLTYPE *SendCommand )( + + HRESULT ( STDMETHODCALLTYPE *SendCommand )( IServerVirtualDevice * This, /* [in] */ struct VDS_Command *pCmd); - - HRESULT ( STDMETHODCALLTYPE *CloseDevice )( + + HRESULT ( STDMETHODCALLTYPE *CloseDevice )( IServerVirtualDevice * This); - + END_INTERFACE } IServerVirtualDeviceVtbl; @@ -800,26 +802,26 @@ EXTERN_C const IID IID_IServerVirtualDevice; CONST_VTBL struct IServerVirtualDeviceVtbl *lpVtbl; }; - + #ifdef COBJMACROS #define IServerVirtualDevice_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IServerVirtualDevice_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) + ( (This)->lpVtbl -> AddRef(This) ) #define IServerVirtualDevice_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) + ( (This)->lpVtbl -> Release(This) ) #define IServerVirtualDevice_SendCommand(This,pCmd) \ - ( (This)->lpVtbl -> SendCommand(This,pCmd) ) + ( (This)->lpVtbl -> SendCommand(This,pCmd) ) #define IServerVirtualDevice_CloseDevice(This) \ - ( (This)->lpVtbl -> CloseDevice(This) ) + ( (This)->lpVtbl -> CloseDevice(This) ) #endif /* COBJMACROS */ @@ -828,7 +830,7 @@ EXTERN_C const IID IID_IServerVirtualDevice; -HRESULT STDMETHODCALLTYPE IServerVirtualDevice_SendCommand_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDevice_SendCommand_Proxy( IServerVirtualDevice * This, /* [in] */ struct VDS_Command *pCmd); @@ -840,7 +842,7 @@ void __RPC_STUB IServerVirtualDevice_SendCommand_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDevice_CloseDevice_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDevice_CloseDevice_Proxy( IServerVirtualDevice * This); @@ -859,109 +861,108 @@ void __RPC_STUB IServerVirtualDevice_CloseDevice_Stub( #define __IServerVirtualDeviceSet_INTERFACE_DEFINED__ /* interface IServerVirtualDeviceSet */ -/* [object][uuid] */ +/* [object][uuid] */ EXTERN_C const IID IID_IServerVirtualDeviceSet; #if defined(__cplusplus) && !defined(CINTERFACE) - + MIDL_INTERFACE("b5e7a132-a7bd-11d1-84c2-00c04fc21759") IServerVirtualDeviceSet : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE Open( + virtual HRESULT STDMETHODCALLTYPE Open( /* [in] */ LPCWSTR lpName) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetConfiguration( + + virtual HRESULT STDMETHODCALLTYPE GetConfiguration( /* [out] */ struct VDConfig *pCfg) = 0; - - virtual HRESULT STDMETHODCALLTYPE SetConfiguration( + + virtual HRESULT STDMETHODCALLTYPE SetConfiguration( /* [in] */ struct VDConfig *pCfg) = 0; - + virtual HRESULT STDMETHODCALLTYPE ExecuteCompletionAgent( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE OpenDevice( + + virtual HRESULT STDMETHODCALLTYPE OpenDevice( /* [in] */ LPCWSTR lpName, /* [out] */ IServerVirtualDevice **ppVirtualDevice) = 0; - - virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( + + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( /* [out] */ BYTE **ppBuffer, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment) = 0; - - virtual HRESULT STDMETHODCALLTYPE FreeBuffer( + + virtual HRESULT STDMETHODCALLTYPE FreeBuffer( /* [in] */ BYTE *pBuffer, /* [in] */ DWORD dwSize) = 0; - - virtual HRESULT STDMETHODCALLTYPE IsSharedBuffer( + + virtual HRESULT STDMETHODCALLTYPE IsSharedBuffer( /* [in] */ BYTE *pBuffer) = 0; - + virtual HRESULT STDMETHODCALLTYPE SignalAbort( void) = 0; - + virtual HRESULT STDMETHODCALLTYPE Close( void) = 0; - + }; - + #else /* C style interface */ typedef struct IServerVirtualDeviceSetVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IServerVirtualDeviceSet * This, /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - __RPC__deref_out void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( + /* [iid_is][out] */ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( IServerVirtualDeviceSet * This); - - ULONG ( STDMETHODCALLTYPE *Release )( + + ULONG ( STDMETHODCALLTYPE *Release )( IServerVirtualDeviceSet * This); - - HRESULT ( STDMETHODCALLTYPE *Open )( + + HRESULT ( STDMETHODCALLTYPE *Open )( IServerVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName); - - HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( IServerVirtualDeviceSet * This, /* [out] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *SetConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *SetConfiguration )( IServerVirtualDeviceSet * This, /* [in] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *ExecuteCompletionAgent )( + + HRESULT ( STDMETHODCALLTYPE *ExecuteCompletionAgent )( IServerVirtualDeviceSet * This); - - HRESULT ( STDMETHODCALLTYPE *OpenDevice )( + + HRESULT ( STDMETHODCALLTYPE *OpenDevice )( IServerVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName, /* [out] */ IServerVirtualDevice **ppVirtualDevice); - - HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( + + HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( IServerVirtualDeviceSet * This, /* [out] */ BYTE **ppBuffer, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment); - - HRESULT ( STDMETHODCALLTYPE *FreeBuffer )( + + HRESULT ( STDMETHODCALLTYPE *FreeBuffer )( IServerVirtualDeviceSet * This, /* [in] */ BYTE *pBuffer, /* [in] */ DWORD dwSize); - - HRESULT ( STDMETHODCALLTYPE *IsSharedBuffer )( + + HRESULT ( STDMETHODCALLTYPE *IsSharedBuffer )( IServerVirtualDeviceSet * This, /* [in] */ BYTE *pBuffer); - - HRESULT ( STDMETHODCALLTYPE *SignalAbort )( + + HRESULT ( STDMETHODCALLTYPE *SignalAbort )( IServerVirtualDeviceSet * This); - - HRESULT ( STDMETHODCALLTYPE *Close )( + + HRESULT ( STDMETHODCALLTYPE *Close )( IServerVirtualDeviceSet * This); - + END_INTERFACE } IServerVirtualDeviceSetVtbl; @@ -970,50 +971,50 @@ EXTERN_C const IID IID_IServerVirtualDeviceSet; CONST_VTBL struct IServerVirtualDeviceSetVtbl *lpVtbl; }; - + #ifdef COBJMACROS #define IServerVirtualDeviceSet_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IServerVirtualDeviceSet_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) + ( (This)->lpVtbl -> AddRef(This) ) #define IServerVirtualDeviceSet_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) + ( (This)->lpVtbl -> Release(This) ) #define IServerVirtualDeviceSet_Open(This,lpName) \ - ( (This)->lpVtbl -> Open(This,lpName) ) + ( (This)->lpVtbl -> Open(This,lpName) ) #define IServerVirtualDeviceSet_GetConfiguration(This,pCfg) \ - ( (This)->lpVtbl -> GetConfiguration(This,pCfg) ) + ( (This)->lpVtbl -> GetConfiguration(This,pCfg) ) #define IServerVirtualDeviceSet_SetConfiguration(This,pCfg) \ - ( (This)->lpVtbl -> SetConfiguration(This,pCfg) ) + ( (This)->lpVtbl -> SetConfiguration(This,pCfg) ) #define IServerVirtualDeviceSet_ExecuteCompletionAgent(This) \ - ( (This)->lpVtbl -> ExecuteCompletionAgent(This) ) + ( (This)->lpVtbl -> ExecuteCompletionAgent(This) ) #define IServerVirtualDeviceSet_OpenDevice(This,lpName,ppVirtualDevice) \ - ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) + ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) #define IServerVirtualDeviceSet_AllocateBuffer(This,ppBuffer,dwSize,dwAlignment) \ - ( (This)->lpVtbl -> AllocateBuffer(This,ppBuffer,dwSize,dwAlignment) ) + ( (This)->lpVtbl -> AllocateBuffer(This,ppBuffer,dwSize,dwAlignment) ) #define IServerVirtualDeviceSet_FreeBuffer(This,pBuffer,dwSize) \ - ( (This)->lpVtbl -> FreeBuffer(This,pBuffer,dwSize) ) + ( (This)->lpVtbl -> FreeBuffer(This,pBuffer,dwSize) ) #define IServerVirtualDeviceSet_IsSharedBuffer(This,pBuffer) \ - ( (This)->lpVtbl -> IsSharedBuffer(This,pBuffer) ) + ( (This)->lpVtbl -> IsSharedBuffer(This,pBuffer) ) #define IServerVirtualDeviceSet_SignalAbort(This) \ - ( (This)->lpVtbl -> SignalAbort(This) ) + ( (This)->lpVtbl -> SignalAbort(This) ) #define IServerVirtualDeviceSet_Close(This) \ - ( (This)->lpVtbl -> Close(This) ) + ( (This)->lpVtbl -> Close(This) ) #endif /* COBJMACROS */ @@ -1022,7 +1023,7 @@ EXTERN_C const IID IID_IServerVirtualDeviceSet; -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_Open_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_Open_Proxy( IServerVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName); @@ -1034,7 +1035,7 @@ void __RPC_STUB IServerVirtualDeviceSet_Open_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_GetConfiguration_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_GetConfiguration_Proxy( IServerVirtualDeviceSet * This, /* [out] */ struct VDConfig *pCfg); @@ -1046,7 +1047,7 @@ void __RPC_STUB IServerVirtualDeviceSet_GetConfiguration_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_SetConfiguration_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_SetConfiguration_Proxy( IServerVirtualDeviceSet * This, /* [in] */ struct VDConfig *pCfg); @@ -1058,7 +1059,7 @@ void __RPC_STUB IServerVirtualDeviceSet_SetConfiguration_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_ExecuteCompletionAgent_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_ExecuteCompletionAgent_Proxy( IServerVirtualDeviceSet * This); @@ -1069,7 +1070,7 @@ void __RPC_STUB IServerVirtualDeviceSet_ExecuteCompletionAgent_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_OpenDevice_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_OpenDevice_Proxy( IServerVirtualDeviceSet * This, /* [in] */ LPCWSTR lpName, /* [out] */ IServerVirtualDevice **ppVirtualDevice); @@ -1082,7 +1083,7 @@ void __RPC_STUB IServerVirtualDeviceSet_OpenDevice_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_AllocateBuffer_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_AllocateBuffer_Proxy( IServerVirtualDeviceSet * This, /* [out] */ BYTE **ppBuffer, /* [in] */ DWORD dwSize, @@ -1096,7 +1097,7 @@ void __RPC_STUB IServerVirtualDeviceSet_AllocateBuffer_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_FreeBuffer_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_FreeBuffer_Proxy( IServerVirtualDeviceSet * This, /* [in] */ BYTE *pBuffer, /* [in] */ DWORD dwSize); @@ -1109,7 +1110,7 @@ void __RPC_STUB IServerVirtualDeviceSet_FreeBuffer_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_IsSharedBuffer_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_IsSharedBuffer_Proxy( IServerVirtualDeviceSet * This, /* [in] */ BYTE *pBuffer); @@ -1121,7 +1122,7 @@ void __RPC_STUB IServerVirtualDeviceSet_IsSharedBuffer_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_SignalAbort_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_SignalAbort_Proxy( IServerVirtualDeviceSet * This); @@ -1132,7 +1133,7 @@ void __RPC_STUB IServerVirtualDeviceSet_SignalAbort_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_Close_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet_Close_Proxy( IServerVirtualDeviceSet * This); @@ -1151,146 +1152,145 @@ void __RPC_STUB IServerVirtualDeviceSet_Close_Stub( #define __IServerVirtualDeviceSet2_INTERFACE_DEFINED__ /* interface IServerVirtualDeviceSet2 */ -/* [object][uuid] */ +/* [object][uuid] */ EXTERN_C const IID IID_IServerVirtualDeviceSet2; #if defined(__cplusplus) && !defined(CINTERFACE) - + MIDL_INTERFACE("AECBD0D6-24C6-11d3-85B7-00C04FC21759") IServerVirtualDeviceSet2 : public IUnknown { public: - virtual HRESULT STDMETHODCALLTYPE Open( + virtual HRESULT STDMETHODCALLTYPE Open( /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpSetName) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetConfiguration( + + virtual HRESULT STDMETHODCALLTYPE GetConfiguration( /* [out] */ struct VDConfig *pCfg) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginConfiguration( + + virtual HRESULT STDMETHODCALLTYPE BeginConfiguration( /* [in] */ DWORD dwFeatures, /* [in] */ DWORD dwBlockSize, /* [in] */ DWORD dwAlignment, /* [in] */ DWORD dwMaxTransferSize, /* [in] */ DWORD dwTimeout) = 0; - + virtual HRESULT STDMETHODCALLTYPE EndConfiguration( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE RequestBuffers( + + virtual HRESULT STDMETHODCALLTYPE RequestBuffers( /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment, /* [in] */ DWORD dwCount) = 0; - - virtual HRESULT STDMETHODCALLTYPE QueryAvailableBuffers( + + virtual HRESULT STDMETHODCALLTYPE QueryAvailableBuffers( /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment, /* [out] */ DWORD *pCount) = 0; - + virtual HRESULT STDMETHODCALLTYPE ExecuteCompletionAgent( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE OpenDevice( + + virtual HRESULT STDMETHODCALLTYPE OpenDevice( /* [in] */ LPCWSTR lpName, /* [out] */ IServerVirtualDevice **ppVirtualDevice) = 0; - - virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( + + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( /* [out] */ BYTE **ppBuffer, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment) = 0; - - virtual HRESULT STDMETHODCALLTYPE FreeBuffer( + + virtual HRESULT STDMETHODCALLTYPE FreeBuffer( /* [in] */ BYTE *pBuffer, /* [in] */ DWORD dwSize) = 0; - - virtual HRESULT STDMETHODCALLTYPE IsSharedBuffer( + + virtual HRESULT STDMETHODCALLTYPE IsSharedBuffer( /* [in] */ BYTE *pBuffer) = 0; - + virtual HRESULT STDMETHODCALLTYPE SignalAbort( void) = 0; - + virtual HRESULT STDMETHODCALLTYPE Close( void) = 0; - + }; - + #else /* C style interface */ typedef struct IServerVirtualDeviceSet2Vtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IServerVirtualDeviceSet2 * This, /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - __RPC__deref_out void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( + /* [iid_is][out] */ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( IServerVirtualDeviceSet2 * This); - - ULONG ( STDMETHODCALLTYPE *Release )( + + ULONG ( STDMETHODCALLTYPE *Release )( IServerVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *Open )( + + HRESULT ( STDMETHODCALLTYPE *Open )( IServerVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpSetName); - - HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *GetConfiguration )( IServerVirtualDeviceSet2 * This, /* [out] */ struct VDConfig *pCfg); - - HRESULT ( STDMETHODCALLTYPE *BeginConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *BeginConfiguration )( IServerVirtualDeviceSet2 * This, /* [in] */ DWORD dwFeatures, /* [in] */ DWORD dwBlockSize, /* [in] */ DWORD dwAlignment, /* [in] */ DWORD dwMaxTransferSize, /* [in] */ DWORD dwTimeout); - - HRESULT ( STDMETHODCALLTYPE *EndConfiguration )( + + HRESULT ( STDMETHODCALLTYPE *EndConfiguration )( IServerVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *RequestBuffers )( + + HRESULT ( STDMETHODCALLTYPE *RequestBuffers )( IServerVirtualDeviceSet2 * This, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment, /* [in] */ DWORD dwCount); - - HRESULT ( STDMETHODCALLTYPE *QueryAvailableBuffers )( + + HRESULT ( STDMETHODCALLTYPE *QueryAvailableBuffers )( IServerVirtualDeviceSet2 * This, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment, /* [out] */ DWORD *pCount); - - HRESULT ( STDMETHODCALLTYPE *ExecuteCompletionAgent )( + + HRESULT ( STDMETHODCALLTYPE *ExecuteCompletionAgent )( IServerVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *OpenDevice )( + + HRESULT ( STDMETHODCALLTYPE *OpenDevice )( IServerVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpName, /* [out] */ IServerVirtualDevice **ppVirtualDevice); - - HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( + + HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( IServerVirtualDeviceSet2 * This, /* [out] */ BYTE **ppBuffer, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment); - - HRESULT ( STDMETHODCALLTYPE *FreeBuffer )( + + HRESULT ( STDMETHODCALLTYPE *FreeBuffer )( IServerVirtualDeviceSet2 * This, /* [in] */ BYTE *pBuffer, /* [in] */ DWORD dwSize); - - HRESULT ( STDMETHODCALLTYPE *IsSharedBuffer )( + + HRESULT ( STDMETHODCALLTYPE *IsSharedBuffer )( IServerVirtualDeviceSet2 * This, /* [in] */ BYTE *pBuffer); - - HRESULT ( STDMETHODCALLTYPE *SignalAbort )( + + HRESULT ( STDMETHODCALLTYPE *SignalAbort )( IServerVirtualDeviceSet2 * This); - - HRESULT ( STDMETHODCALLTYPE *Close )( + + HRESULT ( STDMETHODCALLTYPE *Close )( IServerVirtualDeviceSet2 * This); - + END_INTERFACE } IServerVirtualDeviceSet2Vtbl; @@ -1299,59 +1299,59 @@ EXTERN_C const IID IID_IServerVirtualDeviceSet2; CONST_VTBL struct IServerVirtualDeviceSet2Vtbl *lpVtbl; }; - + #ifdef COBJMACROS #define IServerVirtualDeviceSet2_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IServerVirtualDeviceSet2_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) + ( (This)->lpVtbl -> AddRef(This) ) #define IServerVirtualDeviceSet2_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) + ( (This)->lpVtbl -> Release(This) ) #define IServerVirtualDeviceSet2_Open(This,lpInstanceName,lpSetName) \ - ( (This)->lpVtbl -> Open(This,lpInstanceName,lpSetName) ) + ( (This)->lpVtbl -> Open(This,lpInstanceName,lpSetName) ) #define IServerVirtualDeviceSet2_GetConfiguration(This,pCfg) \ - ( (This)->lpVtbl -> GetConfiguration(This,pCfg) ) + ( (This)->lpVtbl -> GetConfiguration(This,pCfg) ) #define IServerVirtualDeviceSet2_BeginConfiguration(This,dwFeatures,dwBlockSize,dwAlignment,dwMaxTransferSize,dwTimeout) \ - ( (This)->lpVtbl -> BeginConfiguration(This,dwFeatures,dwBlockSize,dwAlignment,dwMaxTransferSize,dwTimeout) ) + ( (This)->lpVtbl -> BeginConfiguration(This,dwFeatures,dwBlockSize,dwAlignment,dwMaxTransferSize,dwTimeout) ) #define IServerVirtualDeviceSet2_EndConfiguration(This) \ - ( (This)->lpVtbl -> EndConfiguration(This) ) + ( (This)->lpVtbl -> EndConfiguration(This) ) #define IServerVirtualDeviceSet2_RequestBuffers(This,dwSize,dwAlignment,dwCount) \ - ( (This)->lpVtbl -> RequestBuffers(This,dwSize,dwAlignment,dwCount) ) + ( (This)->lpVtbl -> RequestBuffers(This,dwSize,dwAlignment,dwCount) ) #define IServerVirtualDeviceSet2_QueryAvailableBuffers(This,dwSize,dwAlignment,pCount) \ - ( (This)->lpVtbl -> QueryAvailableBuffers(This,dwSize,dwAlignment,pCount) ) + ( (This)->lpVtbl -> QueryAvailableBuffers(This,dwSize,dwAlignment,pCount) ) #define IServerVirtualDeviceSet2_ExecuteCompletionAgent(This) \ - ( (This)->lpVtbl -> ExecuteCompletionAgent(This) ) + ( (This)->lpVtbl -> ExecuteCompletionAgent(This) ) #define IServerVirtualDeviceSet2_OpenDevice(This,lpName,ppVirtualDevice) \ - ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) + ( (This)->lpVtbl -> OpenDevice(This,lpName,ppVirtualDevice) ) #define IServerVirtualDeviceSet2_AllocateBuffer(This,ppBuffer,dwSize,dwAlignment) \ - ( (This)->lpVtbl -> AllocateBuffer(This,ppBuffer,dwSize,dwAlignment) ) + ( (This)->lpVtbl -> AllocateBuffer(This,ppBuffer,dwSize,dwAlignment) ) #define IServerVirtualDeviceSet2_FreeBuffer(This,pBuffer,dwSize) \ - ( (This)->lpVtbl -> FreeBuffer(This,pBuffer,dwSize) ) + ( (This)->lpVtbl -> FreeBuffer(This,pBuffer,dwSize) ) #define IServerVirtualDeviceSet2_IsSharedBuffer(This,pBuffer) \ - ( (This)->lpVtbl -> IsSharedBuffer(This,pBuffer) ) + ( (This)->lpVtbl -> IsSharedBuffer(This,pBuffer) ) #define IServerVirtualDeviceSet2_SignalAbort(This) \ - ( (This)->lpVtbl -> SignalAbort(This) ) + ( (This)->lpVtbl -> SignalAbort(This) ) #define IServerVirtualDeviceSet2_Close(This) \ - ( (This)->lpVtbl -> Close(This) ) + ( (This)->lpVtbl -> Close(This) ) #endif /* COBJMACROS */ @@ -1360,7 +1360,7 @@ EXTERN_C const IID IID_IServerVirtualDeviceSet2; -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_Open_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_Open_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpInstanceName, /* [in] */ LPCWSTR lpSetName); @@ -1373,7 +1373,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_Open_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_GetConfiguration_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_GetConfiguration_Proxy( IServerVirtualDeviceSet2 * This, /* [out] */ struct VDConfig *pCfg); @@ -1385,7 +1385,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_GetConfiguration_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_BeginConfiguration_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_BeginConfiguration_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ DWORD dwFeatures, /* [in] */ DWORD dwBlockSize, @@ -1401,7 +1401,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_BeginConfiguration_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_EndConfiguration_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_EndConfiguration_Proxy( IServerVirtualDeviceSet2 * This); @@ -1412,7 +1412,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_EndConfiguration_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_RequestBuffers_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_RequestBuffers_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment, @@ -1426,7 +1426,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_RequestBuffers_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_QueryAvailableBuffers_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_QueryAvailableBuffers_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ DWORD dwSize, /* [in] */ DWORD dwAlignment, @@ -1440,7 +1440,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_QueryAvailableBuffers_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_ExecuteCompletionAgent_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_ExecuteCompletionAgent_Proxy( IServerVirtualDeviceSet2 * This); @@ -1451,7 +1451,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_ExecuteCompletionAgent_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_OpenDevice_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_OpenDevice_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ LPCWSTR lpName, /* [out] */ IServerVirtualDevice **ppVirtualDevice); @@ -1464,7 +1464,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_OpenDevice_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_AllocateBuffer_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_AllocateBuffer_Proxy( IServerVirtualDeviceSet2 * This, /* [out] */ BYTE **ppBuffer, /* [in] */ DWORD dwSize, @@ -1478,7 +1478,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_AllocateBuffer_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_FreeBuffer_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_FreeBuffer_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ BYTE *pBuffer, /* [in] */ DWORD dwSize); @@ -1491,7 +1491,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_FreeBuffer_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_IsSharedBuffer_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_IsSharedBuffer_Proxy( IServerVirtualDeviceSet2 * This, /* [in] */ BYTE *pBuffer); @@ -1503,7 +1503,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_IsSharedBuffer_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_SignalAbort_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_SignalAbort_Proxy( IServerVirtualDeviceSet2 * This); @@ -1514,7 +1514,7 @@ void __RPC_STUB IServerVirtualDeviceSet2_SignalAbort_Stub( DWORD *_pdwStubPhase); -HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_Close_Proxy( +HRESULT STDMETHODCALLTYPE IServerVirtualDeviceSet2_Close_Proxy( IServerVirtualDeviceSet2 * This); @@ -1529,21 +1529,19 @@ void __RPC_STUB IServerVirtualDeviceSet2_Close_Stub( #endif /* __IServerVirtualDeviceSet2_INTERFACE_DEFINED__ */ -/* interface __MIDL_itf_vdi_0000_0006 */ -/* [local] */ +/* interface __MIDL_itf_vdi_0014 */ +/* [local] */ const IID CLSID_WINFS_ClientVirtualDeviceSet = {0x50b99b13, 0x7b84, 0x44d3, {0x9c, 0x98, 0x26, 0x52, 0xbf, 0x14, 0x4d, 0x96}}; const IID CLSID_WINFS_ServerVirtualDeviceSet = {0x92e6b26b, 0x57da, 0x47ed, {0x81, 0x53, 0xdf, 0xf1, 0x87, 0xa7, 0x6d, 0xde}}; -const IID CLSID_WIDVDI_ClientVirtualDeviceSet = {0xa9a3fe12, 0x61c7, 0x496e, { 0xaa, 0xbf, 0xb8, 0x3e, 0x32, 0x87, 0xab, 0x82 }}; -const IID CLSID_WIDVDI_ServerVirtualDeviceSet = {0xa6f16b19, 0x40, 0x4947, { 0x8d, 0x3f, 0x52, 0xde, 0x12, 0x9b, 0xb6, 0x15 }}; #define CLSID_MSSQL_ClientVirtualDeviceSet IID_IClientVirtualDeviceSet #define CLSID_MSSQL_ServerVirtualDeviceSet IID_IServerVirtualDeviceSet #pragma pack(pop, _vdi_h_) -extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_0006_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_vdi_0000_0006_v0_0_s_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_vdi_0014_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_vdi_0014_v0_0_s_ifspec; /* Additional Prototypes for ALL interfaces */ diff --git a/samples/features/sqlvdi/vdierror.h b/samples/features/sqlvdi/include/vdierror.h similarity index 100% rename from samples/features/sqlvdi/vdierror.h rename to samples/features/sqlvdi/include/vdierror.h diff --git a/samples/features/sqlvdi/vdiguid.h b/samples/features/sqlvdi/include/vdiguid.h similarity index 83% rename from samples/features/sqlvdi/vdiguid.h rename to samples/features/sqlvdi/include/vdiguid.h index 0a034566fc..986f35902d 100644 --- a/samples/features/sqlvdi/vdiguid.h +++ b/samples/features/sqlvdi/include/vdiguid.h @@ -1,11 +1,22 @@ + +/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ + /* link this file in with the server and any clients */ -/* File created by MIDL compiler version 7.00.0408 */ + /* File created by MIDL compiler version 7.00.0408 */ /* at Tue Sep 28 18:18:04 2004 */ - +/* Compiler settings for vdi.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) #if !defined(_M_IA64) && !defined(_M_AMD64) @@ -15,7 +26,7 @@ #ifdef __cplusplus extern "C"{ -#endif +#endif #include @@ -99,8 +110,8 @@ MIDL_DEFINE_GUID(IID, IID_IServerVirtualDeviceSet2,0xAECBD0D6,0x24C6,0x11d3,0x85 /* Compiler settings for vdi.idl: Oicf, W1, Zp8, env=Win64 (32b run,appending) protocol : dce , ms_ext, c_ext, robust - error checks: allocation ref bounds_check enum stub_data - VC __declspec() decoration level: + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ @@ -114,7 +125,7 @@ MIDL_DEFINE_GUID(IID, IID_IServerVirtualDeviceSet2,0xAECBD0D6,0x24C6,0x11d3,0x85 #ifdef __cplusplus extern "C"{ -#endif +#endif #include diff --git a/samples/features/sqlvdi/mprocess/mprocess.cpp b/samples/features/sqlvdi/mprocess/mprocess.cpp new file mode 100644 index 0000000000..e2f17b1e2b --- /dev/null +++ b/samples/features/sqlvdi/mprocess/mprocess.cpp @@ -0,0 +1,648 @@ +/*********************************************************************** +Copyright (c) Microsoft Corporation +All Rights Reserved. +***********************************************************************/ +// This source code is an intended supplement to the Microsoft SQL +// Server online references and related electronic documentation. +// +// This sample is for instructional purposes only. +// Code contained herein is not intended to be used "as is" in real applications. +// +// mprocess.cpp : +// +// Test & demonstrate the use of multiple streams where each stream is +// handled by a secondary process. +// +// This is a sample program used to demonstrate the Virtual Device Interface +// feature of Microsoft SQL Server. +// +// The program will backup or restore the 'pubs' sample database. +// +// The program requires two command line parameters. +// 1) +// One of: +// b perform a backup +// r perform a restore +// +// s Act as a secondary client (used internally only) +// +// 2) +// If b or r is given, then a second parm gives the number of streams to use, +// (1-32). +// The secondary processes are invoked automatically, and the second parm is the +// stream id (0..31), the third parm the VDSName. +// + +#define _WIN32_DCOM + +#include // for 'CoInitialize()' +#include // for file operations +#include // for toupper () +#include + +#include "vdi.h" // interface declaration +#include "vdierror.h" // error constants +#include "vdiguid.h" // define the GUIDs + +void LogError ( + LPSTR location, // must always be provided + LPSTR description, // NULL is acceptable + DWORD errCode); // windows status code + +int performTransfer ( + IClientVirtualDevice* vd, + int backup, + int streamId); + +HANDLE execSQL (int doBackup, int nStreams); + +int +runSecondary (int streamId, IClientVirtualDeviceSet *vds); + +int +startSecondaries( + IClientVirtualDeviceSet *vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams, // number of i/o streams + char* pgmName); // the name of this program + +// Using a GUID for the VDS Name is a good way to assure uniqueness. +// +WCHAR wVdsName [100]; + + +// +// main function +// +int main(int argc, char *argv[]) +{ + HRESULT hr; + IClientVirtualDeviceSet* vds = NULL ; + VDConfig config; + int badParm=TRUE; + int doBackup; + HANDLE hProcess; + int termCode = -1; + int nStreams=1; + int isSecondary = FALSE; + + // Check the input parm + // + if (argc >= 3) + { + sscanf (argv[2], "%d", &nStreams); + switch (toupper(argv[1][0])) + { + case 'B': + doBackup = TRUE; + badParm = FALSE; + break; + + case 'R': + doBackup = FALSE; + badParm = FALSE; + break; + + case 'S': + doBackup = FALSE; // we don't know or care + badParm = FALSE; + isSecondary = TRUE; + // nStreams is the streamid! + swprintf (wVdsName, L"%hs", argv[3]); + break; + } + } + + if (badParm) + { + printf ("useage: mprocess {B|R} \n" + "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); + exit (1); + } + + if (isSecondary) + { + printf("Secondary pid %d working on stream %d\n", GetCurrentProcessId (), nStreams); + } + else + { + // 1..32 streams. + // + if (nStreams < 1) + nStreams = 1; + else if (nStreams > 32) + nStreams = 32; + + printf ("Performing a %s using %d virtual device(s).\n", + (doBackup) ? "BACKUP" : "RESTORE", nStreams); + } + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); + + if (!SUCCEEDED (hr)) + { + printf ("Coinit fails: x%X\n", hr); + exit (1); + } + + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance ( + IID_IClientVirtualDeviceSet, + NULL, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet, + (void**)&vds); + + if (!SUCCEEDED (hr)) + { + // This failure might happen if the DLL was not registered. + // + printf ("Could not create component: x%X\n", hr); + printf ("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Perform secondary processing, if this is a + // secondary process. + // + if (isSecondary) + { + termCode = runSecondary (nStreams, vds); + + goto exit; + } + + // The following logic is executed by the primary process. + // + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset (&config, 0, sizeof(config)); + + config.deviceCount = nStreams; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid (&vdsId); + StringFromGUID2 (vdsId, wVdsName, 49); + + // Create the virtual device set + // + hr = vds->Create (wVdsName, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, via isql in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL (doBackup, nStreams); + if (hProcess == NULL) + { + printf ("execSQL failed.\n"); + goto shutdown; + } + + + // Wait for the server to connect, completing the configuration. + // Notice that we wait a maximum of 15 seconds. + // + printf("\nWaiting for SQL to complete configuration...\n"); + + hr = vds->GetConfiguration (15000, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Handle the virtual devices in secondary processes. + // + printf ("\nSpawning secondary processes...\n"); + termCode = startSecondaries (vds, hProcess, nStreams, argv[0]); + +shutdown: + + // Close the set + // + vds->Close (); + + // COM reference counting: Release the interface. + // + vds->Release () ; + +exit: + + // Uninitialize COM Library + // + CoUninitialize () ; + + return termCode; +} + +// +// Execute a basic backup/restore, by starting 'osql' in a subprocess. +// +// Returns: +// NULL : failed to start isql +// else : process handle +// +HANDLE execSQL (int doBackup, int nStreams) +{ + char cmd[5000]; + char extend[100]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + int ix; + + // Build the SQL, submitting it via 'isql' + // If you want to use Windows NT Authentication, please do not use the -U or -P options. + sprintf (cmd, + "osql -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? "BACKUP" : "RESTORE", + (doBackup) ? "TO" : "FROM", + wVdsName); + + for (ix=1; ix= WAIT_OBJECT_0 && + waitStatus < WAIT_OBJECT_0+nActive) + { + // One of the children completed. + // Determine which one. + // + ix = waitStatus - WAIT_OBJECT_0; + + // Check its completion code + // + if (!GetExitCodeProcess (children[ix], &exitCode)) + { + LogError ("startSecondary", "GetExitCode", GetLastError ()); + goto errorExit; + } + + if (exitCode != 0) + { + printf ("A child exitted with code %d\n", exitCode); + goto errorExit; + } + + // It is good programming practice to close handles when + // finished with them. + // Since this sample simply terminates the process for error + // handling, we don't need to do it, as handles are automatically + // closed as part of process termination. + // + CloseHandle (children[ix]); + + // Remove the handle for this child + // + memmove (&children[ix], &children[ix+1], + sizeof (HANDLE) * (nActive-ix-1)); + + nActive--; + + } + else + { + printf("Unexpected wait code: %d\n", waitStatus); + goto errorExit; + } + + } while (nActive > 0); + + printf ("All children completed successfully\n"); + + return 0; + +errorExit: + // Handle all problems in a trivial fashion: + // SignalAbort() will cause all processes using the virtual device set + // to terminate processing. + // Thus, we don't bother waiting for any children to terminate. + // + vds->SignalAbort (); + return -1; + +} + +//------------------------------------------------------------------ +// Perform secondary client processing +// Return 0 if no errors detected, else nonzero. +// +int +runSecondary (int streamId, IClientVirtualDeviceSet *vds) +{ + HRESULT hr; + WCHAR devName[100]; + IClientVirtualDevice* vd; + VDConfig config; + int termCode; + + // Open the device + // + if (streamId == 0) + { + // The first device has the same name as the set. + // + wcscpy (devName, wVdsName); + } + else + { + // For this example, we've simply appended a number + // for additional devices. You are free to name them + // as you wish. + // + swprintf (devName, L"%ls%d", wVdsName, streamId); + } + + // Open the virtual device set in this secondary process. + // + hr = vds->OpenInSecondary (wVdsName); + if (!SUCCEEDED (hr)) + { + printf ("VD::Open(%ls) fails: x%X", devName, hr); + return -1; + } + + // Open the device assigned to this process. + // + hr = vds->OpenDevice (devName, &vd); + if (!SUCCEEDED (hr)) + { + printf ("OpenDevice fails on %ls: x%X", devName, hr); + return -1; + } + + // Grab the config to figure out data direction + // + hr = vds->GetConfiguration (INFINITE, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Getconfig fails: x%X\n", hr); + termCode = -1; + goto errExit; + } + + printf ("\nPerforming data transfer...\n"); + + termCode = performTransfer (vd, + (config.features&VDF_WriteMedia), streamId); + +errExit: + + // If errors were detected, force an abort. + // + if (termCode != 0) + { + vds->SignalAbort (); + } + + vds->Close (); + + return termCode; +} + + +// This routine reads commands from the server until a 'Close' status is received. +// It simply synchronously reads or writes a file on the root of the current drive. +// +// Returns 0, if no errors are detected, else non-zero. +// +int performTransfer ( + IClientVirtualDevice* vd, + int backup, + int streamId) +{ + FILE * fh; + char fname[80]; + VDC_Command * cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + int termCode = -1; + + sprintf (fname, "multi.%d.dmp", streamId); + + fh = fopen (fname, (backup)? "wb" : "rb"); + if (fh == NULL ) + { + printf ("Failed to open: %s\n", fname); + return -1; + } + + while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + + break; + + case VDC_Write: + bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size ) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush (fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + + hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); + if (!SUCCEEDED (hr)) + { + printf ("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf ("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf ("Successfully completed data transfer.\n"); + termCode = 0; + } + + fclose (fh); + + return termCode; +} + +//-------------------------------------------------------------------- +// +// A simple error logger. +// +void LogError ( + LPSTR location, // must always be provided + LPSTR description, // NULL is acceptable + DWORD errCode) // windows status code +{ + LPVOID lpMsgBuf; + + printf ( + "Error at %s: %s StatusCode: %X\n", + location, + (description==NULL)?"":description, + errCode); + + // Attempt to explain the code + // + if (errCode != 0 && FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, 0, NULL ) )// Process any inserts in lpMsgBuf. + { + printf ("Explanation: %s\n", lpMsgBuf); + LocalFree( lpMsgBuf ); + } +} + diff --git a/samples/features/sqlvdi/mprocess/mprocess.dsp b/samples/features/sqlvdi/mprocess/mprocess.dsp new file mode 100644 index 0000000000..646cca91f7 --- /dev/null +++ b/samples/features/sqlvdi/mprocess/mprocess.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="mprocess" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mprocess - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mprocess.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mprocess.mak" CFG="mprocess - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mprocess - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mprocess - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mprocess - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mprocess - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mprocess - Win32 Release" +# Name "mprocess - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\mprocess.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/samples/features/sqlvdi/mprocess/mprocess.dsw b/samples/features/sqlvdi/mprocess/mprocess.dsw new file mode 100644 index 0000000000..b9ae7ee953 --- /dev/null +++ b/samples/features/sqlvdi/mprocess/mprocess.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "mprocess"=.\mprocess.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/samples/features/sqlvdi/mthread/mthread.cpp b/samples/features/sqlvdi/mthread/mthread.cpp new file mode 100644 index 0000000000..3430e8a225 --- /dev/null +++ b/samples/features/sqlvdi/mthread/mthread.cpp @@ -0,0 +1,600 @@ +/*********************************************************************** +Copyright (c) Microsoft Corporation +All Rights Reserved. +***********************************************************************/ +// This source code is an intended supplement to the Microsoft SQL +// Server online references and related electronic documentation. +// +// This sample is for instructional purposes only. +// Code contained herein is not intended to be used "as is" in real applications. +// +// mthread.cpp : +// +// Test & demonstrate the use of multiple streams from a single process. +// +// This is a sample program used to demonstrate the Virtual Device Interface +// feature of Microsoft SQL Server. +// +// The program will backup or restore the 'pubs' sample database. +// +// The program requires two command line parameters. +// 1) +// One of: +// b perform a backup +// r perform a restore +// +// 2) +// The number of streams to use, 1-32. +// + +#define _WIN32_DCOM + +#include // for 'CoInitialize()' +#include // for file operations +#include // for toupper () +#include // for C library-safe _beginthreadex,_endthreadex +#include + +#include "vdi.h" // interface declaration +#include "vdierror.h" // error constants +#include "vdiguid.h" // define the GUIDs + +void LogError ( + LPSTR location, // must always be provided + LPSTR description, // NULL is acceptable + DWORD errCode); // windows status code + +int performTransfer ( + IClientVirtualDevice* vd, + int backup, + int streamId); + +HANDLE execSQL (int doBackup, int nStreams); + +int +startSecondaries( + IClientVirtualDeviceSet *vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams); // number of i/o streams + +unsigned __stdcall +runSecondary (void *parms); + +// Using a GUID for the VDS Name is a good way to assure uniqueness. +// +WCHAR wVdsName [50]; + +// +// main function +// +int main(int argc, char *argv[]) +{ + HRESULT hr; + IClientVirtualDeviceSet* vds = NULL ; + VDConfig config; + int badParm=TRUE; + int doBackup; + HANDLE hProcess; + int termCode = -1; + int nStreams=1; + + // Check the input parm + // + if (argc == 3) + { + sscanf (argv[2], "%d", &nStreams); + switch (toupper(argv[1][0])) + { + case 'B': + doBackup = TRUE; + badParm = FALSE; + break; + + case 'R': + doBackup = FALSE; + badParm = FALSE; + break; + } + } + + if (badParm) + { + printf ("useage: mprocess {B|R} \n" + "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); + exit (1); + } + + // 1..32 streams. + // + if (nStreams < 1) + nStreams = 1; + else if (nStreams > 32) + nStreams = 32; + + printf ("Performing a %s using %d virtual device(s).\n", + (doBackup) ? "BACKUP" : "RESTORE", nStreams); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); + + if (!SUCCEEDED (hr)) + { + printf ("Coinit fails: x%X\n", hr); + exit (1); + } + + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance ( + IID_IClientVirtualDeviceSet, + NULL, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet, + (void**)&vds); + + if (!SUCCEEDED (hr)) + { + // This failure might happen if the DLL was not registered. + // + printf ("Could not create component: x%X\n", hr); + printf ("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid (&vdsId); + StringFromGUID2 (vdsId, wVdsName, 49); + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset (&config, 0, sizeof(config)); + + config.deviceCount = nStreams; + + // Create the virtual device set + // + hr = vds->Create (wVdsName, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, via isql in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL (doBackup, nStreams); + if (hProcess == NULL) + { + printf ("execSQL failed.\n"); + goto shutdown; + } + + + // Wait for the server to connect, completing the configuration. + // Notice that we wait a maximum of 15 seconds. + // + printf("\nWaiting for SQL to complete configuration...\n"); + + hr = vds->GetConfiguration (15000, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Handle the virtual devices in secondary processes. + // + printf ("\nSpawning secondary threads..\n"); + termCode = startSecondaries (vds, hProcess, nStreams); + +shutdown: + + // Close the set + // + vds->Close (); + + // COM reference counting: Release the interface. + // + vds->Release () ; + +exit: + + // Uninitialize COM Library + // + CoUninitialize () ; + + return termCode; +} + +// +// Execute a basic backup/restore, by starting 'isql' in a subprocess. +// +// Returns: +// NULL : failed to start isql +// else : process handle +// +HANDLE execSQL (int doBackup, int nStreams) +{ + char cmd[5000]; + char extend[100]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + int ix; + + sprintf (cmd, "osql -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? "BACKUP" : "RESTORE", + (doBackup) ? "TO" : "FROM", + wVdsName); + + for (ix=1; ix= WAIT_OBJECT_0+nActive) + { + LogError ("startSecondary", "WaitForMultiple", GetLastError ()); + printf("Unexpected wait code: %d\n", waitStatus); + goto errorExit; + } + + // All of the children have completed. + // Get the completion code from 'isql' to check for sucess. + // + if (!GetExitCodeProcess (hSQLProcess, &exitCode)) + { + LogError ("startSecondary", "GetExitCode", GetLastError ()); + goto errorExit; + } + + if (exitCode != 0) + { + printf ("The SQL operation failed with code %d\n", exitCode); + goto errorExit; + } + + printf ("The SQL operation was sucessful.\n"); + + // Be sure to close handles when finished with them. + // + // Notice that in our trivial error handling here we + // don't bother closing them, since handles are + // automatically closed as part of process termination. + // + for (ix = 0; ix < nActive; ix++) + { + CloseHandle (children[ix]); + } + + return 0; + +errorExit: + // Handle all problems in a trivial fashion: + // SignalAbort() will cause all processes using the virtual device set + // to terminate processing. + // + vds->SignalAbort (); + + // However, since the threads are using the virtual device set allocated + // by the main thread, we can't let the main thread close the set before + // the threads are finished with it. There are two options: + // 1) exit the process immediately. + // 2) wait for the threads to terminate. + // + // Option 2 is "cleaner" but requires more code, so we just exit here: + // + ExitProcess ((unsigned)-1); + + return -1; // ExitProcess doesn't return; this avoids a compiler error. +} + +//------------------------------------------------------------------ +// Perform secondary client processing from within a thread. +// Exits with 0 if no errors detected, else nonzero. +// The caller must setup a THREAD_PARMS parameter block when +// spawning the thread. +// +unsigned __stdcall +runSecondary (void *parms) +{ + HRESULT hr; + WCHAR devName[100]; + IClientVirtualDevice* vd; + VDConfig config; + int termCode; + + // Fetch the input parms + // + int streamId = ((THREAD_PARMS*)parms)->streamId; + IClientVirtualDeviceSet * vds = ((THREAD_PARMS*)parms)->vds; + + // Build the name of the device assigned to this thread. + // + if (streamId == 0) + { + // The first device has the same name as the set. + // + wcscpy (devName, wVdsName); + } + else + { + // For this example, we've simply appended a number + // for additional devices. You are free to name them + // as you wish. + // + swprintf (devName, L"%s%d", wVdsName, streamId); + } + + // Open the device assigned to this thread. + // + hr = vds->OpenDevice (devName, &vd); + if (!SUCCEEDED (hr)) + { + printf ("OpenDevice fails on %ls: x%X", devName, hr); + termCode = -1; + goto errExit; + } + + // Grab the config to figure out data direction + // + hr = vds->GetConfiguration (INFINITE, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Getconfig fails: x%X\n", hr); + termCode = -1; + goto errExit; + } + + printf ("\nPerforming data transfer...\n"); + + termCode = performTransfer (vd, + (config.features&VDF_WriteMedia), streamId); + +errExit: + + // If errors were detected, force an abort. + // + if (termCode != 0) + { + vds->SignalAbort (); + } + + return ((unsigned)termCode); + +} + + + +// This routine reads commands from the server until a 'Close' status is received. +// It simply synchronously reads or writes a file on the root of the current drive. +// +// Returns 0, if no errors are detected, else non-zero. +// +int performTransfer ( + IClientVirtualDevice* vd, + int backup, + int streamId) +{ + FILE * fh; + char fname[80]; + VDC_Command * cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + int termCode = -1; + + sprintf (fname, "multi.%d.dmp", streamId); + + fh = fopen (fname, (backup)? "wb" : "rb"); + if (fh == NULL ) + { + printf ("Failed to open: %s\n", fname); + return -1; + } + + while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + + break; + + case VDC_Write: + bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size ) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush (fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + + hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); + if (!SUCCEEDED (hr)) + { + printf ("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf ("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf ("Successfully completed data transfer.\n"); + termCode = 0; + } + + fclose (fh); + + return termCode; +} + + +//-------------------------------------------------------------------- +// +// A simple error logger. +// +void LogError ( + LPSTR location, // must always be provided + LPSTR description, // NULL is acceptable + DWORD errCode) // windows status code +{ + LPVOID lpMsgBuf; + + printf ( + "Error at %s: %s StatusCode: %X\n", + location, + (description==NULL)?"":description, + errCode); + + // Attempt to explain the code + // + if (errCode != 0 && FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, 0, NULL ) )// Process any inserts in lpMsgBuf. + { + printf ("Explanation: %s\n", lpMsgBuf); + LocalFree( lpMsgBuf ); + } +} + diff --git a/samples/features/sqlvdi/mthread/mthread.dsp b/samples/features/sqlvdi/mthread/mthread.dsp new file mode 100644 index 0000000000..9b852163bf --- /dev/null +++ b/samples/features/sqlvdi/mthread/mthread.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="mthread" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mthread - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mthread.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mthread.mak" CFG="mthread - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mthread - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mthread - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mthread - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mthread - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mthread - Win32 Release" +# Name "mthread - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\mthread.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/samples/features/sqlvdi/mthread/mthread.dsw b/samples/features/sqlvdi/mthread/mthread.dsw new file mode 100644 index 0000000000..052e314d3b --- /dev/null +++ b/samples/features/sqlvdi/mthread/mthread.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "mthread"=.\mthread.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/samples/features/sqlvdi/osimple/osimple.cpp b/samples/features/sqlvdi/osimple/osimple.cpp new file mode 100644 index 0000000000..118d080e30 --- /dev/null +++ b/samples/features/sqlvdi/osimple/osimple.cpp @@ -0,0 +1,659 @@ +/*********************************************************************** +Copyright (c) Microsoft Corporation +All Rights Reserved. +***********************************************************************/ +// This source code is an intended supplement to the Microsoft SQL +// Server online references and related electronic documentation. +// +// This sample is for instructional purposes only. +// Code contained herein is not intended to be used "as is" in real applications. +// +// osimple.cpp +// +// This sample extends the "simple.cpp" sample to use an ODBC connection. +// This is intended only as an introduction to ODBC; not as a comprehensive tutorial. +// +// This is a sample program used to demonstrate the Virtual Device Interface +// feature of Microsoft SQL Server together with an ODBC connection. +// +// The program will backup or restore the 'pubs' sample database from +// the default instance of sql server. +// +// The program accepts a single command line parameter. +// One of: +// b perform a backup +// r perform a restore +// + + +// To gain access to free threaded COM, you'll need to define _WIN32_DCOM +// before the system headers, either in the source (as in this example), +// or when invoking the compiler (by using /D "_WIN32_DCOM") +// +// This sample uses Windows NT Authentication, other than mixed mode security, +// to establish connections. If you want to use mixed mode security, please +// set Trusted_Connection to no in the SQLDriverConnect command. +// Make necessary change to the server name in the SQLDriverConnect command. + +#define _WIN32_DCOM + +#include // for 'CoInitialize()' +#include // for file operations +#include // for toupper () +#include // for C library-safe _beginthreadex,_endthreadex + +#include "vdi.h" // interface declaration +#include "vdierror.h" // error constants + +#include "vdiguid.h" // define the interface identifiers. + // IMPORTANT: vdiguid.h can only be included in one source file. + // + +#include +#include "sql.h" +#include "sqlext.h" +#include "odbcss.h" + +void performTransfer ( + IClientVirtualDevice* vd, + int backup ); + +HANDLE execSQL (int doBackup); +int checkSQL (HANDLE); + +// Using a GUID for the VDS Name is a good way to assure uniqueness. +// +WCHAR wVdsName [50]; + +//------------------------------------------------------------ +// +// Mainline +// +int main (int argc, char *argv[]) +{ + HRESULT hr; + IClientVirtualDeviceSet2* vds = NULL ; + IClientVirtualDevice* vd=NULL; + + VDConfig config; + int badParm=TRUE; + int doBackup; + HANDLE hThread = NULL; + + // Check the input parm + // + if (argc == 2) + { + if (toupper(argv[1][0]) == 'B') + { + doBackup = TRUE; + badParm = FALSE; + } + else if (toupper(argv[1][0]) == 'R') + { + doBackup = FALSE; + badParm = FALSE; + } + } + + if (badParm) + { + printf ("useage: osimple {B|R}\n" + "Demonstrate a Backup or Restore using the Virtual Device Interface & ODBC\n"); + exit (1); + } + + printf ("Performing a %s using a virtual device.\n", + (doBackup) ? "BACKUP" : "RESTORE"); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); + + if (!SUCCEEDED (hr)) + { + printf ("Coinit fails: x%X\n", hr); + exit (1); + } + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance ( + CLSID_MSSQL_ClientVirtualDeviceSet, + NULL, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (!SUCCEEDED (hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf ("Could not create component: x%X\n", hr); + printf ("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset (&config, 0, sizeof(config)); + config.deviceCount = 1; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid (&vdsId); + StringFromGUID2 (vdsId, wVdsName, 49); + + // Create the virtual device set + // + hr = vds->CreateEx (NULL, wVdsName, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting a thread to handle the ODBC + // + printf("\nSending the SQL...\n"); + + hThread = execSQL (doBackup); + if (hThread == NULL) + { + printf ("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + printf ("\nWaiting for SQLServer to respond...\n"); + + while (!SUCCEEDED (hr=vds->GetConfiguration (1000, &config))) + { + if (hr == VD_E_TIMEOUT) + { + // Check on the SQL thread + // + DWORD rc = WaitForSingleObject (hThread, 1000); + if (rc == WAIT_OBJECT_0) + { + printf ("SQL command failed before VD transfer\n"); + goto shutdown; + } + if (rc == WAIT_TIMEOUT) + { + continue; + } + printf ("Check on SQL failed: %d\n", rc); + goto shutdown; + } + + printf ("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice (wVdsName, &vd); + if (!SUCCEEDED(hr)) + { + printf ("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf ("\nPerforming data transfer...\n"); + + performTransfer (vd, doBackup); + + +shutdown: + + // Close the set + // + vds->Close (); + + // Obtain the SQL completion information + // + if (hThread != NULL) + { + if (checkSQL (hThread)) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); + + CloseHandle (hThread); + } + + // COM reference counting: Release the interface. + // + vds->Release () ; + +exit: + // Uninitialize COM Library + // + CoUninitialize () ; + + return 0 ; +} + +//--------------------------------------------------------------------------- +// ODBC Message processing routine. +// This is SQLServer specific, to show native message IDs, sev, state. +// +// The routine will watch for message 3014 in order to detect +// a successful backup/restore operation. This is useful for +// operations like RESTORE which can sometimes recover from +// errors (error messages will be followed by the 3014 success message). +// +void ProcessMessages ( + SQLSMALLINT handle_type, // ODBC handle type + SQLHANDLE handle, // ODBC handle + int ConnInd, // TRUE if sucessful connection made + int* pBackupSuccess) // Set TRUE if a 3014 message is seen. +{ + RETCODE plm_retcode = SQL_SUCCESS; + UCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; + UCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; + SDWORD plm_pfNativeError = 0L; + SWORD plm_pcbErrorMsg = 0; + SQLSMALLINT plm_cRecNmbr = 1; + SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; + SQLINTEGER plm_Rownumber = 0; + USHORT plm_SS_Line; + SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; + SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; + + while (plm_retcode != SQL_NO_DATA_FOUND) + { + plm_retcode = SQLGetDiagRec(handle_type, handle, + plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, + plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); + + // Note that if the application has not yet made a + // successful connection, the SQLGetDiagField + // information has not yet been cached by ODBC + // Driver Manager and these calls to SQLGetDiagField + // will fail. + // + if (plm_retcode != SQL_NO_DATA_FOUND) + { + if (ConnInd) + { + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_ROW_NUMBER, &plm_Rownumber, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_LINE, &plm_SS_Line, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, + sizeof(plm_SS_Procname), + &plm_cbSS_Procname); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, + sizeof(plm_SS_Srvname), + &plm_cbSS_Srvname); + + printf ("Msg %d, SevLevel %d, State %d, SQLState %s\n", + plm_pfNativeError, + plm_SS_Severity, + plm_SS_MsgState, + plm_szSqlState); + } + + printf ("%s\n", plm_szErrorMsg); + + if (pBackupSuccess && plm_pfNativeError == 3014) + { + *pBackupSuccess = TRUE; + } + } + + plm_cRecNmbr++; //Increment to next diagnostic record. + } // End while. +} + + + +//------------------------------------------------------------------ +// The mainline of the ODBC thread. +// +// Returns TRUE if a successful backup/restore is performed. +// +unsigned __stdcall +SQLRoutine (void *parms) +{ + int doBackup = (int)parms; + + char sqlCommand [1024]; // way more space than we'll need. + int successDetected = FALSE; + + // ODBC handles + // + SQLHENV henv = NULL; + SQLHDBC hdbc = NULL; + SQLHSTMT hstmt = NULL; + + + sprintf (sqlCommand, "%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? "BACKUP" : "RESTORE", + (doBackup) ? "TO" : "FROM", + wVdsName); + + int sentSQL = FALSE; + int rc; + + #define MAX_CONN_OUT 1024 + SQLCHAR szOutConn[MAX_CONN_OUT]; + SQLSMALLINT cbOutConn; + + // Initialize the ODBC environment. + // + if (SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) + goto exit; + + // This is an ODBC v3 application + // + SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, SQL_IS_INTEGER); + + // Allocate a connection handle + // + if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) + { + printf ("AllocHandle on DBC failed."); + goto exit; + } + + // Connect to the server using Trusted connection. + // Trusted connection uses integrated NT security. + // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. + rc = SQLDriverConnect( + hdbc, + NULL, // no diaglogs please + (SQLCHAR*) "DRIVER={SQL Server};Trusted_Connection=yes;SERVER=(local)", + SQL_NTS, + szOutConn, + MAX_CONN_OUT, + &cbOutConn, + SQL_DRIVER_NOPROMPT); + + if (rc == SQL_ERROR) + { + SQLCHAR szSqlState[20]; + SQLINTEGER ssErr; + SQLCHAR szErrorMsg [MAX_CONN_OUT]; + SQLSMALLINT cbErrorMsg; + + printf ("Connect fails\n"); + + rc = SQLError ( + henv, hdbc, SQL_NULL_HSTMT, + szSqlState, + &ssErr, + szErrorMsg, + MAX_CONN_OUT, + &cbErrorMsg); + + printf ("msg=%s\n", szErrorMsg); + + goto exit; + } + + // Get a statement handle + // + if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) + { + printf ("Failed to get statement handle\n"); + + ProcessMessages (SQL_HANDLE_DBC, hdbc, TRUE, NULL); + goto exit; + } + + // Execute the SQL + // + printf ("Executing %s\n", sqlCommand); + + rc = SQLExecDirect (hstmt, (SQLCHAR*)sqlCommand, SQL_NTS); + + // Extract all the resulting messages + // + + SQLSMALLINT numResultCols; + while (1) + { + switch (rc) + { + case SQL_ERROR: + successDetected = FALSE; + ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, &successDetected); + if (!successDetected) + { + printf ("Errors resulted in failure of the command\n"); + goto exit; + } + printf ("Errors were encountered but the command was able to recover and successfully complete.\n"); + break; + + case SQL_SUCCESS_WITH_INFO: + ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, NULL); + // fall through + + case SQL_SUCCESS: + successDetected = TRUE; + + numResultCols = 0; + SQLNumResultCols (hstmt, &numResultCols); + if (numResultCols > 0) + { + printf ("A result set with %d columns was produced\n", + (int)numResultCols); + } + break; + + case SQL_NO_DATA: + // All results have been processed. We are done. + // + goto exit; + + case SQL_NEED_DATA: + case SQL_INVALID_HANDLE: + case SQL_STILL_EXECUTING: + default: + successDetected = FALSE; + printf ("Unexpected SQLExec result %d\n", rc); + goto exit; + } + rc = SQLMoreResults (hstmt); + } + +exit: + // Release the ODBC resources. + // + if (hstmt != NULL) + { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = NULL; + } + + if (hdbc != NULL) + { + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = NULL; + } + + if (henv != NULL) + { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = NULL; + } + + return successDetected; +} + + +//------------------------------------------------------------ +// +// execSQL: Send the SQL to the server via ODBC. +// +// Return the thread handle (NULL on error). +// +HANDLE execSQL (int doBackup) +{ + unsigned int threadId; + HANDLE hThread; + + hThread = (HANDLE)_beginthreadex ( + NULL, 0, SQLRoutine, (void*)doBackup, 0, &threadId); + if (hThread == NULL) + { + printf ("Failed to create thread. errno is %d\n", errno); + } + return hThread; +} + +//------------------------------------------------------------ +// +// checkSQL: Wait for the T-SQL to complete, +// returns TRUE if statement successfully executed. +// +int checkSQL (HANDLE hThread) +{ + if (hThread == NULL) + return FALSE; + + DWORD rc = WaitForSingleObject (hThread, INFINITE); + if (rc != WAIT_OBJECT_0) + { + printf ("checkSQL failed: %d\n", rc); + return FALSE; + } + if (!GetExitCodeThread (hThread, &rc)) + { + printf ("failed to get exit code: %d\n", GetLastError ()); + return FALSE; + } + return rc == TRUE; +} + + + + +//---------------------------------------------------------------------------------- +// VDI data transfer handler. +// +// This routine reads commands from the server until a 'Close' status is received. +// It simply reads or writes a file 'superbak.dmp' in the current directory. +// +void performTransfer ( + IClientVirtualDevice* vd, + int backup ) +{ + FILE * fh; + char* fname = "superbak.dmp"; + VDC_Command * cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + fh = fopen (fname, (backup)? "wb" : "rb"); + if (fh == NULL ) + { + printf ("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size ) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush (fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); + if (!SUCCEEDED (hr)) + { + printf ("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf ("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf ("Successfully completed data transfer.\n"); + } + + fclose (fh); +} diff --git a/samples/features/sqlvdi/osimple/osimple.dsp b/samples/features/sqlvdi/osimple/osimple.dsp new file mode 100644 index 0000000000..807944019b --- /dev/null +++ b/samples/features/sqlvdi/osimple/osimple.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="osimple" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=osimple - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "osimple.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "osimple.mak" CFG="osimple - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "osimple - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "osimple - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "osimple - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "osimple - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "osimple - Win32 Release" +# Name "osimple - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\osimple.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/samples/features/sqlvdi/osimple/osimple.dsw b/samples/features/sqlvdi/osimple/osimple.dsw new file mode 100644 index 0000000000..52cd0ba33d --- /dev/null +++ b/samples/features/sqlvdi/osimple/osimple.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "osimple"=.\osimple.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/samples/features/sqlvdi/simple/simple.cpp b/samples/features/sqlvdi/simple/simple.cpp new file mode 100644 index 0000000000..60e1bff428 --- /dev/null +++ b/samples/features/sqlvdi/simple/simple.cpp @@ -0,0 +1,348 @@ +/*********************************************************************** +Copyright (c) Microsoft Corporation +All Rights Reserved. +***********************************************************************/ +// This source code is an intended supplement to the Microsoft SQL +// Server online references and related electronic documentation. +// +// This sample is for instructional purposes only. +// Code contained herein is not intended to be used "as is" in real applications. +// +// simple.cpp +// +// This is a sample program used to demonstrate the Virtual Device Interface +// feature of Microsoft SQL Server. +// +// The program will backup or restore the 'pubs' sample database. +// +// The program accepts a single command line parameter. +// One of: +// b perform a backup +// r perform a restore +// + + +// To gain access to free threaded COM, you'll need to define _WIN32_DCOM +// before the system headers, either in the source (as in this example), +// or when invoking the compiler (by using /D "_WIN32_DCOM") +// +#define _WIN32_DCOM + +#include // for 'CoInitialize()' +#include // for file operations +#include // for toupper () +#include // for spawn () + +#include "vdi.h" // interface declaration +#include "vdierror.h" // error constants + +#include "vdiguid.h" // define the interface identifiers. + // IMPORTANT: vdiguid.h can only be included in one source file. + // + + +void performTransfer ( + IClientVirtualDevice* vd, + int backup ); + +int execSQL (int doBackup); + +// Using a GUID for the VDS Name is a good way to assure uniqueness. +// +WCHAR wVdsName [50]; + + +// +// main function +// +int main(int argc, char *argv[]) +{ + HRESULT hr; + IClientVirtualDeviceSet2* vds = NULL ; + IClientVirtualDevice* vd=NULL; + + VDConfig config; + int badParm=TRUE; + int doBackup; + int hProcess; + int termCode; + + // Check the input parm + // + if (argc == 2) + { + if (toupper(argv[1][0]) == 'B') + { + doBackup = TRUE; + badParm = FALSE; + } + else if (toupper(argv[1][0]) == 'R') + { + doBackup = FALSE; + badParm = FALSE; + } + } + + if (badParm) + { + printf ("useage: simple {B|R}\n" + "Demonstrate a Backup or Restore using the Virtual Device Interface\n"); + exit (1); + } + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); + + if (!SUCCEEDED (hr)) + { + printf ("Coinit fails: x%X\n", hr); + exit (1); + } + + // Get an interface to the device set. + // Changes from SQLServer v7.0: + // - we've introduced a symbol for the class ID. + // - We've added a new "multi-instance-aware" interface. + // + hr = CoCreateInstance ( + CLSID_MSSQL_ClientVirtualDeviceSet, + NULL, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (!SUCCEEDED (hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf ("Could not create component: x%X\n", hr); + printf ("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset (&config, 0, sizeof(config)); + config.deviceCount = 1; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid (&vdsId); + StringFromGUID2 (vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // Change the first parameter to identify a named instance. + // + hr = vds->CreateEx (NULL, wVdsName, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting 'isql' in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL (doBackup); + if (hProcess == -1) + { + printf ("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + hr = vds->GetConfiguration (10000, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Getconfig fails: x%X\n", hr); + if (hr == VD_E_TIMEOUT) + { + printf ("Timed out. Was Microsoft SQLServer running?\n"); + } + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice (wVdsName, &vd); + if (!SUCCEEDED(hr)) + { + printf ("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf ("\nPerforming data transfer...\n"); + + performTransfer (vd, doBackup); + + +shutdown: + + // Close the set + // + vds->Close (); + + // Obtain the SQL completion information, by waiting for isql to exit. + // + if (hProcess == _cwait( &termCode, hProcess, NULL)) + { + if (termCode == 0) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); + } + else + { + printf ("cwait failed: %d\n", errno); + } + + // COM reference counting: Release the interface. + // + // Rather than releasing it, the application has the + // option to 'Create' another set, reusing the interface + // that it currently has. Of course that applies to + // a real application, not this simple sample! + // + vds->Release () ; + +exit: + + // Uninitialize COM Library + // + CoUninitialize () ; + + return 0 ; +} + +// +// Execute a basic backup/restore, by spawning a process to execute 'isql'. +// +// Returns: +// -1 : failed to spawn +// else : a "process handle" +// +int execSQL (int doBackup) +{ + char sqlCommand [1024]; // plenty of space for our purpose + + sprintf (sqlCommand, "-Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'\"", + (doBackup) ? "BACKUP" : "RESTORE", + (doBackup) ? "TO" : "FROM", + wVdsName); + int rc; + + printf ("spawning osql to execute: %s\n", sqlCommand); + + // Spawn off the osql utility to execute the SQL. + // Notice the '-b' which causes an error to set a non-zero + // exit code on error. + // + rc = _spawnlp( _P_NOWAIT, "osql", "osql", "-E", "-b", + sqlCommand, NULL); + + if (rc == -1) + { + printf ("Spawn failed with error: %d\n", errno); + } + + return (rc); +} + +// This routine reads commands from the server until a 'Close' status is received. +// It simply reads or writes a file 'superbak.dmp' in the current directory. +// +void performTransfer ( + IClientVirtualDevice* vd, + int backup ) +{ + FILE * fh; + char* fname = "superbak.dmp"; + VDC_Command * cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + fh = fopen (fname, (backup)? "wb" : "rb"); + if (fh == NULL ) + { + printf ("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size ) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush (fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); + if (!SUCCEEDED (hr)) + { + printf ("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf ("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf ("Successfully completed data transfer.\n"); + } + + fclose (fh); +} + + diff --git a/samples/features/sqlvdi/simple/simple.dsp b/samples/features/sqlvdi/simple/simple.dsp new file mode 100644 index 0000000000..d759c37838 --- /dev/null +++ b/samples/features/sqlvdi/simple/simple.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="simple" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=simple - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "simple.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "simple.mak" CFG="simple - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "simple - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "simple - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "simple - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "simple - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "simple - Win32 Release" +# Name "simple - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\simple.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/samples/features/sqlvdi/simple/simple.dsw b/samples/features/sqlvdi/simple/simple.dsw new file mode 100644 index 0000000000..f38a9abfd8 --- /dev/null +++ b/samples/features/sqlvdi/simple/simple.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "simple"=.\simple.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/samples/features/sqlvdi/snapshot/snapshot.cpp b/samples/features/sqlvdi/snapshot/snapshot.cpp new file mode 100644 index 0000000000..be8cf26295 --- /dev/null +++ b/samples/features/sqlvdi/snapshot/snapshot.cpp @@ -0,0 +1,828 @@ +/*********************************************************************** +Copyright (c) Microsoft Corporation +All Rights Reserved. +***********************************************************************/ +// This source code is an intended supplement to the Microsoft SQL +// Server online references and related electronic documentation. +// +// This sample is for instructional purposes only. +// Code contained herein is not intended to be used "as is" in real applications. +// +// snapshot.cpp +// +// This sample extends the "osimple.cpp" sample to demonstrate BACKUP WITH SNAPSHOT. +// It is not fully functional. The ability to take/mount snapshots must be provided. +// +// This is a sample program used to demonstrate the Virtual Device Interface +// feature of Microsoft SQL Server together with an ODBC connection. +// +// The program will request backup or restore of a single database +// on some instance of sql server. +// +// The program accepts input: +// {b | r} [] +// b -> backup +// r -> restore +// + + +// To gain access to free threaded COM, you'll need to define _WIN32_DCOM +// before the system headers, either in the source (as in this example), +// or when invoking the compiler (by using /D "_WIN32_DCOM") +// +// This sample uses Windows NT Authentication, other than mixed mode security, +// to establish connections. If you want to use mixed mode security, please +// set Trusted_Connection to no in the SQLDriverConnect command. +// Make necessary change to the server name in the SQLDriverConnect command. +// +#define _WIN32_DCOM + +#include // for 'CoInitialize()' +#include // for file operations +#include // for toupper () +#include // for C library-safe _beginthreadex,_endthreadex + +#include "vdi.h" // interface declaration +#include "vdierror.h" // error constants + +#include "vdiguid.h" // define the interface identifiers. + // IMPORTANT: vdiguid.h can only be included in one source file. + // + +#include +#include "sql.h" +#include "sqlext.h" +#include "odbcss.h" + +void performTransfer ( + IClientVirtualDeviceSet2* vds, + IClientVirtualDevice* vd, + int backup ); + +HANDLE execSQL (int doBackup, char* pInstanceName, char* pDbName, WCHAR* pVdsName); +int checkSQL (HANDLE); + +BOOL +ynPrompt (char *str); + +//------------------------------------------------------------ +// +// Mainline +// +int __cdecl +main (int argc, char *argv[]) +{ + HRESULT hr; + IClientVirtualDeviceSet2* vds = NULL ; + IClientVirtualDevice* vd=NULL; + + VDConfig config; + int badParm=TRUE; + int doBackup; + HANDLE hThread = NULL; + char* pDbName = NULL; + char* pInstanceName = NULL; + + // Check the input parm + // + if (argc >= 3) + { + if (toupper(argv[1][0]) == 'B') + { + doBackup = TRUE; + badParm = FALSE; + } + else if (toupper(argv[1][0]) == 'R') + { + doBackup = FALSE; + badParm = FALSE; + } + + pDbName = argv[2]; + + if (argc == 4) + { + pInstanceName = argv[3]; + } + } + + if (badParm) + { + printf ("useage: snapshot {B|R} []\n" + "Demonstrate a Backup or Restore WITH SNAPSHOT\n"); + printf ("\n\n** NOTE **\n The ability to take or mount snapshots must be implemented\n" + "before this sample is truely functional.\n"); + exit (1); + } + + printf ("Performing a %s of %s on %s using a VIRTUAL_DEVICE.\n", + (doBackup) ? "BACKUP" : "RESTORE", + pDbName, + (pInstanceName) ? pInstanceName : "Default"); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); + + if (!SUCCEEDED (hr)) + { + printf ("Coinit fails: x%X\n", hr); + exit (1); + } + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance ( + CLSID_MSSQL_ClientVirtualDeviceSet, + NULL, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (!SUCCEEDED (hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf ("Could not create component: x%X\n", hr); + printf ("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset (&config, 0, sizeof(config)); + config.deviceCount = 1; + config.features = VDF_SnapshotPrepare; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + WCHAR wVdsName [50]; + CoCreateGuid (&vdsId); + StringFromGUID2 (vdsId, wVdsName, 49); + + // Create the virtual device set + // Notice that we only support unicode interfaces + // + WCHAR wInstanceName [128]; + int rc = 0; + if (pInstanceName) + { + rc = MultiByteToWideChar (CP_ACP, 0, + pInstanceName, strlen (pInstanceName), + wInstanceName, 127); + } + wInstanceName [rc] = 0; + + hr = vds->CreateEx (wInstanceName, wVdsName, &config); + if (!SUCCEEDED (hr)) + { + printf ("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting a thread to handle the ODBC + // + printf("\nSending the SQL...\n"); + + hThread = execSQL (doBackup, pInstanceName, pDbName, wVdsName); + if (hThread == NULL) + { + printf ("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + printf ("\nWaiting for SQLServer to respond...\n"); + + while (!SUCCEEDED (hr=vds->GetConfiguration (1000, &config))) + { + if (hr == VD_E_TIMEOUT) + { + // Check on the SQL thread + // + DWORD rc = WaitForSingleObject (hThread, 1000); + if (rc == WAIT_OBJECT_0) + { + printf ("SQL command failed before VD transfer\n"); + goto shutdown; + } + if (rc == WAIT_TIMEOUT) + { + continue; + } + printf ("Check on SQL failed: %d\n", rc); + goto shutdown; + } + + printf ("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice (wVdsName, &vd); + if (!SUCCEEDED(hr)) + { + printf ("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf ("\nPerforming data transfer...\n"); + + performTransfer (vds, vd, doBackup); + + +shutdown: + + // Close the set + // + vds->Close (); + + // Obtain the SQL completion information + // + if (hThread != NULL) + { + if (checkSQL (hThread)) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); + + CloseHandle (hThread); + } + + // COM reference counting: Release the interface. + // + vds->Release () ; + +exit: + // Uninitialize COM Library + // + CoUninitialize () ; + + return 0 ; +} + +//--------------------------------------------------------------------------- +// ODBC Message processing routine. +// This is SQLServer specific, to show native message IDs, sev, state. +// +// The routine will watch for message 3014 in order to detect +// a successful backup/restore operation. This is useful for +// operations like RESTORE which can sometimes recover from +// errors (error messages will be followed by the 3014 success message). +// +void ProcessMessages ( + SQLSMALLINT handle_type, // ODBC handle type + SQLHANDLE handle, // ODBC handle + int ConnInd, // TRUE if sucessful connection made + int* pBackupSuccess) // Set TRUE if a 3014 message is seen. +{ + RETCODE plm_retcode = SQL_SUCCESS; + UCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; + UCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; + SDWORD plm_pfNativeError = 0L; + SWORD plm_pcbErrorMsg = 0; + SQLSMALLINT plm_cRecNmbr = 1; + SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; + SQLINTEGER plm_Rownumber = 0; + USHORT plm_SS_Line; + SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; + SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; + + while (plm_retcode != SQL_NO_DATA_FOUND) + { + plm_retcode = SQLGetDiagRec(handle_type, handle, + plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, + plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); + + // Note that if the application has not yet made a + // successful connection, the SQLGetDiagField + // information has not yet been cached by ODBC + // Driver Manager and these calls to SQLGetDiagField + // will fail. + // + if (plm_retcode != SQL_NO_DATA_FOUND) + { + if (ConnInd) + { + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_ROW_NUMBER, &plm_Rownumber, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_LINE, &plm_SS_Line, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, + sizeof(plm_SS_Procname), + &plm_cbSS_Procname); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, + sizeof(plm_SS_Srvname), + &plm_cbSS_Srvname); + + printf ("Msg %d, SevLevel %d, State %d, SQLState %s\n", + plm_pfNativeError, + plm_SS_Severity, + plm_SS_MsgState, + plm_szSqlState); + } + + printf ("%s\n", plm_szErrorMsg); + + if (pBackupSuccess && plm_pfNativeError == 3014) + { + *pBackupSuccess = TRUE; + } + } + + plm_cRecNmbr++; //Increment to next diagnostic record. + } // End while. +} + + + +//------------------------------------------------------------------ +// The mainline of the ODBC thread. +// +// Returns TRUE if a successful backup/restore is performed. +// +struct PARMS +{ + int doBackup; + char* pInstanceName; + char* pDbName; + WCHAR* pVdsName; +}; + +unsigned __stdcall +SQLRoutine (void* input) +{ + PARMS* parms = (PARMS*)input; + + SQLCHAR* pSQLText; // the command being executed. + int successDetected = FALSE; + + // ODBC handles + // + SQLHENV henv = NULL; + SQLHDBC hdbc = NULL; + SQLHSTMT hstmt = NULL; + + char sqlCommand [1024]; + + int sentSQL = FALSE; + int rc; + + #define MAX_CONN_OUT 1024 + SQLCHAR szOutConn[MAX_CONN_OUT]; + SQLSMALLINT cbOutConn; + + // Convert the VDSNAME for use by the non-unicode interfaces we're using here. + // + char aVdsName [50]; + int aSize; + aSize = WideCharToMultiByte ( + CP_ACP, 0, + parms->pVdsName, + -1, // null terminated, so calculate + aVdsName, 49, + NULL, NULL ); // don't worry about fancy conversions + + + // Generate the command to execute + // + sprintf (sqlCommand, "%s DATABASE [%s] %s VIRTUAL_DEVICE='%s' WITH SNAPSHOT", + parms->doBackup ? "BACKUP" : "RESTORE", + parms->pDbName, + parms->doBackup ? "TO" : "FROM", + aVdsName); + + // Initialize the ODBC environment. + // + if (SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) + goto exit; + + // This is an ODBC v3 application + // + SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, SQL_IS_INTEGER); + + // Allocate a connection handle + // + if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) + { + printf ("AllocHandle on DBC failed."); + goto exit; + } + + char connectString [200]; + strcpy (connectString, "DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."); + if (parms->pInstanceName) + { + sprintf (connectString+strlen(connectString), "\\%s", parms->pInstanceName); + } + + printf ("\n\nConnecting with: %s\n", connectString); + + // Connect to the server using Trusted connection. + // Trusted connection uses integrated NT security. + // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. + rc = SQLDriverConnect( + hdbc, + NULL, // no diaglogs please + (SQLCHAR*) connectString, + SQL_NTS, + szOutConn, + MAX_CONN_OUT, + &cbOutConn, + SQL_DRIVER_NOPROMPT); + + if (rc == SQL_ERROR) + { + SQLCHAR szSqlState[20]; + SQLINTEGER ssErr; + SQLCHAR szErrorMsg [MAX_CONN_OUT]; + SQLSMALLINT cbErrorMsg; + + printf ("Connect fails\n"); + + rc = SQLError ( + henv, hdbc, SQL_NULL_HSTMT, + szSqlState, + &ssErr, + szErrorMsg, + MAX_CONN_OUT, + &cbErrorMsg); + + printf ("msg=%s\n", szErrorMsg); + + goto exit; + } + + // Get a statement handle + // + if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) + { + printf ("Failed to get statement handle\n"); + + ProcessMessages (SQL_HANDLE_DBC, hdbc, TRUE, NULL); + goto exit; + } + + // Execute the SQL + // + printf ("\n\nExecuting SQL: %s\n", sqlCommand); + + pSQLText = (SQLCHAR*)sqlCommand; + + rc = SQLExecDirect (hstmt, pSQLText, SQL_NTS); + + // Extract all the resulting messages + // + + SQLSMALLINT numResultCols; + while (1) + { + switch (rc) + { + case SQL_ERROR: + successDetected = FALSE; + ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, &successDetected); + if (!successDetected) + { + printf ("Errors resulted in failure of the command\n"); + goto exit; + } + printf ("Errors were encountered but the command was able to recover and successfully complete.\n"); + break; + + case SQL_SUCCESS_WITH_INFO: + ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, NULL); + // fall through + + case SQL_SUCCESS: + successDetected = TRUE; + + numResultCols = 0; + SQLNumResultCols (hstmt, &numResultCols); + if (numResultCols > 0) + { + printf ("A result set with %d columns was produced\n", + (int)numResultCols); + } + break; + + case SQL_NO_DATA: + // All results have been processed. We are done. + // + goto exit; + + case SQL_NEED_DATA: + case SQL_INVALID_HANDLE: + case SQL_STILL_EXECUTING: + default: + successDetected = FALSE; + printf ("Unexpected SQLExec result %d\n", rc); + goto exit; + } + rc = SQLMoreResults (hstmt); + } + +exit: + // Release the ODBC resources. + // + if (hstmt != NULL) + { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = NULL; + } + + if (hdbc != NULL) + { + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = NULL; + } + + if (henv != NULL) + { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = NULL; + } + + return successDetected; +} + + +//------------------------------------------------------------ +// +// execSQL: Send the SQL to the server via ODBC. +// +// Return the thread handle (NULL on error). +// +HANDLE execSQL (int doBackup, char* pInstanceName, char* pDbName, WCHAR* pVDName) +{ + unsigned int threadId; + HANDLE hThread; + static PARMS parms; // yucky, but only a single command is used.... + + parms.doBackup = doBackup; + parms.pDbName = pDbName; + parms.pInstanceName = pInstanceName; + parms.pVdsName = pVDName; + + hThread = (HANDLE)_beginthreadex ( + NULL, 0, SQLRoutine, (void*)&parms, 0, &threadId); + if (hThread == NULL) + { + printf ("Failed to create thread. errno is %d\n", errno); + } + return hThread; +} + +//------------------------------------------------------------ +// +// checkSQL: Wait for the T-SQL to complete, +// returns TRUE if statement successfully executed. +// +int checkSQL (HANDLE hThread) +{ + if (hThread == NULL) + return FALSE; + + DWORD rc = WaitForSingleObject (hThread, INFINITE); + if (rc != WAIT_OBJECT_0) + { + printf ("checkSQL failed: %d\n", rc); + return FALSE; + } + if (!GetExitCodeThread (hThread, &rc)) + { + printf ("failed to get exit code: %d\n", GetLastError ()); + return FALSE; + } + return rc == TRUE; +} + + +//---------------------------------------------------------------------------------- +// Ask the user a "yes/no" question. +// Return TRUE if he answers "yes" +// +BOOL +ynPrompt (char *str) +{ + char line[256]; + + printf ("\n\n%s", str); + line [0] = 0; + gets (line); + printf ("\n\n"); + return (line [0] == 'y' || line [0] == 'Y'); +} + +//---------------------------------------------------------------------------------- +// VDI data transfer handler. +// +// This routine reads commands from the server until a 'Close' status is received. +// It simply reads or writes a file 'superbak.dmp' in the current directory. +// +void performTransfer ( + IClientVirtualDeviceSet2* iVds, + IClientVirtualDevice* vd, + int backup ) +{ + FILE * fh; + char* fname = "snapshot.dmp"; + VDC_Command * cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + fh = fopen (fname, (backup)? "wb" : "rb"); + if (fh == NULL ) + { + printf ("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size ) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush (fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + case VDC_PrepareToFreeze: + printf ("\n*** SQL Server is prepared to freeze the database now ***\n"); + printf ("At this point the application can perform any final coordination activities.\n"); + + while (!ynPrompt ("Are you ready to freeze the database?")) + { + if (ynPrompt ("Do you want to abort?")) + { + iVds->SignalAbort (); + return; + } + } + // Acknowledging this command results in a freeze of database writes. + // The server will then issue VDC_Write commands to record metadata + // about the frozen state. + // Then the VDC_Snapshot is issued. + // + completionCode = ERROR_SUCCESS; + break; + + case VDC_Snapshot: + // At this point the metadata is complete, so the + // output stream can be closed. Thus it is possible + // to include the metadata with the data of the snapshot. + // + fclose (fh); + fh = NULL; + + printf ("\n*** Make the snapshot now ***\n"); + + while (!ynPrompt ("Did you complete the snapshot?")) + { + if (ynPrompt ("Do you want to abort?")) + { + iVds->SignalAbort (); + return; + } + } + + // For clarity, we "unroll" the loop logic + // in the following block of code so you can + // easily see the sequence of operations. + // + + // Tell SQLServer that the snapshot is done. + // + completionCode = ERROR_SUCCESS; + hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); + if (!SUCCEEDED (hr)) + { + printf ("Completion Failed: x%X\n", hr); + return; + } + + // The only valid command will be a "close" request. + // + hr = vd->GetCommand (INFINITE, &cmd); + if (hr != VD_E_CLOSE) + { + printf ("Unexpected snapshot termination: x%X\n", hr); + } + else + { + printf ("SQLServer is aware that the snapshot is successful.\n"); + } + return; + + case VDC_MountSnapshot: + printf ("\n*** Mount the snapshot now ***\n"); + + while (!ynPrompt ("Did you complete the snapshot?")) + { + if (ynPrompt ("Do you want to abort?")) + { + iVds->SignalAbort (); + return; + } + } + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); + if (!SUCCEEDED (hr)) + { + printf ("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf ("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf ("Successfully completed data transfer.\n"); + } + + if (fh != NULL) + { + fclose (fh); + } +} + + diff --git a/samples/features/sqlvdi/snapshot/snapshot.dsp b/samples/features/sqlvdi/snapshot/snapshot.dsp new file mode 100644 index 0000000000..55f9a285d6 --- /dev/null +++ b/samples/features/sqlvdi/snapshot/snapshot.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="snapshot" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=snapshot - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "snapshot.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "snapshot.mak" CFG="snapshot - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "snapshot - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "snapshot - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "snapshot - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "snapshot - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "snapshot - Win32 Release" +# Name "snapshot - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\snapshot.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/samples/features/sqlvdi/snapshot/snapshot.dsw b/samples/features/sqlvdi/snapshot/snapshot.dsw new file mode 100644 index 0000000000..10da226d1d --- /dev/null +++ b/samples/features/sqlvdi/snapshot/snapshot.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "snapshot"=.\snapshot.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + From 66181fe039d9ad593643387c23fef115f0d1c516 Mon Sep 17 00:00:00 2001 From: soradotwav Date: Fri, 14 Jun 2024 10:09:43 -0700 Subject: [PATCH 048/159] Updated original files with working VS projects --- samples/features/sqlvdi/README.md | 5 - samples/features/sqlvdi/mprocess/mprocess.cpp | 1063 +++++++-------- samples/features/sqlvdi/mprocess/mprocess.dsp | 100 -- samples/features/sqlvdi/mprocess/mprocess.dsw | 29 - .../features/sqlvdi/mprocess/mprocess.vcxproj | 141 ++ .../sqlvdi/mprocess/mprocess.vcxproj.filters | 33 + samples/features/sqlvdi/mthread/mthread.cpp | 942 +++++++------- samples/features/sqlvdi/mthread/mthread.dsp | 100 -- samples/features/sqlvdi/mthread/mthread.dsw | 29 - .../features/sqlvdi/mthread/mthread.vcxproj | 141 ++ .../sqlvdi/mthread/mthread.vcxproj.filters | 33 + samples/features/sqlvdi/osimple/osimple.cpp | 948 +++++++------- samples/features/sqlvdi/osimple/osimple.dsp | 100 -- samples/features/sqlvdi/osimple/osimple.dsw | 29 - .../features/sqlvdi/osimple/osimple.vcxproj | 142 +++ .../sqlvdi/osimple/osimple.vcxproj.filters | 33 + samples/features/sqlvdi/simple/simple.cpp | 527 ++++---- samples/features/sqlvdi/simple/simple.dsp | 100 -- samples/features/sqlvdi/simple/simple.dsw | 29 - samples/features/sqlvdi/simple/simple.vcxproj | 141 ++ .../sqlvdi/simple/simple.vcxproj.filters | 33 + samples/features/sqlvdi/snapshot/snapshot.cpp | 1134 ++++++++--------- samples/features/sqlvdi/snapshot/snapshot.dsp | 100 -- samples/features/sqlvdi/snapshot/snapshot.dsw | 29 - .../features/sqlvdi/snapshot/snapshot.vcxproj | 142 +++ .../sqlvdi/snapshot/snapshot.vcxproj.filters | 33 + 26 files changed, 3194 insertions(+), 2942 deletions(-) delete mode 100644 samples/features/sqlvdi/mprocess/mprocess.dsp delete mode 100644 samples/features/sqlvdi/mprocess/mprocess.dsw create mode 100644 samples/features/sqlvdi/mprocess/mprocess.vcxproj create mode 100644 samples/features/sqlvdi/mprocess/mprocess.vcxproj.filters delete mode 100644 samples/features/sqlvdi/mthread/mthread.dsp delete mode 100644 samples/features/sqlvdi/mthread/mthread.dsw create mode 100644 samples/features/sqlvdi/mthread/mthread.vcxproj create mode 100644 samples/features/sqlvdi/mthread/mthread.vcxproj.filters delete mode 100644 samples/features/sqlvdi/osimple/osimple.dsp delete mode 100644 samples/features/sqlvdi/osimple/osimple.dsw create mode 100644 samples/features/sqlvdi/osimple/osimple.vcxproj create mode 100644 samples/features/sqlvdi/osimple/osimple.vcxproj.filters delete mode 100644 samples/features/sqlvdi/simple/simple.dsp delete mode 100644 samples/features/sqlvdi/simple/simple.dsw create mode 100644 samples/features/sqlvdi/simple/simple.vcxproj create mode 100644 samples/features/sqlvdi/simple/simple.vcxproj.filters delete mode 100644 samples/features/sqlvdi/snapshot/snapshot.dsp delete mode 100644 samples/features/sqlvdi/snapshot/snapshot.dsw create mode 100644 samples/features/sqlvdi/snapshot/snapshot.vcxproj create mode 100644 samples/features/sqlvdi/snapshot/snapshot.vcxproj.filters diff --git a/samples/features/sqlvdi/README.md b/samples/features/sqlvdi/README.md index 11fbcf1f1e..9736b6cc5d 100644 --- a/samples/features/sqlvdi/README.md +++ b/samples/features/sqlvdi/README.md @@ -1,11 +1,6 @@ # SQLVDI This folder contains the latest files and samples required to build a SQL Server VDI based backup/restore application. -### Files available -1. vdi.h -2. vdierror.h -3. vdiguid.h - A new **VDC_Complete** command was added to SQLVDI that indicates SQL Server has completed sending data to the VDI client. Therefore, the VDI client will be able to finish the backup before it sends response to SQL Server. More details about this improvement in the SQLVDI protocol can be found in [KB3188454: Enhance VDI Protocol with VDC_Complete command in SQL Server] (https://support.microsoft.com/en-us/kb/3188454) diff --git a/samples/features/sqlvdi/mprocess/mprocess.cpp b/samples/features/sqlvdi/mprocess/mprocess.cpp index e2f17b1e2b..1b311aa597 100644 --- a/samples/features/sqlvdi/mprocess/mprocess.cpp +++ b/samples/features/sqlvdi/mprocess/mprocess.cpp @@ -44,216 +44,220 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the GUIDs -void LogError ( - LPSTR location, // must always be provided - LPSTR description, // NULL is acceptable - DWORD errCode); // windows status code +void LogError( + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode); // windows status code -int performTransfer ( - IClientVirtualDevice* vd, - int backup, - int streamId); +int performTransfer( + IClientVirtualDevice* vd, + int backup, + int streamId); -HANDLE execSQL (int doBackup, int nStreams); +HANDLE execSQL(bool doBackup, int nStreams); -int -runSecondary (int streamId, IClientVirtualDeviceSet *vds); +int runSecondary(int streamId, IClientVirtualDeviceSet2* vds); -int -startSecondaries( - IClientVirtualDeviceSet *vds, - HANDLE hSQLProcess, // handle to process dealing with the SQL - int nStreams, // number of i/o streams - char* pgmName); // the name of this program +int startSecondaries( + IClientVirtualDeviceSet2* vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams, // number of i/o streams + char* pgmName // the name of this program +); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName [100]; - +WCHAR wVdsName[100]; // // main function // -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet* vds = NULL ; - VDConfig config; - int badParm=TRUE; - int doBackup; - HANDLE hProcess; - int termCode = -1; - int nStreams=1; - int isSecondary = FALSE; - - // Check the input parm - // - if (argc >= 3) - { - sscanf (argv[2], "%d", &nStreams); - switch (toupper(argv[1][0])) - { - case 'B': - doBackup = TRUE; - badParm = FALSE; - break; - - case 'R': - doBackup = FALSE; - badParm = FALSE; - break; - - case 'S': - doBackup = FALSE; // we don't know or care - badParm = FALSE; - isSecondary = TRUE; - // nStreams is the streamid! - swprintf (wVdsName, L"%hs", argv[3]); - break; - } - } - - if (badParm) - { - printf ("useage: mprocess {B|R} \n" - "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); - exit (1); - } - - if (isSecondary) - { - printf("Secondary pid %d working on stream %d\n", GetCurrentProcessId (), nStreams); - } - else - { - // 1..32 streams. - // - if (nStreams < 1) - nStreams = 1; - else if (nStreams > 32) - nStreams = 32; - - printf ("Performing a %s using %d virtual device(s).\n", - (doBackup) ? "BACKUP" : "RESTORE", nStreams); - } - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); - - if (!SUCCEEDED (hr)) - { - printf ("Coinit fails: x%X\n", hr); - exit (1); - } - - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance ( - IID_IClientVirtualDeviceSet, - NULL, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet, - (void**)&vds); - - if (!SUCCEEDED (hr)) - { - // This failure might happen if the DLL was not registered. - // - printf ("Could not create component: x%X\n", hr); - printf ("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Perform secondary processing, if this is a - // secondary process. - // - if (isSecondary) - { - termCode = runSecondary (nStreams, vds); - - goto exit; - } - - // The following logic is executed by the primary process. - // - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset (&config, 0, sizeof(config)); - - config.deviceCount = nStreams; + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hProcess; + int termCode = -1; + int nStreams = 1; + bool isSecondary = false; + + // Check the input parm + // + if (argc >= 3) + { + sscanf_s(argv[2], "%d", &nStreams); + + switch (toupper(argv[1][0])) + { + case 'B': + doBackup = true; + badParm = false; + break; + + case 'R': + doBackup = false; + badParm = false; + break; + + case 'S': + doBackup = false; // we don't know or care + badParm = false; + isSecondary = true; + + // nStreams is the streamid! + swprintf_s(wVdsName, L"%hs", argv[3]); + break; + } + } + + if (badParm) + { + printf("usage: mprocess {B|R} \n" + "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); + exit(1); + } + + if (isSecondary) + { + printf("Secondary pid %d working on stream %d\n", GetCurrentProcessId(), nStreams); + } + else + { + // 1..32 streams. + // + if (nStreams < 1) + nStreams = 1; + else if (nStreams > 32) + nStreams = 32; + + printf("Performing a %s using %d virtual device(s).\n", + (doBackup) ? "BACKUP" : "RESTORE", nStreams); + } + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + IID_IClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered. + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Perform secondary processing, if this is a + // secondary process. + // + if (isSecondary) + { + termCode = runSecondary(nStreams, vds); + + goto exit; + } + + // The following logic is executed by the primary process. + // + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + + config.deviceCount = nStreams; // Create a GUID to use for a unique virtual device name // GUID vdsId; - CoCreateGuid (&vdsId); - StringFromGUID2 (vdsId, wVdsName, 49); - - // Create the virtual device set - // - hr = vds->Create (wVdsName, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, via isql in a subprocess. - // - printf("\nSending the SQL...\n"); - - hProcess = execSQL (doBackup, nStreams); - if (hProcess == NULL) - { - printf ("execSQL failed.\n"); - goto shutdown; - } - - - // Wait for the server to connect, completing the configuration. - // Notice that we wait a maximum of 15 seconds. - // - printf("\nWaiting for SQL to complete configuration...\n"); - - hr = vds->GetConfiguration (15000, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Handle the virtual devices in secondary processes. - // - printf ("\nSpawning secondary processes...\n"); - termCode = startSecondaries (vds, hProcess, nStreams, argv[0]); - + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, via isql in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL(doBackup, nStreams); + if (hProcess == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + + // Wait for the server to connect, completing the configuration. + // Notice that we wait a maximum of 15 seconds. + // + printf("\nWaiting for SQL to complete configuration...\n"); + + hr = vds->GetConfiguration(15000, &config); + if (FAILED(hr)) + { + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Handle the virtual devices in secondary processes. + // + printf("\nSpawning secondary processes...\n"); + termCode = startSecondaries(vds, hProcess, nStreams, argv[0]); + shutdown: - // Close the set - // - vds->Close (); + // Close the set + // + vds->Close(); - // COM reference counting: Release the interface. - // - vds->Release () ; + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize () ; + // Uninitialize COM Library + // + CoUninitialize(); - return termCode; + return termCode; } // @@ -263,50 +267,54 @@ int main(int argc, char *argv[]) // NULL : failed to start isql // else : process handle // -HANDLE execSQL (int doBackup, int nStreams) +HANDLE execSQL(bool doBackup, int nStreams) { - char cmd[5000]; - char extend[100]; - PROCESS_INFORMATION pi; - STARTUPINFO si; - int ix; - - // Build the SQL, submitting it via 'isql' - // If you want to use Windows NT Authentication, please do not use the -U or -P options. - sprintf (cmd, - "osql -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", - (doBackup) ? "BACKUP" : "RESTORE", - (doBackup) ? "TO" : "FROM", + WCHAR cmd[5000]; + WCHAR extend[100]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + int ix; + + // Build the SQL, submitting it via 'isql' + // If you want to use Windows NT Authentication, please do not use the -U or -P options. + // + // To use a named instance, change "-S ." to "-S .\\instance_name" + // + swprintf_s(cmd, L"osql -S . -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", wVdsName); - - for (ix=1; ix= WAIT_OBJECT_0 && - waitStatus < WAIT_OBJECT_0+nActive) - { - // One of the children completed. - // Determine which one. - // - ix = waitStatus - WAIT_OBJECT_0; - - // Check its completion code - // - if (!GetExitCodeProcess (children[ix], &exitCode)) - { - LogError ("startSecondary", "GetExitCode", GetLastError ()); - goto errorExit; - } - - if (exitCode != 0) - { - printf ("A child exitted with code %d\n", exitCode); - goto errorExit; - } - - // It is good programming practice to close handles when - // finished with them. - // Since this sample simply terminates the process for error - // handling, we don't need to do it, as handles are automatically - // closed as part of process termination. - // - CloseHandle (children[ix]); - - // Remove the handle for this child - // - memmove (&children[ix], &children[ix+1], - sizeof (HANDLE) * (nActive-ix-1)); - - nActive--; - - } - else - { - printf("Unexpected wait code: %d\n", waitStatus); - goto errorExit; - } - - } while (nActive > 0); - - printf ("All children completed successfully\n"); - - return 0; + int ix, nActive; + HANDLE children[33]; // 32 is maximum number of streams. + + // plus one for the isql process. + DWORD waitStatus, exitCode; + WCHAR cmd[200]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + + // use my process for startup info + // + GetStartupInfo(&si); + + for (ix = 0; ix < nStreams; ix++) + { + swprintf_s(cmd, L"%hs s %d %ls", pgmName, ix, wVdsName); + + if (!CreateProcess(nullptr, cmd, nullptr, nullptr, + true, // inherit handles (just stdin/stdout I hope!) + 0, // creation flags, + nullptr, nullptr, + &si, // startup info + &pi)) // out: process info + { + wprintf(L"Error starting %s\n", cmd); + LogError("startSecondary", "CreateProcess", GetLastError()); + goto errorExit; + } + // keep the process handle + children[ix] = pi.hProcess; + + CloseHandle(pi.hThread); + } + + // Add the isql process into the array + // + children[nStreams] = hSQLProcess; + nActive = nStreams + 1; + + // Wait for all to finish. + // Max wait is one minute for this tiny test. + // + printf("All children are now running.\n" + "Waiting for their completion...\n"); + + // Notice how this differs from the threaded model in mthread.cpp. + // In the multiprocess model, the primary client (running this code) + // is responsible for detecting abnormal termination of the + // secondary clients. + // A simple "wait-for-all" approach may wait indefinitely if only + // one of the secondaries was to abnormally terminate. + // + do + { + // Wait for any completion + // + waitStatus = WaitForMultipleObjects(nActive, children, + FALSE, INFINITE); + + if (waitStatus >= WAIT_OBJECT_0 && + waitStatus < WAIT_OBJECT_0 + nActive) + { + // One of the children completed. + // Determine which one. + // + ix = waitStatus - WAIT_OBJECT_0; + + // Check its completion code + // + if (!GetExitCodeProcess(children[ix], &exitCode)) + { + LogError("startSecondary", "GetExitCode", GetLastError()); + goto errorExit; + } + + if (exitCode != 0) + { + printf("A child exitted with code %d\n", exitCode); + goto errorExit; + } + + // It is good programming practice to close handles when + // finished with them. + // Since this sample simply terminates the process for error + // handling, we don't need to do it, as handles are automatically + // closed as part of process termination. + // + CloseHandle(children[ix]); + + // Remove the handle for this child + // + memmove(&children[ix], &children[ix + 1], + sizeof(HANDLE) * (nActive - ix - 1)); + + nActive--; + + } + else + { + printf("Unexpected wait code: %d\n", waitStatus); + goto errorExit; + } + + } while (nActive > 0); + + printf("All children completed successfully\n"); + + return 0; errorExit: - // Handle all problems in a trivial fashion: - // SignalAbort() will cause all processes using the virtual device set - // to terminate processing. - // Thus, we don't bother waiting for any children to terminate. - // - vds->SignalAbort (); - return -1; + // Handle all problems in a trivial fashion: + // SignalAbort() will cause all processes using the virtual device set + // to terminate processing. + // Thus, we don't bother waiting for any children to terminate. + // + vds->SignalAbort(); + return -1; } @@ -444,77 +455,79 @@ startSecondaries( // Perform secondary client processing // Return 0 if no errors detected, else nonzero. // -int -runSecondary (int streamId, IClientVirtualDeviceSet *vds) +int runSecondary(int streamId, IClientVirtualDeviceSet2* vds) { - HRESULT hr; - WCHAR devName[100]; - IClientVirtualDevice* vd; - VDConfig config; - int termCode; - - // Open the device - // - if (streamId == 0) - { - // The first device has the same name as the set. - // - wcscpy (devName, wVdsName); - } - else - { - // For this example, we've simply appended a number - // for additional devices. You are free to name them - // as you wish. - // - swprintf (devName, L"%ls%d", wVdsName, streamId); - } - - // Open the virtual device set in this secondary process. - // - hr = vds->OpenInSecondary (wVdsName); - if (!SUCCEEDED (hr)) - { - printf ("VD::Open(%ls) fails: x%X", devName, hr); - return -1; - } - - // Open the device assigned to this process. - // - hr = vds->OpenDevice (devName, &vd); - if (!SUCCEEDED (hr)) - { - printf ("OpenDevice fails on %ls: x%X", devName, hr); - return -1; - } - - // Grab the config to figure out data direction - // - hr = vds->GetConfiguration (INFINITE, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Getconfig fails: x%X\n", hr); - termCode = -1; - goto errExit; - } - - printf ("\nPerforming data transfer...\n"); - - termCode = performTransfer (vd, - (config.features&VDF_WriteMedia), streamId); + HRESULT hr; + WCHAR devName[100]; + IClientVirtualDevice* vd; + VDConfig config; + int termCode; + + // Open the device + // + if (streamId == 0) + { + // The first device has the same name as the set. + // + wcscpy_s(devName, wVdsName); + } + else + { + // For this example, we've simply appended a number + // for additional devices. You are free to name them + // as you wish. + // + swprintf_s(devName, L"%ls%d", wVdsName, streamId); + } + + // Open the virtual device set in this secondary process. + // + // To use a named instance, change the + // first parameter in OpenInSecondaryEx to your instance's name. + // + hr = vds->OpenInSecondaryEx(nullptr, wVdsName); + if (FAILED(hr)) + { + wprintf(L"VD::Open(%ls) fails: x%X", devName, hr); + return -1; + } + + // Open the device assigned to this process. + // + hr = vds->OpenDevice(devName, &vd); + if (FAILED(hr)) + { + wprintf(L"OpenDevice fails on %ls: x%X", devName, hr); + return -1; + } + + // Grab the config to figure out data direction + // + hr = vds->GetConfiguration(INFINITE, &config); + if (FAILED(hr)) + { + wprintf(L"VDS::Getconfig fails: x%X\n", hr); + termCode = -1; + goto errExit; + } + + printf("\nPerforming data transfer...\n"); + + termCode = performTransfer(vd, + (config.features & VDF_WriteMedia), streamId); errExit: - // If errors were detected, force an abort. - // - if (termCode != 0) - { - vds->SignalAbort (); - } + // If errors were detected, force an abort. + // + if (termCode != 0) + { + vds->SignalAbort(); + } - vds->Close (); + vds->Close(); - return termCode; + return termCode; } @@ -523,126 +536,126 @@ runSecondary (int streamId, IClientVirtualDeviceSet *vds) // // Returns 0, if no errors are detected, else non-zero. // -int performTransfer ( - IClientVirtualDevice* vd, - int backup, - int streamId) +int performTransfer( + IClientVirtualDevice* vd, + int backup, + int streamId) { - FILE * fh; - char fname[80]; - VDC_Command * cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - int termCode = -1; - - sprintf (fname, "multi.%d.dmp", streamId); - - fh = fopen (fname, (backup)? "wb" : "rb"); - if (fh == NULL ) - { - printf ("Failed to open: %s\n", fname); - return -1; - } - - while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - - break; - - case VDC_Write: - bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size ) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush (fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - - hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); - if (!SUCCEEDED (hr)) - { - printf ("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf ("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf ("Successfully completed data transfer.\n"); - termCode = 0; - } - - fclose (fh); - - return termCode; + FILE* fh; + char fname[80]; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + int termCode = -1; + + sprintf_s(fname, "multi.%d.dmp", streamId); + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return -1; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + termCode = 0; + } + + fclose(fh); + + return termCode; } //-------------------------------------------------------------------- // // A simple error logger. // -void LogError ( - LPSTR location, // must always be provided - LPSTR description, // NULL is acceptable - DWORD errCode) // windows status code +void LogError( + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode) // windows status code { - LPVOID lpMsgBuf; - - printf ( - "Error at %s: %s StatusCode: %X\n", - location, - (description==NULL)?"":description, - errCode); - - // Attempt to explain the code - // - if (errCode != 0 && FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - errCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, 0, NULL ) )// Process any inserts in lpMsgBuf. - { - printf ("Explanation: %s\n", lpMsgBuf); - LocalFree( lpMsgBuf ); - } + LPWSTR lpMsgBuf; + + printf( + "Error at %s: %s StatusCode: %X\n", + location, + (description == nullptr) ? "" : description, + errCode); + + // Attempt to explain the code + // + if (errCode != 0 && FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + reinterpret_cast(&lpMsgBuf), 0, nullptr))// Process any inserts in lpMsgBuf. + { + printf("Explanation: %ls\n", lpMsgBuf); + LocalFree(lpMsgBuf); + } } diff --git a/samples/features/sqlvdi/mprocess/mprocess.dsp b/samples/features/sqlvdi/mprocess/mprocess.dsp deleted file mode 100644 index 646cca91f7..0000000000 --- a/samples/features/sqlvdi/mprocess/mprocess.dsp +++ /dev/null @@ -1,100 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mprocess" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=mprocess - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mprocess.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mprocess.mak" CFG="mprocess - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mprocess - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "mprocess - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mprocess - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "mprocess - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "mprocess - Win32 Release" -# Name "mprocess - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\mprocess.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/samples/features/sqlvdi/mprocess/mprocess.dsw b/samples/features/sqlvdi/mprocess/mprocess.dsw deleted file mode 100644 index b9ae7ee953..0000000000 --- a/samples/features/sqlvdi/mprocess/mprocess.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "mprocess"=.\mprocess.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/samples/features/sqlvdi/mprocess/mprocess.vcxproj b/samples/features/sqlvdi/mprocess/mprocess.vcxproj new file mode 100644 index 0000000000..cb17bce2e0 --- /dev/null +++ b/samples/features/sqlvdi/mprocess/mprocess.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {fe97585b-08bd-4837-a5ba-5c960e591f29} + mprocess + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\include + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/mprocess/mprocess.vcxproj.filters b/samples/features/sqlvdi/mprocess/mprocess.vcxproj.filters new file mode 100644 index 0000000000..6284fbcad1 --- /dev/null +++ b/samples/features/sqlvdi/mprocess/mprocess.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/mthread/mthread.cpp b/samples/features/sqlvdi/mthread/mthread.cpp index 3430e8a225..b9e1fd63ff 100644 --- a/samples/features/sqlvdi/mthread/mthread.cpp +++ b/samples/features/sqlvdi/mthread/mthread.cpp @@ -39,185 +39,188 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the GUIDs -void LogError ( - LPSTR location, // must always be provided - LPSTR description, // NULL is acceptable - DWORD errCode); // windows status code +void LogError( + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode); // windows status code -int performTransfer ( - IClientVirtualDevice* vd, - int backup, - int streamId); +int performTransfer( + IClientVirtualDevice* vd, + int backup, + int streamId); -HANDLE execSQL (int doBackup, int nStreams); +HANDLE execSQL(bool doBackup, int nStreams); -int -startSecondaries( - IClientVirtualDeviceSet *vds, - HANDLE hSQLProcess, // handle to process dealing with the SQL - int nStreams); // number of i/o streams +int startSecondaries( + IClientVirtualDeviceSet2* vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams); // number of i/o streams unsigned __stdcall -runSecondary (void *parms); +runSecondary(void* parms); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName [50]; +WCHAR wVdsName[50]; // // main function // -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet* vds = NULL ; - VDConfig config; - int badParm=TRUE; - int doBackup; - HANDLE hProcess; - int termCode = -1; - int nStreams=1; - - // Check the input parm - // - if (argc == 3) - { - sscanf (argv[2], "%d", &nStreams); - switch (toupper(argv[1][0])) - { - case 'B': - doBackup = TRUE; - badParm = FALSE; - break; - - case 'R': - doBackup = FALSE; - badParm = FALSE; - break; - } - } - - if (badParm) - { - printf ("useage: mprocess {B|R} \n" - "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); - exit (1); - } - - // 1..32 streams. - // - if (nStreams < 1) - nStreams = 1; - else if (nStreams > 32) - nStreams = 32; - - printf ("Performing a %s using %d virtual device(s).\n", - (doBackup) ? "BACKUP" : "RESTORE", nStreams); - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); - - if (!SUCCEEDED (hr)) - { - printf ("Coinit fails: x%X\n", hr); - exit (1); - } - - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance ( - IID_IClientVirtualDeviceSet, - NULL, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet, - (void**)&vds); - - if (!SUCCEEDED (hr)) - { - // This failure might happen if the DLL was not registered. - // - printf ("Could not create component: x%X\n", hr); - printf ("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hProcess; + int termCode = -1; + int nStreams = 1; + + // Check the input parm + // + if (argc == 3) + { + sscanf_s(argv[2], "%d", &nStreams); + + switch (toupper(argv[1][0])) + { + case 'B': + doBackup = true; + badParm = false; + break; + + case 'R': + doBackup = false; + badParm = false; + break; + } + } + + if (badParm) + { + printf("usage: mthread {B|R} \n" + "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); + exit(1); + } + + // 1..32 streams. + // + if (nStreams < 1) + nStreams = 1; + else if (nStreams > 32) + nStreams = 32; + + printf("Performing a %s using %d virtual device(s).\n", + (doBackup) ? "BACKUP" : "RESTORE", nStreams); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered. + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = nStreams; // Create a GUID to use for a unique virtual device name // GUID vdsId; - CoCreateGuid (&vdsId); - StringFromGUID2 (vdsId, wVdsName, 49); - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset (&config, 0, sizeof(config)); - - config.deviceCount = nStreams; - - // Create the virtual device set - // - hr = vds->Create (wVdsName, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, via isql in a subprocess. - // - printf("\nSending the SQL...\n"); - - hProcess = execSQL (doBackup, nStreams); - if (hProcess == NULL) - { - printf ("execSQL failed.\n"); - goto shutdown; - } - - - // Wait for the server to connect, completing the configuration. - // Notice that we wait a maximum of 15 seconds. - // - printf("\nWaiting for SQL to complete configuration...\n"); - - hr = vds->GetConfiguration (15000, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Handle the virtual devices in secondary processes. - // - printf ("\nSpawning secondary threads..\n"); - termCode = startSecondaries (vds, hProcess, nStreams); - + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, via isql in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL(doBackup, nStreams); + if (hProcess == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + + // Wait for the server to connect, completing the configuration. + // Notice that we wait a maximum of 15 seconds. + // + printf("\nWaiting for SQL to complete configuration...\n"); + + hr = vds->GetConfiguration(15000, &config); + if (FAILED(hr)) + { + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Handle the virtual devices in secondary processes. + // + printf("\nSpawning secondary threads..\n"); + termCode = startSecondaries(vds, hProcess, nStreams); + shutdown: - // Close the set - // - vds->Close (); + // Close the set + // + vds->Close(); - // COM reference counting: Release the interface. - // - vds->Release () ; + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize () ; + // Uninitialize COM Library + // + CoUninitialize(); - return termCode; + return termCode; } // @@ -227,47 +230,50 @@ int main(int argc, char *argv[]) // NULL : failed to start isql // else : process handle // -HANDLE execSQL (int doBackup, int nStreams) +HANDLE execSQL(bool doBackup, int nStreams) { - char cmd[5000]; - char extend[100]; - PROCESS_INFORMATION pi; - STARTUPINFO si; - int ix; - - sprintf (cmd, "osql -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", - (doBackup) ? "BACKUP" : "RESTORE", - (doBackup) ? "TO" : "FROM", + WCHAR cmd[5000]; + WCHAR extend[100]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + int ix; + + // To use a named instance, change "-S ." to "-S .\\instance_name" + swprintf_s(cmd, L"osql -S . -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", wVdsName); - - for (ix=1; ix= WAIT_OBJECT_0+nActive) - { - LogError ("startSecondary", "WaitForMultiple", GetLastError ()); - printf("Unexpected wait code: %d\n", waitStatus); - goto errorExit; - } - - // All of the children have completed. - // Get the completion code from 'isql' to check for sucess. - // - if (!GetExitCodeProcess (hSQLProcess, &exitCode)) - { - LogError ("startSecondary", "GetExitCode", GetLastError ()); - goto errorExit; - } - - if (exitCode != 0) - { - printf ("The SQL operation failed with code %d\n", exitCode); - goto errorExit; - } - - printf ("The SQL operation was sucessful.\n"); - - // Be sure to close handles when finished with them. - // - // Notice that in our trivial error handling here we - // don't bother closing them, since handles are - // automatically closed as part of process termination. - // - for (ix = 0; ix < nActive; ix++) - { - CloseHandle (children[ix]); - } - - return 0; + THREAD_PARMS parms[32]; // each thread needs its own parm block + int ix, nActive; + HANDLE children[33]; // 32 is maximum number of streams. + + // plus one for the isql process. + DWORD waitStatus, exitCode; + unsigned threadId; + + for (ix = 0; ix < nStreams; ix++) + { + // All threads share the same virtual device set, + // but must operate on different virtual devices. + // + parms[ix].vds = vds; + parms[ix].streamId = ix; + + children[ix] = (HANDLE)_beginthreadex( + nullptr, 0, runSecondary, (void*)&parms[ix], 0, &threadId); + + if (children[ix] == nullptr) + { + printf("Failed to create thread. errno is %d\n", errno); + goto errorExit; + } + + printf("\nStarted thread %d\n", threadId); + } + + // Add the isql process into the array + // + children[nStreams] = hSQLProcess; + nActive = nStreams + 1; + + // Wait for all to finish. + // Max wait is one minute for this tiny test. + // + printf("All children are now running.\n" + "Waiting for their completion...\n"); + + waitStatus = WaitForMultipleObjects(nActive, children, + true, 60000); + + if (waitStatus < WAIT_OBJECT_0 || + waitStatus >= WAIT_OBJECT_0 + nActive) + { + LogError("startSecondary", "WaitForMultiple", GetLastError()); + printf("Unexpected wait code: %d\n", waitStatus); + goto errorExit; + } + + // All of the children have completed. + // Get the completion code from 'isql' to check for sucess. + // + if (!GetExitCodeProcess(hSQLProcess, &exitCode)) + { + LogError("startSecondary", "GetExitCode", GetLastError()); + goto errorExit; + } + + if (exitCode != 0) + { + printf("The SQL operation failed with code %d\n", exitCode); + goto errorExit; + } + + printf("The SQL operation was sucessful.\n"); + + // Be sure to close handles when finished with them. + // + // Notice that in our trivial error handling here we + // don't bother closing them, since handles are + // automatically closed as part of process termination. + // + for (ix = 0; ix < nActive; ix++) + { + CloseHandle(children[ix]); + } + + return 0; errorExit: - // Handle all problems in a trivial fashion: - // SignalAbort() will cause all processes using the virtual device set - // to terminate processing. - // - vds->SignalAbort (); - - // However, since the threads are using the virtual device set allocated - // by the main thread, we can't let the main thread close the set before - // the threads are finished with it. There are two options: - // 1) exit the process immediately. - // 2) wait for the threads to terminate. - // - // Option 2 is "cleaner" but requires more code, so we just exit here: - // - ExitProcess ((unsigned)-1); - - return -1; // ExitProcess doesn't return; this avoids a compiler error. + // Handle all problems in a trivial fashion: + // SignalAbort() will cause all processes using the virtual device set + // to terminate processing. + // + vds->SignalAbort(); + + // However, since the threads are using the virtual device set allocated + // by the main thread, we can't let the main thread close the set before + // the threads are finished with it. There are two options: + // 1) exit the process immediately. + // 2) wait for the threads to terminate. + // + // Option 2 is "cleaner" but requires more code, so we just exit here: + // + ExitProcess((unsigned)-1); + + return -1; // ExitProcess doesn't return; this avoids a compiler error. } //------------------------------------------------------------------ @@ -399,71 +407,71 @@ startSecondaries( // spawning the thread. // unsigned __stdcall -runSecondary (void *parms) +runSecondary(void* parms) { - HRESULT hr; - WCHAR devName[100]; - IClientVirtualDevice* vd; - VDConfig config; - int termCode; - - // Fetch the input parms - // - int streamId = ((THREAD_PARMS*)parms)->streamId; - IClientVirtualDeviceSet * vds = ((THREAD_PARMS*)parms)->vds; - - // Build the name of the device assigned to this thread. - // - if (streamId == 0) - { - // The first device has the same name as the set. - // - wcscpy (devName, wVdsName); - } - else - { - // For this example, we've simply appended a number - // for additional devices. You are free to name them - // as you wish. - // - swprintf (devName, L"%s%d", wVdsName, streamId); - } - - // Open the device assigned to this thread. - // - hr = vds->OpenDevice (devName, &vd); - if (!SUCCEEDED (hr)) - { - printf ("OpenDevice fails on %ls: x%X", devName, hr); - termCode = -1; - goto errExit; - } - - // Grab the config to figure out data direction - // - hr = vds->GetConfiguration (INFINITE, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Getconfig fails: x%X\n", hr); - termCode = -1; - goto errExit; - } - - printf ("\nPerforming data transfer...\n"); - - termCode = performTransfer (vd, - (config.features&VDF_WriteMedia), streamId); + HRESULT hr; + WCHAR devName[100]; + IClientVirtualDevice* vd; + VDConfig config; + int termCode; + + // Fetch the input parms + // + int streamId = ((THREAD_PARMS*)parms)->streamId; + IClientVirtualDeviceSet* vds = ((THREAD_PARMS*)parms)->vds; + + // Build the name of the device assigned to this thread. + // + if (streamId == 0) + { + // The first device has the same name as the set. + // + wcscpy_s(devName, wVdsName); + } + else + { + // For this example, we've simply appended a number + // for additional devices. You are free to name them + // as you wish. + // + swprintf_s(devName, L"%s%d", wVdsName, streamId); + } + + // Open the device assigned to this thread. + // + hr = vds->OpenDevice(devName, &vd); + if (FAILED(hr)) + { + wprintf(L"OpenDevice fails on %ls: x%X", devName, hr); + termCode = -1; + goto errExit; + } + + // Grab the config to figure out data direction + // + hr = vds->GetConfiguration(INFINITE, &config); + if (FAILED(hr)) + { + wprintf(L"VDS::Getconfig fails: x%X\n", hr); + termCode = -1; + goto errExit; + } + + printf("\nPerforming data transfer...\n"); + + termCode = performTransfer(vd, + (config.features & VDF_WriteMedia), streamId); errExit: - // If errors were detected, force an abort. - // - if (termCode != 0) - { - vds->SignalAbort (); - } + // If errors were detected, force an abort. + // + if (termCode != 0) + { + vds->SignalAbort(); + } - return ((unsigned)termCode); + return ((unsigned)termCode); } @@ -474,95 +482,95 @@ runSecondary (void *parms) // // Returns 0, if no errors are detected, else non-zero. // -int performTransfer ( - IClientVirtualDevice* vd, - int backup, - int streamId) +int performTransfer( + IClientVirtualDevice* vd, + int backup, + int streamId) { - FILE * fh; - char fname[80]; - VDC_Command * cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - int termCode = -1; - - sprintf (fname, "multi.%d.dmp", streamId); - - fh = fopen (fname, (backup)? "wb" : "rb"); - if (fh == NULL ) - { - printf ("Failed to open: %s\n", fname); - return -1; - } - - while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - - break; - - case VDC_Write: - bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size ) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush (fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - - hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); - if (!SUCCEEDED (hr)) - { - printf ("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf ("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf ("Successfully completed data transfer.\n"); - termCode = 0; - } - - fclose (fh); - - return termCode; + FILE* fh; + char fname[80]; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + int termCode = -1; + + sprintf_s(fname, "multi.%d.dmp", streamId); + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return -1; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + termCode = 0; + } + + fclose(fh); + + return termCode; } @@ -570,31 +578,31 @@ int performTransfer ( // // A simple error logger. // -void LogError ( - LPSTR location, // must always be provided - LPSTR description, // NULL is acceptable - DWORD errCode) // windows status code +void LogError( + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode) // windows status code { - LPVOID lpMsgBuf; - - printf ( - "Error at %s: %s StatusCode: %X\n", - location, - (description==NULL)?"":description, - errCode); - - // Attempt to explain the code - // - if (errCode != 0 && FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - errCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, 0, NULL ) )// Process any inserts in lpMsgBuf. - { - printf ("Explanation: %s\n", lpMsgBuf); - LocalFree( lpMsgBuf ); - } + LPWSTR lpMsgBuf = nullptr; + + printf( + "Error at %s: %s StatusCode: %X\n", + location, + (description == nullptr) ? "" : description, + errCode); + + // Attempt to explain the code + // + if (errCode != 0 && FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + reinterpret_cast(&lpMsgBuf), 0, nullptr)) // Process any inserts in lpMsgBuf. + { + printf("Explanation: %ls\n", lpMsgBuf); + LocalFree(lpMsgBuf); + } } diff --git a/samples/features/sqlvdi/mthread/mthread.dsp b/samples/features/sqlvdi/mthread/mthread.dsp deleted file mode 100644 index 9b852163bf..0000000000 --- a/samples/features/sqlvdi/mthread/mthread.dsp +++ /dev/null @@ -1,100 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mthread" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=mthread - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mthread.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mthread.mak" CFG="mthread - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mthread - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "mthread - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mthread - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "mthread - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "mthread - Win32 Release" -# Name "mthread - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\mthread.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/samples/features/sqlvdi/mthread/mthread.dsw b/samples/features/sqlvdi/mthread/mthread.dsw deleted file mode 100644 index 052e314d3b..0000000000 --- a/samples/features/sqlvdi/mthread/mthread.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "mthread"=.\mthread.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/samples/features/sqlvdi/mthread/mthread.vcxproj b/samples/features/sqlvdi/mthread/mthread.vcxproj new file mode 100644 index 0000000000..82b3c0c2a3 --- /dev/null +++ b/samples/features/sqlvdi/mthread/mthread.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {f4600084-90ad-42b9-9809-ade6e1c06423} + mthread + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\include + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/mthread/mthread.vcxproj.filters b/samples/features/sqlvdi/mthread/mthread.vcxproj.filters new file mode 100644 index 0000000000..606cc8a8dc --- /dev/null +++ b/samples/features/sqlvdi/mthread/mthread.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/osimple/osimple.cpp b/samples/features/sqlvdi/osimple/osimple.cpp index 118d080e30..12c99f50bd 100644 --- a/samples/features/sqlvdi/osimple/osimple.cpp +++ b/samples/features/sqlvdi/osimple/osimple.cpp @@ -46,204 +46,210 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the interface identifiers. - // IMPORTANT: vdiguid.h can only be included in one source file. - // + // IMPORTANT: vdiguid.h can only be included in one source file. + // #include #include "sql.h" #include "sqlext.h" #include "odbcss.h" -void performTransfer ( - IClientVirtualDevice* vd, - int backup ); +void performTransfer( + IClientVirtualDevice* vd, + int backup); -HANDLE execSQL (int doBackup); -int checkSQL (HANDLE); +HANDLE execSQL(bool doBackup); +bool checkSQL(HANDLE); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName [50]; +WCHAR wVdsName[50]; //------------------------------------------------------------ // // Mainline // -int main (int argc, char *argv[]) +int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = NULL ; - IClientVirtualDevice* vd=NULL; - - VDConfig config; - int badParm=TRUE; - int doBackup; - HANDLE hThread = NULL; - - // Check the input parm - // - if (argc == 2) - { - if (toupper(argv[1][0]) == 'B') - { - doBackup = TRUE; - badParm = FALSE; - } - else if (toupper(argv[1][0]) == 'R') - { - doBackup = FALSE; - badParm = FALSE; - } - } - - if (badParm) - { - printf ("useage: osimple {B|R}\n" - "Demonstrate a Backup or Restore using the Virtual Device Interface & ODBC\n"); - exit (1); - } - - printf ("Performing a %s using a virtual device.\n", - (doBackup) ? "BACKUP" : "RESTORE"); - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); - - if (!SUCCEEDED (hr)) - { - printf ("Coinit fails: x%X\n", hr); - exit (1); - } - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance ( - CLSID_MSSQL_ClientVirtualDeviceSet, - NULL, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (!SUCCEEDED (hr)) - { - // This failure might happen if the DLL was not registered, - // or if the application is using the wrong interface id (IID). - // - printf ("Could not create component: x%X\n", hr); - printf ("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset (&config, 0, sizeof(config)); - config.deviceCount = 1; + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + IClientVirtualDevice* vd = nullptr; + + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hThread = nullptr; + + // Check the input parm + // + if (argc == 2) + { + char param = toupper(argv[1][0]); + + if (param == 'B') + { + doBackup = true; + badParm = false; + } + else if (param == 'R') + { + doBackup = false; + badParm = false; + } + } + + if (badParm) + { + printf("usage: osimple {B|R}\n" + "Demonstrate a Backup or Restore using the Virtual Device Interface & ODBC\n"); + exit(1); + } + + printf("Performing a %s using a virtual device.\n", + (doBackup) ? "BACKUP" : "RESTORE"); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = 1; // Create a GUID to use for a unique virtual device name // GUID vdsId; - CoCreateGuid (&vdsId); - StringFromGUID2 (vdsId, wVdsName, 49); - - // Create the virtual device set - // - hr = vds->CreateEx (NULL, wVdsName, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, by starting a thread to handle the ODBC - // + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting a thread to handle the ODBC + // printf("\nSending the SQL...\n"); - hThread = execSQL (doBackup); - if (hThread == NULL) - { - printf ("execSQL failed.\n"); - goto shutdown; - } - - // Wait for the server to connect, completing the configuration. - // - printf ("\nWaiting for SQLServer to respond...\n"); - - while (!SUCCEEDED (hr=vds->GetConfiguration (1000, &config))) - { - if (hr == VD_E_TIMEOUT) - { + hThread = execSQL(doBackup); + if (hThread == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + printf("\nWaiting for SQLServer to respond...\n"); + + while (FAILED(hr = vds->GetConfiguration(1000, &config))) + { + if (hr == VD_E_TIMEOUT) + { // Check on the SQL thread // - DWORD rc = WaitForSingleObject (hThread, 1000); + DWORD rc = WaitForSingleObject(hThread, 1000); if (rc == WAIT_OBJECT_0) { - printf ("SQL command failed before VD transfer\n"); + printf("SQL command failed before VD transfer\n"); goto shutdown; } if (rc == WAIT_TIMEOUT) { continue; } - printf ("Check on SQL failed: %d\n", rc); + printf("Check on SQL failed: %d\n", rc); goto shutdown; } - - printf ("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Open the single device in the set. - // - hr = vds->OpenDevice (wVdsName, &vd); - if (!SUCCEEDED(hr)) - { - printf ("VDS::OpenDevice fails: x%X\n", hr); - goto shutdown; - } - - printf ("\nPerforming data transfer...\n"); - - performTransfer (vd, doBackup); - - + + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice(wVdsName, &vd); + if (FAILED(hr)) + { + printf("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf("\nPerforming data transfer...\n"); + + performTransfer(vd, doBackup); + + shutdown: - // Close the set - // - vds->Close (); + // Close the set + // + vds->Close(); - // Obtain the SQL completion information - // - if (hThread != NULL) + // Obtain the SQL completion information + // + if (hThread != nullptr) { - if (checkSQL (hThread)) + if (checkSQL(hThread)) printf("\nThe SQL command executed successfully.\n"); else printf("\nThe SQL command failed.\n"); - CloseHandle (hThread); + CloseHandle(hThread); } - // COM reference counting: Release the interface. - // - vds->Release () ; + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize () ; + // Uninitialize COM Library + // + CoUninitialize(); - return 0 ; + return 0; } //--------------------------------------------------------------------------- @@ -255,93 +261,93 @@ int main (int argc, char *argv[]) // operations like RESTORE which can sometimes recover from // errors (error messages will be followed by the 3014 success message). // -void ProcessMessages ( +void ProcessMessages( SQLSMALLINT handle_type, // ODBC handle type - SQLHANDLE handle, // ODBC handle - int ConnInd, // TRUE if sucessful connection made - int* pBackupSuccess) // Set TRUE if a 3014 message is seen. + SQLHANDLE handle, // ODBC handle + bool ConnInd, // TRUE if sucessful connection made + bool* pBackupSuccess) // Set TRUE if a 3014 message is seen. { - RETCODE plm_retcode = SQL_SUCCESS; - UCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; - UCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; - SDWORD plm_pfNativeError = 0L; - SWORD plm_pcbErrorMsg = 0; - SQLSMALLINT plm_cRecNmbr = 1; - SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; - SQLINTEGER plm_Rownumber = 0; - USHORT plm_SS_Line; - SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; - SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; - - while (plm_retcode != SQL_NO_DATA_FOUND) + RETCODE plm_retcode = SQL_SUCCESS; + SQLWCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; + SQLWCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; + SDWORD plm_pfNativeError = 0L; + SWORD plm_pcbErrorMsg = 0; + SQLSMALLINT plm_cRecNmbr = 1; + SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; + SQLBIGINT plm_Rownumber = 0; + USHORT plm_SS_Line; + SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; + SQLWCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; + + while (plm_retcode != SQL_NO_DATA_FOUND) { - plm_retcode = SQLGetDiagRec(handle_type, handle, - plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, - plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); - - // Note that if the application has not yet made a - // successful connection, the SQLGetDiagField - // information has not yet been cached by ODBC - // Driver Manager and these calls to SQLGetDiagField - // will fail. - // - if (plm_retcode != SQL_NO_DATA_FOUND) + plm_retcode = SQLGetDiagRec(handle_type, handle, + plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, + plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); + + // Note that if the application has not yet made a + // successful connection, the SQLGetDiagField + // information has not yet been cached by ODBC + // Driver Manager and these calls to SQLGetDiagField + // will fail. + // + if (plm_retcode != SQL_NO_DATA_FOUND) { - if (ConnInd) + if (ConnInd) { - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_ROW_NUMBER, &plm_Rownumber, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_LINE, &plm_SS_Line, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, - sizeof(plm_SS_Procname), - &plm_cbSS_Procname); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, - sizeof(plm_SS_Srvname), - &plm_cbSS_Srvname); - - printf ("Msg %d, SevLevel %d, State %d, SQLState %s\n", - plm_pfNativeError, - plm_SS_Severity, - plm_SS_MsgState, - plm_szSqlState); - } - - printf ("%s\n", plm_szErrorMsg); - - if (pBackupSuccess && plm_pfNativeError == 3014) - { - *pBackupSuccess = TRUE; - } - } - - plm_cRecNmbr++; //Increment to next diagnostic record. - } // End while. + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_ROW_NUMBER, &plm_Rownumber, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_LINE, &plm_SS_Line, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, + sizeof(plm_SS_Procname), + &plm_cbSS_Procname); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, + sizeof(plm_SS_Srvname), + &plm_cbSS_Srvname); + + printf_s("Msg %d, SevLevel %d, State %d, SQLState %ls\n", + plm_pfNativeError, + plm_SS_Severity, + plm_SS_MsgState, + plm_szSqlState); + } + + printf_s("%ls\n", plm_szErrorMsg); + + if (pBackupSuccess && plm_pfNativeError == 3014) + { + *pBackupSuccess = TRUE; + } + } + + plm_cRecNmbr++; //Increment to next diagnostic record. + } // End while. } @@ -352,99 +358,103 @@ void ProcessMessages ( // Returns TRUE if a successful backup/restore is performed. // unsigned __stdcall -SQLRoutine (void *parms) +SQLRoutine(void* parms) { - int doBackup = (int)parms; - - char sqlCommand [1024]; // way more space than we'll need. - int successDetected = FALSE; + bool doBackup = (bool)parms; + + wchar_t sqlCommand[1024]; // way more space than we'll need. + bool successDetected = false; // ODBC handles // - SQLHENV henv = NULL; - SQLHDBC hdbc = NULL; - SQLHSTMT hstmt = NULL; + SQLHENV henv = nullptr; + SQLHDBC hdbc = nullptr; + SQLHSTMT hstmt = nullptr; - sprintf (sqlCommand, "%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", - (doBackup) ? "BACKUP" : "RESTORE", - (doBackup) ? "TO" : "FROM", + swprintf_s(sqlCommand, L"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", wVdsName); - int sentSQL = FALSE; - int rc; - - #define MAX_CONN_OUT 1024 - SQLCHAR szOutConn[MAX_CONN_OUT]; - SQLSMALLINT cbOutConn; - - // Initialize the ODBC environment. - // - if (SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) - goto exit; - - // This is an ODBC v3 application - // - SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, SQL_IS_INTEGER); - - // Allocate a connection handle - // - if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) - { - printf ("AllocHandle on DBC failed."); - goto exit; - } - - // Connect to the server using Trusted connection. - // Trusted connection uses integrated NT security. - // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. - rc = SQLDriverConnect( - hdbc, - NULL, // no diaglogs please - (SQLCHAR*) "DRIVER={SQL Server};Trusted_Connection=yes;SERVER=(local)", - SQL_NTS, - szOutConn, - MAX_CONN_OUT, - &cbOutConn, - SQL_DRIVER_NOPROMPT); - - if (rc == SQL_ERROR) - { - SQLCHAR szSqlState[20]; - SQLINTEGER ssErr; - SQLCHAR szErrorMsg [MAX_CONN_OUT]; - SQLSMALLINT cbErrorMsg; - - printf ("Connect fails\n"); - - rc = SQLError ( - henv, hdbc, SQL_NULL_HSTMT, - szSqlState, - &ssErr, - szErrorMsg, - MAX_CONN_OUT, - &cbErrorMsg); - - printf ("msg=%s\n", szErrorMsg); - - goto exit; - } - - // Get a statement handle - // - if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) - { - printf ("Failed to get statement handle\n"); - - ProcessMessages (SQL_HANDLE_DBC, hdbc, TRUE, NULL); - goto exit; - } - - // Execute the SQL - // - printf ("Executing %s\n", sqlCommand); - - rc = SQLExecDirect (hstmt, (SQLCHAR*)sqlCommand, SQL_NTS); + bool sentSQL = false; + int rc; + + #define MAX_CONN_OUT 1024 + SQLWCHAR szOutConn[MAX_CONN_OUT]; + SQLSMALLINT cbOutConn; + + // Initialize the ODBC environment. + // + if (SQLAllocHandle(SQL_HANDLE_ENV, nullptr, &henv) == SQL_ERROR) + goto exit; + + // This is an ODBC v3 application + // + SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER); + + // Allocate a connection handle + // + if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) + { + printf("AllocHandle on DBC failed."); + goto exit; + } + + // Connect to the server using Trusted connection. + // Trusted connection uses integrated NT security. + // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. + // + // To use a named instance, change "SERVER=." to "SERVER=.\\instance_name" + // + + rc = SQLDriverConnectW( + hdbc, + nullptr, // no diaglogs please + const_cast(L"DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."), + SQL_NTS, + szOutConn, + MAX_CONN_OUT, + &cbOutConn, + SQL_DRIVER_NOPROMPT); + + if (rc == SQL_ERROR) + { + SQLWCHAR szSqlState[20]; + SQLINTEGER ssErr; + SQLWCHAR szErrorMsg[MAX_CONN_OUT]; + SQLSMALLINT cbErrorMsg; + + printf("Connect fails\n"); + + rc = SQLError( + henv, hdbc, SQL_NULL_HSTMT, + szSqlState, + &ssErr, + szErrorMsg, + MAX_CONN_OUT, + &cbErrorMsg); + + printf("msg=%ls\n", szErrorMsg); + + goto exit; + } + + // Get a statement handle + // + if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) + { + printf("Failed to get statement handle\n"); + + ProcessMessages(SQL_HANDLE_DBC, hdbc, true, nullptr); + goto exit; + } + + // Execute the SQL + // + printf_s("Executing %ls\n", sqlCommand); + + rc = SQLExecDirectW(hstmt, const_cast(sqlCommand), SQL_NTS); // Extract all the resulting messages // @@ -454,72 +464,72 @@ SQLRoutine (void *parms) { switch (rc) { - case SQL_ERROR: - successDetected = FALSE; - ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, &successDetected); - if (!successDetected) - { - printf ("Errors resulted in failure of the command\n"); - goto exit; - } - printf ("Errors were encountered but the command was able to recover and successfully complete.\n"); - break; - - case SQL_SUCCESS_WITH_INFO: - ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, NULL); - // fall through - - case SQL_SUCCESS: - successDetected = TRUE; - - numResultCols = 0; - SQLNumResultCols (hstmt, &numResultCols); - if (numResultCols > 0) - { - printf ("A result set with %d columns was produced\n", - (int)numResultCols); - } - break; - - case SQL_NO_DATA: - // All results have been processed. We are done. - // + case SQL_ERROR: + successDetected = false; + ProcessMessages(SQL_HANDLE_STMT, hstmt, true, &successDetected); + if (!successDetected) + { + printf("Errors resulted in failure of the command\n"); goto exit; + } + printf("Errors were encountered but the command was able to recover and successfully complete.\n"); + break; - case SQL_NEED_DATA: - case SQL_INVALID_HANDLE: - case SQL_STILL_EXECUTING: - default: - successDetected = FALSE; - printf ("Unexpected SQLExec result %d\n", rc); - goto exit; + case SQL_SUCCESS_WITH_INFO: + ProcessMessages(SQL_HANDLE_STMT, hstmt, true, nullptr); + // fall through + + case SQL_SUCCESS: + successDetected = true; + + numResultCols = 0; + SQLNumResultCols(hstmt, &numResultCols); + if (numResultCols > 0) + { + printf("A result set with %d columns was produced\n", + (int)numResultCols); + } + break; + + case SQL_NO_DATA: + // All results have been processed. We are done. + // + goto exit; + + case SQL_NEED_DATA: + case SQL_INVALID_HANDLE: + case SQL_STILL_EXECUTING: + default: + successDetected = false; + printf("Unexpected SQLExec result %d\n", rc); + goto exit; } - rc = SQLMoreResults (hstmt); + rc = SQLMoreResults(hstmt); } exit: // Release the ODBC resources. // - if (hstmt != NULL) - { - SQLFreeHandle(SQL_HANDLE_STMT, hstmt); - hstmt = NULL; - } - - if (hdbc != NULL) - { - SQLDisconnect(hdbc); - SQLFreeHandle(SQL_HANDLE_DBC, hdbc); - hdbc = NULL; - } - - if (henv != NULL) - { - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = NULL; - } - - return successDetected; + if (hstmt != nullptr) + { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = nullptr; + } + + if (hdbc != nullptr) + { + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = nullptr; + } + + if (henv != nullptr) + { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = nullptr; + } + + return successDetected; } @@ -529,16 +539,16 @@ SQLRoutine (void *parms) // // Return the thread handle (NULL on error). // -HANDLE execSQL (int doBackup) +HANDLE execSQL(bool doBackup) { unsigned int threadId; HANDLE hThread; - hThread = (HANDLE)_beginthreadex ( - NULL, 0, SQLRoutine, (void*)doBackup, 0, &threadId); - if (hThread == NULL) + hThread = (HANDLE)_beginthreadex( + nullptr, 0, SQLRoutine, (void*)doBackup, 0, &threadId); + if (hThread == nullptr) { - printf ("Failed to create thread. errno is %d\n", errno); + printf("Failed to create thread. errno is %d\n", errno); } return hThread; } @@ -548,23 +558,23 @@ HANDLE execSQL (int doBackup) // checkSQL: Wait for the T-SQL to complete, // returns TRUE if statement successfully executed. // -int checkSQL (HANDLE hThread) +bool checkSQL(HANDLE hThread) { - if (hThread == NULL) - return FALSE; + if (hThread == nullptr) + return false; - DWORD rc = WaitForSingleObject (hThread, INFINITE); + DWORD rc = WaitForSingleObject(hThread, INFINITE); if (rc != WAIT_OBJECT_0) { - printf ("checkSQL failed: %d\n", rc); - return FALSE; + printf("checkSQL failed: %d\n", rc); + return false; } - if (!GetExitCodeThread (hThread, &rc)) + if (!GetExitCodeThread(hThread, &rc)) { - printf ("failed to get exit code: %d\n", GetLastError ()); - return FALSE; + printf("failed to get exit code: %d\n", GetLastError()); + return false; } - return rc == TRUE; + return rc == true; } @@ -576,84 +586,84 @@ int checkSQL (HANDLE hThread) // This routine reads commands from the server until a 'Close' status is received. // It simply reads or writes a file 'superbak.dmp' in the current directory. // -void performTransfer ( - IClientVirtualDevice* vd, - int backup ) +void performTransfer( + IClientVirtualDevice* vd, + int backup) { - FILE * fh; - char* fname = "superbak.dmp"; - VDC_Command * cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - - fh = fopen (fname, (backup)? "wb" : "rb"); - if (fh == NULL ) - { - printf ("Failed to open: %s\n", fname); - return; - } - - while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) + FILE* fh; + char* fname = (char*)"superbak.dmp"; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - break; - - case VDC_Write: - bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size ) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush (fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); - if (!SUCCEEDED (hr)) - { - printf ("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf ("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf ("Successfully completed data transfer.\n"); - } - - fclose (fh); + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + } + + fclose(fh); } diff --git a/samples/features/sqlvdi/osimple/osimple.dsp b/samples/features/sqlvdi/osimple/osimple.dsp deleted file mode 100644 index 807944019b..0000000000 --- a/samples/features/sqlvdi/osimple/osimple.dsp +++ /dev/null @@ -1,100 +0,0 @@ -# Microsoft Developer Studio Project File - Name="osimple" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=osimple - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "osimple.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "osimple.mak" CFG="osimple - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "osimple - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "osimple - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "osimple - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "osimple - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "osimple - Win32 Release" -# Name "osimple - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\osimple.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/samples/features/sqlvdi/osimple/osimple.dsw b/samples/features/sqlvdi/osimple/osimple.dsw deleted file mode 100644 index 52cd0ba33d..0000000000 --- a/samples/features/sqlvdi/osimple/osimple.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "osimple"=.\osimple.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/samples/features/sqlvdi/osimple/osimple.vcxproj b/samples/features/sqlvdi/osimple/osimple.vcxproj new file mode 100644 index 0000000000..aae1e09a9a --- /dev/null +++ b/samples/features/sqlvdi/osimple/osimple.vcxproj @@ -0,0 +1,142 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {a0d4d328-678f-46d3-8af1-3530d8c55507} + osimple + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + false + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\include + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/osimple/osimple.vcxproj.filters b/samples/features/sqlvdi/osimple/osimple.vcxproj.filters new file mode 100644 index 0000000000..ca1fc0599c --- /dev/null +++ b/samples/features/sqlvdi/osimple/osimple.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/simple/simple.cpp b/samples/features/sqlvdi/simple/simple.cpp index 60e1bff428..e9aa57f6fa 100644 --- a/samples/features/sqlvdi/simple/simple.cpp +++ b/samples/features/sqlvdi/simple/simple.cpp @@ -37,193 +37,193 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the interface identifiers. - // IMPORTANT: vdiguid.h can only be included in one source file. - // + // IMPORTANT: vdiguid.h can only be included in one source file. + // +void performTransfer( + IClientVirtualDevice* vd, + bool backup); -void performTransfer ( - IClientVirtualDevice* vd, - int backup ); - -int execSQL (int doBackup); +int execSQL(bool doBackup); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName [50]; +WCHAR wVdsName[50]; // // main function // -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = NULL ; - IClientVirtualDevice* vd=NULL; - - VDConfig config; - int badParm=TRUE; - int doBackup; - int hProcess; - int termCode; - - // Check the input parm - // - if (argc == 2) - { - if (toupper(argv[1][0]) == 'B') - { - doBackup = TRUE; - badParm = FALSE; - } - else if (toupper(argv[1][0]) == 'R') - { - doBackup = FALSE; - badParm = FALSE; - } - } - - if (badParm) - { - printf ("useage: simple {B|R}\n" - "Demonstrate a Backup or Restore using the Virtual Device Interface\n"); - exit (1); - } - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); - - if (!SUCCEEDED (hr)) - { - printf ("Coinit fails: x%X\n", hr); - exit (1); - } - - // Get an interface to the device set. - // Changes from SQLServer v7.0: - // - we've introduced a symbol for the class ID. - // - We've added a new "multi-instance-aware" interface. - // - hr = CoCreateInstance ( - CLSID_MSSQL_ClientVirtualDeviceSet, - NULL, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (!SUCCEEDED (hr)) - { - // This failure might happen if the DLL was not registered, - // or if the application is using the wrong interface id (IID). - // - printf ("Could not create component: x%X\n", hr); - printf ("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset (&config, 0, sizeof(config)); - config.deviceCount = 1; + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + IClientVirtualDevice* vd = nullptr; + + VDConfig config; + bool badParm = true; + bool doBackup; + bool isUnnamed = false; + int hProcess; + int termCode; + + // Check the input parm + // + if (argc == 2) + { + char param = toupper(argv[1][0]); + + if (param == 'B') + { + doBackup = true; + badParm = false; + } + else if (param == 'R') + { + doBackup = false; + badParm = false; + } + } + + if (badParm) + { + printf("usage: simple {B|R}\n" + "Demonstrate a Backup or Restore using the Virtual Device Interface\n"); + exit(1); + } + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + // Get an interface to the device set. + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = 1; // Create a GUID to use for a unique virtual device name // GUID vdsId; - CoCreateGuid (&vdsId); - StringFromGUID2 (vdsId, wVdsName, 49); + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); - // Create the virtual device set + // Create the virtual device set // for use by the default instance. - // Change the first parameter to identify a named instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting 'isql' in a subprocess. // - hr = vds->CreateEx (NULL, wVdsName, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, by starting 'isql' in a subprocess. - // - printf("\nSending the SQL...\n"); - - hProcess = execSQL (doBackup); - if (hProcess == -1) - { - printf ("execSQL failed.\n"); - goto shutdown; - } - - // Wait for the server to connect, completing the configuration. - // - hr = vds->GetConfiguration (10000, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Getconfig fails: x%X\n", hr); - if (hr == VD_E_TIMEOUT) - { - printf ("Timed out. Was Microsoft SQLServer running?\n"); - } - goto shutdown; - } - - // Open the single device in the set. - // - hr = vds->OpenDevice (wVdsName, &vd); - if (!SUCCEEDED(hr)) - { - printf ("VDS::OpenDevice fails: x%X\n", hr); - goto shutdown; - } - - printf ("\nPerforming data transfer...\n"); - - performTransfer (vd, doBackup); - - + printf("\nSending the SQL...\n"); + + hProcess = execSQL(doBackup); + if (hProcess == -1) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + hr = vds->GetConfiguration(10000, &config); + if (FAILED(hr)) + { + printf("VDS::Getconfig fails: x%X\n", hr); + if (hr == VD_E_TIMEOUT) + { + printf("Timed out. Was Microsoft SQLServer running?\n"); + } + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice(wVdsName, &vd); + if (FAILED(hr)) + { + printf("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf("\nPerforming data transfer...\n"); + + performTransfer(vd, doBackup); + + shutdown: - // Close the set - // - vds->Close (); - - // Obtain the SQL completion information, by waiting for isql to exit. - // - if (hProcess == _cwait( &termCode, hProcess, NULL)) - { - if (termCode == 0) - printf("\nThe SQL command executed successfully.\n"); - else - printf("\nThe SQL command failed.\n"); - } - else - { - printf ("cwait failed: %d\n", errno); - } - - // COM reference counting: Release the interface. - // - // Rather than releasing it, the application has the - // option to 'Create' another set, reusing the interface - // that it currently has. Of course that applies to - // a real application, not this simple sample! - // - vds->Release () ; + // Close the set + // + vds->Close(); + + // Obtain the SQL completion information, by waiting for isql to exit. + // + if (hProcess == _cwait(&termCode, hProcess, 0)) + { + if (termCode == 0) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); + } + else + { + printf("cwait failed: %d\n", errno); + } + + // COM reference counting: Release the interface. + // + // Rather than releasing it, the application has the + // option to 'Create' another set, reusing the interface + // that it currently has. Of course that applies to + // a real application, not this simple sample! + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize () ; + // Uninitialize COM Library + // + CoUninitialize(); - return 0 ; + return 0; } // @@ -233,116 +233,115 @@ int main(int argc, char *argv[]) // -1 : failed to spawn // else : a "process handle" // -int execSQL (int doBackup) +int execSQL(bool doBackup) { - char sqlCommand [1024]; // plenty of space for our purpose + wchar_t sqlCommand[1024]; // plenty of space for our purpose - sprintf (sqlCommand, "-Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'\"", - (doBackup) ? "BACKUP" : "RESTORE", - (doBackup) ? "TO" : "FROM", + // To use a named instance, change "-S ." to "-S .\\instance_name" + swprintf_s(sqlCommand, L"-S . -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'\"", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", wVdsName); - int rc; + intptr_t rc; - printf ("spawning osql to execute: %s\n", sqlCommand); + wprintf(L"spawning osql to execute: %ls\n", sqlCommand); - // Spawn off the osql utility to execute the SQL. - // Notice the '-b' which causes an error to set a non-zero - // exit code on error. + // Spawn off the osql utility to execute the SQL. + // Notice the '-b' which causes an error to set a non-zero + // exit code on error. // - rc = _spawnlp( _P_NOWAIT, "osql", "osql", "-E", "-b", - sqlCommand, NULL); - - if (rc == -1) - { - printf ("Spawn failed with error: %d\n", errno); - } - - return (rc); + rc = _wspawnlp(_P_NOWAIT, L"osql", L"osql", L"-E", L"-b", + sqlCommand, NULL); + + if (rc == -1) + { + printf("Spawn failed with error: %d\n", errno); + } + + return (rc); } // This routine reads commands from the server until a 'Close' status is received. // It simply reads or writes a file 'superbak.dmp' in the current directory. // -void performTransfer ( - IClientVirtualDevice* vd, - int backup ) +void performTransfer( + IClientVirtualDevice* vd, + bool backup) { - FILE * fh; - char* fname = "superbak.dmp"; - VDC_Command * cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - - fh = fopen (fname, (backup)? "wb" : "rb"); - if (fh == NULL ) - { - printf ("Failed to open: %s\n", fname); - return; - } - - while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - break; - - case VDC_Write: - bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size ) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush (fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); - if (!SUCCEEDED (hr)) - { - printf ("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf ("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf ("Successfully completed data transfer.\n"); - } - - fclose (fh); -} - - + FILE* fh; + char* fname = (char*)"superbak.dmp"; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + } + + fclose(fh); +} \ No newline at end of file diff --git a/samples/features/sqlvdi/simple/simple.dsp b/samples/features/sqlvdi/simple/simple.dsp deleted file mode 100644 index d759c37838..0000000000 --- a/samples/features/sqlvdi/simple/simple.dsp +++ /dev/null @@ -1,100 +0,0 @@ -# Microsoft Developer Studio Project File - Name="simple" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=simple - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "simple.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "simple.mak" CFG="simple - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "simple - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "simple - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "simple - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "simple - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "simple - Win32 Release" -# Name "simple - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\simple.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/samples/features/sqlvdi/simple/simple.dsw b/samples/features/sqlvdi/simple/simple.dsw deleted file mode 100644 index f38a9abfd8..0000000000 --- a/samples/features/sqlvdi/simple/simple.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "simple"=.\simple.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/samples/features/sqlvdi/simple/simple.vcxproj b/samples/features/sqlvdi/simple/simple.vcxproj new file mode 100644 index 0000000000..65fd7f65ce --- /dev/null +++ b/samples/features/sqlvdi/simple/simple.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {13df2fa4-99d2-44ac-b218-3463730b6f08} + simple + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions); + true + ..\include + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/simple/simple.vcxproj.filters b/samples/features/sqlvdi/simple/simple.vcxproj.filters new file mode 100644 index 0000000000..3a45a4311d --- /dev/null +++ b/samples/features/sqlvdi/simple/simple.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/snapshot/snapshot.cpp b/samples/features/sqlvdi/snapshot/snapshot.cpp index be8cf26295..62d761199f 100644 --- a/samples/features/sqlvdi/snapshot/snapshot.cpp +++ b/samples/features/sqlvdi/snapshot/snapshot.cpp @@ -46,57 +46,60 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the interface identifiers. - // IMPORTANT: vdiguid.h can only be included in one source file. - // + // IMPORTANT: vdiguid.h can only be included in one source file. + // #include #include "sql.h" #include "sqlext.h" #include "odbcss.h" -void performTransfer ( - IClientVirtualDeviceSet2* vds, - IClientVirtualDevice* vd, - int backup ); +void performTransfer( + IClientVirtualDeviceSet2* vds, + IClientVirtualDevice* vd, + int backup); -HANDLE execSQL (int doBackup, char* pInstanceName, char* pDbName, WCHAR* pVdsName); -int checkSQL (HANDLE); +HANDLE execSQL(bool doBackup, WCHAR* pInstanceName, WCHAR* pDbName, WCHAR* pVdsName); +bool checkSQL(HANDLE); -BOOL -ynPrompt (char *str); +bool ynPrompt(const char* str); //------------------------------------------------------------ // // Mainline // int __cdecl -main (int argc, char *argv[]) +main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = NULL ; - IClientVirtualDevice* vd=NULL; - - VDConfig config; - int badParm=TRUE; - int doBackup; - HANDLE hThread = NULL; - char* pDbName = NULL; - char* pInstanceName = NULL; - - // Check the input parm - // - if (argc >= 3) - { - if (toupper(argv[1][0]) == 'B') - { - doBackup = TRUE; - badParm = FALSE; - } - else if (toupper(argv[1][0]) == 'R') - { - doBackup = FALSE; - badParm = FALSE; - } + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + IClientVirtualDevice* vd = nullptr; + + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hThread = nullptr; + char* pDbName = nullptr; + char* pInstanceName = nullptr; + WCHAR wInstanceName[128] = { 0 }; + int rc = 0; + + // Check the input parm + // + if (argc >= 3) + { + char param = toupper(argv[1][0]); + + if (param == 'B') + { + doBackup = true; + badParm = false; + } + else if (param == 'R') + { + doBackup = false; + badParm = false; + } pDbName = argv[2]; @@ -104,173 +107,177 @@ main (int argc, char *argv[]) { pInstanceName = argv[3]; } - } + } - if (badParm) - { - printf ("useage: snapshot {B|R} []\n" - "Demonstrate a Backup or Restore WITH SNAPSHOT\n"); - printf ("\n\n** NOTE **\n The ability to take or mount snapshots must be implemented\n" + if (badParm) + { + printf("usage: snapshot {B|R} []\n" + "Demonstrate a Backup or Restore WITH SNAPSHOT\n"); + printf("\n\n** NOTE **\n The ability to take or mount snapshots must be implemented\n" "before this sample is truely functional.\n"); - exit (1); - } + exit(1); + } - printf ("Performing a %s of %s on %s using a VIRTUAL_DEVICE.\n", - (doBackup) ? "BACKUP" : "RESTORE", + printf("Performing a %s of %s on %s using a VIRTUAL_DEVICE.\n", + (doBackup) ? "BACKUP" : "RESTORE", pDbName, (pInstanceName) ? pInstanceName : "Default"); - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); - - if (!SUCCEEDED (hr)) - { - printf ("Coinit fails: x%X\n", hr); - exit (1); - } - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance ( - CLSID_MSSQL_ClientVirtualDeviceSet, - NULL, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (!SUCCEEDED (hr)) - { - // This failure might happen if the DLL was not registered, - // or if the application is using the wrong interface id (IID). - // - printf ("Could not create component: x%X\n", hr); - printf ("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset (&config, 0, sizeof(config)); - config.deviceCount = 1; + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = 1; config.features = VDF_SnapshotPrepare; // Create a GUID to use for a unique virtual device name // GUID vdsId; - WCHAR wVdsName [50]; - CoCreateGuid (&vdsId); - StringFromGUID2 (vdsId, wVdsName, 49); + WCHAR wVdsName[50]; + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); - // Create the virtual device set - // Notice that we only support unicode interfaces + // Create the virtual device set + // Notice that we only support unicode interfaces // - WCHAR wInstanceName [128]; - int rc = 0; + if (pInstanceName) { - rc = MultiByteToWideChar (CP_ACP, 0, - pInstanceName, strlen (pInstanceName), + rc = MultiByteToWideChar(CP_ACP, 0, + pInstanceName, strlen(pInstanceName), wInstanceName, 127); } - wInstanceName [rc] = 0; + wInstanceName[rc] = 0; - hr = vds->CreateEx (wInstanceName, wVdsName, &config); - if (!SUCCEEDED (hr)) - { - printf ("VDS::Create fails: x%X", hr); - goto exit; - } + hr = vds->CreateEx(wInstanceName, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } - // Send the SQL command, by starting a thread to handle the ODBC - // + // Send the SQL command, by starting a thread to handle the ODBC + // printf("\nSending the SQL...\n"); - hThread = execSQL (doBackup, pInstanceName, pDbName, wVdsName); - if (hThread == NULL) - { - printf ("execSQL failed.\n"); - goto shutdown; - } - - // Wait for the server to connect, completing the configuration. - // - printf ("\nWaiting for SQLServer to respond...\n"); - - while (!SUCCEEDED (hr=vds->GetConfiguration (1000, &config))) - { - if (hr == VD_E_TIMEOUT) - { + WCHAR wDbName[128]; + MultiByteToWideChar(CP_ACP, 0, + pDbName, -1, + wDbName, 127); + + hThread = execSQL(doBackup, wInstanceName, wDbName, wVdsName); + if (hThread == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + printf("\nWaiting for SQLServer to respond...\n"); + + while (FAILED(hr = vds->GetConfiguration(1000, &config))) + { + if (hr == VD_E_TIMEOUT) + { // Check on the SQL thread // - DWORD rc = WaitForSingleObject (hThread, 1000); + DWORD rc = WaitForSingleObject(hThread, 1000); if (rc == WAIT_OBJECT_0) { - printf ("SQL command failed before VD transfer\n"); + printf("SQL command failed before VD transfer\n"); goto shutdown; } if (rc == WAIT_TIMEOUT) { continue; } - printf ("Check on SQL failed: %d\n", rc); + printf("Check on SQL failed: %d\n", rc); goto shutdown; } - - printf ("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Open the single device in the set. - // - hr = vds->OpenDevice (wVdsName, &vd); - if (!SUCCEEDED(hr)) - { - printf ("VDS::OpenDevice fails: x%X\n", hr); - goto shutdown; - } - - printf ("\nPerforming data transfer...\n"); - - performTransfer (vds, vd, doBackup); - - + + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice(wVdsName, &vd); + if (FAILED(hr)) + { + printf("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf("\nPerforming data transfer...\n"); + + performTransfer(vds, vd, doBackup); + + shutdown: - // Close the set - // - vds->Close (); + // Close the set + // + vds->Close(); - // Obtain the SQL completion information - // - if (hThread != NULL) + // Obtain the SQL completion information + // + if (hThread != nullptr) { - if (checkSQL (hThread)) + if (checkSQL(hThread)) printf("\nThe SQL command executed successfully.\n"); else printf("\nThe SQL command failed.\n"); - CloseHandle (hThread); + CloseHandle(hThread); } - // COM reference counting: Release the interface. - // - vds->Release () ; + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize () ; + // Uninitialize COM Library + // + CoUninitialize(); - return 0 ; + return 0; } //--------------------------------------------------------------------------- @@ -282,93 +289,93 @@ main (int argc, char *argv[]) // operations like RESTORE which can sometimes recover from // errors (error messages will be followed by the 3014 success message). // -void ProcessMessages ( +void ProcessMessages( SQLSMALLINT handle_type, // ODBC handle type - SQLHANDLE handle, // ODBC handle - int ConnInd, // TRUE if sucessful connection made - int* pBackupSuccess) // Set TRUE if a 3014 message is seen. + SQLHANDLE handle, // ODBC handle + bool ConnInd, // TRUE if sucessful connection made + bool* pBackupSuccess) // Set TRUE if a 3014 message is seen. { - RETCODE plm_retcode = SQL_SUCCESS; - UCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; - UCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; - SDWORD plm_pfNativeError = 0L; - SWORD plm_pcbErrorMsg = 0; - SQLSMALLINT plm_cRecNmbr = 1; - SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; - SQLINTEGER plm_Rownumber = 0; - USHORT plm_SS_Line; - SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; - SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; - - while (plm_retcode != SQL_NO_DATA_FOUND) + RETCODE plm_retcode = SQL_SUCCESS; + SQLWCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; + SQLWCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; + SDWORD plm_pfNativeError = 0L; + SWORD plm_pcbErrorMsg = 0; + SQLSMALLINT plm_cRecNmbr = 1; + SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; + SQLBIGINT plm_Rownumber = 0; + USHORT plm_SS_Line; + SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; + SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; + + while (plm_retcode != SQL_NO_DATA_FOUND) { - plm_retcode = SQLGetDiagRec(handle_type, handle, - plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, - plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); - - // Note that if the application has not yet made a - // successful connection, the SQLGetDiagField - // information has not yet been cached by ODBC - // Driver Manager and these calls to SQLGetDiagField - // will fail. - // - if (plm_retcode != SQL_NO_DATA_FOUND) + plm_retcode = SQLGetDiagRec(handle_type, handle, + plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, + plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); + + // Note that if the application has not yet made a + // successful connection, the SQLGetDiagField + // information has not yet been cached by ODBC + // Driver Manager and these calls to SQLGetDiagField + // will fail. + // + if (plm_retcode != SQL_NO_DATA_FOUND) { - if (ConnInd) + if (ConnInd) + { + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_ROW_NUMBER, &plm_Rownumber, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_LINE, &plm_SS_Line, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, + sizeof(plm_SS_Procname), + &plm_cbSS_Procname); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, + sizeof(plm_SS_Srvname), + &plm_cbSS_Srvname); + + printf_s("Msg %ld, SevLevel %ld, State %ld, SQLState %ls\n", + plm_pfNativeError, + plm_SS_Severity, + plm_SS_MsgState, + plm_szSqlState); + } + + printf("%ls\n", plm_szErrorMsg); + + if (pBackupSuccess && plm_pfNativeError == 3014) { - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_ROW_NUMBER, &plm_Rownumber, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_LINE, &plm_SS_Line, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, - sizeof(plm_SS_Procname), - &plm_cbSS_Procname); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, - sizeof(plm_SS_Srvname), - &plm_cbSS_Srvname); - - printf ("Msg %d, SevLevel %d, State %d, SQLState %s\n", - plm_pfNativeError, - plm_SS_Severity, - plm_SS_MsgState, - plm_szSqlState); - } - - printf ("%s\n", plm_szErrorMsg); - - if (pBackupSuccess && plm_pfNativeError == 3014) - { - *pBackupSuccess = TRUE; - } - } - - plm_cRecNmbr++; //Increment to next diagnostic record. - } // End while. + *pBackupSuccess = TRUE; + } + } + + plm_cRecNmbr++; //Increment to next diagnostic record. + } // End while. } @@ -380,133 +387,122 @@ void ProcessMessages ( // struct PARMS { - int doBackup; - char* pInstanceName; - char* pDbName; + bool doBackup; + WCHAR* pInstanceName; + WCHAR* pDbName; WCHAR* pVdsName; }; unsigned __stdcall -SQLRoutine (void* input) +SQLRoutine(void* input) { - PARMS* parms = (PARMS*)input; + PARMS* parms = (PARMS*)input; - SQLCHAR* pSQLText; // the command being executed. - int successDetected = FALSE; + SQLWCHAR* pSQLText; // the command being executed. + bool successDetected = false; // ODBC handles // - SQLHENV henv = NULL; - SQLHDBC hdbc = NULL; - SQLHSTMT hstmt = NULL; + SQLHENV henv = nullptr; + SQLHDBC hdbc = nullptr; + SQLHSTMT hstmt = nullptr; - char sqlCommand [1024]; + WCHAR sqlCommand[1024]; + SQLWCHAR connectString[200] = { 0 }; - int sentSQL = FALSE; - int rc; + bool sentSQL = false; + int rc; - #define MAX_CONN_OUT 1024 - SQLCHAR szOutConn[MAX_CONN_OUT]; - SQLSMALLINT cbOutConn; - - // Convert the VDSNAME for use by the non-unicode interfaces we're using here. - // - char aVdsName [50]; - int aSize; - aSize = WideCharToMultiByte ( - CP_ACP, 0, - parms->pVdsName, - -1, // null terminated, so calculate - aVdsName, 49, - NULL, NULL ); // don't worry about fancy conversions + #define MAX_CONN_OUT 1024 + SQLWCHAR szOutConn[MAX_CONN_OUT] = { 0 }; + SQLSMALLINT cbOutConn; // Generate the command to execute // - sprintf (sqlCommand, "%s DATABASE [%s] %s VIRTUAL_DEVICE='%s' WITH SNAPSHOT", - parms->doBackup ? "BACKUP" : "RESTORE", + swprintf_s(sqlCommand, L"%ls DATABASE [%ls] %ls VIRTUAL_DEVICE='%ls' WITH SNAPSHOT", + parms->doBackup ? L"BACKUP" : L"RESTORE", parms->pDbName, - parms->doBackup ? "TO" : "FROM", - aVdsName); - - // Initialize the ODBC environment. - // - if (SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) - goto exit; - - // This is an ODBC v3 application - // - SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, SQL_IS_INTEGER); - - // Allocate a connection handle - // - if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) - { - printf ("AllocHandle on DBC failed."); - goto exit; - } - - char connectString [200]; - strcpy (connectString, "DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."); + parms->doBackup ? L"TO" : L"FROM", + parms->pVdsName); + + // Initialize the ODBC environment. + // + if (SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) + goto exit; + + // This is an ODBC v3 application + // + SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER); + + // Allocate a connection handle + // + if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) + { + printf("AllocHandle on DBC failed."); + goto exit; + } + + wcscpy_s(connectString, 200, L"DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."); if (parms->pInstanceName) { - sprintf (connectString+strlen(connectString), "\\%s", parms->pInstanceName); + swprintf_s(connectString + wcslen(connectString), 200 - wcslen(connectString), L"\\%ls", parms->pInstanceName); } - printf ("\n\nConnecting with: %s\n", connectString); + printf("\n\nConnecting with: %ls\n", connectString); - // Connect to the server using Trusted connection. - // Trusted connection uses integrated NT security. + // Connect to the server using Trusted connection. + // Trusted connection uses integrated NT security. // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. - rc = SQLDriverConnect( - hdbc, - NULL, // no diaglogs please - (SQLCHAR*) connectString, - SQL_NTS, - szOutConn, - MAX_CONN_OUT, - &cbOutConn, - SQL_DRIVER_NOPROMPT); - - if (rc == SQL_ERROR) - { - SQLCHAR szSqlState[20]; - SQLINTEGER ssErr; - SQLCHAR szErrorMsg [MAX_CONN_OUT]; - SQLSMALLINT cbErrorMsg; - - printf ("Connect fails\n"); - - rc = SQLError ( - henv, hdbc, SQL_NULL_HSTMT, - szSqlState, - &ssErr, - szErrorMsg, - MAX_CONN_OUT, - &cbErrorMsg); - - printf ("msg=%s\n", szErrorMsg); - - goto exit; - } - - // Get a statement handle - // - if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) - { - printf ("Failed to get statement handle\n"); - - ProcessMessages (SQL_HANDLE_DBC, hdbc, TRUE, NULL); - goto exit; - } - - // Execute the SQL - // - printf ("\n\nExecuting SQL: %s\n", sqlCommand); - - pSQLText = (SQLCHAR*)sqlCommand; - - rc = SQLExecDirect (hstmt, pSQLText, SQL_NTS); + rc = SQLDriverConnect( + hdbc, + nullptr, // no diaglogs please + connectString, + SQL_NTS, + szOutConn, + MAX_CONN_OUT, + &cbOutConn, + SQL_DRIVER_NOPROMPT); + + if (rc == SQL_ERROR) + { + SQLWCHAR szSqlState[20]; + SQLINTEGER ssErr; + SQLWCHAR szErrorMsg[MAX_CONN_OUT]; + SQLSMALLINT cbErrorMsg; + + printf("Connect fails\n"); + + rc = SQLError( + henv, hdbc, SQL_NULL_HSTMT, + szSqlState, + &ssErr, + szErrorMsg, + MAX_CONN_OUT, + &cbErrorMsg); + + printf("msg=%ls\n", szErrorMsg); + + goto exit; + } + + // Get a statement handle + // + if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) + { + printf("Failed to get statement handle\n"); + + ProcessMessages(SQL_HANDLE_DBC, hdbc, true, nullptr); + goto exit; + } + + // Execute the SQL + // + printf("\n\nExecuting SQL: %ls\n", sqlCommand); + + pSQLText = sqlCommand; + + rc = SQLExecDirect(hstmt, pSQLText, SQL_NTS); // Extract all the resulting messages // @@ -516,72 +512,72 @@ SQLRoutine (void* input) { switch (rc) { - case SQL_ERROR: - successDetected = FALSE; - ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, &successDetected); - if (!successDetected) - { - printf ("Errors resulted in failure of the command\n"); - goto exit; - } - printf ("Errors were encountered but the command was able to recover and successfully complete.\n"); - break; - - case SQL_SUCCESS_WITH_INFO: - ProcessMessages (SQL_HANDLE_STMT, hstmt, TRUE, NULL); - // fall through + case SQL_ERROR: + successDetected = false; + ProcessMessages(SQL_HANDLE_STMT, hstmt, true, &successDetected); + if (!successDetected) + { + printf("Errors resulted in failure of the command\n"); + goto exit; + } + printf("Errors were encountered but the command was able to recover and successfully complete.\n"); + break; - case SQL_SUCCESS: - successDetected = TRUE; + case SQL_SUCCESS_WITH_INFO: + ProcessMessages(SQL_HANDLE_STMT, hstmt, TRUE, NULL); + // fall through - numResultCols = 0; - SQLNumResultCols (hstmt, &numResultCols); - if (numResultCols > 0) - { - printf ("A result set with %d columns was produced\n", - (int)numResultCols); - } - break; + case SQL_SUCCESS: + successDetected = true; - case SQL_NO_DATA: - // All results have been processed. We are done. - // - goto exit; + numResultCols = 0; + SQLNumResultCols(hstmt, &numResultCols); + if (numResultCols > 0) + { + printf("A result set with %d columns was produced\n", + (int)numResultCols); + } + break; - case SQL_NEED_DATA: - case SQL_INVALID_HANDLE: - case SQL_STILL_EXECUTING: - default: - successDetected = FALSE; - printf ("Unexpected SQLExec result %d\n", rc); - goto exit; + case SQL_NO_DATA: + // All results have been processed. We are done. + // + goto exit; + + case SQL_NEED_DATA: + case SQL_INVALID_HANDLE: + case SQL_STILL_EXECUTING: + default: + successDetected = false; + printf("Unexpected SQLExec result %d\n", rc); + goto exit; } - rc = SQLMoreResults (hstmt); + rc = SQLMoreResults(hstmt); } exit: // Release the ODBC resources. // - if (hstmt != NULL) - { - SQLFreeHandle(SQL_HANDLE_STMT, hstmt); - hstmt = NULL; - } - - if (hdbc != NULL) - { - SQLDisconnect(hdbc); - SQLFreeHandle(SQL_HANDLE_DBC, hdbc); - hdbc = NULL; - } - - if (henv != NULL) - { - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = NULL; - } - - return successDetected; + if (hstmt != nullptr) + { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = nullptr; + } + + if (hdbc != nullptr) + { + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = nullptr; + } + + if (henv != nullptr) + { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = nullptr; + } + + return successDetected; } @@ -591,7 +587,7 @@ SQLRoutine (void* input) // // Return the thread handle (NULL on error). // -HANDLE execSQL (int doBackup, char* pInstanceName, char* pDbName, WCHAR* pVDName) +HANDLE execSQL(bool doBackup, WCHAR* pInstanceName, WCHAR* pDbName, WCHAR* pVDName) { unsigned int threadId; HANDLE hThread; @@ -602,11 +598,11 @@ HANDLE execSQL (int doBackup, char* pInstanceName, char* pDbName, WCHAR* pVDName parms.pInstanceName = pInstanceName; parms.pVdsName = pVDName; - hThread = (HANDLE)_beginthreadex ( - NULL, 0, SQLRoutine, (void*)&parms, 0, &threadId); - if (hThread == NULL) + hThread = (HANDLE)_beginthreadex( + nullptr, 0, SQLRoutine, (void*)&parms, 0, &threadId); + if (hThread == nullptr) { - printf ("Failed to create thread. errno is %d\n", errno); + printf("Failed to create thread. errno is %d\n", errno); } return hThread; } @@ -616,23 +612,23 @@ HANDLE execSQL (int doBackup, char* pInstanceName, char* pDbName, WCHAR* pVDName // checkSQL: Wait for the T-SQL to complete, // returns TRUE if statement successfully executed. // -int checkSQL (HANDLE hThread) +bool checkSQL(HANDLE hThread) { - if (hThread == NULL) - return FALSE; + if (hThread == nullptr) + return false; - DWORD rc = WaitForSingleObject (hThread, INFINITE); + DWORD rc = WaitForSingleObject(hThread, INFINITE); if (rc != WAIT_OBJECT_0) { - printf ("checkSQL failed: %d\n", rc); - return FALSE; + printf("checkSQL failed: %d\n", rc); + return false; } - if (!GetExitCodeThread (hThread, &rc)) + if (!GetExitCodeThread(hThread, &rc)) { - printf ("failed to get exit code: %d\n", GetLastError ()); - return FALSE; + printf("failed to get exit code: %d\n", GetLastError()); + return false; } - return rc == TRUE; + return rc == true; } @@ -640,16 +636,20 @@ int checkSQL (HANDLE hThread) // Ask the user a "yes/no" question. // Return TRUE if he answers "yes" // -BOOL -ynPrompt (char *str) +bool ynPrompt(const char* str) { - char line[256]; + char line[256]; + + printf("\n\n%s\n", str); + fgets(line, sizeof(line), stdin); - printf ("\n\n%s", str); - line [0] = 0; - gets (line); - printf ("\n\n"); - return (line [0] == 'y' || line [0] == 'Y'); + // Remove newline character if fgets reads in a newline. + size_t len = strlen(line); + if (len > 0 && line[len - 1] == '\n') { + line[len - 1] = '\0'; + } + + return (line[0] == 'y' || line[0] == 'Y'); } //---------------------------------------------------------------------------------- @@ -658,170 +658,170 @@ ynPrompt (char *str) // This routine reads commands from the server until a 'Close' status is received. // It simply reads or writes a file 'superbak.dmp' in the current directory. // -void performTransfer ( - IClientVirtualDeviceSet2* iVds, - IClientVirtualDevice* vd, - int backup ) +void performTransfer( + IClientVirtualDeviceSet2* iVds, + IClientVirtualDevice* vd, + int backup) { - FILE * fh; - char* fname = "snapshot.dmp"; - VDC_Command * cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - - fh = fopen (fname, (backup)? "wb" : "rb"); - if (fh == NULL ) - { - printf ("Failed to open: %s\n", fname); - return; - } - - while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - break; - - case VDC_Write: - bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size ) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush (fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - case VDC_PrepareToFreeze: - printf ("\n*** SQL Server is prepared to freeze the database now ***\n"); - printf ("At this point the application can perform any final coordination activities.\n"); - - while (!ynPrompt ("Are you ready to freeze the database?")) - { - if (ynPrompt ("Do you want to abort?")) - { - iVds->SignalAbort (); - return; - } - } - // Acknowledging this command results in a freeze of database writes. - // The server will then issue VDC_Write commands to record metadata - // about the frozen state. - // Then the VDC_Snapshot is issued. - // + FILE* fh; + char* fname = (char*)"snapshot.dmp"; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) completionCode = ERROR_SUCCESS; - break; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; - case VDC_Snapshot: - // At this point the metadata is complete, so the - // output stream can be closed. Thus it is possible - // to include the metadata with the data of the snapshot. - // - fclose (fh); - fh = NULL; + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; - printf ("\n*** Make the snapshot now ***\n"); + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; - while (!ynPrompt ("Did you complete the snapshot?")) + case VDC_PrepareToFreeze: + printf("\n*** SQL Server is prepared to freeze the database now ***\n"); + printf("At this point the application can perform any final coordination activities.\n"); + + while (!ynPrompt("Are you ready to freeze the database?")) + { + if (ynPrompt("Do you want to abort?")) { - if (ynPrompt ("Do you want to abort?")) - { - iVds->SignalAbort (); - return; - } + iVds->SignalAbort(); + return; } + } + // Acknowledging this command results in a freeze of database writes. + // The server will then issue VDC_Write commands to record metadata + // about the frozen state. + // Then the VDC_Snapshot is issued. + // + completionCode = ERROR_SUCCESS; + break; - // For clarity, we "unroll" the loop logic - // in the following block of code so you can - // easily see the sequence of operations. - // + case VDC_Snapshot: + // At this point the metadata is complete, so the + // output stream can be closed. Thus it is possible + // to include the metadata with the data of the snapshot. + // + fclose(fh); + fh = nullptr; - // Tell SQLServer that the snapshot is done. - // - completionCode = ERROR_SUCCESS; - hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); - if (!SUCCEEDED (hr)) + printf("\n*** Make the snapshot now ***\n"); + + while (!ynPrompt("Did you complete the snapshot?")) + { + if (ynPrompt("Do you want to abort?")) { - printf ("Completion Failed: x%X\n", hr); + iVds->SignalAbort(); return; } + } - // The only valid command will be a "close" request. - // - hr = vd->GetCommand (INFINITE, &cmd); - if (hr != VD_E_CLOSE) - { - printf ("Unexpected snapshot termination: x%X\n", hr); - } - else - { - printf ("SQLServer is aware that the snapshot is successful.\n"); - } + // For clarity, we "unroll" the loop logic + // in the following block of code so you can + // easily see the sequence of operations. + // + + // Tell SQLServer that the snapshot is done. + // + completionCode = ERROR_SUCCESS; + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); return; + } - case VDC_MountSnapshot: - printf ("\n*** Mount the snapshot now ***\n"); + // The only valid command will be a "close" request. + // + hr = vd->GetCommand(INFINITE, &cmd); + if (hr != VD_E_CLOSE) + { + printf("Unexpected snapshot termination: x%X\n", hr); + } + else + { + printf("SQLServer is aware that the snapshot is successful.\n"); + } + return; + + case VDC_MountSnapshot: + printf("\n*** Mount the snapshot now ***\n"); - while (!ynPrompt ("Did you complete the snapshot?")) + while (!ynPrompt("Did you complete the snapshot?")) + { + if (ynPrompt("Do you want to abort?")) { - if (ynPrompt ("Do you want to abort?")) - { - iVds->SignalAbort (); - return; - } + iVds->SignalAbort(); + return; } - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0); - if (!SUCCEEDED (hr)) - { - printf ("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf ("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf ("Successfully completed data transfer.\n"); - } - - if (fh != NULL) + } + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + } + + if (fh != nullptr) { - fclose (fh); + fclose(fh); } } diff --git a/samples/features/sqlvdi/snapshot/snapshot.dsp b/samples/features/sqlvdi/snapshot/snapshot.dsp deleted file mode 100644 index 55f9a285d6..0000000000 --- a/samples/features/sqlvdi/snapshot/snapshot.dsp +++ /dev/null @@ -1,100 +0,0 @@ -# Microsoft Developer Studio Project File - Name="snapshot" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=snapshot - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "snapshot.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "snapshot.mak" CFG="snapshot - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "snapshot - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "snapshot - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "snapshot - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "snapshot - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "snapshot - Win32 Release" -# Name "snapshot - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\snapshot.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/samples/features/sqlvdi/snapshot/snapshot.dsw b/samples/features/sqlvdi/snapshot/snapshot.dsw deleted file mode 100644 index 10da226d1d..0000000000 --- a/samples/features/sqlvdi/snapshot/snapshot.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "snapshot"=.\snapshot.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/samples/features/sqlvdi/snapshot/snapshot.vcxproj b/samples/features/sqlvdi/snapshot/snapshot.vcxproj new file mode 100644 index 0000000000..8865b53804 --- /dev/null +++ b/samples/features/sqlvdi/snapshot/snapshot.vcxproj @@ -0,0 +1,142 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {f51dacf4-9aba-4f84-a508-041d3c1f2399} + snapshot + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + false + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\include + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/features/sqlvdi/snapshot/snapshot.vcxproj.filters b/samples/features/sqlvdi/snapshot/snapshot.vcxproj.filters new file mode 100644 index 0000000000..1f3779567d --- /dev/null +++ b/samples/features/sqlvdi/snapshot/snapshot.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file From fa6bd5dbdde4d13fcb744edaf4b8cae9029d06e6 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Sat, 15 Jun 2024 20:05:07 -0700 Subject: [PATCH 049/159] Tested version --- .../activate-pcore-license.md | 87 ++++--------------- 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index 35ca9ccb83..ac230f79f4 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -1,82 +1,33 @@ -# -# This script performes a scheduled activation of a SQL Server p-core license. -# -# The script accepts the following command line parameters: -# -# -LicenseID (The specific resource URI) -# -UseInRunbook (True to use Azure Runbook) -# +<# + .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 15, 2024 +#> param ( [Parameter (Mandatory= $true)] [string] $LicenseId, - [Parameter (Mandatory= $true)] - [bool] $UseInRunbook ) -function CheckModule ($m) { - - # This function ensures that the specified module is imported into the session - # If module is already imported - do nothing - - if (!(Get-Module | Where-Object {$_.Name -eq $m})) { - # If module is not imported, but available on disk then import - if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { - Import-Module $m - } - else { - - # If module is not imported, not available on disk, but is in online gallery then install and import - if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { - Install-Module -Name $m -Force -Verbose -Scope CurrentUser - Import-Module $m - } - else { - - # If module is not imported, not available and not in online gallery then abort - write-host "Module $m not imported, not available and not in online gallery, exiting." - EXIT 1 - } - } - } -} - # # Suppress warnings # Update-AzConfig -DisplayBreakingChangeWarning $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 - } -}else{ - # Ensure that the required modules are imported - # In Runbooks these modules must be added to the automation account manually - - $requiredModules = @( - "Az.Accounts", - "Az.Resources" - ) - $requiredModules | Foreach-Object {CheckModule $_} +# Logging in to Azure..." +try +{ + Connect-AzAccount -Identity +} +catch { + Write-Error -Message $_.Exception + throw $_.Exception } $currentLicense = Get-AzResource -ResourceId $LicenseId From 1be0d7cfe8d9836960cfcec253a2c96f41b3a366 Mon Sep 17 00:00:00 2001 From: soradotwav Date: Mon, 17 Jun 2024 12:42:56 -0700 Subject: [PATCH 050/159] Swapped out tabs for spaces and fixed certain formatting --- samples/features/sqlvdi/mprocess/mprocess.cpp | 1060 ++++++------- samples/features/sqlvdi/mthread/mthread.cpp | 936 ++++++------ samples/features/sqlvdi/osimple/osimple.cpp | 1062 ++++++------- samples/features/sqlvdi/simple/simple.cpp | 534 +++---- samples/features/sqlvdi/snapshot/snapshot.cpp | 1352 ++++++++--------- 5 files changed, 2472 insertions(+), 2472 deletions(-) diff --git a/samples/features/sqlvdi/mprocess/mprocess.cpp b/samples/features/sqlvdi/mprocess/mprocess.cpp index 1b311aa597..a4c6ae22b4 100644 --- a/samples/features/sqlvdi/mprocess/mprocess.cpp +++ b/samples/features/sqlvdi/mprocess/mprocess.cpp @@ -45,219 +45,219 @@ All Rights Reserved. #include "vdiguid.h" // define the GUIDs void LogError( - const char* location, // must always be provided - const char* description, // NULL is acceptable - DWORD errCode); // windows status code + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode); // windows status code int performTransfer( - IClientVirtualDevice* vd, - int backup, - int streamId); + IClientVirtualDevice* vd, + int backup, + int streamId); HANDLE execSQL(bool doBackup, int nStreams); int runSecondary(int streamId, IClientVirtualDeviceSet2* vds); int startSecondaries( - IClientVirtualDeviceSet2* vds, - HANDLE hSQLProcess, // handle to process dealing with the SQL - int nStreams, // number of i/o streams - char* pgmName // the name of this program -); + IClientVirtualDeviceSet2* vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams, // number of i/o streams + char* pgmName // the name of this program +); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName[100]; +WCHAR wVdsName[100]; // // main function // int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = nullptr; - VDConfig config; - bool badParm = true; - bool doBackup; - HANDLE hProcess; - int termCode = -1; - int nStreams = 1; - bool isSecondary = false; - - // Check the input parm - // - if (argc >= 3) - { - sscanf_s(argv[2], "%d", &nStreams); - - switch (toupper(argv[1][0])) - { - case 'B': - doBackup = true; - badParm = false; - break; - - case 'R': - doBackup = false; - badParm = false; - break; - - case 'S': - doBackup = false; // we don't know or care - badParm = false; - isSecondary = true; - - // nStreams is the streamid! - swprintf_s(wVdsName, L"%hs", argv[3]); - break; - } - } - - if (badParm) - { - printf("usage: mprocess {B|R} \n" - "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); - exit(1); - } - - if (isSecondary) - { - printf("Secondary pid %d working on stream %d\n", GetCurrentProcessId(), nStreams); - } - else - { - // 1..32 streams. - // - if (nStreams < 1) - nStreams = 1; - else if (nStreams > 32) - nStreams = 32; - - printf("Performing a %s using %d virtual device(s).\n", - (doBackup) ? "BACKUP" : "RESTORE", nStreams); - } - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - if (FAILED(hr)) - { - printf("Coinit fails: x%X\n", hr); - exit(1); - } - - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance( - IID_IClientVirtualDeviceSet, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet, - (void**)&vds); - - if (FAILED(hr)) - { - // This failure might happen if the DLL was not registered. - // - printf("Could not create component: x%X\n", hr); - printf("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Perform secondary processing, if this is a - // secondary process. - // - if (isSecondary) - { - termCode = runSecondary(nStreams, vds); - - goto exit; - } - - // The following logic is executed by the primary process. - // - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset(&config, 0, sizeof(config)); - - config.deviceCount = nStreams; - - // Create a GUID to use for a unique virtual device name - // - GUID vdsId; - CoCreateGuid(&vdsId); - StringFromGUID2(vdsId, wVdsName, 49); - - // Create the virtual device set - // for use by the default instance. - // - // To use a named instance, change the - // first parameter in CreateEx to your instance's name. - // - hr = vds->CreateEx(nullptr, wVdsName, &config); - if (FAILED(hr)) - { - printf("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, via isql in a subprocess. - // - printf("\nSending the SQL...\n"); - - hProcess = execSQL(doBackup, nStreams); - if (hProcess == nullptr) - { - printf("execSQL failed.\n"); - goto shutdown; - } - - - // Wait for the server to connect, completing the configuration. - // Notice that we wait a maximum of 15 seconds. - // - printf("\nWaiting for SQL to complete configuration...\n"); - - hr = vds->GetConfiguration(15000, &config); - if (FAILED(hr)) - { - printf("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Handle the virtual devices in secondary processes. - // - printf("\nSpawning secondary processes...\n"); - termCode = startSecondaries(vds, hProcess, nStreams, argv[0]); + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hProcess; + int termCode = -1; + int nStreams = 1; + bool isSecondary = false; + + // Check the input parm + // + if (argc >= 3) + { + sscanf_s(argv[2], "%d", &nStreams); + + switch (toupper(argv[1][0])) + { + case 'B': + doBackup = true; + badParm = false; + break; + + case 'R': + doBackup = false; + badParm = false; + break; + + case 'S': + doBackup = false; // we don't know or care + badParm = false; + isSecondary = true; + + // nStreams is the streamid! + swprintf_s(wVdsName, L"%hs", argv[3]); + break; + } + } + + if (badParm) + { + printf("usage: mprocess {B|R} \n" + "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); + exit(1); + } + + if (isSecondary) + { + printf("Secondary pid %d working on stream %d\n", GetCurrentProcessId(), nStreams); + } + else + { + // 1..32 streams. + // + if (nStreams < 1) + nStreams = 1; + else if (nStreams > 32) + nStreams = 32; + + printf("Performing a %s using %d virtual device(s).\n", + (doBackup) ? "BACKUP" : "RESTORE", nStreams); + } + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + IID_IClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered. + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Perform secondary processing, if this is a + // secondary process. + // + if (isSecondary) + { + termCode = runSecondary(nStreams, vds); + + goto exit; + } + + // The following logic is executed by the primary process. + // + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + + config.deviceCount = nStreams; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, via isql in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL(doBackup, nStreams); + if (hProcess == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + + // Wait for the server to connect, completing the configuration. + // Notice that we wait a maximum of 15 seconds. + // + printf("\nWaiting for SQL to complete configuration...\n"); + + hr = vds->GetConfiguration(15000, &config); + if (FAILED(hr)) + { + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Handle the virtual devices in secondary processes. + // + printf("\nSpawning secondary processes...\n"); + termCode = startSecondaries(vds, hProcess, nStreams, argv[0]); shutdown: - // Close the set - // - vds->Close(); + // Close the set + // + vds->Close(); - // COM reference counting: Release the interface. - // - vds->Release(); + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize(); + // Uninitialize COM Library + // + CoUninitialize(); - return termCode; + return termCode; } // @@ -269,52 +269,52 @@ int main(int argc, char* argv[]) // HANDLE execSQL(bool doBackup, int nStreams) { - WCHAR cmd[5000]; - WCHAR extend[100]; - PROCESS_INFORMATION pi; - STARTUPINFO si; - int ix; - - // Build the SQL, submitting it via 'isql' - // If you want to use Windows NT Authentication, please do not use the -U or -P options. - // - // To use a named instance, change "-S ." to "-S .\\instance_name" - // - swprintf_s(cmd, L"osql -S . -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", - (doBackup) ? L"BACKUP" : L"RESTORE", - (doBackup) ? L"TO" : L"FROM", - wVdsName); - - for (ix = 1; ix < nStreams; ix++) - { - swprintf_s(extend, L", VIRTUAL_DEVICE='%ls%d'", wVdsName, ix); - wcscat_s(cmd, extend); - } - - wcscat_s(cmd, L"\""); - - wprintf(L"Submitting SQL:\n%s\n\n", cmd); - - // use my process for startup info - // - GetStartupInfo(&si); - - if (!CreateProcess(nullptr, cmd, nullptr, nullptr, - true, // inherit handles (stdin/stdout) - 0, // creation flags, - nullptr, nullptr, - &si, // startup info - &pi)) // out: process info - { - LogError("startSecondary", "CreateProcess", GetLastError()); - return nullptr; - } - - CloseHandle(pi.hThread); - - // Return the process handle - // - return (pi.hProcess); + WCHAR cmd[5000]; + WCHAR extend[100]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + int ix; + + // Build the SQL, submitting it via 'isql' + // If you want to use Windows NT Authentication, please do not use the -U or -P options. + // + // To use a named instance, change "-S ." to "-S .\\instance_name" + // + swprintf_s(cmd, L"osql -S . -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", + wVdsName); + + for (ix = 1; ix < nStreams; ix++) + { + swprintf_s(extend, L", VIRTUAL_DEVICE='%ls%d'", wVdsName, ix); + wcscat_s(cmd, extend); + } + + wcscat_s(cmd, L"\""); + + wprintf(L"Submitting SQL:\n%s\n\n", cmd); + + // use my process for startup info + // + GetStartupInfo(&si); + + if (!CreateProcess(nullptr, cmd, nullptr, nullptr, + true, // inherit handles (stdin/stdout) + 0, // creation flags, + nullptr, nullptr, + &si, // startup info + &pi)) // out: process info + { + LogError("startSecondary", "CreateProcess", GetLastError()); + return nullptr; + } + + CloseHandle(pi.hThread); + + // Return the process handle + // + return (pi.hProcess); } //----------------------------------------------------------- @@ -325,129 +325,129 @@ HANDLE execSQL(bool doBackup, int nStreams) // // int startSecondaries( - IClientVirtualDeviceSet2* vds, - HANDLE hSQLProcess, // handle to process dealing with the SQL - int nStreams, // number of i/o streams - char* pgmName // the name of this program + IClientVirtualDeviceSet2* vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams, // number of i/o streams + char* pgmName // the name of this program ) { - int ix, nActive; - HANDLE children[33]; // 32 is maximum number of streams. - - // plus one for the isql process. - DWORD waitStatus, exitCode; - WCHAR cmd[200]; - PROCESS_INFORMATION pi; - STARTUPINFO si; - - // use my process for startup info - // - GetStartupInfo(&si); - - for (ix = 0; ix < nStreams; ix++) - { - swprintf_s(cmd, L"%hs s %d %ls", pgmName, ix, wVdsName); - - if (!CreateProcess(nullptr, cmd, nullptr, nullptr, - true, // inherit handles (just stdin/stdout I hope!) - 0, // creation flags, - nullptr, nullptr, - &si, // startup info - &pi)) // out: process info - { - wprintf(L"Error starting %s\n", cmd); - LogError("startSecondary", "CreateProcess", GetLastError()); - goto errorExit; - } - // keep the process handle - children[ix] = pi.hProcess; - - CloseHandle(pi.hThread); - } - - // Add the isql process into the array - // - children[nStreams] = hSQLProcess; - nActive = nStreams + 1; - - // Wait for all to finish. - // Max wait is one minute for this tiny test. - // - printf("All children are now running.\n" - "Waiting for their completion...\n"); - - // Notice how this differs from the threaded model in mthread.cpp. - // In the multiprocess model, the primary client (running this code) - // is responsible for detecting abnormal termination of the - // secondary clients. - // A simple "wait-for-all" approach may wait indefinitely if only - // one of the secondaries was to abnormally terminate. - // - do - { - // Wait for any completion - // - waitStatus = WaitForMultipleObjects(nActive, children, - FALSE, INFINITE); - - if (waitStatus >= WAIT_OBJECT_0 && - waitStatus < WAIT_OBJECT_0 + nActive) - { - // One of the children completed. - // Determine which one. - // - ix = waitStatus - WAIT_OBJECT_0; - - // Check its completion code - // - if (!GetExitCodeProcess(children[ix], &exitCode)) - { - LogError("startSecondary", "GetExitCode", GetLastError()); - goto errorExit; - } - - if (exitCode != 0) - { - printf("A child exitted with code %d\n", exitCode); - goto errorExit; - } - - // It is good programming practice to close handles when - // finished with them. - // Since this sample simply terminates the process for error - // handling, we don't need to do it, as handles are automatically - // closed as part of process termination. - // - CloseHandle(children[ix]); - - // Remove the handle for this child - // - memmove(&children[ix], &children[ix + 1], - sizeof(HANDLE) * (nActive - ix - 1)); - - nActive--; - - } - else - { - printf("Unexpected wait code: %d\n", waitStatus); - goto errorExit; - } - - } while (nActive > 0); - - printf("All children completed successfully\n"); - - return 0; + int ix, nActive; + HANDLE children[33]; // 32 is maximum number of streams. + + // plus one for the isql process. + DWORD waitStatus, exitCode; + WCHAR cmd[200]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + + // use my process for startup info + // + GetStartupInfo(&si); + + for (ix = 0; ix < nStreams; ix++) + { + swprintf_s(cmd, L"%hs s %d %ls", pgmName, ix, wVdsName); + + if (!CreateProcess(nullptr, cmd, nullptr, nullptr, + true, // inherit handles (just stdin/stdout I hope!) + 0, // creation flags, + nullptr, nullptr, + &si, // startup info + &pi)) // out: process info + { + wprintf(L"Error starting %s\n", cmd); + LogError("startSecondary", "CreateProcess", GetLastError()); + goto errorExit; + } + // keep the process handle + children[ix] = pi.hProcess; + + CloseHandle(pi.hThread); + } + + // Add the isql process into the array + // + children[nStreams] = hSQLProcess; + nActive = nStreams + 1; + + // Wait for all to finish. + // Max wait is one minute for this tiny test. + // + printf("All children are now running.\n" + "Waiting for their completion...\n"); + + // Notice how this differs from the threaded model in mthread.cpp. + // In the multiprocess model, the primary client (running this code) + // is responsible for detecting abnormal termination of the + // secondary clients. + // A simple "wait-for-all" approach may wait indefinitely if only + // one of the secondaries was to abnormally terminate. + // + do + { + // Wait for any completion + // + waitStatus = WaitForMultipleObjects(nActive, children, + FALSE, INFINITE); + + if (waitStatus >= WAIT_OBJECT_0 && + waitStatus < WAIT_OBJECT_0 + nActive) + { + // One of the children completed. + // Determine which one. + // + ix = waitStatus - WAIT_OBJECT_0; + + // Check its completion code + // + if (!GetExitCodeProcess(children[ix], &exitCode)) + { + LogError("startSecondary", "GetExitCode", GetLastError()); + goto errorExit; + } + + if (exitCode != 0) + { + printf("A child exitted with code %d\n", exitCode); + goto errorExit; + } + + // It is good programming practice to close handles when + // finished with them. + // Since this sample simply terminates the process for error + // handling, we don't need to do it, as handles are automatically + // closed as part of process termination. + // + CloseHandle(children[ix]); + + // Remove the handle for this child + // + memmove(&children[ix], &children[ix + 1], + sizeof(HANDLE) * (nActive - ix - 1)); + + nActive--; + + } + else + { + printf("Unexpected wait code: %d\n", waitStatus); + goto errorExit; + } + + } while (nActive > 0); + + printf("All children completed successfully\n"); + + return 0; errorExit: - // Handle all problems in a trivial fashion: - // SignalAbort() will cause all processes using the virtual device set - // to terminate processing. - // Thus, we don't bother waiting for any children to terminate. - // - vds->SignalAbort(); - return -1; + // Handle all problems in a trivial fashion: + // SignalAbort() will cause all processes using the virtual device set + // to terminate processing. + // Thus, we don't bother waiting for any children to terminate. + // + vds->SignalAbort(); + return -1; } @@ -457,77 +457,77 @@ int startSecondaries( // int runSecondary(int streamId, IClientVirtualDeviceSet2* vds) { - HRESULT hr; - WCHAR devName[100]; - IClientVirtualDevice* vd; - VDConfig config; - int termCode; - - // Open the device - // - if (streamId == 0) - { - // The first device has the same name as the set. - // - wcscpy_s(devName, wVdsName); - } - else - { - // For this example, we've simply appended a number - // for additional devices. You are free to name them - // as you wish. - // - swprintf_s(devName, L"%ls%d", wVdsName, streamId); - } - - // Open the virtual device set in this secondary process. - // - // To use a named instance, change the - // first parameter in OpenInSecondaryEx to your instance's name. - // - hr = vds->OpenInSecondaryEx(nullptr, wVdsName); - if (FAILED(hr)) - { - wprintf(L"VD::Open(%ls) fails: x%X", devName, hr); - return -1; - } - - // Open the device assigned to this process. - // - hr = vds->OpenDevice(devName, &vd); - if (FAILED(hr)) - { - wprintf(L"OpenDevice fails on %ls: x%X", devName, hr); - return -1; - } - - // Grab the config to figure out data direction - // - hr = vds->GetConfiguration(INFINITE, &config); - if (FAILED(hr)) - { - wprintf(L"VDS::Getconfig fails: x%X\n", hr); - termCode = -1; - goto errExit; - } - - printf("\nPerforming data transfer...\n"); - - termCode = performTransfer(vd, - (config.features & VDF_WriteMedia), streamId); + HRESULT hr; + WCHAR devName[100]; + IClientVirtualDevice* vd; + VDConfig config; + int termCode; + + // Open the device + // + if (streamId == 0) + { + // The first device has the same name as the set. + // + wcscpy_s(devName, wVdsName); + } + else + { + // For this example, we've simply appended a number + // for additional devices. You are free to name them + // as you wish. + // + swprintf_s(devName, L"%ls%d", wVdsName, streamId); + } + + // Open the virtual device set in this secondary process. + // + // To use a named instance, change the + // first parameter in OpenInSecondaryEx to your instance's name. + // + hr = vds->OpenInSecondaryEx(nullptr, wVdsName); + if (FAILED(hr)) + { + wprintf(L"VD::Open(%ls) fails: x%X", devName, hr); + return -1; + } + + // Open the device assigned to this process. + // + hr = vds->OpenDevice(devName, &vd); + if (FAILED(hr)) + { + wprintf(L"OpenDevice fails on %ls: x%X", devName, hr); + return -1; + } + + // Grab the config to figure out data direction + // + hr = vds->GetConfiguration(INFINITE, &config); + if (FAILED(hr)) + { + wprintf(L"VDS::Getconfig fails: x%X\n", hr); + termCode = -1; + goto errExit; + } + + printf("\nPerforming data transfer...\n"); + + termCode = performTransfer(vd, + (config.features & VDF_WriteMedia), streamId); errExit: - // If errors were detected, force an abort. - // - if (termCode != 0) - { - vds->SignalAbort(); - } + // If errors were detected, force an abort. + // + if (termCode != 0) + { + vds->SignalAbort(); + } - vds->Close(); + vds->Close(); - return termCode; + return termCode; } @@ -537,94 +537,94 @@ int runSecondary(int streamId, IClientVirtualDeviceSet2* vds) // Returns 0, if no errors are detected, else non-zero. // int performTransfer( - IClientVirtualDevice* vd, - int backup, - int streamId) + IClientVirtualDevice* vd, + int backup, + int streamId) { - FILE* fh; - char fname[80]; - VDC_Command* cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - int termCode = -1; - - sprintf_s(fname, "multi.%d.dmp", streamId); - - errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); - if (error != 0) - { - printf("Failed to open: %s\n", fname); - return -1; - } - - while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - - break; - - case VDC_Write: - bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush(fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - - hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); - if (FAILED(hr)) - { - printf("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf("Successfully completed data transfer.\n"); - termCode = 0; - } - - fclose(fh); - - return termCode; + FILE* fh; + char fname[80]; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + int termCode = -1; + + sprintf_s(fname, "multi.%d.dmp", streamId); + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return -1; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + termCode = 0; + } + + fclose(fh); + + return termCode; } //-------------------------------------------------------------------- @@ -632,30 +632,30 @@ int performTransfer( // A simple error logger. // void LogError( - const char* location, // must always be provided - const char* description, // NULL is acceptable - DWORD errCode) // windows status code + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode) // windows status code { - LPWSTR lpMsgBuf; - - printf( - "Error at %s: %s StatusCode: %X\n", - location, - (description == nullptr) ? "" : description, - errCode); - - // Attempt to explain the code - // - if (errCode != 0 && FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - errCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - reinterpret_cast(&lpMsgBuf), 0, nullptr))// Process any inserts in lpMsgBuf. - { - printf("Explanation: %ls\n", lpMsgBuf); - LocalFree(lpMsgBuf); - } + LPWSTR lpMsgBuf = nullptr; + + printf( + "Error at %s: %s StatusCode: %X\n", + location, + (description == nullptr) ? "" : description, + errCode); + + // Attempt to explain the code + // + if (errCode != 0 && FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + reinterpret_cast(&lpMsgBuf), 0, nullptr))// Process any inserts in lpMsgBuf. + { + printf("Explanation: %ls\n", lpMsgBuf); + LocalFree(lpMsgBuf); + } } diff --git a/samples/features/sqlvdi/mthread/mthread.cpp b/samples/features/sqlvdi/mthread/mthread.cpp index b9e1fd63ff..6dddbf385f 100644 --- a/samples/features/sqlvdi/mthread/mthread.cpp +++ b/samples/features/sqlvdi/mthread/mthread.cpp @@ -40,187 +40,187 @@ All Rights Reserved. #include "vdiguid.h" // define the GUIDs void LogError( - const char* location, // must always be provided - const char* description, // NULL is acceptable - DWORD errCode); // windows status code + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode); // windows status code int performTransfer( - IClientVirtualDevice* vd, - int backup, - int streamId); + IClientVirtualDevice* vd, + int backup, + int streamId); HANDLE execSQL(bool doBackup, int nStreams); int startSecondaries( - IClientVirtualDeviceSet2* vds, - HANDLE hSQLProcess, // handle to process dealing with the SQL - int nStreams); // number of i/o streams + IClientVirtualDeviceSet2* vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams); // number of i/o streams unsigned __stdcall runSecondary(void* parms); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName[50]; +WCHAR wVdsName[50]; // // main function // int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = nullptr; - VDConfig config; - bool badParm = true; - bool doBackup; - HANDLE hProcess; - int termCode = -1; - int nStreams = 1; - - // Check the input parm - // - if (argc == 3) - { - sscanf_s(argv[2], "%d", &nStreams); - - switch (toupper(argv[1][0])) - { - case 'B': - doBackup = true; - badParm = false; - break; - - case 'R': - doBackup = false; - badParm = false; - break; - } - } - - if (badParm) - { - printf("usage: mthread {B|R} \n" - "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); - exit(1); - } - - // 1..32 streams. - // - if (nStreams < 1) - nStreams = 1; - else if (nStreams > 32) - nStreams = 32; - - printf("Performing a %s using %d virtual device(s).\n", - (doBackup) ? "BACKUP" : "RESTORE", nStreams); - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - if (FAILED(hr)) - { - printf("Coinit fails: x%X\n", hr); - exit(1); - } - - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance( - CLSID_MSSQL_ClientVirtualDeviceSet, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (FAILED(hr)) - { - // This failure might happen if the DLL was not registered. - // - printf("Could not create component: x%X\n", hr); - printf("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset(&config, 0, sizeof(config)); - config.deviceCount = nStreams; - - // Create a GUID to use for a unique virtual device name - // - GUID vdsId; - CoCreateGuid(&vdsId); - StringFromGUID2(vdsId, wVdsName, 49); - - // Create the virtual device set - // for use by the default instance. - // - // To use a named instance, change the - // first parameter in CreateEx to your instance's name. - // - hr = vds->CreateEx(nullptr, wVdsName, &config); - if (FAILED(hr)) - { - printf("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, via isql in a subprocess. - // - printf("\nSending the SQL...\n"); - - hProcess = execSQL(doBackup, nStreams); - if (hProcess == nullptr) - { - printf("execSQL failed.\n"); - goto shutdown; - } - - - // Wait for the server to connect, completing the configuration. - // Notice that we wait a maximum of 15 seconds. - // - printf("\nWaiting for SQL to complete configuration...\n"); - - hr = vds->GetConfiguration(15000, &config); - if (FAILED(hr)) - { - printf("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Handle the virtual devices in secondary processes. - // - printf("\nSpawning secondary threads..\n"); - termCode = startSecondaries(vds, hProcess, nStreams); + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hProcess; + int termCode = -1; + int nStreams = 1; + + // Check the input parm + // + if (argc == 3) + { + sscanf_s(argv[2], "%d", &nStreams); + + switch (toupper(argv[1][0])) + { + case 'B': + doBackup = true; + badParm = false; + break; + + case 'R': + doBackup = false; + badParm = false; + break; + } + } + + if (badParm) + { + printf("usage: mthread {B|R} \n" + "Demonstrate a multistream Backup or Restore using the Virtual Device Interface\n"); + exit(1); + } + + // 1..32 streams. + // + if (nStreams < 1) + nStreams = 1; + else if (nStreams > 32) + nStreams = 32; + + printf("Performing a %s using %d virtual device(s).\n", + (doBackup) ? "BACKUP" : "RESTORE", nStreams); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered. + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = nStreams; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, via isql in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL(doBackup, nStreams); + if (hProcess == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + + // Wait for the server to connect, completing the configuration. + // Notice that we wait a maximum of 15 seconds. + // + printf("\nWaiting for SQL to complete configuration...\n"); + + hr = vds->GetConfiguration(15000, &config); + if (FAILED(hr)) + { + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Handle the virtual devices in secondary processes. + // + printf("\nSpawning secondary threads..\n"); + termCode = startSecondaries(vds, hProcess, nStreams); shutdown: - // Close the set - // - vds->Close(); + // Close the set + // + vds->Close(); - // COM reference counting: Release the interface. - // - vds->Release(); + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize(); + // Uninitialize COM Library + // + CoUninitialize(); - return termCode; + return termCode; } // @@ -232,48 +232,48 @@ int main(int argc, char* argv[]) // HANDLE execSQL(bool doBackup, int nStreams) { - WCHAR cmd[5000]; - WCHAR extend[100]; - PROCESS_INFORMATION pi; - STARTUPINFO si; - int ix; - - // To use a named instance, change "-S ." to "-S .\\instance_name" - swprintf_s(cmd, L"osql -S . -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", - (doBackup) ? L"BACKUP" : L"RESTORE", - (doBackup) ? L"TO" : L"FROM", - wVdsName); - - for (ix = 1; ix < nStreams; ix++) - { - swprintf_s(extend, L", VIRTUAL_DEVICE='%ls%d'", wVdsName, ix); - wcscat_s(cmd, extend); - } - - wcscat_s(cmd, L"\""); - - wprintf(L"Submitting SQL:\n%s\n\n", cmd); - - // use my process for startup info - // - GetStartupInfo(&si); - - if (!CreateProcess(nullptr, cmd, nullptr, nullptr, - true, // inherit handles (stdin/stdout) - 0, // creation flags, - nullptr, nullptr, - &si, // startup info - &pi)) // out: process info - { - LogError("startSecondary", "CreateProcess", GetLastError()); - return nullptr; - } - - CloseHandle(pi.hThread); - - // Return the process handle - // - return (pi.hProcess); + WCHAR cmd[5000]; + WCHAR extend[100]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + int ix; + + // To use a named instance, change "-S ." to "-S .\\instance_name" + swprintf_s(cmd, L"osql -S . -E -b -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", + wVdsName); + + for (ix = 1; ix < nStreams; ix++) + { + swprintf_s(extend, L", VIRTUAL_DEVICE='%ls%d'", wVdsName, ix); + wcscat_s(cmd, extend); + } + + wcscat_s(cmd, L"\""); + + wprintf(L"Submitting SQL:\n%s\n\n", cmd); + + // use my process for startup info + // + GetStartupInfo(&si); + + if (!CreateProcess(nullptr, cmd, nullptr, nullptr, + true, // inherit handles (stdin/stdout) + 0, // creation flags, + nullptr, nullptr, + &si, // startup info + &pi)) // out: process info + { + LogError("startSecondary", "CreateProcess", GetLastError()); + return nullptr; + } + + CloseHandle(pi.hThread); + + // Return the process handle + // + return (pi.hProcess); } //----------------------------------------------------------- @@ -281,8 +281,8 @@ HANDLE execSQL(bool doBackup, int nStreams) // A parmameter block to use when spawning secondaries. // struct THREAD_PARMS { - IClientVirtualDeviceSet* vds; - int streamId; + IClientVirtualDeviceSet* vds; + int streamId; }; @@ -295,109 +295,109 @@ struct THREAD_PARMS { // int startSecondaries( - IClientVirtualDeviceSet2* vds, - HANDLE hSQLProcess, // handle to process dealing with the SQL - int nStreams // number of i/o streams + IClientVirtualDeviceSet2* vds, + HANDLE hSQLProcess, // handle to process dealing with the SQL + int nStreams // number of i/o streams ) { - THREAD_PARMS parms[32]; // each thread needs its own parm block - int ix, nActive; - HANDLE children[33]; // 32 is maximum number of streams. - - // plus one for the isql process. - DWORD waitStatus, exitCode; - unsigned threadId; - - for (ix = 0; ix < nStreams; ix++) - { - // All threads share the same virtual device set, - // but must operate on different virtual devices. - // - parms[ix].vds = vds; - parms[ix].streamId = ix; - - children[ix] = (HANDLE)_beginthreadex( - nullptr, 0, runSecondary, (void*)&parms[ix], 0, &threadId); - - if (children[ix] == nullptr) - { - printf("Failed to create thread. errno is %d\n", errno); - goto errorExit; - } - - printf("\nStarted thread %d\n", threadId); - } - - // Add the isql process into the array - // - children[nStreams] = hSQLProcess; - nActive = nStreams + 1; - - // Wait for all to finish. - // Max wait is one minute for this tiny test. - // - printf("All children are now running.\n" - "Waiting for their completion...\n"); - - waitStatus = WaitForMultipleObjects(nActive, children, - true, 60000); - - if (waitStatus < WAIT_OBJECT_0 || - waitStatus >= WAIT_OBJECT_0 + nActive) - { - LogError("startSecondary", "WaitForMultiple", GetLastError()); - printf("Unexpected wait code: %d\n", waitStatus); - goto errorExit; - } - - // All of the children have completed. - // Get the completion code from 'isql' to check for sucess. - // - if (!GetExitCodeProcess(hSQLProcess, &exitCode)) - { - LogError("startSecondary", "GetExitCode", GetLastError()); - goto errorExit; - } - - if (exitCode != 0) - { - printf("The SQL operation failed with code %d\n", exitCode); - goto errorExit; - } - - printf("The SQL operation was sucessful.\n"); - - // Be sure to close handles when finished with them. - // - // Notice that in our trivial error handling here we - // don't bother closing them, since handles are - // automatically closed as part of process termination. - // - for (ix = 0; ix < nActive; ix++) - { - CloseHandle(children[ix]); - } - - return 0; + THREAD_PARMS parms[32]; // each thread needs its own parm block + int ix, nActive; + HANDLE children[33]; // 32 is maximum number of streams. + + // plus one for the isql process. + DWORD waitStatus, exitCode; + unsigned threadId; + + for (ix = 0; ix < nStreams; ix++) + { + // All threads share the same virtual device set, + // but must operate on different virtual devices. + // + parms[ix].vds = vds; + parms[ix].streamId = ix; + + children[ix] = (HANDLE)_beginthreadex( + nullptr, 0, runSecondary, (void*)&parms[ix], 0, &threadId); + + if (children[ix] == nullptr) + { + printf("Failed to create thread. errno is %d\n", errno); + goto errorExit; + } + + printf("\nStarted thread %d\n", threadId); + } + + // Add the isql process into the array + // + children[nStreams] = hSQLProcess; + nActive = nStreams + 1; + + // Wait for all to finish. + // Max wait is one minute for this tiny test. + // + printf("All children are now running.\n" + "Waiting for their completion...\n"); + + waitStatus = WaitForMultipleObjects(nActive, children, + true, 60000); + + if (waitStatus < WAIT_OBJECT_0 || + waitStatus >= WAIT_OBJECT_0 + nActive) + { + LogError("startSecondary", "WaitForMultiple", GetLastError()); + printf("Unexpected wait code: %d\n", waitStatus); + goto errorExit; + } + + // All of the children have completed. + // Get the completion code from 'isql' to check for sucess. + // + if (!GetExitCodeProcess(hSQLProcess, &exitCode)) + { + LogError("startSecondary", "GetExitCode", GetLastError()); + goto errorExit; + } + + if (exitCode != 0) + { + printf("The SQL operation failed with code %d\n", exitCode); + goto errorExit; + } + + printf("The SQL operation was sucessful.\n"); + + // Be sure to close handles when finished with them. + // + // Notice that in our trivial error handling here we + // don't bother closing them, since handles are + // automatically closed as part of process termination. + // + for (ix = 0; ix < nActive; ix++) + { + CloseHandle(children[ix]); + } + + return 0; errorExit: - // Handle all problems in a trivial fashion: - // SignalAbort() will cause all processes using the virtual device set - // to terminate processing. - // - vds->SignalAbort(); - - // However, since the threads are using the virtual device set allocated - // by the main thread, we can't let the main thread close the set before - // the threads are finished with it. There are two options: - // 1) exit the process immediately. - // 2) wait for the threads to terminate. - // - // Option 2 is "cleaner" but requires more code, so we just exit here: - // - ExitProcess((unsigned)-1); - - return -1; // ExitProcess doesn't return; this avoids a compiler error. + // Handle all problems in a trivial fashion: + // SignalAbort() will cause all processes using the virtual device set + // to terminate processing. + // + vds->SignalAbort(); + + // However, since the threads are using the virtual device set allocated + // by the main thread, we can't let the main thread close the set before + // the threads are finished with it. There are two options: + // 1) exit the process immediately. + // 2) wait for the threads to terminate. + // + // Option 2 is "cleaner" but requires more code, so we just exit here: + // + ExitProcess((unsigned)-1); + + return -1; // ExitProcess doesn't return; this avoids a compiler error. } //------------------------------------------------------------------ @@ -409,69 +409,69 @@ startSecondaries( unsigned __stdcall runSecondary(void* parms) { - HRESULT hr; - WCHAR devName[100]; - IClientVirtualDevice* vd; - VDConfig config; - int termCode; - - // Fetch the input parms - // - int streamId = ((THREAD_PARMS*)parms)->streamId; - IClientVirtualDeviceSet* vds = ((THREAD_PARMS*)parms)->vds; - - // Build the name of the device assigned to this thread. - // - if (streamId == 0) - { - // The first device has the same name as the set. - // - wcscpy_s(devName, wVdsName); - } - else - { - // For this example, we've simply appended a number - // for additional devices. You are free to name them - // as you wish. - // - swprintf_s(devName, L"%s%d", wVdsName, streamId); - } - - // Open the device assigned to this thread. - // - hr = vds->OpenDevice(devName, &vd); - if (FAILED(hr)) - { - wprintf(L"OpenDevice fails on %ls: x%X", devName, hr); - termCode = -1; - goto errExit; - } - - // Grab the config to figure out data direction - // - hr = vds->GetConfiguration(INFINITE, &config); - if (FAILED(hr)) - { - wprintf(L"VDS::Getconfig fails: x%X\n", hr); - termCode = -1; - goto errExit; - } - - printf("\nPerforming data transfer...\n"); - - termCode = performTransfer(vd, - (config.features & VDF_WriteMedia), streamId); + HRESULT hr; + WCHAR devName[100]; + IClientVirtualDevice* vd; + VDConfig config; + int termCode; + + // Fetch the input parms + // + int streamId = ((THREAD_PARMS*)parms)->streamId; + IClientVirtualDeviceSet* vds = ((THREAD_PARMS*)parms)->vds; + + // Build the name of the device assigned to this thread. + // + if (streamId == 0) + { + // The first device has the same name as the set. + // + wcscpy_s(devName, wVdsName); + } + else + { + // For this example, we've simply appended a number + // for additional devices. You are free to name them + // as you wish. + // + swprintf_s(devName, L"%s%d", wVdsName, streamId); + } + + // Open the device assigned to this thread. + // + hr = vds->OpenDevice(devName, &vd); + if (FAILED(hr)) + { + wprintf(L"OpenDevice fails on %ls: x%X", devName, hr); + termCode = -1; + goto errExit; + } + + // Grab the config to figure out data direction + // + hr = vds->GetConfiguration(INFINITE, &config); + if (FAILED(hr)) + { + wprintf(L"VDS::Getconfig fails: x%X\n", hr); + termCode = -1; + goto errExit; + } + + printf("\nPerforming data transfer...\n"); + + termCode = performTransfer(vd, + (config.features & VDF_WriteMedia), streamId); errExit: - // If errors were detected, force an abort. - // - if (termCode != 0) - { - vds->SignalAbort(); - } + // If errors were detected, force an abort. + // + if (termCode != 0) + { + vds->SignalAbort(); + } - return ((unsigned)termCode); + return ((unsigned)termCode); } @@ -483,94 +483,94 @@ runSecondary(void* parms) // Returns 0, if no errors are detected, else non-zero. // int performTransfer( - IClientVirtualDevice* vd, - int backup, - int streamId) + IClientVirtualDevice* vd, + int backup, + int streamId) { - FILE* fh; - char fname[80]; - VDC_Command* cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - int termCode = -1; - - sprintf_s(fname, "multi.%d.dmp", streamId); - - errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); - if (error != 0) - { - printf("Failed to open: %s\n", fname); - return -1; - } - - while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - - break; - - case VDC_Write: - bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush(fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - - hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); - if (FAILED(hr)) - { - printf("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf("Successfully completed data transfer.\n"); - termCode = 0; - } - - fclose(fh); - - return termCode; + FILE* fh; + char fname[80]; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + int termCode = -1; + + sprintf_s(fname, "multi.%d.dmp", streamId); + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return -1; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + termCode = 0; + } + + fclose(fh); + + return termCode; } @@ -579,30 +579,30 @@ int performTransfer( // A simple error logger. // void LogError( - const char* location, // must always be provided - const char* description, // NULL is acceptable - DWORD errCode) // windows status code + const char* location, // must always be provided + const char* description, // NULL is acceptable + DWORD errCode) // windows status code { - LPWSTR lpMsgBuf = nullptr; - - printf( - "Error at %s: %s StatusCode: %X\n", - location, - (description == nullptr) ? "" : description, - errCode); - - // Attempt to explain the code - // - if (errCode != 0 && FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - errCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - reinterpret_cast(&lpMsgBuf), 0, nullptr)) // Process any inserts in lpMsgBuf. - { - printf("Explanation: %ls\n", lpMsgBuf); - LocalFree(lpMsgBuf); - } + LPWSTR lpMsgBuf = nullptr; + + printf( + "Error at %s: %s StatusCode: %X\n", + location, + (description == nullptr) ? "" : description, + errCode); + + // Attempt to explain the code + // + if (errCode != 0 && FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + reinterpret_cast(&lpMsgBuf), 0, nullptr)) // Process any inserts in lpMsgBuf. + { + printf("Explanation: %ls\n", lpMsgBuf); + LocalFree(lpMsgBuf); + } } diff --git a/samples/features/sqlvdi/osimple/osimple.cpp b/samples/features/sqlvdi/osimple/osimple.cpp index 12c99f50bd..d3f6663e4c 100644 --- a/samples/features/sqlvdi/osimple/osimple.cpp +++ b/samples/features/sqlvdi/osimple/osimple.cpp @@ -46,8 +46,8 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the interface identifiers. - // IMPORTANT: vdiguid.h can only be included in one source file. - // + // IMPORTANT: vdiguid.h can only be included in one source file. + // #include #include "sql.h" @@ -55,15 +55,15 @@ All Rights Reserved. #include "odbcss.h" void performTransfer( - IClientVirtualDevice* vd, - int backup); + IClientVirtualDevice* vd, + int backup); HANDLE execSQL(bool doBackup); bool checkSQL(HANDLE); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName[50]; +WCHAR wVdsName[50]; //------------------------------------------------------------ // @@ -71,185 +71,185 @@ WCHAR wVdsName[50]; // int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = nullptr; - IClientVirtualDevice* vd = nullptr; - - VDConfig config; - bool badParm = true; - bool doBackup; - HANDLE hThread = nullptr; - - // Check the input parm - // - if (argc == 2) - { - char param = toupper(argv[1][0]); - - if (param == 'B') - { - doBackup = true; - badParm = false; - } - else if (param == 'R') - { - doBackup = false; - badParm = false; - } - } - - if (badParm) - { - printf("usage: osimple {B|R}\n" - "Demonstrate a Backup or Restore using the Virtual Device Interface & ODBC\n"); - exit(1); - } - - printf("Performing a %s using a virtual device.\n", - (doBackup) ? "BACKUP" : "RESTORE"); - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - if (FAILED(hr)) - { - printf("Coinit fails: x%X\n", hr); - exit(1); - } - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance( - CLSID_MSSQL_ClientVirtualDeviceSet, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (FAILED(hr)) - { - // This failure might happen if the DLL was not registered, - // or if the application is using the wrong interface id (IID). - // - printf("Could not create component: x%X\n", hr); - printf("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset(&config, 0, sizeof(config)); - config.deviceCount = 1; - - // Create a GUID to use for a unique virtual device name - // - GUID vdsId; - CoCreateGuid(&vdsId); - StringFromGUID2(vdsId, wVdsName, 49); - - // Create the virtual device set - // for use by the default instance. - // - // To use a named instance, change the - // first parameter in CreateEx to your instance's name. - // - hr = vds->CreateEx(nullptr, wVdsName, &config); - if (FAILED(hr)) - { - printf("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, by starting a thread to handle the ODBC - // - printf("\nSending the SQL...\n"); - - hThread = execSQL(doBackup); - if (hThread == nullptr) - { - printf("execSQL failed.\n"); - goto shutdown; - } - - // Wait for the server to connect, completing the configuration. - // - printf("\nWaiting for SQLServer to respond...\n"); - - while (FAILED(hr = vds->GetConfiguration(1000, &config))) - { - if (hr == VD_E_TIMEOUT) - { - // Check on the SQL thread - // - DWORD rc = WaitForSingleObject(hThread, 1000); - if (rc == WAIT_OBJECT_0) - { - printf("SQL command failed before VD transfer\n"); - goto shutdown; - } - if (rc == WAIT_TIMEOUT) - { - continue; - } - printf("Check on SQL failed: %d\n", rc); - goto shutdown; - } - - printf("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Open the single device in the set. - // - hr = vds->OpenDevice(wVdsName, &vd); - if (FAILED(hr)) - { - printf("VDS::OpenDevice fails: x%X\n", hr); - goto shutdown; - } - - printf("\nPerforming data transfer...\n"); - - performTransfer(vd, doBackup); + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + IClientVirtualDevice* vd = nullptr; + + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hThread = nullptr; + + // Check the input parm + // + if (argc == 2) + { + char param = toupper(argv[1][0]); + + if (param == 'B') + { + doBackup = true; + badParm = false; + } + else if (param == 'R') + { + doBackup = false; + badParm = false; + } + } + + if (badParm) + { + printf("usage: osimple {B|R}\n" + "Demonstrate a Backup or Restore using the Virtual Device Interface & ODBC\n"); + exit(1); + } + + printf("Performing a %s using a virtual device.\n", + (doBackup) ? "BACKUP" : "RESTORE"); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = 1; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting a thread to handle the ODBC + // + printf("\nSending the SQL...\n"); + + hThread = execSQL(doBackup); + if (hThread == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + printf("\nWaiting for SQLServer to respond...\n"); + + while (FAILED(hr = vds->GetConfiguration(1000, &config))) + { + if (hr == VD_E_TIMEOUT) + { + // Check on the SQL thread + // + DWORD rc = WaitForSingleObject(hThread, 1000); + if (rc == WAIT_OBJECT_0) + { + printf("SQL command failed before VD transfer\n"); + goto shutdown; + } + if (rc == WAIT_TIMEOUT) + { + continue; + } + printf("Check on SQL failed: %d\n", rc); + goto shutdown; + } + + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice(wVdsName, &vd); + if (FAILED(hr)) + { + printf("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf("\nPerforming data transfer...\n"); + + performTransfer(vd, doBackup); shutdown: - // Close the set - // - vds->Close(); + // Close the set + // + vds->Close(); - // Obtain the SQL completion information - // - if (hThread != nullptr) - { - if (checkSQL(hThread)) - printf("\nThe SQL command executed successfully.\n"); - else - printf("\nThe SQL command failed.\n"); + // Obtain the SQL completion information + // + if (hThread != nullptr) + { + if (checkSQL(hThread)) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); - CloseHandle(hThread); - } + CloseHandle(hThread); + } - // COM reference counting: Release the interface. - // - vds->Release(); + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize(); + // Uninitialize COM Library + // + CoUninitialize(); - return 0; + return 0; } //--------------------------------------------------------------------------- @@ -262,92 +262,92 @@ int main(int argc, char* argv[]) // errors (error messages will be followed by the 3014 success message). // void ProcessMessages( - SQLSMALLINT handle_type, // ODBC handle type - SQLHANDLE handle, // ODBC handle - bool ConnInd, // TRUE if sucessful connection made - bool* pBackupSuccess) // Set TRUE if a 3014 message is seen. + SQLSMALLINT handle_type, // ODBC handle type + SQLHANDLE handle, // ODBC handle + bool ConnInd, // TRUE if sucessful connection made + bool* pBackupSuccess) // Set TRUE if a 3014 message is seen. { - RETCODE plm_retcode = SQL_SUCCESS; - SQLWCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; - SQLWCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; - SDWORD plm_pfNativeError = 0L; - SWORD plm_pcbErrorMsg = 0; - SQLSMALLINT plm_cRecNmbr = 1; - SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; - SQLBIGINT plm_Rownumber = 0; - USHORT plm_SS_Line; - SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; - SQLWCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; - - while (plm_retcode != SQL_NO_DATA_FOUND) - { - plm_retcode = SQLGetDiagRec(handle_type, handle, - plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, - plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); - - // Note that if the application has not yet made a - // successful connection, the SQLGetDiagField - // information has not yet been cached by ODBC - // Driver Manager and these calls to SQLGetDiagField - // will fail. - // - if (plm_retcode != SQL_NO_DATA_FOUND) - { - if (ConnInd) - { - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_ROW_NUMBER, &plm_Rownumber, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_LINE, &plm_SS_Line, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, - sizeof(plm_SS_Procname), - &plm_cbSS_Procname); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, - sizeof(plm_SS_Srvname), - &plm_cbSS_Srvname); - - printf_s("Msg %d, SevLevel %d, State %d, SQLState %ls\n", - plm_pfNativeError, - plm_SS_Severity, - plm_SS_MsgState, - plm_szSqlState); - } - - printf_s("%ls\n", plm_szErrorMsg); - - if (pBackupSuccess && plm_pfNativeError == 3014) - { - *pBackupSuccess = TRUE; - } - } - - plm_cRecNmbr++; //Increment to next diagnostic record. - } // End while. + RETCODE plm_retcode = SQL_SUCCESS; + SQLWCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; + SQLWCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; + SDWORD plm_pfNativeError = 0L; + SWORD plm_pcbErrorMsg = 0; + SQLSMALLINT plm_cRecNmbr = 1; + SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; + SQLBIGINT plm_Rownumber = 0; + USHORT plm_SS_Line; + SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; + SQLWCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; + + while (plm_retcode != SQL_NO_DATA_FOUND) + { + plm_retcode = SQLGetDiagRec(handle_type, handle, + plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, + plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); + + // Note that if the application has not yet made a + // successful connection, the SQLGetDiagField + // information has not yet been cached by ODBC + // Driver Manager and these calls to SQLGetDiagField + // will fail. + // + if (plm_retcode != SQL_NO_DATA_FOUND) + { + if (ConnInd) + { + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_ROW_NUMBER, &plm_Rownumber, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_LINE, &plm_SS_Line, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, + sizeof(plm_SS_Procname), + &plm_cbSS_Procname); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, + sizeof(plm_SS_Srvname), + &plm_cbSS_Srvname); + + printf_s("Msg %d, SevLevel %d, State %d, SQLState %ls\n", + plm_pfNativeError, + plm_SS_Severity, + plm_SS_MsgState, + plm_szSqlState); + } + + printf_s("%ls\n", plm_szErrorMsg); + + if (pBackupSuccess && plm_pfNativeError == 3014) + { + *pBackupSuccess = TRUE; + } + } + + plm_cRecNmbr++; //Increment to next diagnostic record. + } // End while. } @@ -360,176 +360,176 @@ void ProcessMessages( unsigned __stdcall SQLRoutine(void* parms) { - bool doBackup = (bool)parms; - - wchar_t sqlCommand[1024]; // way more space than we'll need. - bool successDetected = false; - - // ODBC handles - // - SQLHENV henv = nullptr; - SQLHDBC hdbc = nullptr; - SQLHSTMT hstmt = nullptr; - - - swprintf_s(sqlCommand, L"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", - (doBackup) ? L"BACKUP" : L"RESTORE", - (doBackup) ? L"TO" : L"FROM", - wVdsName); - - bool sentSQL = false; - int rc; - - #define MAX_CONN_OUT 1024 - SQLWCHAR szOutConn[MAX_CONN_OUT]; - SQLSMALLINT cbOutConn; - - // Initialize the ODBC environment. - // - if (SQLAllocHandle(SQL_HANDLE_ENV, nullptr, &henv) == SQL_ERROR) - goto exit; - - // This is an ODBC v3 application - // - SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER); - - // Allocate a connection handle - // - if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) - { - printf("AllocHandle on DBC failed."); - goto exit; - } - - // Connect to the server using Trusted connection. - // Trusted connection uses integrated NT security. - // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. - // - // To use a named instance, change "SERVER=." to "SERVER=.\\instance_name" - // - - rc = SQLDriverConnectW( - hdbc, - nullptr, // no diaglogs please - const_cast(L"DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."), - SQL_NTS, - szOutConn, - MAX_CONN_OUT, - &cbOutConn, - SQL_DRIVER_NOPROMPT); - - if (rc == SQL_ERROR) - { - SQLWCHAR szSqlState[20]; - SQLINTEGER ssErr; - SQLWCHAR szErrorMsg[MAX_CONN_OUT]; - SQLSMALLINT cbErrorMsg; - - printf("Connect fails\n"); - - rc = SQLError( - henv, hdbc, SQL_NULL_HSTMT, - szSqlState, - &ssErr, - szErrorMsg, - MAX_CONN_OUT, - &cbErrorMsg); - - printf("msg=%ls\n", szErrorMsg); - - goto exit; - } - - // Get a statement handle - // - if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) - { - printf("Failed to get statement handle\n"); - - ProcessMessages(SQL_HANDLE_DBC, hdbc, true, nullptr); - goto exit; - } - - // Execute the SQL - // - printf_s("Executing %ls\n", sqlCommand); - - rc = SQLExecDirectW(hstmt, const_cast(sqlCommand), SQL_NTS); - - // Extract all the resulting messages - // - - SQLSMALLINT numResultCols; - while (1) - { - switch (rc) - { - case SQL_ERROR: - successDetected = false; - ProcessMessages(SQL_HANDLE_STMT, hstmt, true, &successDetected); - if (!successDetected) - { - printf("Errors resulted in failure of the command\n"); - goto exit; - } - printf("Errors were encountered but the command was able to recover and successfully complete.\n"); - break; - - case SQL_SUCCESS_WITH_INFO: - ProcessMessages(SQL_HANDLE_STMT, hstmt, true, nullptr); - // fall through - - case SQL_SUCCESS: - successDetected = true; - - numResultCols = 0; - SQLNumResultCols(hstmt, &numResultCols); - if (numResultCols > 0) - { - printf("A result set with %d columns was produced\n", - (int)numResultCols); - } - break; - - case SQL_NO_DATA: - // All results have been processed. We are done. - // - goto exit; - - case SQL_NEED_DATA: - case SQL_INVALID_HANDLE: - case SQL_STILL_EXECUTING: - default: - successDetected = false; - printf("Unexpected SQLExec result %d\n", rc); - goto exit; - } - rc = SQLMoreResults(hstmt); - } + bool doBackup = (bool)parms; + + wchar_t sqlCommand[1024]; // way more space than we'll need. + bool successDetected = false; + + // ODBC handles + // + SQLHENV henv = nullptr; + SQLHDBC hdbc = nullptr; + SQLHSTMT hstmt = nullptr; + + + swprintf_s(sqlCommand, L"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", + wVdsName); + + bool sentSQL = false; + int rc; + + #define MAX_CONN_OUT 1024 + SQLWCHAR szOutConn[MAX_CONN_OUT]; + SQLSMALLINT cbOutConn; + + // Initialize the ODBC environment. + // + if (SQLAllocHandle(SQL_HANDLE_ENV, nullptr, &henv) == SQL_ERROR) + goto exit; + + // This is an ODBC v3 application + // + SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER); + + // Allocate a connection handle + // + if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) + { + printf("AllocHandle on DBC failed."); + goto exit; + } + + // Connect to the server using Trusted connection. + // Trusted connection uses integrated NT security. + // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. + // + // To use a named instance, change "SERVER=." to "SERVER=.\\instance_name" + // + + rc = SQLDriverConnectW( + hdbc, + nullptr, // no diaglogs please + const_cast(L"DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."), + SQL_NTS, + szOutConn, + MAX_CONN_OUT, + &cbOutConn, + SQL_DRIVER_NOPROMPT); + + if (rc == SQL_ERROR) + { + SQLWCHAR szSqlState[20]; + SQLINTEGER ssErr; + SQLWCHAR szErrorMsg[MAX_CONN_OUT]; + SQLSMALLINT cbErrorMsg; + + printf("Connect fails\n"); + + rc = SQLError( + henv, hdbc, SQL_NULL_HSTMT, + szSqlState, + &ssErr, + szErrorMsg, + MAX_CONN_OUT, + &cbErrorMsg); + + printf("msg=%ls\n", szErrorMsg); + + goto exit; + } + + // Get a statement handle + // + if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) + { + printf("Failed to get statement handle\n"); + + ProcessMessages(SQL_HANDLE_DBC, hdbc, true, nullptr); + goto exit; + } + + // Execute the SQL + // + printf_s("Executing %ls\n", sqlCommand); + + rc = SQLExecDirectW(hstmt, const_cast(sqlCommand), SQL_NTS); + + // Extract all the resulting messages + // + + SQLSMALLINT numResultCols; + while (1) + { + switch (rc) + { + case SQL_ERROR: + successDetected = false; + ProcessMessages(SQL_HANDLE_STMT, hstmt, true, &successDetected); + if (!successDetected) + { + printf("Errors resulted in failure of the command\n"); + goto exit; + } + printf("Errors were encountered but the command was able to recover and successfully complete.\n"); + break; + + case SQL_SUCCESS_WITH_INFO: + ProcessMessages(SQL_HANDLE_STMT, hstmt, true, nullptr); + // fall through + + case SQL_SUCCESS: + successDetected = true; + + numResultCols = 0; + SQLNumResultCols(hstmt, &numResultCols); + if (numResultCols > 0) + { + printf("A result set with %d columns was produced\n", + (int)numResultCols); + } + break; + + case SQL_NO_DATA: + // All results have been processed. We are done. + // + goto exit; + + case SQL_NEED_DATA: + case SQL_INVALID_HANDLE: + case SQL_STILL_EXECUTING: + default: + successDetected = false; + printf("Unexpected SQLExec result %d\n", rc); + goto exit; + } + rc = SQLMoreResults(hstmt); + } exit: - // Release the ODBC resources. - // - if (hstmt != nullptr) - { - SQLFreeHandle(SQL_HANDLE_STMT, hstmt); - hstmt = nullptr; - } - - if (hdbc != nullptr) - { - SQLDisconnect(hdbc); - SQLFreeHandle(SQL_HANDLE_DBC, hdbc); - hdbc = nullptr; - } - - if (henv != nullptr) - { - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = nullptr; - } - - return successDetected; + // Release the ODBC resources. + // + if (hstmt != nullptr) + { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = nullptr; + } + + if (hdbc != nullptr) + { + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = nullptr; + } + + if (henv != nullptr) + { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = nullptr; + } + + return successDetected; } @@ -541,40 +541,40 @@ SQLRoutine(void* parms) // HANDLE execSQL(bool doBackup) { - unsigned int threadId; - HANDLE hThread; - - hThread = (HANDLE)_beginthreadex( - nullptr, 0, SQLRoutine, (void*)doBackup, 0, &threadId); - if (hThread == nullptr) - { - printf("Failed to create thread. errno is %d\n", errno); - } - return hThread; + unsigned int threadId; + HANDLE hThread; + + hThread = (HANDLE)_beginthreadex( + nullptr, 0, SQLRoutine, (void*)doBackup, 0, &threadId); + if (hThread == nullptr) + { + printf("Failed to create thread. errno is %d\n", errno); + } + return hThread; } //------------------------------------------------------------ // // checkSQL: Wait for the T-SQL to complete, -// returns TRUE if statement successfully executed. +// returns TRUE if statement successfully executed. // bool checkSQL(HANDLE hThread) { - if (hThread == nullptr) - return false; - - DWORD rc = WaitForSingleObject(hThread, INFINITE); - if (rc != WAIT_OBJECT_0) - { - printf("checkSQL failed: %d\n", rc); - return false; - } - if (!GetExitCodeThread(hThread, &rc)) - { - printf("failed to get exit code: %d\n", GetLastError()); - return false; - } - return rc == true; + if (hThread == nullptr) + return false; + + DWORD rc = WaitForSingleObject(hThread, INFINITE); + if (rc != WAIT_OBJECT_0) + { + printf("checkSQL failed: %d\n", rc); + return false; + } + if (!GetExitCodeThread(hThread, &rc)) + { + printf("failed to get exit code: %d\n", GetLastError()); + return false; + } + return rc == true; } @@ -587,83 +587,83 @@ bool checkSQL(HANDLE hThread) // It simply reads or writes a file 'superbak.dmp' in the current directory. // void performTransfer( - IClientVirtualDevice* vd, - int backup) + IClientVirtualDevice* vd, + int backup) { - FILE* fh; - char* fname = (char*)"superbak.dmp"; - VDC_Command* cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - - errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); - if (error != 0) - { - printf("Failed to open: %s\n", fname); - return; - } - - while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - break; - - case VDC_Write: - bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush(fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); - if (FAILED(hr)) - { - printf("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf("Successfully completed data transfer.\n"); - } - - fclose(fh); + FILE* fh; + char* fname = (char*)"superbak.dmp"; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + } + + fclose(fh); } diff --git a/samples/features/sqlvdi/simple/simple.cpp b/samples/features/sqlvdi/simple/simple.cpp index e9aa57f6fa..e52dcd0b6c 100644 --- a/samples/features/sqlvdi/simple/simple.cpp +++ b/samples/features/sqlvdi/simple/simple.cpp @@ -37,18 +37,18 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the interface identifiers. - // IMPORTANT: vdiguid.h can only be included in one source file. - // + // IMPORTANT: vdiguid.h can only be included in one source file. + // void performTransfer( - IClientVirtualDevice* vd, - bool backup); + IClientVirtualDevice* vd, + bool backup); int execSQL(bool doBackup); // Using a GUID for the VDS Name is a good way to assure uniqueness. // -WCHAR wVdsName[50]; +WCHAR wVdsName[50]; // @@ -56,174 +56,174 @@ WCHAR wVdsName[50]; // int main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = nullptr; - IClientVirtualDevice* vd = nullptr; - - VDConfig config; - bool badParm = true; - bool doBackup; - bool isUnnamed = false; - int hProcess; - int termCode; - - // Check the input parm - // - if (argc == 2) - { - char param = toupper(argv[1][0]); - - if (param == 'B') - { - doBackup = true; - badParm = false; - } - else if (param == 'R') - { - doBackup = false; - badParm = false; - } - } - - if (badParm) - { - printf("usage: simple {B|R}\n" - "Demonstrate a Backup or Restore using the Virtual Device Interface\n"); - exit(1); - } - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - if (FAILED(hr)) - { - printf("Coinit fails: x%X\n", hr); - exit(1); - } - - // Get an interface to the device set. - hr = CoCreateInstance( - CLSID_MSSQL_ClientVirtualDeviceSet, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (FAILED(hr)) - { - // This failure might happen if the DLL was not registered, - // or if the application is using the wrong interface id (IID). - // - printf("Could not create component: x%X\n", hr); - printf("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset(&config, 0, sizeof(config)); - config.deviceCount = 1; - - // Create a GUID to use for a unique virtual device name - // - GUID vdsId; - CoCreateGuid(&vdsId); - StringFromGUID2(vdsId, wVdsName, 49); - - // Create the virtual device set - // for use by the default instance. - // - // To use a named instance, change the - // first parameter in CreateEx to your instance's name. - // - hr = vds->CreateEx(nullptr, wVdsName, &config); - if (FAILED(hr)) - { - printf("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, by starting 'isql' in a subprocess. - // - printf("\nSending the SQL...\n"); - - hProcess = execSQL(doBackup); - if (hProcess == -1) - { - printf("execSQL failed.\n"); - goto shutdown; - } - - // Wait for the server to connect, completing the configuration. - // - hr = vds->GetConfiguration(10000, &config); - if (FAILED(hr)) - { - printf("VDS::Getconfig fails: x%X\n", hr); - if (hr == VD_E_TIMEOUT) - { - printf("Timed out. Was Microsoft SQLServer running?\n"); - } - goto shutdown; - } - - // Open the single device in the set. - // - hr = vds->OpenDevice(wVdsName, &vd); - if (FAILED(hr)) - { - printf("VDS::OpenDevice fails: x%X\n", hr); - goto shutdown; - } - - printf("\nPerforming data transfer...\n"); - - performTransfer(vd, doBackup); + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + IClientVirtualDevice* vd = nullptr; + + VDConfig config; + bool badParm = true; + bool doBackup; + bool isUnnamed = false; + int hProcess; + int termCode; + + // Check the input parm + // + if (argc == 2) + { + char param = toupper(argv[1][0]); + + if (param == 'B') + { + doBackup = true; + badParm = false; + } + else if (param == 'R') + { + doBackup = false; + badParm = false; + } + } + + if (badParm) + { + printf("usage: simple {B|R}\n" + "Demonstrate a Backup or Restore using the Virtual Device Interface\n"); + exit(1); + } + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + // Get an interface to the device set. + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = 1; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // for use by the default instance. + // + // To use a named instance, change the + // first parameter in CreateEx to your instance's name. + // + hr = vds->CreateEx(nullptr, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting 'isql' in a subprocess. + // + printf("\nSending the SQL...\n"); + + hProcess = execSQL(doBackup); + if (hProcess == -1) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + hr = vds->GetConfiguration(10000, &config); + if (FAILED(hr)) + { + printf("VDS::Getconfig fails: x%X\n", hr); + if (hr == VD_E_TIMEOUT) + { + printf("Timed out. Was Microsoft SQLServer running?\n"); + } + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice(wVdsName, &vd); + if (FAILED(hr)) + { + printf("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf("\nPerforming data transfer...\n"); + + performTransfer(vd, doBackup); shutdown: - // Close the set - // - vds->Close(); - - // Obtain the SQL completion information, by waiting for isql to exit. - // - if (hProcess == _cwait(&termCode, hProcess, 0)) - { - if (termCode == 0) - printf("\nThe SQL command executed successfully.\n"); - else - printf("\nThe SQL command failed.\n"); - } - else - { - printf("cwait failed: %d\n", errno); - } - - // COM reference counting: Release the interface. - // - // Rather than releasing it, the application has the - // option to 'Create' another set, reusing the interface - // that it currently has. Of course that applies to - // a real application, not this simple sample! - // - vds->Release(); + // Close the set + // + vds->Close(); + + // Obtain the SQL completion information, by waiting for isql to exit. + // + if (hProcess == _cwait(&termCode, hProcess, 0)) + { + if (termCode == 0) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); + } + else + { + printf("cwait failed: %d\n", errno); + } + + // COM reference counting: Release the interface. + // + // Rather than releasing it, the application has the + // option to 'Create' another set, reusing the interface + // that it currently has. Of course that applies to + // a real application, not this simple sample! + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize(); + // Uninitialize COM Library + // + CoUninitialize(); - return 0; + return 0; } // @@ -235,113 +235,113 @@ int main(int argc, char* argv[]) // int execSQL(bool doBackup) { - wchar_t sqlCommand[1024]; // plenty of space for our purpose - - // To use a named instance, change "-S ." to "-S .\\instance_name" - swprintf_s(sqlCommand, L"-S . -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'\"", - (doBackup) ? L"BACKUP" : L"RESTORE", - (doBackup) ? L"TO" : L"FROM", - wVdsName); - intptr_t rc; - - wprintf(L"spawning osql to execute: %ls\n", sqlCommand); - - // Spawn off the osql utility to execute the SQL. - // Notice the '-b' which causes an error to set a non-zero - // exit code on error. - // - rc = _wspawnlp(_P_NOWAIT, L"osql", L"osql", L"-E", L"-b", - sqlCommand, NULL); - - if (rc == -1) - { - printf("Spawn failed with error: %d\n", errno); - } - - return (rc); + wchar_t sqlCommand[1024]; // plenty of space for our purpose + + // To use a named instance, change "-S ." to "-S .\\instance_name" + swprintf_s(sqlCommand, L"-S . -Q\"%s DATABASE PUBS %s VIRTUAL_DEVICE='%ls'\"", + (doBackup) ? L"BACKUP" : L"RESTORE", + (doBackup) ? L"TO" : L"FROM", + wVdsName); + intptr_t rc; + + wprintf(L"spawning osql to execute: %ls\n", sqlCommand); + + // Spawn off the osql utility to execute the SQL. + // Notice the '-b' which causes an error to set a non-zero + // exit code on error. + // + rc = _wspawnlp(_P_NOWAIT, L"osql", L"osql", L"-E", L"-b", + sqlCommand, NULL); + + if (rc == -1) + { + printf("Spawn failed with error: %d\n", errno); + } + + return (rc); } // This routine reads commands from the server until a 'Close' status is received. // It simply reads or writes a file 'superbak.dmp' in the current directory. // void performTransfer( - IClientVirtualDevice* vd, - bool backup) + IClientVirtualDevice* vd, + bool backup) { - FILE* fh; - char* fname = (char*)"superbak.dmp"; - VDC_Command* cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - - errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); - if (error != 0) - { - printf("Failed to open: %s\n", fname); - return; - } - - while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - break; - - case VDC_Write: - bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush(fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); - if (FAILED(hr)) - { - printf("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf("Successfully completed data transfer.\n"); - } - - fclose(fh); + FILE* fh; + char* fname = (char*)"superbak.dmp"; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + } + + fclose(fh); } \ No newline at end of file diff --git a/samples/features/sqlvdi/snapshot/snapshot.cpp b/samples/features/sqlvdi/snapshot/snapshot.cpp index 62d761199f..2e0cc9f199 100644 --- a/samples/features/sqlvdi/snapshot/snapshot.cpp +++ b/samples/features/sqlvdi/snapshot/snapshot.cpp @@ -20,7 +20,7 @@ All Rights Reserved. // on some instance of sql server. // // The program accepts input: -// {b | r} [] +// {b | r} [] // b -> backup // r -> restore // @@ -46,8 +46,8 @@ All Rights Reserved. #include "vdierror.h" // error constants #include "vdiguid.h" // define the interface identifiers. - // IMPORTANT: vdiguid.h can only be included in one source file. - // + // IMPORTANT: vdiguid.h can only be included in one source file. + // #include #include "sql.h" @@ -55,9 +55,9 @@ All Rights Reserved. #include "odbcss.h" void performTransfer( - IClientVirtualDeviceSet2* vds, - IClientVirtualDevice* vd, - int backup); + IClientVirtualDeviceSet2* vds, + IClientVirtualDevice* vd, + int backup); HANDLE execSQL(bool doBackup, WCHAR* pInstanceName, WCHAR* pDbName, WCHAR* pVdsName); bool checkSQL(HANDLE); @@ -71,213 +71,213 @@ bool ynPrompt(const char* str); int __cdecl main(int argc, char* argv[]) { - HRESULT hr; - IClientVirtualDeviceSet2* vds = nullptr; - IClientVirtualDevice* vd = nullptr; - - VDConfig config; - bool badParm = true; - bool doBackup; - HANDLE hThread = nullptr; - char* pDbName = nullptr; - char* pInstanceName = nullptr; - WCHAR wInstanceName[128] = { 0 }; - int rc = 0; - - // Check the input parm - // - if (argc >= 3) - { - char param = toupper(argv[1][0]); - - if (param == 'B') - { - doBackup = true; - badParm = false; - } - else if (param == 'R') - { - doBackup = false; - badParm = false; - } - - pDbName = argv[2]; - - if (argc == 4) - { - pInstanceName = argv[3]; - } - } - - if (badParm) - { - printf("usage: snapshot {B|R} []\n" - "Demonstrate a Backup or Restore WITH SNAPSHOT\n"); - printf("\n\n** NOTE **\n The ability to take or mount snapshots must be implemented\n" - "before this sample is truely functional.\n"); - exit(1); - } - - printf("Performing a %s of %s on %s using a VIRTUAL_DEVICE.\n", - (doBackup) ? "BACKUP" : "RESTORE", - pDbName, - (pInstanceName) ? pInstanceName : "Default"); - - // Initialize COM Library - // Note: _WIN32_DCOM must be defined during the compile. - // - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - if (FAILED(hr)) - { - printf("Coinit fails: x%X\n", hr); - exit(1); - } - - // Get an interface to the device set. - // Notice how we use a single IID for both the class and interface - // identifiers. - // - hr = CoCreateInstance( - CLSID_MSSQL_ClientVirtualDeviceSet, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IClientVirtualDeviceSet2, - (void**)&vds); - - if (FAILED(hr)) - { - // This failure might happen if the DLL was not registered, - // or if the application is using the wrong interface id (IID). - // - printf("Could not create component: x%X\n", hr); - printf("Check registration of SQLVDI.DLL and value of IID\n"); - goto exit; - } - - // Setup the VDI configuration we want to use. - // This program doesn't use any fancy features, so the - // only field to setup is the deviceCount. - // - // The server will treat the virtual device just like a pipe: - // I/O will be strictly sequential with only the basic commands. - // - memset(&config, 0, sizeof(config)); - config.deviceCount = 1; - config.features = VDF_SnapshotPrepare; - - // Create a GUID to use for a unique virtual device name - // - GUID vdsId; - WCHAR wVdsName[50]; - CoCreateGuid(&vdsId); - StringFromGUID2(vdsId, wVdsName, 49); - - // Create the virtual device set - // Notice that we only support unicode interfaces - // - - if (pInstanceName) - { - rc = MultiByteToWideChar(CP_ACP, 0, - pInstanceName, strlen(pInstanceName), - wInstanceName, 127); - } - wInstanceName[rc] = 0; - - hr = vds->CreateEx(wInstanceName, wVdsName, &config); - if (FAILED(hr)) - { - printf("VDS::Create fails: x%X", hr); - goto exit; - } - - // Send the SQL command, by starting a thread to handle the ODBC - // - printf("\nSending the SQL...\n"); - - WCHAR wDbName[128]; - MultiByteToWideChar(CP_ACP, 0, - pDbName, -1, - wDbName, 127); - - hThread = execSQL(doBackup, wInstanceName, wDbName, wVdsName); - if (hThread == nullptr) - { - printf("execSQL failed.\n"); - goto shutdown; - } - - // Wait for the server to connect, completing the configuration. - // - printf("\nWaiting for SQLServer to respond...\n"); - - while (FAILED(hr = vds->GetConfiguration(1000, &config))) - { - if (hr == VD_E_TIMEOUT) - { - // Check on the SQL thread - // - DWORD rc = WaitForSingleObject(hThread, 1000); - if (rc == WAIT_OBJECT_0) - { - printf("SQL command failed before VD transfer\n"); - goto shutdown; - } - if (rc == WAIT_TIMEOUT) - { - continue; - } - printf("Check on SQL failed: %d\n", rc); - goto shutdown; - } - - printf("VDS::Getconfig fails: x%X\n", hr); - goto shutdown; - } - - // Open the single device in the set. - // - hr = vds->OpenDevice(wVdsName, &vd); - if (FAILED(hr)) - { - printf("VDS::OpenDevice fails: x%X\n", hr); - goto shutdown; - } - - printf("\nPerforming data transfer...\n"); - - performTransfer(vds, vd, doBackup); + HRESULT hr; + IClientVirtualDeviceSet2* vds = nullptr; + IClientVirtualDevice* vd = nullptr; + + VDConfig config; + bool badParm = true; + bool doBackup; + HANDLE hThread = nullptr; + char* pDbName = nullptr; + char* pInstanceName = nullptr; + WCHAR wInstanceName[128] = { 0 }; + int rc = 0; + + // Check the input parm + // + if (argc >= 3) + { + char param = toupper(argv[1][0]); + + if (param == 'B') + { + doBackup = true; + badParm = false; + } + else if (param == 'R') + { + doBackup = false; + badParm = false; + } + + pDbName = argv[2]; + + if (argc == 4) + { + pInstanceName = argv[3]; + } + } + + if (badParm) + { + printf("usage: snapshot {B|R} []\n" + "Demonstrate a Backup or Restore WITH SNAPSHOT\n"); + printf("\n\n** NOTE **\n The ability to take or mount snapshots must be implemented\n" + "before this sample is truely functional.\n"); + exit(1); + } + + printf("Performing a %s of %s on %s using a VIRTUAL_DEVICE.\n", + (doBackup) ? "BACKUP" : "RESTORE", + pDbName, + (pInstanceName) ? pInstanceName : "Default"); + + // Initialize COM Library + // Note: _WIN32_DCOM must be defined during the compile. + // + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + if (FAILED(hr)) + { + printf("Coinit fails: x%X\n", hr); + exit(1); + } + + // Get an interface to the device set. + // Notice how we use a single IID for both the class and interface + // identifiers. + // + hr = CoCreateInstance( + CLSID_MSSQL_ClientVirtualDeviceSet, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IClientVirtualDeviceSet2, + (void**)&vds); + + if (FAILED(hr)) + { + // This failure might happen if the DLL was not registered, + // or if the application is using the wrong interface id (IID). + // + printf("Could not create component: x%X\n", hr); + printf("Check registration of SQLVDI.DLL and value of IID\n"); + goto exit; + } + + // Setup the VDI configuration we want to use. + // This program doesn't use any fancy features, so the + // only field to setup is the deviceCount. + // + // The server will treat the virtual device just like a pipe: + // I/O will be strictly sequential with only the basic commands. + // + memset(&config, 0, sizeof(config)); + config.deviceCount = 1; + config.features = VDF_SnapshotPrepare; + + // Create a GUID to use for a unique virtual device name + // + GUID vdsId; + WCHAR wVdsName[50]; + CoCreateGuid(&vdsId); + StringFromGUID2(vdsId, wVdsName, 49); + + // Create the virtual device set + // Notice that we only support unicode interfaces + // + + if (pInstanceName) + { + rc = MultiByteToWideChar(CP_ACP, 0, + pInstanceName, strlen(pInstanceName), + wInstanceName, 127); + } + wInstanceName[rc] = 0; + + hr = vds->CreateEx(wInstanceName, wVdsName, &config); + if (FAILED(hr)) + { + printf("VDS::Create fails: x%X", hr); + goto exit; + } + + // Send the SQL command, by starting a thread to handle the ODBC + // + printf("\nSending the SQL...\n"); + + WCHAR wDbName[128]; + MultiByteToWideChar(CP_ACP, 0, + pDbName, -1, + wDbName, 127); + + hThread = execSQL(doBackup, wInstanceName, wDbName, wVdsName); + if (hThread == nullptr) + { + printf("execSQL failed.\n"); + goto shutdown; + } + + // Wait for the server to connect, completing the configuration. + // + printf("\nWaiting for SQLServer to respond...\n"); + + while (FAILED(hr = vds->GetConfiguration(1000, &config))) + { + if (hr == VD_E_TIMEOUT) + { + // Check on the SQL thread + // + DWORD rc = WaitForSingleObject(hThread, 1000); + if (rc == WAIT_OBJECT_0) + { + printf("SQL command failed before VD transfer\n"); + goto shutdown; + } + if (rc == WAIT_TIMEOUT) + { + continue; + } + printf("Check on SQL failed: %d\n", rc); + goto shutdown; + } + + printf("VDS::Getconfig fails: x%X\n", hr); + goto shutdown; + } + + // Open the single device in the set. + // + hr = vds->OpenDevice(wVdsName, &vd); + if (FAILED(hr)) + { + printf("VDS::OpenDevice fails: x%X\n", hr); + goto shutdown; + } + + printf("\nPerforming data transfer...\n"); + + performTransfer(vds, vd, doBackup); shutdown: - // Close the set - // - vds->Close(); + // Close the set + // + vds->Close(); - // Obtain the SQL completion information - // - if (hThread != nullptr) - { - if (checkSQL(hThread)) - printf("\nThe SQL command executed successfully.\n"); - else - printf("\nThe SQL command failed.\n"); + // Obtain the SQL completion information + // + if (hThread != nullptr) + { + if (checkSQL(hThread)) + printf("\nThe SQL command executed successfully.\n"); + else + printf("\nThe SQL command failed.\n"); - CloseHandle(hThread); - } + CloseHandle(hThread); + } - // COM reference counting: Release the interface. - // - vds->Release(); + // COM reference counting: Release the interface. + // + vds->Release(); exit: - // Uninitialize COM Library - // - CoUninitialize(); + // Uninitialize COM Library + // + CoUninitialize(); - return 0; + return 0; } //--------------------------------------------------------------------------- @@ -290,92 +290,92 @@ main(int argc, char* argv[]) // errors (error messages will be followed by the 3014 success message). // void ProcessMessages( - SQLSMALLINT handle_type, // ODBC handle type - SQLHANDLE handle, // ODBC handle - bool ConnInd, // TRUE if sucessful connection made - bool* pBackupSuccess) // Set TRUE if a 3014 message is seen. + SQLSMALLINT handle_type, // ODBC handle type + SQLHANDLE handle, // ODBC handle + bool ConnInd, // TRUE if sucessful connection made + bool* pBackupSuccess) // Set TRUE if a 3014 message is seen. { - RETCODE plm_retcode = SQL_SUCCESS; - SQLWCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; - SQLWCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; - SDWORD plm_pfNativeError = 0L; - SWORD plm_pcbErrorMsg = 0; - SQLSMALLINT plm_cRecNmbr = 1; - SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; - SQLBIGINT plm_Rownumber = 0; - USHORT plm_SS_Line; - SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; - SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; - - while (plm_retcode != SQL_NO_DATA_FOUND) - { - plm_retcode = SQLGetDiagRec(handle_type, handle, - plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, - plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); - - // Note that if the application has not yet made a - // successful connection, the SQLGetDiagField - // information has not yet been cached by ODBC - // Driver Manager and these calls to SQLGetDiagField - // will fail. - // - if (plm_retcode != SQL_NO_DATA_FOUND) - { - if (ConnInd) - { - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_ROW_NUMBER, &plm_Rownumber, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_LINE, &plm_SS_Line, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, - SQL_IS_INTEGER, - NULL); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, - sizeof(plm_SS_Procname), - &plm_cbSS_Procname); - - plm_retcode = SQLGetDiagField( - handle_type, handle, plm_cRecNmbr, - SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, - sizeof(plm_SS_Srvname), - &plm_cbSS_Srvname); - - printf_s("Msg %ld, SevLevel %ld, State %ld, SQLState %ls\n", - plm_pfNativeError, - plm_SS_Severity, - plm_SS_MsgState, - plm_szSqlState); - } - - printf("%ls\n", plm_szErrorMsg); - - if (pBackupSuccess && plm_pfNativeError == 3014) - { - *pBackupSuccess = TRUE; - } - } - - plm_cRecNmbr++; //Increment to next diagnostic record. - } // End while. + RETCODE plm_retcode = SQL_SUCCESS; + SQLWCHAR plm_szSqlState[SQL_SQLSTATE_SIZE + 1]; + SQLWCHAR plm_szErrorMsg[SQL_MAX_MESSAGE_LENGTH + 1]; + SDWORD plm_pfNativeError = 0L; + SWORD plm_pcbErrorMsg = 0; + SQLSMALLINT plm_cRecNmbr = 1; + SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0; + SQLBIGINT plm_Rownumber = 0; + USHORT plm_SS_Line; + SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname; + SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME]; + + while (plm_retcode != SQL_NO_DATA_FOUND) + { + plm_retcode = SQLGetDiagRec(handle_type, handle, + plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError, + plm_szErrorMsg, SQL_MAX_MESSAGE_LENGTH, &plm_pcbErrorMsg); + + // Note that if the application has not yet made a + // successful connection, the SQLGetDiagField + // information has not yet been cached by ODBC + // Driver Manager and these calls to SQLGetDiagField + // will fail. + // + if (plm_retcode != SQL_NO_DATA_FOUND) + { + if (ConnInd) + { + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_ROW_NUMBER, &plm_Rownumber, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_LINE, &plm_SS_Line, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SEVERITY, &plm_SS_Severity, + SQL_IS_INTEGER, + NULL); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_PROCNAME, &plm_SS_Procname, + sizeof(plm_SS_Procname), + &plm_cbSS_Procname); + + plm_retcode = SQLGetDiagField( + handle_type, handle, plm_cRecNmbr, + SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname, + sizeof(plm_SS_Srvname), + &plm_cbSS_Srvname); + + printf_s("Msg %ld, SevLevel %ld, State %ld, SQLState %ls\n", + plm_pfNativeError, + plm_SS_Severity, + plm_SS_MsgState, + plm_szSqlState); + } + + printf("%ls\n", plm_szErrorMsg); + + if (pBackupSuccess && plm_pfNativeError == 3014) + { + *pBackupSuccess = TRUE; + } + } + + plm_cRecNmbr++; //Increment to next diagnostic record. + } // End while. } @@ -387,197 +387,197 @@ void ProcessMessages( // struct PARMS { - bool doBackup; - WCHAR* pInstanceName; - WCHAR* pDbName; - WCHAR* pVdsName; + bool doBackup; + WCHAR* pInstanceName; + WCHAR* pDbName; + WCHAR* pVdsName; }; unsigned __stdcall SQLRoutine(void* input) { - PARMS* parms = (PARMS*)input; - - SQLWCHAR* pSQLText; // the command being executed. - bool successDetected = false; - - // ODBC handles - // - SQLHENV henv = nullptr; - SQLHDBC hdbc = nullptr; - SQLHSTMT hstmt = nullptr; - - WCHAR sqlCommand[1024]; - SQLWCHAR connectString[200] = { 0 }; - - bool sentSQL = false; - int rc; - - #define MAX_CONN_OUT 1024 - SQLWCHAR szOutConn[MAX_CONN_OUT] = { 0 }; - SQLSMALLINT cbOutConn; - - - // Generate the command to execute - // - swprintf_s(sqlCommand, L"%ls DATABASE [%ls] %ls VIRTUAL_DEVICE='%ls' WITH SNAPSHOT", - parms->doBackup ? L"BACKUP" : L"RESTORE", - parms->pDbName, - parms->doBackup ? L"TO" : L"FROM", - parms->pVdsName); - - // Initialize the ODBC environment. - // - if (SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) - goto exit; - - // This is an ODBC v3 application - // - SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER); - - // Allocate a connection handle - // - if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) - { - printf("AllocHandle on DBC failed."); - goto exit; - } - - wcscpy_s(connectString, 200, L"DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."); - if (parms->pInstanceName) - { - swprintf_s(connectString + wcslen(connectString), 200 - wcslen(connectString), L"\\%ls", parms->pInstanceName); - } - - printf("\n\nConnecting with: %ls\n", connectString); - - // Connect to the server using Trusted connection. - // Trusted connection uses integrated NT security. - // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. - rc = SQLDriverConnect( - hdbc, - nullptr, // no diaglogs please - connectString, - SQL_NTS, - szOutConn, - MAX_CONN_OUT, - &cbOutConn, - SQL_DRIVER_NOPROMPT); - - if (rc == SQL_ERROR) - { - SQLWCHAR szSqlState[20]; - SQLINTEGER ssErr; - SQLWCHAR szErrorMsg[MAX_CONN_OUT]; - SQLSMALLINT cbErrorMsg; - - printf("Connect fails\n"); - - rc = SQLError( - henv, hdbc, SQL_NULL_HSTMT, - szSqlState, - &ssErr, - szErrorMsg, - MAX_CONN_OUT, - &cbErrorMsg); - - printf("msg=%ls\n", szErrorMsg); - - goto exit; - } - - // Get a statement handle - // - if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) - { - printf("Failed to get statement handle\n"); - - ProcessMessages(SQL_HANDLE_DBC, hdbc, true, nullptr); - goto exit; - } - - // Execute the SQL - // - printf("\n\nExecuting SQL: %ls\n", sqlCommand); - - pSQLText = sqlCommand; - - rc = SQLExecDirect(hstmt, pSQLText, SQL_NTS); - - // Extract all the resulting messages - // - - SQLSMALLINT numResultCols; - while (1) - { - switch (rc) - { - case SQL_ERROR: - successDetected = false; - ProcessMessages(SQL_HANDLE_STMT, hstmt, true, &successDetected); - if (!successDetected) - { - printf("Errors resulted in failure of the command\n"); - goto exit; - } - printf("Errors were encountered but the command was able to recover and successfully complete.\n"); - break; - - case SQL_SUCCESS_WITH_INFO: - ProcessMessages(SQL_HANDLE_STMT, hstmt, TRUE, NULL); - // fall through - - case SQL_SUCCESS: - successDetected = true; - - numResultCols = 0; - SQLNumResultCols(hstmt, &numResultCols); - if (numResultCols > 0) - { - printf("A result set with %d columns was produced\n", - (int)numResultCols); - } - break; - - case SQL_NO_DATA: - // All results have been processed. We are done. - // - goto exit; - - case SQL_NEED_DATA: - case SQL_INVALID_HANDLE: - case SQL_STILL_EXECUTING: - default: - successDetected = false; - printf("Unexpected SQLExec result %d\n", rc); - goto exit; - } - rc = SQLMoreResults(hstmt); - } + PARMS* parms = (PARMS*)input; + + SQLWCHAR* pSQLText; // the command being executed. + bool successDetected = false; + + // ODBC handles + // + SQLHENV henv = nullptr; + SQLHDBC hdbc = nullptr; + SQLHSTMT hstmt = nullptr; + + WCHAR sqlCommand[1024]; + SQLWCHAR connectString[200] = { 0 }; + + bool sentSQL = false; + int rc; + + #define MAX_CONN_OUT 1024 + SQLWCHAR szOutConn[MAX_CONN_OUT] = { 0 }; + SQLSMALLINT cbOutConn; + + + // Generate the command to execute + // + swprintf_s(sqlCommand, L"%ls DATABASE [%ls] %ls VIRTUAL_DEVICE='%ls' WITH SNAPSHOT", + parms->doBackup ? L"BACKUP" : L"RESTORE", + parms->pDbName, + parms->doBackup ? L"TO" : L"FROM", + parms->pVdsName); + + // Initialize the ODBC environment. + // + if (SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR) + goto exit; + + // This is an ODBC v3 application + // + SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER); + + // Allocate a connection handle + // + if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) + { + printf("AllocHandle on DBC failed."); + goto exit; + } + + wcscpy_s(connectString, 200, L"DRIVER={SQL Server};Trusted_Connection=yes;SERVER=."); + if (parms->pInstanceName) + { + swprintf_s(connectString + wcslen(connectString), 200 - wcslen(connectString), L"\\%ls", parms->pInstanceName); + } + + printf("\n\nConnecting with: %ls\n", connectString); + + // Connect to the server using Trusted connection. + // Trusted connection uses integrated NT security. + // If you want to use mixed-mode Authentication, please set Trusted_Connection to no. + rc = SQLDriverConnect( + hdbc, + nullptr, // no diaglogs please + connectString, + SQL_NTS, + szOutConn, + MAX_CONN_OUT, + &cbOutConn, + SQL_DRIVER_NOPROMPT); + + if (rc == SQL_ERROR) + { + SQLWCHAR szSqlState[20]; + SQLINTEGER ssErr; + SQLWCHAR szErrorMsg[MAX_CONN_OUT]; + SQLSMALLINT cbErrorMsg; + + printf("Connect fails\n"); + + rc = SQLError( + henv, hdbc, SQL_NULL_HSTMT, + szSqlState, + &ssErr, + szErrorMsg, + MAX_CONN_OUT, + &cbErrorMsg); + + printf("msg=%ls\n", szErrorMsg); + + goto exit; + } + + // Get a statement handle + // + if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) + { + printf("Failed to get statement handle\n"); + + ProcessMessages(SQL_HANDLE_DBC, hdbc, true, nullptr); + goto exit; + } + + // Execute the SQL + // + printf("\n\nExecuting SQL: %ls\n", sqlCommand); + + pSQLText = sqlCommand; + + rc = SQLExecDirect(hstmt, pSQLText, SQL_NTS); + + // Extract all the resulting messages + // + + SQLSMALLINT numResultCols; + while (1) + { + switch (rc) + { + case SQL_ERROR: + successDetected = false; + ProcessMessages(SQL_HANDLE_STMT, hstmt, true, &successDetected); + if (!successDetected) + { + printf("Errors resulted in failure of the command\n"); + goto exit; + } + printf("Errors were encountered but the command was able to recover and successfully complete.\n"); + break; + + case SQL_SUCCESS_WITH_INFO: + ProcessMessages(SQL_HANDLE_STMT, hstmt, TRUE, NULL); + // fall through + + case SQL_SUCCESS: + successDetected = true; + + numResultCols = 0; + SQLNumResultCols(hstmt, &numResultCols); + if (numResultCols > 0) + { + printf("A result set with %d columns was produced\n", + (int)numResultCols); + } + break; + + case SQL_NO_DATA: + // All results have been processed. We are done. + // + goto exit; + + case SQL_NEED_DATA: + case SQL_INVALID_HANDLE: + case SQL_STILL_EXECUTING: + default: + successDetected = false; + printf("Unexpected SQLExec result %d\n", rc); + goto exit; + } + rc = SQLMoreResults(hstmt); + } exit: - // Release the ODBC resources. - // - if (hstmt != nullptr) - { - SQLFreeHandle(SQL_HANDLE_STMT, hstmt); - hstmt = nullptr; - } - - if (hdbc != nullptr) - { - SQLDisconnect(hdbc); - SQLFreeHandle(SQL_HANDLE_DBC, hdbc); - hdbc = nullptr; - } - - if (henv != nullptr) - { - SQLFreeHandle(SQL_HANDLE_ENV, henv); - henv = nullptr; - } - - return successDetected; + // Release the ODBC resources. + // + if (hstmt != nullptr) + { + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + hstmt = nullptr; + } + + if (hdbc != nullptr) + { + SQLDisconnect(hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + hdbc = nullptr; + } + + if (henv != nullptr) + { + SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = nullptr; + } + + return successDetected; } @@ -589,46 +589,46 @@ SQLRoutine(void* input) // HANDLE execSQL(bool doBackup, WCHAR* pInstanceName, WCHAR* pDbName, WCHAR* pVDName) { - unsigned int threadId; - HANDLE hThread; - static PARMS parms; // yucky, but only a single command is used.... - - parms.doBackup = doBackup; - parms.pDbName = pDbName; - parms.pInstanceName = pInstanceName; - parms.pVdsName = pVDName; - - hThread = (HANDLE)_beginthreadex( - nullptr, 0, SQLRoutine, (void*)&parms, 0, &threadId); - if (hThread == nullptr) - { - printf("Failed to create thread. errno is %d\n", errno); - } - return hThread; + unsigned int threadId; + HANDLE hThread; + static PARMS parms; // yucky, but only a single command is used.... + + parms.doBackup = doBackup; + parms.pDbName = pDbName; + parms.pInstanceName = pInstanceName; + parms.pVdsName = pVDName; + + hThread = (HANDLE)_beginthreadex( + nullptr, 0, SQLRoutine, (void*)&parms, 0, &threadId); + if (hThread == nullptr) + { + printf("Failed to create thread. errno is %d\n", errno); + } + return hThread; } //------------------------------------------------------------ // // checkSQL: Wait for the T-SQL to complete, -// returns TRUE if statement successfully executed. +// returns TRUE if statement successfully executed. // bool checkSQL(HANDLE hThread) { - if (hThread == nullptr) - return false; - - DWORD rc = WaitForSingleObject(hThread, INFINITE); - if (rc != WAIT_OBJECT_0) - { - printf("checkSQL failed: %d\n", rc); - return false; - } - if (!GetExitCodeThread(hThread, &rc)) - { - printf("failed to get exit code: %d\n", GetLastError()); - return false; - } - return rc == true; + if (hThread == nullptr) + return false; + + DWORD rc = WaitForSingleObject(hThread, INFINITE); + if (rc != WAIT_OBJECT_0) + { + printf("checkSQL failed: %d\n", rc); + return false; + } + if (!GetExitCodeThread(hThread, &rc)) + { + printf("failed to get exit code: %d\n", GetLastError()); + return false; + } + return rc == true; } @@ -638,18 +638,18 @@ bool checkSQL(HANDLE hThread) // bool ynPrompt(const char* str) { - char line[256]; + char line[256]; - printf("\n\n%s\n", str); - fgets(line, sizeof(line), stdin); + printf("\n\n%s\n", str); + fgets(line, sizeof(line), stdin); - // Remove newline character if fgets reads in a newline. - size_t len = strlen(line); - if (len > 0 && line[len - 1] == '\n') { - line[len - 1] = '\0'; - } + // Remove newline character if fgets reads in a newline. + size_t len = strlen(line); + if (len > 0 && line[len - 1] == '\n') { + line[len - 1] = '\0'; + } - return (line[0] == 'y' || line[0] == 'Y'); + return (line[0] == 'y' || line[0] == 'Y'); } //---------------------------------------------------------------------------------- @@ -659,170 +659,170 @@ bool ynPrompt(const char* str) // It simply reads or writes a file 'superbak.dmp' in the current directory. // void performTransfer( - IClientVirtualDeviceSet2* iVds, - IClientVirtualDevice* vd, - int backup) + IClientVirtualDeviceSet2* iVds, + IClientVirtualDevice* vd, + int backup) { - FILE* fh; - char* fname = (char*)"snapshot.dmp"; - VDC_Command* cmd; - DWORD completionCode; - DWORD bytesTransferred; - HRESULT hr; - - errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); - if (error != 0) - { - printf("Failed to open: %s\n", fname); - return; - } - - while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) - { - bytesTransferred = 0; - switch (cmd->commandCode) - { - case VDC_Read: - bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - completionCode = ERROR_SUCCESS; - else - // assume failure is eof - completionCode = ERROR_HANDLE_EOF; - break; - - case VDC_Write: - bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); - if (bytesTransferred == cmd->size) - { - completionCode = ERROR_SUCCESS; - } - else - // assume failure is disk full - completionCode = ERROR_DISK_FULL; - break; - - case VDC_Flush: - fflush(fh); - completionCode = ERROR_SUCCESS; - break; - - case VDC_ClearError: - completionCode = ERROR_SUCCESS; - break; - - case VDC_PrepareToFreeze: - printf("\n*** SQL Server is prepared to freeze the database now ***\n"); - printf("At this point the application can perform any final coordination activities.\n"); - - while (!ynPrompt("Are you ready to freeze the database?")) - { - if (ynPrompt("Do you want to abort?")) - { - iVds->SignalAbort(); - return; - } - } - // Acknowledging this command results in a freeze of database writes. - // The server will then issue VDC_Write commands to record metadata - // about the frozen state. - // Then the VDC_Snapshot is issued. - // - completionCode = ERROR_SUCCESS; - break; - - case VDC_Snapshot: - // At this point the metadata is complete, so the - // output stream can be closed. Thus it is possible - // to include the metadata with the data of the snapshot. - // - fclose(fh); - fh = nullptr; - - printf("\n*** Make the snapshot now ***\n"); - - while (!ynPrompt("Did you complete the snapshot?")) - { - if (ynPrompt("Do you want to abort?")) - { - iVds->SignalAbort(); - return; - } - } - - // For clarity, we "unroll" the loop logic - // in the following block of code so you can - // easily see the sequence of operations. - // - - // Tell SQLServer that the snapshot is done. - // - completionCode = ERROR_SUCCESS; - hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); - if (FAILED(hr)) - { - printf("Completion Failed: x%X\n", hr); - return; - } - - // The only valid command will be a "close" request. - // - hr = vd->GetCommand(INFINITE, &cmd); - if (hr != VD_E_CLOSE) - { - printf("Unexpected snapshot termination: x%X\n", hr); - } - else - { - printf("SQLServer is aware that the snapshot is successful.\n"); - } - return; - - case VDC_MountSnapshot: - printf("\n*** Mount the snapshot now ***\n"); - - while (!ynPrompt("Did you complete the snapshot?")) - { - if (ynPrompt("Do you want to abort?")) - { - iVds->SignalAbort(); - return; - } - } - completionCode = ERROR_SUCCESS; - break; - - default: - // If command is unknown... - completionCode = ERROR_NOT_SUPPORTED; - } - - hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); - if (FAILED(hr)) - { - printf("Completion Failed: x%X\n", hr); - break; - } - } - - if (hr != VD_E_CLOSE) - { - printf("Unexpected termination: x%X\n", hr); - } - else - { - // As far as the data transfer is concerned, no - // errors occurred. The code which issues the SQL - // must determine if the backup/restore was - // really successful. - // - printf("Successfully completed data transfer.\n"); - } - - if (fh != nullptr) - { - fclose(fh); - } + FILE* fh; + char* fname = (char*)"snapshot.dmp"; + VDC_Command* cmd; + DWORD completionCode; + DWORD bytesTransferred; + HRESULT hr; + + errno_t error = fopen_s(&fh, fname, (backup) ? "wb" : "rb"); + if (error != 0) + { + printf("Failed to open: %s\n", fname); + return; + } + + while (SUCCEEDED(hr = vd->GetCommand(INFINITE, &cmd))) + { + bytesTransferred = 0; + switch (cmd->commandCode) + { + case VDC_Read: + bytesTransferred = fread(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + completionCode = ERROR_SUCCESS; + else + // assume failure is eof + completionCode = ERROR_HANDLE_EOF; + break; + + case VDC_Write: + bytesTransferred = fwrite(cmd->buffer, 1, cmd->size, fh); + if (bytesTransferred == cmd->size) + { + completionCode = ERROR_SUCCESS; + } + else + // assume failure is disk full + completionCode = ERROR_DISK_FULL; + break; + + case VDC_Flush: + fflush(fh); + completionCode = ERROR_SUCCESS; + break; + + case VDC_ClearError: + completionCode = ERROR_SUCCESS; + break; + + case VDC_PrepareToFreeze: + printf("\n*** SQL Server is prepared to freeze the database now ***\n"); + printf("At this point the application can perform any final coordination activities.\n"); + + while (!ynPrompt("Are you ready to freeze the database?")) + { + if (ynPrompt("Do you want to abort?")) + { + iVds->SignalAbort(); + return; + } + } + // Acknowledging this command results in a freeze of database writes. + // The server will then issue VDC_Write commands to record metadata + // about the frozen state. + // Then the VDC_Snapshot is issued. + // + completionCode = ERROR_SUCCESS; + break; + + case VDC_Snapshot: + // At this point the metadata is complete, so the + // output stream can be closed. Thus it is possible + // to include the metadata with the data of the snapshot. + // + fclose(fh); + fh = nullptr; + + printf("\n*** Make the snapshot now ***\n"); + + while (!ynPrompt("Did you complete the snapshot?")) + { + if (ynPrompt("Do you want to abort?")) + { + iVds->SignalAbort(); + return; + } + } + + // For clarity, we "unroll" the loop logic + // in the following block of code so you can + // easily see the sequence of operations. + // + + // Tell SQLServer that the snapshot is done. + // + completionCode = ERROR_SUCCESS; + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + return; + } + + // The only valid command will be a "close" request. + // + hr = vd->GetCommand(INFINITE, &cmd); + if (hr != VD_E_CLOSE) + { + printf("Unexpected snapshot termination: x%X\n", hr); + } + else + { + printf("SQLServer is aware that the snapshot is successful.\n"); + } + return; + + case VDC_MountSnapshot: + printf("\n*** Mount the snapshot now ***\n"); + + while (!ynPrompt("Did you complete the snapshot?")) + { + if (ynPrompt("Do you want to abort?")) + { + iVds->SignalAbort(); + return; + } + } + completionCode = ERROR_SUCCESS; + break; + + default: + // If command is unknown... + completionCode = ERROR_NOT_SUPPORTED; + } + + hr = vd->CompleteCommand(cmd, completionCode, bytesTransferred, 0); + if (FAILED(hr)) + { + printf("Completion Failed: x%X\n", hr); + break; + } + } + + if (hr != VD_E_CLOSE) + { + printf("Unexpected termination: x%X\n", hr); + } + else + { + // As far as the data transfer is concerned, no + // errors occurred. The code which issues the SQL + // must determine if the backup/restore was + // really successful. + // + printf("Successfully completed data transfer.\n"); + } + + if (fh != nullptr) + { + fclose(fh); + } } From 1ab5906816e0203abf244eaf686fbc1b6fb15dbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 23:48:30 +0000 Subject: [PATCH 051/159] Bump braces Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 5dc1f9f1f1..3a44a26a01 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -3885,11 +3885,21 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" + }, + "dependencies": { + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "requires": { + "to-regex-range": "^5.0.1" + } + } } }, "browser-process-hrtime": { @@ -6098,14 +6108,6 @@ "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, "finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", From d17352781f22d9c1d9968ef29f385fc8269b4059 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Mon, 24 Jun 2024 16:21:09 -0700 Subject: [PATCH 052/159] Updated read.me --- .../activate-pcore-license/README.md | 47 ++----------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index edc77eeb9b..67334113c8 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -3,7 +3,7 @@ services: Azure SQL platforms: Azure author: anosov1960 ms.author: sashan -ms.date: 06/12/2024 +ms.date: 06/24/2024 --- # Overview @@ -21,47 +21,7 @@ Your RBAC role must include the following permissions: - Microsoft.Resources/subscriptions/resourceGroups/read - Microsoft.Support/supporttickets/write -# Launching the script - -The script accepts the following command line parameters: - -| **Parameter**                                         | **Value**                                                                       | **Description** | -|:--|:--|:--| -|-LicenseId| License resource URI | -|-UseInRunbook| \$True or \$False (default) | Optional: must be $True when executed as a Runbook| - - -## Example - -The following command activate the license - -```PowerShell -.\activate-pcore-license.ps1 -LicenseID -``` - -# Running the script using Cloud Shell - -To run the script in the Cloud Shell, use the following steps: - -1. Launch the [Cloud Shell](https://shell.azure.com/). For details, read [PowerShell in Cloud Shell](https://aka.ms/pscloudshell/docs). - -2. Upload the script to the shell using the following command: - - ```console - curl https://raw.githubusercontent.com/anosov1960/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md -o activate-pcore-license.ps1 - ``` - -3. Run the script with a set of parameters that reflect your desired configuration. - - ```console - .\activate-pcore-license.ps1 -licenseID - ``` - -> [!NOTE] -> - To paste the commands into the shell, use `Ctrl-Shift-V` on Windows or `Cmd-v` on MacOS. -> - The `curl` command will copy the script directly to the home folder associated with your Cloud Shell session. - -# Running the script as a Azure runbook +# 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. @@ -73,10 +33,9 @@ curl https://raw.githubusercontent.com/anosov1960/sql-server-samples/master/samp 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 with the desired frequency of runs and the expiration time. +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 - - USEINRUNBOOKS. Select True to activate the logic that authenticates the runbook using the *Azure Run As Account*. 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) From ab587b593f58b4fad4ec1cb92f2d873cd84c6c66 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Mon, 24 Jun 2024 16:24:24 -0700 Subject: [PATCH 053/159] Updated URL for curl --- .../activate-pcore-license/README.md | 2 +- .../activate-pcore-license/activate-pcore-license.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index 67334113c8..4fb20a449e 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -27,7 +27,7 @@ You can scahedule to run the the command as a runbook. To set it up using Azure 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/anosov1960/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md -o activate-pcore-license.ps1 +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. diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index ac230f79f4..c0fa4e9350 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -7,7 +7,7 @@ .NOTES AUTHOR: Alexander (Sasha) Nosov - LASTEDIT: June 15, 2024 + LASTEDIT: June 24, 2024 #> param ( From 783c14406bba99b17e70d0097b6846ed5d4e8cb4 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Mon, 24 Jun 2024 17:47:15 -0700 Subject: [PATCH 054/159] Updated read.me --- .../activate-pcore-license/README.md | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index 4fb20a449e..51b08de574 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -29,13 +29,26 @@ You can scahedule to run the the command as a runbook. To set it up using Azure ```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. [Create a new automation account](https://ms.portal.azure.com/#create/Microsoft.AutomationAccount) or open an existing one. In the Advanced section, make sure that *System assigned identity* is selecetd. +1. In the **Process automation** group select **Runbooks** +1. Click on the *Import a runbook* tab and configure it: + * select the file you downloaded in Step 1 + * type in a name of the runbook + * select the typr as PowerShell + * select the runtime version 5.1 + * click **Import**. 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. Once the status changes to *Published* on the runbook blade, click on the *Link to schedule* button +1. Select *Link a schedule to your runbook* and click *+ Add a schedule* +1. Configure the schedule: + * type in the name of the schedule + * set the start time + * set *Recurrance* to Once + * click **Create** +1. In a separate browser window, open the Azure resource of your inactive licence, go to the *Settings* group, select *Properties* and copy the license ID (URI) to te clipboard. +1. Go back to *Schedule runbook page*, click on *Parameters and run settings* and paste the license ID value you copied to the clipboard. 1. Click **OK** to link to the schedule and **OK** again to create the job. +1. On the runbook Overview page, click to open a recent job that was completed right after the specified start time. +1. Click on the *Output* tab and notice the `Properties.activationState=Activated`. Your license is now active. For more information about the runbooks, see the [Runbook tutorial](https://docs.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual-powershell) From 7ee181f0be894eda13835293b5a5e7c529d6f676 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 25 Jun 2024 11:56:26 -0700 Subject: [PATCH 055/159] fixed sa typo --- .../activate-pcore-license/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index 51b08de574..07c9e4691e 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -34,7 +34,7 @@ curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/sampl 1. Click on the *Import a runbook* tab and configure it: * select the file you downloaded in Step 1 * type in a name of the runbook - * select the typr as PowerShell + * select the type as PowerShell * select the runtime version 5.1 * click **Import**. 1. When import is completed, click the *Publish* button. From 0eaf0690144e7ac9b2662d3bb1662f212bb06d83 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 25 Jun 2024 11:58:11 -0700 Subject: [PATCH 056/159] Fixed more typos --- .../activate-pcore-license/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md index 07c9e4691e..2ce4b9ac7c 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/README.md @@ -45,7 +45,7 @@ curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/sampl * set the start time * set *Recurrance* to Once * click **Create** -1. In a separate browser window, open the Azure resource of your inactive licence, go to the *Settings* group, select *Properties* and copy the license ID (URI) to te clipboard. +1. In a separate browser window, open the Azure resource of your inactive licence, go to the *Settings* group, select *Properties* and copy the license ID (URI) to the clipboard. 1. Go back to *Schedule runbook page*, click on *Parameters and run settings* and paste the license ID value you copied to the clipboard. 1. Click **OK** to link to the schedule and **OK** again to create the job. 1. On the runbook Overview page, click to open a recent job that was completed right after the specified start time. From 6d1372e920c9534039bf92dc476264862a09a55b Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 27 Jun 2024 14:06:31 -0700 Subject: [PATCH 057/159] Update activate-pcore-license.md --- .../activate-pcore-license/activate-pcore-license.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md index c0fa4e9350..cb4b28fb47 100644 --- a/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md +++ b/samples/manage/azure-arc-enabled-sql-server/activate-pcore-license/activate-pcore-license.md @@ -1,4 +1,4 @@ -<# +.<# .DESCRIPTION This runbook activates a SQL Server license using the Managed Identity The runbook accepts the following parameters: @@ -12,7 +12,7 @@ param ( [Parameter (Mandatory= $true)] - [string] $LicenseId, + [string] $LicenseId ) # From fd1d974a24e4d2881d924f3ff972cc7c25aefde1 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 3 Jul 2024 23:33:24 -0700 Subject: [PATCH 058/159] Update install-payg-sql-server.ps1 Added volume mounting and key extraction --- .../install-payg-sql-server.ps1 | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 6ff5d8f1f8..4bb0bddf94 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -14,13 +14,9 @@ param ( [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 + [string]$isoFolder ) # This function checks if the specified module is imported into the session and if not installes and/or imports it @@ -125,24 +121,38 @@ try { New-AzConnectedMachine -ResourceGroupName $AzureResourceGroupUri -Name $hostName -Location $AzureRegion - # Step 4: Automatically download installable media + # Step 4: Retrieve the product key - $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." - } + $keyFiles = Get-ChildItem $isoFolder -Filter "*.txt" + + foreach ($keyFile in $keyFiles) { + # Read each line from the file + Get-Content $keyFile | ForEach-Object { + if ($_ -match "(?i)$($SqlServerEdition)" -and $_ -match "[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*") { + # Extract the product key (including any following string after a space) + $productKey = [regex]::Match($_, '[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*').Value + # Strip any text after the product key + $productKey = $productKey -replace " .*$" + Write-Host "Found product key in $($keyFile.Name): $productKey" + } + } } # Step 5: Mount the ISO file as a volume - $volumeInfo = Mount-DiskImage -ImagePath $isoLocation -PassThru | Get-Volume + $isoFiles = Get-ChildItem $isoFolder -Filter "*.iso" + + foreach ($isoFile in $isoFiles) { + # Mount the ISO file + $mountResult = Mount-DiskImage -ImagePath $isoFile.FullName + $driveLetter = ($mountResult | Get-Volume).DriveLetter + $mountedIsoFile = $isoFile + Write-Host "ISO file $($isoFile.Name) mounted as drive $driveLetter" + break + } + # Step 6: Run unattended SQL Server setup from the mounted volume - $setupPath = ($volumeInfo.DriveLetter + ":\setup.exe") + $setupPath = ($driveLetter + ":\setup.exe") $argumentList = " /q /ACTION=Install @@ -154,7 +164,7 @@ try { /AGTSVCACCOUNT='$($SqlServerSvcAccount)' /AGTSVCPASSWORD='$($SqlServerSvcPassword)' /IACCEPTSQLSERVERLICENSETERMS - /PID='$($SqlServerProductKey)' + /PID='$($productKey)' /Edition='$($SqlServerEdition)' " if ($SqlServerInstanceName) { @@ -172,13 +182,10 @@ try { } 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: Dismount the ISO file after installation + Dismount-DiskImage -ImagePath $isoFolder + $mountedIsoFile - # Step 8: Display the status of the Azure resource for Arc-enabled SQL Server + # Step 9: Display the status of the Azure resource for Arc-enabled SQL Server $query = " resources | where type =~ 'microsoft.hybridcompute/machines' From 59de812fed041b2acd207a9574dc5c85da36f314 Mon Sep 17 00:00:00 2001 From: Alex Talarico <3521183+getalex@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:52:16 -0400 Subject: [PATCH 059/159] Updated handling of relative path references Updated GetSnkPath to set the target path based on source when folder structure is identical, assuming like for like relative folder structure. --- .../ssrs-migration-rss/ssrs_migration.rss | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss b/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss index 49164e10af..a733a7e0eb 100644 --- a/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss +++ b/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss @@ -16,19 +16,19 @@ ' 1) Download ssrs_migration.rss ' 2) Open a command prompt and navigate to the folder containing ssrs_migration.rss, for example c:\rss ' 3) Run the following command (in one line): -' rs.exe -i ssrs_migration.rss -e Mgmt2010 +' rs.exe -i ssrs_migration.rss -e Mgmt2010 ' -' -s SOURCE_URL 'URL of the source RS server. -' -u domain\username -p password 'Credentials for source server. OPTIONAL, default credentials are used if missing. -' -v st="SITE" 'Specifies SharePoint site, in case source server is in SharePoint integrated mode -' -v f="SOURCEFOLDER" 'Set to "/" for migrating everything, or to something like "/folder/subfolder" for partial migration. Everything within this folder will be copied. OPTIONAL, default is "/". +' -s SOURCE_URL 'URL of the source RS server. +' -u domain\username -p password 'Credentials for source server. OPTIONAL, default credentials are used if missing. +' -v st="SITE" 'Specifies SharePoint site, in case source server is in SharePoint integrated mode +' -v f="SOURCEFOLDER" 'Set to "/" for migrating everything, or to something like "/folder/subfolder" for partial migration. Everything within this folder will be copied. OPTIONAL, default is "/". ' -' -v ts="TARGET_URL" 'URL of the target RS server" -' -v tu="domain\username" -v tp="password" 'Credentials for target server. OPTIONAL, default credentials are used if missing. -' -v tst="SITE" 'Specifies SharePoint site, in case target server is in SharePoint integrated mode -' -v tf="TARGETFOLDER" 'Set to "/" for migrating into the root level, or to something like "/folder/subfolder" for copying into some folder, which must be already existing. Everything within "SOURCEFOLDER" will be copied into "TARGETFOLDER". OPTIONAL, default is "/". -' -v security= "True/False" 'If set to "False", destination catalog items will inherit security setting according to the settings of the target system. Default is false. -' -v logprefix="PREFIX" 'Prefix name to the output log file. +' -v ts="TARGET_URL" 'URL of the target RS server" +' -v tu="domain\username" -v tp="password" 'Credentials for target server. OPTIONAL, default credentials are used if missing. +' -v tst="SITE" 'Specifies SharePoint site, in case target server is in SharePoint integrated mode +' -v tf="TARGETFOLDER" 'Set to "/" for migrating into the root level, or to something like "/folder/subfolder" for copying into some folder, which must be already existing. Everything within "SOURCEFOLDER" will be copied into "TARGETFOLDER". OPTIONAL, default is "/". +' -v security= "True/False" 'If set to "False", destination catalog items will inherit security setting according to the settings of the target system. Default is false. +' -v logprefix="PREFIX" 'Prefix name to the output log file (default is MigrationLog.csv created from where script is run). ' ' Example: rs.exe -i ssrs_migration.rss -e Mgmt2010 -s http://server1/reportserver -v ts="http://server2/_vti_bin/reportserver" ' Example: rs.exe -i ssrs_migration.rss -e Mgmt2010 -s http://server1/reportserver -u domain1\user1 -p password1 -v f="/SOURCEFOLDER" -v ts="http://server2/_vti_bin/reportserver" -v tu="domain1\user2" -v tp="password2" -v tf="/TARGETFOLDER" @@ -1015,7 +1015,11 @@ Function GetSnkPath(srcPath As String) As String Dim snkPath As String = SnkFolder If Not srcPath = "" Then - snkPath = snkPath + IIf(SrcFolder = "/", srcPath, srcPath.Remove(0, SrcFolder.Length)) + If SrcFolder = SnkFolder Then ' exact relative folder paths assumed between source and target + snkPath = srcPath + Else + snkPath = snkPath + IIf(SrcFolder = "/", srcPath, srcPath.Remove(0, SrcFolder.Length)) + End If End If If snkPath.StartsWith("//") Then From d8a9c3d722cfb8a90e031917b52d275f0bb1b224 Mon Sep 17 00:00:00 2001 From: Alex Talarico <3521183+getalex@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:36:25 -0400 Subject: [PATCH 060/159] Added log entry on catalog item migration warnings Added a call to LogErrorToFile so that warnings are also captured in the output log file. --- .../reporting-services/ssrs-migration-rss/ssrs_migration.rss | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss b/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss index 49164e10af..81f2f3f3a0 100644 --- a/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss +++ b/samples/features/reporting-services/ssrs-migration-rss/ssrs_migration.rss @@ -579,6 +579,7 @@ Function MigrateCatalogItem(srcItem As CatalogItem) As CatalogItem For Each w As Warning In warnings If w.Code <> "rsDataSourceReferenceNotPublished" And w.Code <> "rsDataSetReferenceNotPublished" Then 'This should be fine after re-linking Console.WriteLine("Warning: " + w.Message) + LogErrorToFile("CATALOGITEM", "Warning: " + srcItem.Path, w.Message) End If Next Console.ResetColor() From df79461986a0a1e5e2d18ec8e6bc61f73dc1d58a Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Fri, 5 Jul 2024 17:05:23 -0700 Subject: [PATCH 061/159] Modified to remove downloading the image file --- .../install-payg-sql-server.ps1 | 186 ++++++++++++------ 1 file changed, 131 insertions(+), 55 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 4bb0bddf94..7f78eda05d 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -2,7 +2,7 @@ param ( [Parameter (Mandatory=$true)] [string]$AzureSubscriptionId, [Parameter (Mandatory=$true)] - [string]$AzureResourceGroupUri, + [string]$AzureResourceGroup, [Parameter (Mandatory=$true)] [string]$AzureRegion, [Parameter (Mandatory=$false)] @@ -16,7 +16,9 @@ param ( [Parameter (Mandatory=$true)] [string]$SqlServerEdition, [Parameter (Mandatory=$true)] - [string]$isoFolder + [string]$IsoFolder, + [Parameter (Mandatory=$false)] + [string]$Proxy ) # This function checks if the specified module is imported into the session and if not installes and/or imports it @@ -49,7 +51,7 @@ function LoadModule # 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 + Install-Module -Name $name -Force -Scope CurrentUser try { Import-Module $name -ErrorAction SilentlyContinue @@ -75,7 +77,8 @@ function LoadModule try { - #Step 0: Ensure PS version and load missing Azure modules + write-host "==== Ensure PS version and load missing Azure modules ====" + # # Suppress warnings # @@ -89,41 +92,55 @@ try { "Az.ResourceGraph" ) $requiredModules | Foreach-Object {LoadModule $_} + + write-host "==== Check if setup.exe is already running and kill it if so ====" - # 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 + write-host "==== Log in to Azure ====" + + Connect-AzAccount | Out-Null $subscription = Get-AzSubscription -SubscriptionId $AzureSubscriptionId -ErrorAction SilentlyContinue if (-not $subscription) { Write-Error "Azure subscription with ID '$AzureSubscriptionId' does not exist." exit } + Set-AzContext -Subscription $AzureSubscriptionId | Out-Null - # Step 2: Block auto-onboarding to Arc by tagging the resource group - $existingResourceGroup = Get-AzResourceGroup -Name $AzureResourceGroupUri -ErrorAction SilentlyContinue + write-host "==== Block auto-onboarding to Arc ====" + + $existingResourceGroup = Get-AzResourceGroup -Name $AzureResourceGroup -ErrorAction SilentlyContinue if ($existingResourceGroup) { - Write-Host "Resource group '$AzureResourceGroupUri' exists." + $tags = @{"ArcOnboarding" = "Blocked"} + Set-AzResourceGroup -Name $AzureResourceGroup -Tag $tags | Out-Null } else { - Write-Error "Resource group '$AzureResourceGroupUri' does not exist." + Write-Error "Resource group '$AzureResourceGroup' 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 + write-host "==== Mount the ISO file as a volume ====" - New-AzConnectedMachine -ResourceGroupName $AzureResourceGroupUri -Name $hostName -Location $AzureRegion + $isoFiles = Get-ChildItem $IsoFolder -Filter "*.iso" - # Step 4: Retrieve the product key + foreach ($isoFile in $isoFiles) { + # Mount the ISO file + $imagePath = $isoFile.FullName + $mountResult = Mount-DiskImage -ImagePath $imagePath + $driveLetter = ($mountResult | Get-Volume).DriveLetter + Write-Host "ISO file $($isoFile.Name) mounted as drive $($driveLetter):" + break + } + + + write-host "==== Run unattended SQL Server setup from the mounted volume ====" + + # Retrieve the product key - $keyFiles = Get-ChildItem $isoFolder -Filter "*.txt" + $keyFiles = Get-ChildItem $IsoFolder -Filter "*.txt" foreach ($keyFile in $keyFiles) { # Read each line from the file @@ -133,25 +150,12 @@ try { $productKey = [regex]::Match($_, '[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*').Value # Strip any text after the product key $productKey = $productKey -replace " .*$" - Write-Host "Found product key in $($keyFile.Name): $productKey" } } } - # Step 5: Mount the ISO file as a volume - $isoFiles = Get-ChildItem $isoFolder -Filter "*.iso" - - foreach ($isoFile in $isoFiles) { - # Mount the ISO file - $mountResult = Mount-DiskImage -ImagePath $isoFile.FullName - $driveLetter = ($mountResult | Get-Volume).DriveLetter - $mountedIsoFile = $isoFile - Write-Host "ISO file $($isoFile.Name) mounted as drive $driveLetter" - break - } + # Launch setup - - # Step 6: Run unattended SQL Server setup from the mounted volume $setupPath = ($driveLetter + ":\setup.exe") $argumentList = " /q @@ -172,45 +176,117 @@ try { } Start-Process -FilePath $setupPath -ArgumentList $argumentList + + write-host "==== Dismount the ISO file after installation ====" + + Dismount-DiskImage -ImagePath $imagePath | Out-Null + + write-host "==== Onboard the VM to Azure Arc ====" + + $hostName = (Get-WmiObject Win32_ComputerSystem).Name + + if ($Proxy) { + Connect-AzConnectedMachine -ResourceGroupName $AzureResourceGroup -Name $hostName -Location $AzureRegion -Proxi $Proxy | Out-Null + } else { + Connect-AzConnectedMachine -ResourceGroupName $AzureResourceGroup -Name $hostName -Location $AzureRegion | Out-Null + } + + write-host "==== Install SQL Arc extension with LT=PAYG and upgrade to the latest version ====" - # Step 7: Install SQL Arc extension with LT=PAYG + $extensionName = "WindowsAgent.SqlServer" $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 + New-AzConnectedMachineExtension -ResourceGroupName $AzureResourceGroup -MachineName $hostName -Name "Microsoft.AzureData" -Publisher "Microsoft.AzureData" -ExtensionType "WindowsAgent.SqlServer" -Location $AzureRegion -Settings $Settings -EnableAutomaticUpgrade - # Step 8: Dismount the ISO file after installation - Dismount-DiskImage -ImagePath $isoFolder + $mountedIsoFile + # Step 10: Display the status of the Azure resource for Arc-enabled SQL Server + write-host "==== Display the status of the billable Arc-enabled host ====" - # Step 9: 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 + | where type =~ 'Microsoft.HybridCompute/machines' + | where subscriptionId =~ '$($AzureSubscriptionId)' + | where resourceGroup =~ '$($AzureResourceGroup)' + | extend status = tostring(properties.status) + | where status =~ 'Connected' + | extend machineID = tolower(id) + | extend VMbyManufacturer = toboolean(iff(properties.detectedProperties.manufacturer in ( + 'VMware', + 'QEMU', + 'Amazon EC2', + 'OpenStack', + 'Hetzner', + 'Mission Critical Cloud', + 'DigitalOcean', + 'UpCloud', + 'oVirt', + 'Alibaba', + 'KubeVirt', + 'Parallels', + 'XEN' + ), 1, 0)) + | extend VMbyModel = toboolean(iff(properties.detectedProperties.model in ( + 'OpenStack', + 'Droplet', + 'oVirt', + 'Hypervisor', + 'Virtual', + 'BHYVE', + 'KVM' + ), 1, 0)) + | extend GoogleVM = toboolean(iff((properties.detectedProperties.manufacturer =~ 'Google') and (properties.detectedProperties.model =~ 'Google Compute Engine'), 1, 0)) + | extend NutanixVM = toboolean(iff((properties.detectedProperties.manufacturer =~ 'Nutanix') and (properties.detectedProperties.model =~ 'AHV'), 1, 0)) + | extend MicrosoftVM = toboolean(iff((properties.detectedProperties.manufacturer =~ 'Microsoft Corporation') and (properties.detectedProperties.model =~ 'Virtual Machine'), 1, 0)) + | extend billableCores = iff(VMbyManufacturer or VMbyModel or GoogleVM or NutanixVM or MicrosoftVM, properties.detectedProperties.logicalCoreCount, properties.detectedProperties.coreCount) + | join kind = leftouter // Join Extension + ( + resources + | where type =~ 'Microsoft.HybridCompute/machines/extensions' + | where name == 'WindowsAgent.SqlServer' or name == 'LinuxAgent.SqlServer' + | extend extMachineID = substring(id, 0, indexof(id, '/extensions')) + | extend extensionId = id + ) + on `$left.id == `$right.extMachineID + | join kind = inner // Join SQL Arc + ( + resources + | where type =~ 'microsoft.azurearcdata/sqlserverinstances' + | extend sqlVersion = tostring(properties.version) + | extend sqlEdition = tostring(properties.edition) + | extend is_Enterprise = toint(iff(sqlEdition == 'Enterprise', 1, 0)) + | extend sqlStatus = tostring(properties.status) + | extend licenseType = tostring(properties.licenseType) + | where sqlEdition in ('Enterprise', 'Standard') + | where licenseType !~ 'HADR' + | where sqlStatus =~ 'Connected' + | extend ArcServer = tolower(tostring(properties.containerResourceId)) + | order by sqlEdition + ) + on `$left.machineID == `$right.ArcServer + | where isnotnull(extensionId) + | summarize Edition = iff(sum(is_Enterprise) > 0, 'Enterprise', 'Standard') by machineID + , name + , resourceGroup + , subscriptionId + , Model = tostring(properties.detectedProperties.model) + , Manufacturer = tostring(properties.detectedProperties.manufacturer) + , License_Type = tostring(properties1.settings.LicenseType) + , OS = tostring(properties.osName) + , Uses_UV = tostring(properties1.settings.UsePhysicalCoreLicense.IsApplied) + , Cores = tostring(billableCores) + , Version = sqlVersion + | project-away machineID + | order by Edition, name asc " - Search-AzGraph -Query "$($query)" + 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." + Write-Host "==== Installation completed ====" } From 29be53596f8d988f7e32f4f38a5b951c60a5bd81 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Sat, 6 Jul 2024 09:08:23 -0700 Subject: [PATCH 062/159] Make disk mount idempotant --- .../install-payg-sql-server.ps1 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 7f78eda05d..6f8e40c5cf 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -128,8 +128,12 @@ try { foreach ($isoFile in $isoFiles) { # Mount the ISO file - $imagePath = $isoFile.FullName - $mountResult = Mount-DiskImage -ImagePath $imagePath + $imagePath = $isoFile.FullName + if (!(Get-DiskImage -ImagePath $imagePath).Attached) { + $mountResult = Mount-DiskImage -ImagePath $imagePath + } else { + $mountResult = Get-DiskImage -ImagePath $imagePath + } $driveLetter = ($mountResult | Get-Volume).DriveLetter Write-Host "ISO file $($isoFile.Name) mounted as drive $($driveLetter):" break @@ -186,9 +190,9 @@ try { $hostName = (Get-WmiObject Win32_ComputerSystem).Name if ($Proxy) { - Connect-AzConnectedMachine -ResourceGroupName $AzureResourceGroup -Name $hostName -Location $AzureRegion -Proxi $Proxy | Out-Null + Connect-AzConnectedMachine -ResourceGroupName $AzureResourceGroup -Name $hostName -Location $AzureRegion -Proxi $Proxy | Out-Null } else { - Connect-AzConnectedMachine -ResourceGroupName $AzureResourceGroup -Name $hostName -Location $AzureRegion | Out-Null + Connect-AzConnectedMachine -ResourceGroupName $AzureResourceGroup -Name $hostName -Location $AzureRegion | Out-Null } write-host "==== Install SQL Arc extension with LT=PAYG and upgrade to the latest version ====" From 80e7b2757f2681a56b70bab6da39e3dc4346a270 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Sat, 6 Jul 2024 09:51:19 -0700 Subject: [PATCH 063/159] Removed /Edition --- .../install-payg-sql-server.ps1 | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 6f8e40c5cf..b072f3850c 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -163,17 +163,16 @@ try { $setupPath = ($driveLetter + ":\setup.exe") $argumentList = " /q - /ACTION=Install + /ACTION=`"Install`" /FEATURES=SQL /INSTANCEDIR=C:\SQL - /SQLSYSADMINACCOUNTS='$($SqlServerAdminAccounts)' - /SQLSVCACCOUNT='$($SqlServerSvcAccount)' - /SQLSVCPASSWORD='$($SqlServerSvcPassword)' - /AGTSVCACCOUNT='$($SqlServerSvcAccount)' - /AGTSVCPASSWORD='$($SqlServerSvcPassword)' + /SQLSYSADMINACCOUNTS=`"$($SqlServerAdminAccounts)`" + /SQLSVCACCOUNT=`"$($SqlServerSvcAccount)`" + /SQLSVCPASSWORD=`"$($SqlServerSvcPassword)`" + /AGTSVCACCOUNT=`"$($SqlServerSvcAccount)`" + /AGTSVCPASSWORD=`"$($SqlServerSvcPassword)`" /IACCEPTSQLSERVERLICENSETERMS - /PID='$($productKey)' - /Edition='$($SqlServerEdition)' + /PID=`"$($productKey)`" " if ($SqlServerInstanceName) { $argumentList += "/INSTANCENAME='$($SqlServerInstanceName)'" From 39346584cf5ac10dc5ed704c80d4e8de5a12454f Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 9 Jul 2024 18:05:09 -0700 Subject: [PATCH 064/159] Modified to support prePIDed .iso --- .../install-payg-sql-server.ps1 | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index b072f3850c..7c9aece867 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -7,14 +7,16 @@ param ( [string]$AzureRegion, [Parameter (Mandatory=$false)] [string]$SqlServerInstanceName, - [Parameter (Mandatory=$true)] - [string]$SqlServerAdminAccounts, - [Parameter (Mandatory=$true)] - [string]$SqlServerSvcAccount, - [Parameter (Mandatory=$true)] + [Parameter (Mandatory=$false)] + [string]$SqlServerAdminAccounts = "BUILTIN\ADMINISTRATORS", + [Parameter (Mandatory=$false)] + [string]$SqlServerSvcAccount = "NT AUTHORITY\SYSTEM", + [Parameter (Mandatory=$false)] [string]$SqlServerSvcPassword, + [Parameter (Mandatory=$false)] + [string]$AgtServerSvcAccount = "NT AUTHORITY\NETWORK SERVICE", [Parameter (Mandatory=$true)] - [string]$SqlServerEdition, + [string]$AgtServerEdition, [Parameter (Mandatory=$true)] [string]$IsoFolder, [Parameter (Mandatory=$false)] @@ -124,11 +126,31 @@ try { write-host "==== Mount the ISO file as a volume ====" + # Retrieve the product key if any + + $keyFiles = Get-ChildItem $IsoFolder -Filter "*.txt" + + foreach ($keyFile in $keyFiles) { + # Read each line from the file + Get-Content $keyFile | ForEach-Object { + if ($_ -match "(?i)$($SqlServerEdition)" -and $_ -match "[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*") { + # Extract the product key (including any following string after a space) + $productKey = [regex]::Match($_, '[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*').Value + # Strip any text after the product key + $productKey = $productKey -replace " .*$" + } + } + } + $isoFiles = Get-ChildItem $IsoFolder -Filter "*.iso" + # Pick the .iso file and mount + + $noKeylist = "SQLFULL_ENU_ENTVL", "SQLFULL_ENU_STDVL", "SQLServer2022-x64-ENU-Ent", "SQLServer2022-x64-ENU-Std" + foreach ($isoFile in $isoFiles) { - # Mount the ISO file - $imagePath = $isoFile.FullName + $imagePath = $isoFile.FullName + if ($noKeylist -contains $isoFile.Name) {$productKey = ""} if (!(Get-DiskImage -ImagePath $imagePath).Attached) { $mountResult = Mount-DiskImage -ImagePath $imagePath } else { @@ -142,21 +164,7 @@ try { write-host "==== Run unattended SQL Server setup from the mounted volume ====" - # Retrieve the product key - - $keyFiles = Get-ChildItem $IsoFolder -Filter "*.txt" - - foreach ($keyFile in $keyFiles) { - # Read each line from the file - Get-Content $keyFile | ForEach-Object { - if ($_ -match "(?i)$($SqlServerEdition)" -and $_ -match "[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*") { - # Extract the product key (including any following string after a space) - $productKey = [regex]::Match($_, '[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*').Value - # Strip any text after the product key - $productKey = $productKey -replace " .*$" - } - } - } + # Launch setup @@ -168,16 +176,26 @@ try { /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS=`"$($SqlServerAdminAccounts)`" /SQLSVCACCOUNT=`"$($SqlServerSvcAccount)`" - /SQLSVCPASSWORD=`"$($SqlServerSvcPassword)`" /AGTSVCACCOUNT=`"$($SqlServerSvcAccount)`" - /AGTSVCPASSWORD=`"$($SqlServerSvcPassword)`" /IACCEPTSQLSERVERLICENSETERMS - /PID=`"$($productKey)`" " - if ($SqlServerInstanceName) { - $argumentList += "/INSTANCENAME='$($SqlServerInstanceName)'" + if ($SqlServerSvcPassword) { + $argumentList += " /SQLSVCPASSWORD=`"$($SqlServerSvcPassword)`" + " } - + if ($AgtServerSvcPassword) { + $argumentList += " /SQLAGTPASSWORD=`"$($AgtServerSvcPassword)`" + " + } + if ($SqlServerInstanceName) { + $argumentList += " /INSTANCENAME=`"$($SqlServerInstanceName) `" + " + } + if ($productKey) { + $argumentList += " /PID=`"$($productKey)`" + " + } + $argumentList Start-Process -FilePath $setupPath -ArgumentList $argumentList write-host "==== Dismount the ISO file after installation ====" From 2c0c27ecc7cc76950320ee2113b55094d4cce6c3 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 9 Jul 2024 18:17:35 -0700 Subject: [PATCH 065/159] Removed Edition parameter --- .../install-payg-sql-server/install-payg-sql-server.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 7c9aece867..769bfd4d9f 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -16,8 +16,6 @@ param ( [Parameter (Mandatory=$false)] [string]$AgtServerSvcAccount = "NT AUTHORITY\NETWORK SERVICE", [Parameter (Mandatory=$true)] - [string]$AgtServerEdition, - [Parameter (Mandatory=$true)] [string]$IsoFolder, [Parameter (Mandatory=$false)] [string]$Proxy @@ -195,7 +193,7 @@ try { $argumentList += " /PID=`"$($productKey)`" " } - $argumentList + Start-Process -FilePath $setupPath -ArgumentList $argumentList write-host "==== Dismount the ISO file after installation ====" From 083232599d0cce05414f6415be51ecf0d2922177 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 9 Jul 2024 18:52:14 -0700 Subject: [PATCH 066/159] Added Az.Resources module --- .../install-payg-sql-server/install-payg-sql-server.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 769bfd4d9f..bd91c8ed49 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -88,6 +88,7 @@ try { $requiredModules = @( "AzureAD", "Az.Accounts", + "Az.Resources", "Az.ConnectedMachine", "Az.ResourceGraph" ) From 6c61562967c765647e4f2f2aea97a5df8d07b1b6 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 9 Jul 2024 19:00:07 -0700 Subject: [PATCH 067/159] Fixed a typo --- .../install-payg-sql-server/install-payg-sql-server.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index bd91c8ed49..9373ae2ead 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -145,7 +145,7 @@ try { # Pick the .iso file and mount - $noKeylist = "SQLFULL_ENU_ENTVL", "SQLFULL_ENU_STDVL", "SQLServer2022-x64-ENU-Ent", "SQLServer2022-x64-ENU-Std" + $noKeylist = "SQLFULL_ENU_ENTVL.iso", "SQLFULL_ENU_STDVL.iso", "SQLServer2022-x64-ENU-Ent.iso", "SQLServer2022-x64-ENU-Std.iso" foreach ($isoFile in $isoFiles) { $imagePath = $isoFile.FullName @@ -175,7 +175,7 @@ try { /INSTANCEDIR=C:\SQL /SQLSYSADMINACCOUNTS=`"$($SqlServerAdminAccounts)`" /SQLSVCACCOUNT=`"$($SqlServerSvcAccount)`" - /AGTSVCACCOUNT=`"$($SqlServerSvcAccount)`" + /AGTSVCACCOUNT=`"$($AgtServerSvcAccount)`" /IACCEPTSQLSERVERLICENSETERMS " if ($SqlServerSvcPassword) { From bda5076491bf50f14c679ae5caf006df73b20827 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 17:13:55 +0000 Subject: [PATCH 068/159] Bump com.azure:azure-identity Bumps [com.azure:azure-identity](https://github.com/Azure/azure-sdk-for-java) from 1.0.4 to 1.12.2. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-sdk-bom_1.0.4...azure-identity_1.12.2) --- updated-dependencies: - dependency-name: com.azure:azure-identity dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../java/Unix-based/AzureSqlSample/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlSample/pom.xml b/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlSample/pom.xml index 38e3a77e96..cbf298da03 100644 --- a/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlSample/pom.xml +++ b/samples/tutorials/AzureSqlGettingStartedSamples/java/Unix-based/AzureSqlSample/pom.xml @@ -42,7 +42,7 @@ com.azure azure-identity - 1.0.4 + 1.12.2 org.slf4j From 9d46ee3be734c9859a81ab0b1738786554322683 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 17:15:16 +0000 Subject: [PATCH 069/159] Bump ws, engine.io and engine.io-client Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/engine.io) and [engine.io-client](https://github.com/socketio/engine.io-client). These dependencies needed to be updated together. Updates `ws` from 7.4.6 to 7.5.10 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/7.4.6...7.5.10) Updates `engine.io` from 3.6.1 to 3.6.2 - [Release notes](https://github.com/socketio/engine.io/releases) - [Changelog](https://github.com/socketio/engine.io/blob/3.6.2/CHANGELOG.md) - [Commits](https://github.com/socketio/engine.io/compare/3.6.1...3.6.2) Updates `engine.io-client` from 3.5.3 to 3.5.4 - [Release notes](https://github.com/socketio/engine.io-client/releases) - [Changelog](https://github.com/socketio/engine.io-client/blob/3.5.4/CHANGELOG.md) - [Commits](https://github.com/socketio/engine.io-client/compare/3.5.3...3.5.4) --- updated-dependencies: - dependency-name: ws dependency-type: indirect - dependency-name: engine.io dependency-type: indirect - dependency-name: engine.io-client dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../lib/webcomponentsjs/package-lock.json | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json index 008b8bcec6..5867327605 100644 --- a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json +++ b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json @@ -4014,6 +4014,12 @@ "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", "dev": true }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -4645,9 +4651,9 @@ } }, "engine.io": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.6.1.tgz", - "integrity": "sha512-dfs8EVg/i7QjFsXxn7cCRQ+Wai1G1TlEvHhdYEi80fxn5R1vZ2K661O6v/rezj1FP234SZ14r9CmJke99iYDGg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.6.2.tgz", + "integrity": "sha512-C4JjGQZLY3kWlIDx0BQNKizbrfpb7NahxDztGdN5jrPK2ghmXiNDN+E/t0JzDeNRZxPVaszxEng42Pmj27X/0w==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -4655,15 +4661,9 @@ "cookie": "~0.4.1", "debug": "~4.1.0", "engine.io-parser": "~2.2.0", - "ws": "~7.4.2" + "ws": "~7.5.10" }, "dependencies": { - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true - }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -4678,13 +4678,19 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true + }, + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true } } }, "engine.io-client": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.3.tgz", - "integrity": "sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.4.tgz", + "integrity": "sha512-ydc8uuMMDxC5KCKNJN3zZKYJk2sgyTuTZQ7Aj1DJSsLKAcizA/PzWivw8fZMIjJVBo2CJOYzntv4FSjY/Lr//g==", "dev": true, "requires": { "component-emitter": "~1.3.0", @@ -4695,9 +4701,17 @@ "indexof": "0.0.1", "parseqs": "0.0.6", "parseuri": "0.0.6", - "ws": "~7.4.2", + "ws": "~7.5.10", "xmlhttprequest-ssl": "~1.6.2", "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true + } } }, "engine.io-parser": { @@ -14373,12 +14387,6 @@ "signal-exit": "^3.0.2" } }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true - }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", From d9c1d1b437a0adc4d8edd21f6b7478eac41d2c00 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 12 Jul 2024 16:48:31 -0700 Subject: [PATCH 070/159] Update modify-license-type.ps1 --- .../modify-license-type/modify-license-type.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 8c7e8a3fe8..29906728d0 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -12,7 +12,7 @@ # -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group) # -MachineName [machine_name] (Optional. Limits the scope to a specific machine) # -LicenseType [license_type_value] (Optional. Sets the license type to the specified value) -# -EnabelESU [Yes or No] (Optional. Enables the ESU policy the value is "Yes" or disables it if the value is "No" +# -EnableESU [Yes or 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 chnahge 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 @@ -115,7 +115,7 @@ function LoadModule } catch { - write-host "The request to lload module $($name) failed with the following error:" + write-host "The request to load module $($name) failed with the following error:" write-host $_.Exception.Message $retVal = $false } @@ -257,4 +257,4 @@ foreach ($sub in $subscriptions){ } } - \ No newline at end of file + From a00731d2636594adbcefa69613bc31b2a870b47d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 02:38:22 +0000 Subject: [PATCH 071/159] Bump socket.io-parser Bumps [socket.io-parser](https://github.com/Automattic/socket.io-parser) from 3.3.3 to 3.3.4. - [Release notes](https://github.com/Automattic/socket.io-parser/releases) - [Changelog](https://github.com/socketio/socket.io-parser/blob/3.3.4/CHANGELOG.md) - [Commits](https://github.com/Automattic/socket.io-parser/compare/3.3.3...3.3.4) --- updated-dependencies: - dependency-name: socket.io-parser dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json index 5867327605..da7f05a007 100644 --- a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json +++ b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json @@ -11986,9 +11986,9 @@ "dev": true }, "socket.io-parser": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz", - "integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.4.tgz", + "integrity": "sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==", "dev": true, "requires": { "component-emitter": "~1.3.0", From 814fbdee20277af02e534d0e8374238f4f5fcc37 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Mon, 29 Jul 2024 20:24:13 -0700 Subject: [PATCH 072/159] Update install-payg-sql-server.ps1 --- .../install-payg-sql-server/install-payg-sql-server.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 9373ae2ead..b8d1bd1668 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -217,7 +217,7 @@ try { $Settings = @{ SqlManagement = @{ IsEnabled = $true }; LicenseType = "PAYG"; - enableExtendedSecurityUpdates = $True; + enableExtendedSecurityUpdates = $False; esuLastUpdatedTimestamp = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') } New-AzConnectedMachineExtension -ResourceGroupName $AzureResourceGroup -MachineName $hostName -Name "Microsoft.AzureData" -Publisher "Microsoft.AzureData" -ExtensionType "WindowsAgent.SqlServer" -Location $AzureRegion -Settings $Settings -EnableAutomaticUpgrade From 1c452eed191ff9f318c45a17bfeb244e2cf14672 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 7 Aug 2024 18:17:18 -0700 Subject: [PATCH 073/159] Updated script and added readme --- .../install-payg-sql-server/README.md | 67 ++++++++++++++++ .../install-payg-sql-server.ps1 | 79 +++++++++---------- 2 files changed, 105 insertions(+), 41 deletions(-) create mode 100644 samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md new file mode 100644 index 0000000000..e474aa4e8d --- /dev/null +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -0,0 +1,67 @@ +# Overview + +This script installs a pay-as-you-go SQL Server instance on your machine and automatically connext it to Azure Arc using a downloaded SQL Server media. + +# Prerequisites + +- You have met the [onboarding prerequisites](https://learn.microsoft.com/sql/sql-server/azure-arc/prerequisites). +- You have downloded a SQL Server image file from the workspace provided by Microsoft technical support. Tpo obtain it, open a support request using "Get SQL Installation Media" subcategory and soecify the desired version and edition. +- You are a local admin on the machine where you run the script. +- Your n +- If you are using a machine running Windows Server 2016, you have completed the mitigation steps as described below. + + +# Mitigating the TLS version issue on Windows Server 2016 + +When running the script on Windows Server 2016, the OS may be configured with a TLS version that does not meet the Azure security requirements. You need to enable strong TLS versions (TLS 1.2 and 1.3) when they are available, while still supporting older TLS versions (1.0 and 1.1) when TLS 1.2 and 1.3 are unavailable. You need to also disable versions SSL2 and SSL3, which are insecure. + +To see if you need to make the change, run the command below from an elevated PowerShell prompt. +```PowerShell +[Net.ServicePointManager]::SecurityProtocol +``` + +If the result is `SSL3, Tls`, you need to fix the TLS version using one of the following options. + +__Option 1__: run the following command below from an elevated PowerShell prompt: +```PowerShell +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls, [Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls12, [Net.SecurityProtocolType]::Tls13 +``` + +__Option 2__: run these two commands from an elevated PowerShell prompt: + +```PowerShell +Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord +Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord +``` + +After running either of these command options, close and reopen PowerShell or reboot the machine (in case currently-running applications were referencing previous values). To verify that the changes were applied correctly, run this command again: +```PowerShell +[Net.ServicePointManager]::SecurityProtocol +``` +The result should be `Tls, Tls11, Tls12, Tls13` + +# Launching the script + +The script must be launched from and elevated PowerShell prompt. It accepts the following command line parameters: + +| **Parameter**                                         | **Value**                                                                       | **Description** | +|:--|:--|:--| +|-AzureSubscriptionId|subscription_id|Required: Subscription id that will contain the Arc-enabled machime and Arc-enable SQL Server resources. That subscription will be billed for SQL Server software using a pay-as-you-go method. | +|-AzureResourceGroup |resource_group_name|Required: Resource group that will contain the Arc-enabled machime and Arc-enable SQL Server resource.| +|-AzureRegion |region name| Required: the region to store the machuine and SQL Server meta-data. | +|-SqlServerInstanceName | name of the instance|Optional: the machine name will be used if not specified| +|-SqlServerAdminAccounts | SQL Server admin accounts | Optional. By default "BUILTIN\ADMINISTRATORS" will be used.| +|-SqlServerSvcAccount| SQL Server services account |Optional. By default "NT AUTHORITY\SYSTEM" will be used.| +|-SqlServerSvcPassword| SQL Server service account password| Required if a custom service account is specified.| +|-AgtServerSvcAccount|SQL Agent service account|Optional. By default "NT AUTHORITY\NETWORK SERVICE" will be used.| +|-AgtServerSvcPassword|SQL Agent service account pasdsword|Required if a custom service account is specified.| +|-IsoFolder|Folder path|Required. The folder contrainng the files downloaded from the workspace.| +|-Proxy|HTTP proxy URL|Optional. Needed if your networks is using a HTTP proxy.| + +## Example + +The following command installs a SQL Server instance from the folder `c:\downloads`, connect it to subscription ID ``, resource group `` in West US, and configure it with LicenseType=PAYG. It use the default admin and service accounts and direct connectivity to Azure. + +```PowerShell +.\install-payg-sql-server.ps1 -AzureSubscriptionId -AzureResourceGroup -AzureRegion westus -IsoFolder c:\downloads +``` diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index b8d1bd1668..4f1d544b4f 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -15,6 +15,8 @@ param ( [string]$SqlServerSvcPassword, [Parameter (Mandatory=$false)] [string]$AgtServerSvcAccount = "NT AUTHORITY\NETWORK SERVICE", + [Parameter (Mandatory=$false)] + [string]$AgtServerSvcPassword, [Parameter (Mandatory=$true)] [string]$IsoFolder, [Parameter (Mandatory=$false)] @@ -76,9 +78,8 @@ function LoadModule } try { - + write-host "==== Ensure PS version and load missing Azure modules ====" - # # Suppress warnings # @@ -103,6 +104,7 @@ try { write-host "==== Log in to Azure ====" + Update-AzConfig -EnableLoginByWam $false Connect-AzAccount | Out-Null $subscription = Get-AzSubscription -SubscriptionId $AzureSubscriptionId -ErrorAction SilentlyContinue if (-not $subscription) { @@ -127,31 +129,34 @@ try { # Retrieve the product key if any - $keyFiles = Get-ChildItem $IsoFolder -Filter "*.txt" - + $keyFiles = (Get-ChildItem $IsoFolder -Filter "*.txt") + $productKey = "" foreach ($keyFile in $keyFiles) { # Read each line from the file - Get-Content $keyFile | ForEach-Object { - if ($_ -match "(?i)$($SqlServerEdition)" -and $_ -match "[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*") { + Get-Content $keyFile.fullname | ForEach-Object { + if ($_ -match "[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{4,}.*") { # Extract the product key (including any following string after a space) - $productKey = [regex]::Match($_, '[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}.*').Value + $productKey = [regex]::Match($_, '[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{5,}-[A-Z0-9]{4,}.*').Value # Strip any text after the product key $productKey = $productKey -replace " .*$" } } } - - $isoFiles = Get-ChildItem $IsoFolder -Filter "*.iso" + + $isoFiles = (Get-ChildItem $IsoFolder -Filter "*.iso") + + # Pick the .iso file and mount $noKeylist = "SQLFULL_ENU_ENTVL.iso", "SQLFULL_ENU_STDVL.iso", "SQLServer2022-x64-ENU-Ent.iso", "SQLServer2022-x64-ENU-Std.iso" foreach ($isoFile in $isoFiles) { + write-host("****isoFile: $($isoFile)") $imagePath = $isoFile.FullName if ($noKeylist -contains $isoFile.Name) {$productKey = ""} if (!(Get-DiskImage -ImagePath $imagePath).Attached) { - $mountResult = Mount-DiskImage -ImagePath $imagePath + $mountResult = Mount-DiskImage -ImagePath $imagePath -PassThru } else { $mountResult = Get-DiskImage -ImagePath $imagePath } @@ -164,40 +169,31 @@ try { write-host "==== Run unattended SQL Server setup from the mounted volume ====" - # Launch setup $setupPath = ($driveLetter + ":\setup.exe") - $argumentList = " - /q - /ACTION=`"Install`" - /FEATURES=SQL - /INSTANCEDIR=C:\SQL - /SQLSYSADMINACCOUNTS=`"$($SqlServerAdminAccounts)`" - /SQLSVCACCOUNT=`"$($SqlServerSvcAccount)`" - /AGTSVCACCOUNT=`"$($AgtServerSvcAccount)`" - /IACCEPTSQLSERVERLICENSETERMS - " - if ($SqlServerSvcPassword) { - $argumentList += " /SQLSVCPASSWORD=`"$($SqlServerSvcPassword)`" - " + + + $argumentList = "/q /ACTION=Install /FEATURES=SQL /SQLSVCACCOUNT=`"$($SqlServerSvcAccount)`" /SQLSYSADMINACCOUNTS=`"$($SqlServerAdminAccounts)`" /AGTSVCACCOUNT=`"$($AgtServerSvcAccount)`" /IACCEPTSQLSERVERLICENSETERMS" + # some optional arguments + if ($SqlServerInstanceName) { + $argumentList += " /INSTANCENAME= $($SqlServerInstanceName)" } - if ($AgtServerSvcPassword) { - $argumentList += " /SQLAGTPASSWORD=`"$($AgtServerSvcPassword)`" - " + if ($productKey) { + $argumentList += " /PID=`"$($productKey)`"" } - if ($SqlServerInstanceName) { - $argumentList += " /INSTANCENAME=`"$($SqlServerInstanceName) `" - " + + if ($SqlServerSvcPassword) { + $argumentList += " /SQLSVCPASSWORD=`"$($SqlServerSvcPassword)`"" } - if ($productKey) { - $argumentList += " /PID=`"$($productKey)`" - " - } - - Start-Process -FilePath $setupPath -ArgumentList $argumentList - write-host "==== Dismount the ISO file after installation ====" + if ($AgtSvCPassword) { + $argumentList += " /AGTSVCPASSWORD=`"$($AgtSvCPassword)`"" + } + + + Start-Process -Wait -FilePath $setupPath -ArgumentList $argumentList -RedirectStandardOutput setup-output.txt + Dismount-DiskImage -ImagePath $imagePath | Out-Null @@ -213,16 +209,17 @@ try { write-host "==== Install SQL Arc extension with LT=PAYG and upgrade to the latest version ====" - $extensionName = "WindowsAgent.SqlServer" + $Settings = @{ SqlManagement = @{ IsEnabled = $true }; LicenseType = "PAYG"; enableExtendedSecurityUpdates = $False; - esuLastUpdatedTimestamp = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') } - New-AzConnectedMachineExtension -ResourceGroupName $AzureResourceGroup -MachineName $hostName -Name "Microsoft.AzureData" -Publisher "Microsoft.AzureData" -ExtensionType "WindowsAgent.SqlServer" -Location $AzureRegion -Settings $Settings -EnableAutomaticUpgrade - # Step 10: Display the status of the Azure resource for Arc-enabled SQL Server + + New-AzConnectedMachineExtension -ResourceGroupName $AzureResourceGroup -MachineName $hostName -Name "WindowsAgent.SqlServer" -Publisher "Microsoft.AzureData" -ExtensionType "WindowsAgent.SqlServer" -Location $AzureRegion -Settings $Settings -EnableAutomaticUpgrade + + write-host "==== Display the status of the billable Arc-enabled host ====" $query = " From f901d45077b57239b0861c0f3c517ae2e60e8b78 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 7 Aug 2024 18:21:18 -0700 Subject: [PATCH 074/159] Minor edits --- .../install-payg-sql-server/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index e474aa4e8d..d7a4826618 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -1,14 +1,13 @@ # Overview -This script installs a pay-as-you-go SQL Server instance on your machine and automatically connext it to Azure Arc using a downloaded SQL Server media. +This script installs a pay-as-you-go SQL Server instance on your machine and automatically connects it to Azure using a downloaded SQL Server media. # Prerequisites - You have met the [onboarding prerequisites](https://learn.microsoft.com/sql/sql-server/azure-arc/prerequisites). -- You have downloded a SQL Server image file from the workspace provided by Microsoft technical support. Tpo obtain it, open a support request using "Get SQL Installation Media" subcategory and soecify the desired version and edition. +- You have downloded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using "Get SQL Installation Media" subcategory and specify the desired version and edition. - You are a local admin on the machine where you run the script. -- Your n -- If you are using a machine running Windows Server 2016, you have completed the mitigation steps as described below. +- If you are installing SQL Server on Windows Server 2016, you have a secure TLS configuration as described below. # Mitigating the TLS version issue on Windows Server 2016 From 624e84a759c5ed55d3c4f2fecd9812d8f74fafc7 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 7 Aug 2024 18:32:27 -0700 Subject: [PATCH 075/159] Added curl --- .../install-payg-sql-server/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index d7a4826618..58b13ed98d 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -39,9 +39,17 @@ After running either of these command options, close and reopen PowerShell or re ``` The result should be `Tls, Tls11, Tls12, Tls13` +# Downloading the script + +To download the script to your current folder run: + + ```console + curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 -o install-payg-sql-server.ps1 + ``` + # Launching the script -The script must be launched from and elevated PowerShell prompt. It accepts the following command line parameters: +The script must be run in an elevated PowerShell session. It accepts the following command line parameters: | **Parameter**                                         | **Value**                                                                       | **Description** | |:--|:--|:--| From 0f55a71131f02293a506b69dece86ae012c12a75 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 7 Aug 2024 18:36:24 -0700 Subject: [PATCH 076/159] Update README.md --- .../install-payg-sql-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 58b13ed98d..a33be9d250 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -6,7 +6,7 @@ This script installs a pay-as-you-go SQL Server instance on your machine and aut - You have met the [onboarding prerequisites](https://learn.microsoft.com/sql/sql-server/azure-arc/prerequisites). - You have downloded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using "Get SQL Installation Media" subcategory and specify the desired version and edition. -- You are a local admin on the machine where you run the script. +- You are logged in to the machine with a administrator account. - If you are installing SQL Server on Windows Server 2016, you have a secure TLS configuration as described below. From 83b383409b12355a6cfb2fdb02351e2b7065cec1 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 7 Aug 2024 18:37:43 -0700 Subject: [PATCH 077/159] Update README.md --- .../install-payg-sql-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index a33be9d250..b20d37970a 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -63,7 +63,7 @@ The script must be run in an elevated PowerShell session. It accepts the followi |-AgtServerSvcAccount|SQL Agent service account|Optional. By default "NT AUTHORITY\NETWORK SERVICE" will be used.| |-AgtServerSvcPassword|SQL Agent service account pasdsword|Required if a custom service account is specified.| |-IsoFolder|Folder path|Required. The folder contrainng the files downloaded from the workspace.| -|-Proxy|HTTP proxy URL|Optional. Needed if your networks is using a HTTP proxy.| +|-Proxy|HTTP proxy URL|Optional. Needed if your networks is configured with an HTTP proxy.| ## Example From 1984db06617e245cc898ff733a09984dce428c6d Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 7 Aug 2024 18:38:16 -0700 Subject: [PATCH 078/159] Update README.md --- .../install-payg-sql-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index b20d37970a..f072322f17 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -65,7 +65,7 @@ The script must be run in an elevated PowerShell session. It accepts the followi |-IsoFolder|Folder path|Required. The folder contrainng the files downloaded from the workspace.| |-Proxy|HTTP proxy URL|Optional. Needed if your networks is configured with an HTTP proxy.| -## Example +# Example The following command installs a SQL Server instance from the folder `c:\downloads`, connect it to subscription ID ``, resource group `` in West US, and configure it with LicenseType=PAYG. It use the default admin and service accounts and direct connectivity to Azure. From 8e2f6ae8205d45881d6898d85a110579637aead4 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 8 Aug 2024 10:40:37 -0700 Subject: [PATCH 079/159] Update README.md --- .../install-payg-sql-server/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index f072322f17..53f56d98ff 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -6,7 +6,7 @@ This script installs a pay-as-you-go SQL Server instance on your machine and aut - You have met the [onboarding prerequisites](https://learn.microsoft.com/sql/sql-server/azure-arc/prerequisites). - You have downloded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using "Get SQL Installation Media" subcategory and specify the desired version and edition. -- You are logged in to the machine with a administrator account. +- You are logged in to the machine with an administrator account. - If you are installing SQL Server on Windows Server 2016, you have a secure TLS configuration as described below. @@ -67,7 +67,7 @@ The script must be run in an elevated PowerShell session. It accepts the followi # Example -The following command installs a SQL Server instance from the folder `c:\downloads`, connect it to subscription ID ``, resource group `` in West US, and configure it with LicenseType=PAYG. It use the default admin and service accounts and direct connectivity to Azure. +The following command installs a SQL Server instance from the folder `c:\downloads`, connects it to subscription ID ``, resource group `` in the West US region, and configures it with LicenseType=PAYG. It uses the default admin and service accounts, and uses a direct connection to Azure. ```PowerShell .\install-payg-sql-server.ps1 -AzureSubscriptionId -AzureResourceGroup -AzureRegion westus -IsoFolder c:\downloads From 4849fcc911f1d53541863d4b9034b996efbec5d0 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 13 Aug 2024 10:46:08 -0700 Subject: [PATCH 080/159] Fixed typos --- .../install-payg-sql-server/README.md | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 53f56d98ff..771490b072 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -5,7 +5,7 @@ This script installs a pay-as-you-go SQL Server instance on your machine and aut # Prerequisites - You have met the [onboarding prerequisites](https://learn.microsoft.com/sql/sql-server/azure-arc/prerequisites). -- You have downloded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using "Get SQL Installation Media" subcategory and specify the desired version and edition. +- You have downloaded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using "Get SQL Installation Media" subcategory and specify the desired version and edition. - You are logged in to the machine with an administrator account. - If you are installing SQL Server on Windows Server 2016, you have a secure TLS configuration as described below. @@ -19,21 +19,15 @@ To see if you need to make the change, run the command below from an elevated Po [Net.ServicePointManager]::SecurityProtocol ``` -If the result is `SSL3, Tls`, you need to fix the TLS version using one of the following options. - -__Option 1__: run the following command below from an elevated PowerShell prompt: -```PowerShell -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls, [Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls12, [Net.SecurityProtocolType]::Tls13 -``` - -__Option 2__: run these two commands from an elevated PowerShell prompt: +If the result is `SSL3, Tls`, you need to fix the TLS version by running the following commands. ```PowerShell Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord ``` -After running either of these command options, close and reopen PowerShell or reboot the machine (in case currently-running applications were referencing previous values). To verify that the changes were applied correctly, run this command again: +After running these commands, reboot the machine (in case currently-running applications were referencing previous values). To verify that the changes were applied correctly, run this command again: + ```PowerShell [Net.ServicePointManager]::SecurityProtocol ``` @@ -53,16 +47,16 @@ The script must be run in an elevated PowerShell session. It accepts the followi | **Parameter**                                         | **Value**                                                                       | **Description** | |:--|:--|:--| -|-AzureSubscriptionId|subscription_id|Required: Subscription id that will contain the Arc-enabled machime and Arc-enable SQL Server resources. That subscription will be billed for SQL Server software using a pay-as-you-go method. | -|-AzureResourceGroup |resource_group_name|Required: Resource group that will contain the Arc-enabled machime and Arc-enable SQL Server resource.| +|-AzureSubscriptionId|subscription_id|Required: Subscription id that will contain the Arc-enabled machine and Arc-enable SQL Server resources. That subscription will be billed for SQL Server software using a pay-as-you-go method. | +|-AzureResourceGroup |resource_group_name|Required: Resource group that will contain the Arc-enabled machine and Arc-enable SQL Server resource.| |-AzureRegion |region name| Required: the region to store the machuine and SQL Server meta-data. | |-SqlServerInstanceName | name of the instance|Optional: the machine name will be used if not specified| |-SqlServerAdminAccounts | SQL Server admin accounts | Optional. By default "BUILTIN\ADMINISTRATORS" will be used.| |-SqlServerSvcAccount| SQL Server services account |Optional. By default "NT AUTHORITY\SYSTEM" will be used.| |-SqlServerSvcPassword| SQL Server service account password| Required if a custom service account is specified.| |-AgtServerSvcAccount|SQL Agent service account|Optional. By default "NT AUTHORITY\NETWORK SERVICE" will be used.| -|-AgtServerSvcPassword|SQL Agent service account pasdsword|Required if a custom service account is specified.| -|-IsoFolder|Folder path|Required. The folder contrainng the files downloaded from the workspace.| +|-AgtServerSvcPassword|SQL Agent service account password|Required if a custom service account is specified.| +|-IsoFolder|Folder path|Required. The folder containing the files downloaded from the workspace.| |-Proxy|HTTP proxy URL|Optional. Needed if your networks is configured with an HTTP proxy.| # Example From f17e36fdfe37dcd1a13ddb844a00971c502b355a Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 13 Aug 2024 10:49:35 -0700 Subject: [PATCH 081/159] Fixed curl command --- .../install-payg-sql-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 771490b072..59a15e2020 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -37,7 +37,7 @@ The result should be `Tls, Tls11, Tls12, Tls13` To download the script to your current folder run: - ```console + ```PowerShell curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 -o install-payg-sql-server.ps1 ``` From 58d176fb224f0e9a91e00305652dbf2ecab84285 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 13 Aug 2024 10:50:40 -0700 Subject: [PATCH 082/159] Fixed concole command --- .../install-payg-sql-server/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 59a15e2020..86cd0cdf14 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -37,9 +37,9 @@ The result should be `Tls, Tls11, Tls12, Tls13` To download the script to your current folder run: - ```PowerShell - curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 -o install-payg-sql-server.ps1 - ``` +```console +curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 -o install-payg-sql-server.ps1 +``` # Launching the script From e125b27e275cf29b2478e53009be0440bd87802d Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 13 Aug 2024 10:52:33 -0700 Subject: [PATCH 083/159] Fixed services default --- .../install-payg-sql-server/README.md | 2 +- .../install-payg-sql-server/install-payg-sql-server.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 86cd0cdf14..148332680f 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -52,7 +52,7 @@ The script must be run in an elevated PowerShell session. It accepts the followi |-AzureRegion |region name| Required: the region to store the machuine and SQL Server meta-data. | |-SqlServerInstanceName | name of the instance|Optional: the machine name will be used if not specified| |-SqlServerAdminAccounts | SQL Server admin accounts | Optional. By default "BUILTIN\ADMINISTRATORS" will be used.| -|-SqlServerSvcAccount| SQL Server services account |Optional. By default "NT AUTHORITY\SYSTEM" will be used.| +|-SqlServerSvcAccount| SQL Server services account |Optional. By default "NT AUTHORITY\NETWORK SERVICE" will be used.| |-SqlServerSvcPassword| SQL Server service account password| Required if a custom service account is specified.| |-AgtServerSvcAccount|SQL Agent service account|Optional. By default "NT AUTHORITY\NETWORK SERVICE" will be used.| |-AgtServerSvcPassword|SQL Agent service account password|Required if a custom service account is specified.| diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 index 4f1d544b4f..0a4efb6353 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/install-payg-sql-server.ps1 @@ -10,7 +10,7 @@ param ( [Parameter (Mandatory=$false)] [string]$SqlServerAdminAccounts = "BUILTIN\ADMINISTRATORS", [Parameter (Mandatory=$false)] - [string]$SqlServerSvcAccount = "NT AUTHORITY\SYSTEM", + [string]$SqlServerSvcAccount = "NT AUTHORITY\NETWORK SERVICE", [Parameter (Mandatory=$false)] [string]$SqlServerSvcPassword, [Parameter (Mandatory=$false)] From a6de85e07e80312089a053bb46b71ea3003b54cc Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 13 Aug 2024 14:26:14 -0700 Subject: [PATCH 084/159] Fixed download folder --- .../install-payg-sql-server/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 148332680f..94164dff3a 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -5,7 +5,7 @@ This script installs a pay-as-you-go SQL Server instance on your machine and aut # Prerequisites - You have met the [onboarding prerequisites](https://learn.microsoft.com/sql/sql-server/azure-arc/prerequisites). -- You have downloaded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using "Get SQL Installation Media" subcategory and specify the desired version and edition. +- You have downloaded a SQL Server image file from the workspace provided by Microsoft technical support. To obtain it, open a support request using the "Get SQL Installation Media" subcategory and specify the desired version and edition. - You are logged in to the machine with an administrator account. - If you are installing SQL Server on Windows Server 2016, you have a secure TLS configuration as described below. @@ -61,8 +61,9 @@ The script must be run in an elevated PowerShell session. It accepts the followi # Example -The following command installs a SQL Server instance from the folder `c:\downloads`, connects it to subscription ID ``, resource group `` in the West US region, and configures it with LicenseType=PAYG. It uses the default admin and service accounts, and uses a direct connection to Azure. +The following command installs a SQL Server instance from the download folder, connects it to subscription ID ``, resource group `` in the West US region, and configures it with LicenseType=PAYG. It uses the default admin and service accounts, and uses a direct connection to Azure. ```PowerShell -.\install-payg-sql-server.ps1 -AzureSubscriptionId -AzureResourceGroup -AzureRegion westus -IsoFolder c:\downloads +.\install-payg-sql-server.ps1 -AzureSubscriptionId -AzureResourceGroup -AzureRegion westus -IsoFolder C:\Users\[YourUsername]\Downloads + ``` From 9c82e6ef31efaa54aeaa8f37ece8b9efceb6b0b5 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 13 Aug 2024 14:28:58 -0700 Subject: [PATCH 085/159] Update README.md --- .../install-payg-sql-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md index 94164dff3a..fd67a5b8e7 100644 --- a/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md +++ b/samples/manage/azure-arc-enabled-sql-server/install-payg-sql-server/README.md @@ -61,7 +61,7 @@ The script must be run in an elevated PowerShell session. It accepts the followi # Example -The following command installs a SQL Server instance from the download folder, connects it to subscription ID ``, resource group `` in the West US region, and configures it with LicenseType=PAYG. It uses the default admin and service accounts, and uses a direct connection to Azure. +The following command installs a SQL Server instance from the Downloads folder, connects it to subscription ID ``, resource group `` in the West US region, and configures it with LicenseType=PAYG. It uses the default admin and service accounts, and uses a direct connection to Azure. ```PowerShell .\install-payg-sql-server.ps1 -AzureSubscriptionId -AzureResourceGroup -AzureRegion westus -IsoFolder C:\Users\[YourUsername]\Downloads From d43a5c54aa623d14b2bd8621c5bf5d8d456b8550 Mon Sep 17 00:00:00 2001 From: Randolph West MSFT <97149825+rwestMSFT@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:09:46 -0600 Subject: [PATCH 086/159] Remove unnecessary files --- .../machine-learning/spark/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/features/sql-big-data-cluster/machine-learning/spark/.DS_Store diff --git a/samples/features/sql-big-data-cluster/machine-learning/spark/.DS_Store b/samples/features/sql-big-data-cluster/machine-learning/spark/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Fri, 30 Aug 2024 11:11:03 +0000 Subject: [PATCH 087/159] Bump webpack Bumps [webpack](https://github.com/webpack/webpack) from 5.76.1 to 5.94.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.76.1...v5.94.0) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 524 +++++++++++------- 1 file changed, 327 insertions(+), 197 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 3a44a26a01..8c0b6a8ff6 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -2688,15 +2688,6 @@ "@types/json-schema": "*" } }, - "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "@types/estree": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", @@ -3000,137 +2991,6 @@ "eslint-visitor-keys": "^3.3.0" } }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -3196,10 +3056,10 @@ } } }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==" }, "acorn-jsx": { "version": "5.3.2", @@ -4999,22 +4859,6 @@ } } }, - "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - } - } - }, "entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -5082,11 +4926,6 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" - }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -13202,15 +13041,6 @@ "makeerror": "1.0.12" } }, - "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, "wbuf": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", @@ -13225,40 +13055,259 @@ "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" }, "webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "requires": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "requires": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001655", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", + "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "electron-to-chromium": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" + }, + "enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==" + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "eslint-scope": { "version": "5.1.1", @@ -13274,10 +13323,15 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "mime-db": { "version": "1.52.0", @@ -13291,6 +13345,82 @@ "requires": { "mime-db": "1.52.0" } + }, + "node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "terser": { + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + } + }, + "update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + } + }, + "watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } } } }, From 5d0277be37583ca5a4a1a8b1132bee329709af64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:05:01 +0000 Subject: [PATCH 088/159] Bump micromatch Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8. - [Release notes](https://github.com/micromatch/micromatch/releases) - [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8) --- updated-dependencies: - dependency-name: micromatch dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../SqlDbEdgeDemo.Web/ClientApp/package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 3a44a26a01..12195e2829 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -9308,11 +9308,11 @@ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, From e93515f0b23ff72b4eedca1a37cfd49ecf6a57e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:35:44 +0000 Subject: [PATCH 089/159] Bump cryptography Bumps [cryptography](https://github.com/pyca/cryptography) from 41.0.4 to 43.0.1. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/41.0.4...43.0.1) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../kms_plugin_app/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt index 7105f927bc..581a49efb8 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt @@ -1,6 +1,6 @@ pycrypto==2.6.1 pycryptodome==3.19.1 -cryptography==41.0.4 +cryptography==43.0.1 hvac==0.10.11 azure-identity==1.16.1 azure-keyvault-keys==4.3.1 From 0f974821a05a5d141353948ded01094530334fe2 Mon Sep 17 00:00:00 2001 From: Eldar Kuli-zade Date: Wed, 11 Sep 2024 14:18:49 +0200 Subject: [PATCH 090/159] Blank Dashboard fix - review needed I noticed that importing this dashboard template doesn't work anymore - when I try to import it shows blank dashboard without tiles, no error messages. I changed some brackets from "{" to "[" and removed part names and it works again. I am not an expert in Azure Dashboard JSON format, so please review! --- .../dashboard/Arc - SQL Server Inventory.json | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json b/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json index 03fb8669dc..f33f344780 100644 --- a/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json +++ b/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json @@ -1,10 +1,10 @@ { "properties": { - "lenses": { - "0": { + "lenses": [ + { "order": 0, - "parts": { - "0": { + "parts": [ + { "position": { "x": 0, "y": 0, @@ -25,7 +25,7 @@ } } }, - "1": { + { "position": { "x": 0, "y": 2, @@ -77,7 +77,7 @@ } } }, - "2": { + { "position": { "x": 3, "y": 2, @@ -129,7 +129,7 @@ } } }, - "3": { + { "position": { "x": 6, "y": 2, @@ -181,7 +181,7 @@ } } }, - "4": { + { "position": { "x": 0, "y": 6, @@ -234,7 +234,7 @@ } } }, - "5": { + { "position": { "x": 0, "y": 11, @@ -287,7 +287,7 @@ } } }, - "6": { + { "position": { "x": 0, "y": 16, @@ -340,7 +340,7 @@ } } }, - "7": { + { "position": { "x": 0, "y": 21, @@ -393,7 +393,7 @@ } } }, - "8": { + { "position": { "x": 6, "y": 21, @@ -446,7 +446,7 @@ } } }, - "9": { + { "position": { "x": 12, "y": 21, @@ -499,7 +499,7 @@ } } }, - "10": { + { "position": { "x": 0, "y": 27, @@ -552,7 +552,7 @@ } } }, - "11": { + { "position": { "x": 12, "y": 27, @@ -606,7 +606,7 @@ } } }, - "12": { + { "position": { "x": 0, "y": 34, @@ -627,7 +627,7 @@ } } }, - "13": { + { "position": { "x": 0, "y": 35, @@ -680,7 +680,7 @@ } } }, - "14": { + { "position": { "x": 0, "y": 42, @@ -731,11 +731,11 @@ }, "partHeader": { "title": "SQL Server Instances by Location", - "subtitle": "SQL Servers instances by \"Location\" tag values" + "subtitle": "SQL Servers instasnces by \"Location\" tag values" } } }, - "15": { + { "position": { "x": 0, "y": 49, @@ -785,12 +785,12 @@ "content": {} }, "partHeader": { - "title": "SQL Server Instances by Data Center", + "title": "SQL Server Instasnces by Data Center", "subtitle": "SQL Servers instances by \"Datacenter\" tag values." } } }, - "16": { + { "position": { "x": 0, "y": 56, @@ -845,9 +845,9 @@ } } } - } + ] } - }, + ], "metadata": { "model": { "timeRange": { From 35d6b334c1890139a475e5c53d43ffaf6cd2739c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:01:40 +0000 Subject: [PATCH 091/159] Bump send and express Bumps [send](https://github.com/pillarjs/send) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `send` from 0.18.0 to 0.19.0 - [Release notes](https://github.com/pillarjs/send/releases) - [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md) - [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0) Updates `express` from 4.19.2 to 4.20.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0) --- updated-dependencies: - dependency-name: send dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 446 +++++++++++++----- 1 file changed, 328 insertions(+), 118 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index c6eaa692f7..5324a15952 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -3712,6 +3712,103 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + } + } + }, "bonjour-service": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", @@ -4200,6 +4297,11 @@ "safe-buffer": "~5.1.1" } }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -4575,6 +4677,16 @@ "execa": "^5.0.0" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -4926,6 +5038,38 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -5729,36 +5873,36 @@ } }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", + "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5771,42 +5915,6 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - } - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5815,26 +5923,105 @@ "ms": "2.0.0" } }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + } + } + } } } }, @@ -6405,6 +6592,14 @@ "minimatch": "~3.0.2" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -6469,6 +6664,11 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -6487,6 +6687,21 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -9126,11 +9341,6 @@ } } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9943,11 +10153,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10883,6 +11088,24 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, "react": { "version": "16.11.0", "resolved": "https://registry.npmjs.org/react/-/react-16.11.0.tgz", @@ -11901,48 +12124,6 @@ "lru-cache": "^6.0.0" } }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -12011,22 +12192,51 @@ } } }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + } + } + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", From fa5d06d0cafc5232143094f1a753d8e1f3cd7d0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:01:45 +0000 Subject: [PATCH 092/159] Bump serve-static and express Bumps [serve-static](https://github.com/expressjs/serve-static) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `serve-static` from 1.15.0 to 1.16.0 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...1.16.0) Updates `express` from 4.19.2 to 4.20.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0) --- updated-dependencies: - dependency-name: serve-static dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 446 +++++++++++++----- 1 file changed, 328 insertions(+), 118 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index c6eaa692f7..5324a15952 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -3712,6 +3712,103 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + } + } + }, "bonjour-service": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", @@ -4200,6 +4297,11 @@ "safe-buffer": "~5.1.1" } }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -4575,6 +4677,16 @@ "execa": "^5.0.0" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -4926,6 +5038,38 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -5729,36 +5873,36 @@ } }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", + "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5771,42 +5915,6 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - } - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5815,26 +5923,105 @@ "ms": "2.0.0" } }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + } + } + } } } }, @@ -6405,6 +6592,14 @@ "minimatch": "~3.0.2" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -6469,6 +6664,11 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -6487,6 +6687,21 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -9126,11 +9341,6 @@ } } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9943,11 +10153,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10883,6 +11088,24 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, "react": { "version": "16.11.0", "resolved": "https://registry.npmjs.org/react/-/react-16.11.0.tgz", @@ -11901,48 +12124,6 @@ "lru-cache": "^6.0.0" } }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -12011,22 +12192,51 @@ } } }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + } + } + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", From d654a948714c44fa8bca166dbc1abfecd2d4f662 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:02:30 +0000 Subject: [PATCH 093/159] Bump express Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.20.0. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 446 +++++++++++++----- 1 file changed, 328 insertions(+), 118 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index c6eaa692f7..5324a15952 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -3712,6 +3712,103 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + } + } + }, "bonjour-service": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", @@ -4200,6 +4297,11 @@ "safe-buffer": "~5.1.1" } }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -4575,6 +4677,16 @@ "execa": "^5.0.0" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -4926,6 +5038,38 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -5729,36 +5873,36 @@ } }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", + "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5771,42 +5915,6 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - } - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5815,26 +5923,105 @@ "ms": "2.0.0" } }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + } + } + } } } }, @@ -6405,6 +6592,14 @@ "minimatch": "~3.0.2" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -6469,6 +6664,11 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -6487,6 +6687,21 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -9126,11 +9341,6 @@ } } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9943,11 +10153,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10883,6 +11088,24 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, "react": { "version": "16.11.0", "resolved": "https://registry.npmjs.org/react/-/react-16.11.0.tgz", @@ -11901,48 +12124,6 @@ "lru-cache": "^6.0.0" } }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -12011,22 +12192,51 @@ } } }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + } + } + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", From 8f01bc622b3eef4f9b7a4026837bdb8ad6d4b8fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:04:27 +0000 Subject: [PATCH 094/159] Bump requirejs Bumps [requirejs](https://github.com/jrburke/r.js) from 2.3.6 to 2.3.7. - [Commits](https://github.com/jrburke/r.js/compare/2.3.6...2.3.7) --- updated-dependencies: - dependency-name: requirejs dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json index da7f05a007..0f74db87ec 100644 --- a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json +++ b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json @@ -11041,9 +11041,9 @@ } }, "requirejs": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", - "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.7.tgz", + "integrity": "sha512-DouTG8T1WanGok6Qjg2SXuCMzszOo0eHeH9hDZ5Y4x8Je+9JB38HdTLT4/VA8OaUhBa0JPVHJ0pyBkM1z+pDsw==", "dev": true }, "requires-port": { From 5237f59d7d047daefd250489964e73670b883d45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:13:27 +0000 Subject: [PATCH 095/159] Bump Azure.Identity Bumps [Azure.Identity](https://github.com/Azure/azure-sdk-for-net) from 1.11.0 to 1.11.4. - [Release notes](https://github.com/Azure/azure-sdk-for-net/releases) - [Commits](https://github.com/Azure/azure-sdk-for-net/compare/Azure.Identity_1.11.0...Azure.Identity_1.11.4) --- updated-dependencies: - dependency-name: Azure.Identity dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../AlwaysEncryptedConsole/AlwaysEncryptedConsole.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/features/security/always-encrypted-with-secure-enclaves/sample-application/AlwaysEncryptedConsole/AlwaysEncryptedConsole.csproj b/samples/features/security/always-encrypted-with-secure-enclaves/sample-application/AlwaysEncryptedConsole/AlwaysEncryptedConsole.csproj index 8bd770b771..0137486778 100644 --- a/samples/features/security/always-encrypted-with-secure-enclaves/sample-application/AlwaysEncryptedConsole/AlwaysEncryptedConsole.csproj +++ b/samples/features/security/always-encrypted-with-secure-enclaves/sample-application/AlwaysEncryptedConsole/AlwaysEncryptedConsole.csproj @@ -11,7 +11,7 @@ - + From f6132161255aaef3bd4356db697a6252d1ac2af7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:50:10 +0000 Subject: [PATCH 096/159] Bump path-to-regexp Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 1.8.0 to 1.9.0. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v1.8.0...v1.9.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 5324a15952..83c5f4a951 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -10153,6 +10153,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -11371,14 +11386,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } } } }, From 0bb5407623364b3dd5daf7ef9578048c60bfd1fb Mon Sep 17 00:00:00 2001 From: Mike Ray <15928587+MikeRayMSFT@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:26:40 -0700 Subject: [PATCH 097/159] Add hybrid compute-extension-last-connect --- .../hybrid-compute-extension-last-connect.kql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 samples/features/azure-arc/troubleshooting/hybrid-compute-extension-last-connect.kql diff --git a/samples/features/azure-arc/troubleshooting/hybrid-compute-extension-last-connect.kql b/samples/features/azure-arc/troubleshooting/hybrid-compute-extension-last-connect.kql new file mode 100644 index 0000000000..6536813a03 --- /dev/null +++ b/samples/features/azure-arc/troubleshooting/hybrid-compute-extension-last-connect.kql @@ -0,0 +1,7 @@ +resources + | where type =~ 'microsoft.hybridcompute/machines/extensions' + | where properties.type in ('WindowsAgent.SqlServer','LinuxAgent.SqlServer') + | parse id with * '/providers/Microsoft.HybridCompute/machines/' machineName '/extensions/' * + | parse properties with * 'timestampUTC : ' timestampUTC ';' * + | project timestampUTC, subscriptionId, resourceGroup, machineName + | order by timestampUTC desc \ No newline at end of file From 0d208b6d49fc59c3250cd3787c7e44d57629f704 Mon Sep 17 00:00:00 2001 From: Daniel Ferrer Date: Fri, 27 Sep 2024 14:31:21 +0200 Subject: [PATCH 098/159] Added rollback transaction before an exception is thrown --- .../aspstate_sql2016_with_retry.sql | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/samples/applications/aspnet-session-state/aspstate_sql2016_with_retry.sql b/samples/applications/aspnet-session-state/aspstate_sql2016_with_retry.sql index 765775d555..1945710ecc 100644 --- a/samples/applications/aspnet-session-state/aspstate_sql2016_with_retry.sql +++ b/samples/applications/aspnet-session-state/aspstate_sql2016_with_retry.sql @@ -204,6 +204,9 @@ BEGIN ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -287,6 +290,9 @@ BEGIN ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -348,6 +354,9 @@ BEGIN ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -410,6 +419,9 @@ BEGIN ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -471,6 +483,9 @@ BEGIN ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -772,6 +787,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -838,6 +856,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -916,6 +937,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -996,6 +1020,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1080,6 +1107,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1149,6 +1179,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1214,6 +1247,9 @@ AS ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1255,6 +1291,9 @@ DECLARE @retry INT = 10; ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1296,6 +1335,9 @@ DECLARE @retry INT = 10; ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1335,6 +1377,9 @@ DECLARE @retry INT = 10; ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH @@ -1382,6 +1427,9 @@ DECLARE @retry INT = 10; ELSE BEGIN PRINT 'Suffered an error for which Retry is inappropriate.'; + IF XACT_STATE() = -1 + ROLLBACK TRANSACTION; + THROW; END END CATCH From 1e4098718855b0bf3af242c5077c0adafd874c7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 18:12:46 +0000 Subject: [PATCH 099/159] Bump rollup Bumps [rollup](https://github.com/rollup/rollup) from 2.79.1 to 2.79.2. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v2.79.1...v2.79.2) --- updated-dependencies: - dependency-name: rollup dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../SqlDbEdgeDemo.Web/ClientApp/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 5324a15952..42a0dbfbb8 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -11891,9 +11891,9 @@ } }, "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "requires": { "fsevents": "~2.3.2" } From a1b84be7a5c8dbf3fe1bdeeab8a6bcb5057f4f36 Mon Sep 17 00:00:00 2001 From: Dick Baker Date: Tue, 8 Oct 2024 20:10:39 +0100 Subject: [PATCH 100/159] Add files via upload Entity Relationship Diagram (ERD) of the major tables in Northwind sample database for those developers [all?] favouring the visual approach ! --- Northwind-major8.png | Bin 0 -> 51214 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Northwind-major8.png diff --git a/Northwind-major8.png b/Northwind-major8.png new file mode 100644 index 0000000000000000000000000000000000000000..8c1ad5e43f06e030ffac8906b46a473bb2f28631 GIT binary patch literal 51214 zcmc$`byU?`+ct`VAR-_kjYum1493WE_Ybshl!hJPobVgm(*)C~S}ugx+;9}221 zMO2Va{=MdQtyDHsht;b4+^1g_5eJXV)>`x)Yr+R$PAZSSHFMfqq^5fEo;E_wNDs$Z zXC}N9H9n5^KCZDqwG0^Wz#mTM83oFRS z?fUp^Q}}OmV57sR$xE0Z1rPY zBmC+d@P9a5iaG8E#e1~}yMbB(UDER0=8)*V-S&er0w`(snvYd5J5c6y?Rd4Hc{Q9r zZo@$h6Idovf8^j*drbeDhDdr$Q~Tl`)KMF5hS*P}evD7u|8JJ8iLk7_K!1Otws#5M z5i5H$)J8CibYufQtBL=RSc1x^iFd7AJwFOZpv_?m zaHNBcFN}02>juBdh99{tC=ybQxu+_Wv_J(cDIcw(@M_$5_?bdgSI_r(`E46NO2W^_ z8hdP03)ogOp+${TgIk|a#1giduOe0P&z1qve*X2LL@GrC0nA7AG#R)TH_YeL^s z@?Jcl3Vl_9YrybcZKEPAUBfAi>73y2A1rWJi`{75s*cZo7)CaF?6z!-mo2tibDb-h z^ztfelv5+bKu3Z3nCsR4mRAa9sIUg=9>sW(N?~ox1bleWrb)-KqmLh_s8$ye#~{M@ z^~u&>;ghq@Ssk)*qm-6|MiKV)m2&Ruu~ z^|KO`pUx2Y1m@{iGB`Q%5s`XedeCxqKhIdNoL%(!%*xh8g!IN&7vJ8b$uT zIIeWUNtS4`9OWCi>aqg$944D*CQAremlZz&8)#}M@PFY-ON^Wd%2l^}Ii`_0d`R9w ztW}SILgSARsuZiGo^LT;ThE%YrPOc?-GH*u7e{l-#|OA_fwNkU*3beXIY(St_A+&X z)><0#=jzK|_d`%Mr)1dBmWyfptJMxQ$7J0heXz*8tlX!5&P3U z?YgCmmGM@}Ls29r=!>afv4#%cyU8@PtiN&9y|~w4bH(-pmJx55^c@`F`GOX(Z}_=h z^cIwq> z$+@o4f~8)o+(+qN-r9G~jL%{=c5Ta+sv#5L z9I&*lqaMwIS(`YQ1@TqX)qgONb_&Bpe_khxZ8x{*1NfJUox(tV^IVS^Z*GcdoN@S~ zt-)wgnkw%4OT86p@!adPlT@dyg_5e4-18sD&>vRM<$7w4e!DTY0K0R?kxsH*hy|9GK zrHi?1kVE~2Mi!3y)tLL$iTm}*^|9qO8G|Ej^He0u-l&vRU;e;&k!xxq$NoV-Z?Svh z7qE_$v&2>{92YE5W3=K*L@EldKEM&y1)&YdTbF`d4r1mmFIN+m`Uox?F*6w=qBy_Z zJ6dID_XaClxUA*yz68=@!g|Sy_5A7KkW~Hk)%8^i4QM|fWRihXzfUPue>GJPS|qp@ zf4iUf`hD2J=Ed={K^aY5rtD+BNL;(k%v1HXITl`irywHT)Vy`vyx7c*LsS;uo_tAF z67^i`rWhWSK4%Q5pqB5mm+6!%T}M8r-GwXBO8z*vnPUH z3AFvfmB>aFex$%<$e8^uIozsj9+a@?&gxRknP#B-m=jOPZOqD6IlikK*OcS?== zrR%^gjUhMBJ6h}LI8awy-*mjPY-c^xi$s2ypjkfejz|!lw?s?4f>UfQyrD)JGp8<7&{5btUM@FwFG= zP3yAz;cF?a>vICPefW(&THD8cg()935>JYeGyQ_*73yFm!kQX?na*7a^na;r+5;?l zI(L0#sCC+ue>IWd)!}~GCbe68GUt9ibWP6SD2+Dj=9WP7oTkjJ`A9iSNa21J0zCUR z21;R=K-ABYX%Ue=89{1GF@X_M-)wqThpcVPuPgH8RH)Q4y@v~9CBj7o-TZH$ej&o! z4etm~4`HN$UJ2ir_JI@6MM&0~NKP!P=N|L?^2ONnULX@apL5t5=GFr3lhuLRMOzi+KKaOFKK@Q@ zHYXH1Ii+wWUFviN{$&b8M%}Hv+$~S_eGgBuuL4?6)nGufiybftMcqb(P`x^pl2y6a z1)=keBj*B_KjC;1drxua-k)zM)pue5?&V#E^Teh!nF8H992SSpeoWDxpSn`GEu^?1 z74}0+;z=d45)3K^qKI1LJn3N>f-hP|98_7IJ34J(i-8y0o0PaDUb``Q=Dfp2t) zbrVPati!W%Xpa@>-`=TMv=#-&7&YsKaOCr|>@?x}Y~8_ab+zswZZ|{-xU2V$3}3Q) zuZ|BiQ2!{e@{$*N4ICB2BwLM@A`b(}LcQ*nS0AV&f%9r-7j!vy*>ioqF2xfb#ks~y zQ*^1J<>8LzorQD?AX_=S7^DP$S&p=V&4}bq^XLfOWF+*&6|Xy&0em|SW-dZeHLvvlTzwa+C*+N z-_rsu4>|8%owpIVi-Yxzl)=;0PsiDId#k=vuzx8qDo|HTQYA^w)YnXYILBv>0zcy<`2IVa-cUo3hpZc);TLl=&eM)3fxFJCCIy%<4_Tc@cc zIY6{hX4u~z0#rqzRq`gz6A5U+oo*!xrt8C*V60k|MuJlE-CY!93|G(Pfhlhxa6LS9 zu0QD_a62Vb(I-Pb2jGdf?FkTjdjO47h&^iSb31mgzuM-x>Y2ODci+Qw2ZbfLoabMk z=K~%agX$MRE#Mz=e-RISv)lKE?UZkJ*;J8r=RR8s%Xi)G(mEfcasAZ@X9k1^D2Eii z&pcZH8{3{ekaRNX;cX>)CM*z5zyf&;^L+J6@OOmMaK`f`jM zE2;zf9m@^CA6xoI+O&PScmX0947}PdIi|gy5(PuG^+UV3Phl_NJ{%>2w)}$#0XB(S z(t;f5d59+jvoRU)|M9P4xTbUqXuxD(^#za}F-vEhiNp%9LFK?58NPl2a?uAemzkeK z3qHc&!``9M!5;y0(# zvVDv!6RAwwfNSJWfCIly=+~~0nAgJ^Weuf_ywO*;hV?9&x={NAOFsq=BkG_4dT4gZ zMslM9;5M%uZz%yD4*VD!SdN0~ZU3NoK6Y*zuLXtrE%MfbU#u`;J!Xf*E$PNp95`cUGD|E1FWP!gyCsfnu6%f zz6N75l51P7uGSAx^K4$geaIG9;C#|Yo@`9dK0c$`X|2-^dhn(VY@r9xHCA8B-XD)7 z%!-oLM8#QFw#c)F*jZ|7mh5ij7XUFlZn~tn8UC95mBI+2rhl_wG_8g~f|V@s!+x; zvq$ggQ654=`=OtwQsbx7in#nUGoY&ql^S@OBMKQi*| z+a|vujO5<&mtgnHMS!p-xXvTg9~-)3I4$si7Sm5=FLrsZ)~~|=i?k=jOKCZ?rz3KY z9Os2*rrEio=CUde%wv!QG zca(7rst1HUBps-wA(ypA$G9KE`6qB@H$qc>(T)-thX3FOTzu@=X6nB}w!gvRM7_iP zqi1jThMoUl8b_UArolc;1QmzwA-Ox+J*}S{-Kta?YK$3848Bnf0({A-#Oo2Tkx9ni z&7BU??NIU_?2+(Am^+kbv94J?&&{MZR^3b$(PTQ*;kPfpe~2pVirldRdMJrY;4R+?53N$*fr|B7b59prD| z0Ku{-%>`c0gwJUm;{YV!SorgtRQ7?k=eVyxyF9LoxO11m*FSwRher_Y49ujeCqv}S zcX6UjRJAM_Hp+#X>>e&dB@zw{hT4ijf7vm3?~5K~|6DJ+n|sy27;7DtSRV+cPab~nY z^VYkCBeu(iuczi@;*u#ec2+Bd7mGhr9QV~iL!vQItm|Oy`S%v?H7>sN_9|4sL}Z-C zaGys=xC-NOJO`rUS^Zhe_0dp*8wG$wiHkJDtsz1B{h66cg7nze5(2xoFfsP*ERupTb#MCDdw)Z7it(h7v6_uf2fluM$Ew|C^eT(1 zWo6=q`OwyqJ3Gy4goc%sY<#cg8;~r+B>;kLp$L-07`P~YZ?azahd!Fe151NKHFJ;Z zdwMda(f(IsDi~~IU&XPdl%Iw?7xiPL< z^^^!3lyZZYm#x^RkAvo$ebzh5_bGm3WEqFVSB+OPQdCpp_S`bBUXt0qRZ6Rf=v{bF zmac+mu&egOLQ6yb#13k50jcF0rmC<$Zq(xRI&hSbkco;YJi@{&?j3U#H1?2wT^GJ= zrCtXy@r{k-pZW&gVJ88tB~;XagwBhTsC{#;31g)72U0HUvLsy4N%1xg5ON_qL_{ww zc6k0n#$)c~GXael!keWY=ZN4y$|SdUmZKxBCpSF}evi{3)|g-Q3D;L7gY#}PkMth| zdtq>2y_^=RQ~OqAqv=%M%f=V;KzI#cJ-R_z1b{Z7Qp+tvX@8Uv;{S^}1&}eNJdkS} zFA4UaTJUpnvmV!wX3RG6wrvqyjT$Pd6x*)#!`;5&W+tkF0VTr#bMyA>k_Qy4EguSD zZx8~If<1>(e*h|%N6wm@XeE@H)jX*~8|)cXTDqU2VNavbx+2VRQ|AGIfS9Tjr~=)} zh^0XCN5t{|O{cLhE>5O;uZs=U9v^!RHok5u`HW?p`Cwxb_7M{S{2vie{CEhW!2B-& z5!T%5>g>?CF&)fzhkyV7$2b1hkU^9LX2bwH`-1U!9N`TN0etTR2xIKTrlTMdRyFxp z#VpWdkOe>rZI(y|&qcD{dw{ezvhsO!RPw4__JeB;!a_ep#HaxNC{iIF4*lVQ@Kg9B z!y69y9E)6pmJJi4?w5u?GH%cNpZlZ2EW*H(t=@;Q+2sJNr~j%75AE3JjZ5l@RBlEj z-(yiyh;+ZFVgTHhL_MwZUc>zqKhN{x8-DvF0FC5ZEJ8^O0+^IKxdoDsRT%Hb|2Z=E zu${v(GBGayUlMX}^ciHd*El-jN=bTy^&(4&g`*Cnm{2*d0f|{(tKpr)w@~L_5q1T7 zer3>=2OC~DEsvrY!6rA|*!P(fxGEsGtSk_Wh$JXJWfDMvTB)0G(4rr4Mp|Y2gfhFW zY0{2hDYibJ;G$b>fDUk9lLrEy{B~cuoi-DE0d{J@l52bqRxc|+hUi&pzr?t2*oz$f zIkj2_WdZG&lj^g2S4SJ()M2pJ^$-zY@jO1_Fl33SjU+Gy94Yekrcx<7Bo#~8>*EU` z+ZmrnJV%uv&DAzaJX>L@KRfH==}6!?{X`>c_zH+Av|b#=^fNK=!g>yE+^FKcE!b1K z$+Vu_--GOW`Q6l7n0sQ>Yb3>*E8oi>H-;NEk7+0R&8LRn1;dm^nl&lTw}qIbiuKYKBU7OG*l}Fn8JwrAgZr_(*4vY z-O`*D$!d4rkF^&UY2_vv$1l>rPXVHX0X zPcUIN1ENoxGgGk{S+(b%_}7u-?|Pl_8?3XFR2?IPsiDZ*Fbe_IAM9^Nfq=s86_iZ3 zG~-MJ@HXHD9SBpX95E+R{(i)c9FP(9?sNK4;pEbCv>yz}8NDSZ8#_spmd)17Cky(8Y`YdP(^a zBaehF2V9Kf1AJQkzg6S1&o+Xx6}}dBNZd!Dj!cW>zKK@-`zZuhpRdnhh=I<~=cj=^I`zS*Hwy!V=63}C zO}zjJVJ!R@x2?Si%VIZ>X-LguOlEp9U}HZcF8LjSQK2V_Y`k!z(3^$OkYX+tR1i0 z%AY@y1ZG?Sny!8Kn;*9Bm1gbr`xAw3=^$`3zjc@P`O%cOICYQB2B$bFSSW^N*4XSA zOepQ>Woxp`X6@%o6;oDTT-sE<{UcIPuGp(@%l%WS&bpwX`!~cb(dddi% zGb7B|)(Ps-(VLi43mbV+?@Dd5-wIjvP(i%J_Uaz4z}_k`Lm9Pkqq^7IL9x^+El{(t zH=HW%kgLVdAX054Ft`s6`4o4t3Cy#S-gIDZfcy_lR&Mr?XFG?^I%qhq{^Ibh&$aB0)^}6XcGRFdhi+jba-l!6u{PGLuxHEwAWFR z6Ieg*_2?(q!Z`E!{v>X!{48pcY1`0xWP~p`qzmL!)OYUoEkOpTnsAD0OL7;5u@ zf6?4>B|+`A#Rhfu+mdy)W#$gq^W2DXq(K;NOv}pZa6@DDOw*Zci@$l!AihUZxgV}B zh#_v2msT#E?Iud9uk|D7wzn@wO^**>HHcr zuiS(8hSp(Kh$ePWtJ*4ZPX?TGr5pR}mGQS!#8(WxJpsekA3~!}^i|tpJR)x}eBs{V zOGw;T^teY{Fa%aax?7?eF`Hc{AG1Wt*m}${qpx^(OeAKhd|ff7SZP^hF!N_QYS)E; z/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 Date: Tue, 8 Oct 2024 20:16:17 +0100 Subject: [PATCH 101/159] Update README.md I added a new image (alas should have a better description), but hope this PR may help someone. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e3f9266233..3ac4765303 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Releases provide convenient downloads of sample databases and applications, elim - [IoT Smart Grid sample v1.0](https://github.com/Microsoft/sql-server-samples/releases/tag/iot-smart-grid-v1.0) illustrates how SQL Server can be leveraged to ingest data from IoT devices and sensors, and how you can run analytics on that data. To see the complete list of resources in this repository, navigate to [Releases](https://github.com/Microsoft/sql-server-samples/releases) +(this now includes an entity diagram of Northwind database) to help visual learners. ## Working in GitHub To contribute on GitHub, follow these steps: From ae21bdd87961828a761874cecda5b699fc90f4be Mon Sep 17 00:00:00 2001 From: Ted Malone Date: Thu, 17 Oct 2024 14:19:48 -0700 Subject: [PATCH 102/159] Update Schema of existing dashboards and add new SQL Health Dashboard Example --- .vscode/settings.json | 3 + .../dashboard/Arc - Deployment Progress.json | 92 +- .../azure-arc/dashboard/Arc - ESU.json | 46 +- .../dashboard/Arc - Estate Profile.json | 76 +- .../dashboard/Arc - SQL Server Inventory.json | 38 +- .../dashboard/Arc - Server Deployment.json | 54 +- .../dashboard/SQL Server Estate Health.json | 874 ++++++++++++++++++ .../dashboard/SQL Server Instances.json | 42 +- 8 files changed, 1051 insertions(+), 174 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 samples/features/azure-arc/dashboard/SQL Server Estate Health.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..c9a6001477 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.defaultSolution": "disable" +} \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/Arc - Deployment Progress.json b/samples/features/azure-arc/dashboard/Arc - Deployment Progress.json index b3df74aa80..a037953023 100644 --- a/samples/features/azure-arc/dashboard/Arc - Deployment Progress.json +++ b/samples/features/azure-arc/dashboard/Arc - Deployment Progress.json @@ -1,10 +1,10 @@ { "properties": { - "lenses": { - "0": { + "lenses": [ + { "order": 0, - "parts": { - "0": { + "parts": [ + { "position": { "x": 0, "y": 0, @@ -25,7 +25,7 @@ } } }, - "1": { + { "position": { "x": 0, "y": 2, @@ -77,7 +77,7 @@ } } }, - "2": { + { "position": { "x": 3, "y": 2, @@ -129,7 +129,7 @@ } } }, - "3": { + { "position": { "x": 7, "y": 2, @@ -181,7 +181,7 @@ } } }, - "4": { + { "position": { "x": 11, "y": 2, @@ -233,7 +233,7 @@ } } }, - "5": { + { "position": { "x": 14, "y": 2, @@ -254,7 +254,7 @@ } } }, - "6": { + { "position": { "x": 0, "y": 4, @@ -302,11 +302,11 @@ "settings": {}, "partHeader": { "title": "Windows Servers", - "subtitle": "Count of Windws Servers registered to Arc" + "subtitle": "Count of Windows Servers registered to Arc" } } }, - "7": { + { "position": { "x": 3, "y": 4, @@ -354,11 +354,11 @@ "settings": {}, "partHeader": { "title": "Windows Servers Core Count", - "subtitle": "Count of Windws Servers Cores registered to Arc" + "subtitle": "Count of Windows Servers Cores registered to Arc" } } }, - "8": { + { "position": { "x": 7, "y": 4, @@ -410,7 +410,7 @@ } } }, - "9": { + { "position": { "x": 11, "y": 4, @@ -462,7 +462,7 @@ } } }, - "10": { + { "position": { "x": 0, "y": 6, @@ -514,7 +514,7 @@ } } }, - "11": { + { "position": { "x": 3, "y": 6, @@ -566,7 +566,7 @@ } } }, - "12": { + { "position": { "x": 7, "y": 6, @@ -618,7 +618,7 @@ } } }, - "13": { + { "position": { "x": 11, "y": 6, @@ -639,7 +639,7 @@ } } }, - "14": { + { "position": { "x": 0, "y": 8, @@ -691,7 +691,7 @@ } } }, - "15": { + { "position": { "x": 3, "y": 8, @@ -739,11 +739,11 @@ "settings": {}, "partHeader": { "title": "Servers with SQL Server Ent/Std Edition", - "subtitle": "Servers with at least one instance of Standard or Enterprisre Edition" + "subtitle": "Servers with at least one instance of Standard or Enterprise Edition" } } }, - "16": { + { "position": { "x": 7, "y": 8, @@ -795,7 +795,7 @@ } } }, - "17": { + { "position": { "x": 11, "y": 8, @@ -816,7 +816,7 @@ } } }, - "18": { + { "position": { "x": 16, "y": 8, @@ -868,7 +868,7 @@ } } }, - "19": { + { "position": { "x": 0, "y": 10, @@ -915,12 +915,12 @@ "type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile", "settings": {}, "partHeader": { - "title": "Provisioned SQL Server Instasnces", + "title": "Provisioned SQL Server Instances", "subtitle": "Count of SQL Server instances provisioned" } } }, - "20": { + { "position": { "x": 3, "y": 10, @@ -972,7 +972,7 @@ } } }, - "21": { + { "position": { "x": 7, "y": 10, @@ -993,7 +993,7 @@ } } }, - "22": { + { "position": { "x": 0, "y": 12, @@ -1046,7 +1046,7 @@ } } }, - "23": { + { "position": { "x": 13, "y": 12, @@ -1099,7 +1099,7 @@ } } }, - "24": { + { "position": { "x": 0, "y": 18, @@ -1152,7 +1152,7 @@ } } }, - "25": { + { "position": { "x": 0, "y": 24, @@ -1205,7 +1205,7 @@ } } }, - "26": { + { "position": { "x": 0, "y": 31, @@ -1258,7 +1258,7 @@ } } }, - "27": { + { "position": { "x": 9, "y": 31, @@ -1310,7 +1310,7 @@ } } }, - "28": { + { "position": { "x": 0, "y": 38, @@ -1359,11 +1359,11 @@ "settings": {}, "partHeader": { "title": "SQL Server Instances by Version", - "subtitle": "SQL Server instasnces enabled by Azure Arc by SQL Server version" + "subtitle": "SQL Server instances enabled by Azure Arc by SQL Server version" } } }, - "29": { + { "position": { "x": 9, "y": 38, @@ -1416,7 +1416,7 @@ } } }, - "30": { + { "position": { "x": 0, "y": 45, @@ -1468,7 +1468,7 @@ } } }, - "31": { + { "position": { "x": 0, "y": 51, @@ -1520,7 +1520,7 @@ } } }, - "32": { + { "position": { "x": 0, "y": 56, @@ -1572,7 +1572,7 @@ } } }, - "33": { + { "position": { "x": 0, "y": 61, @@ -1624,7 +1624,7 @@ } } }, - "34": { + { "position": { "x": 0, "y": 67, @@ -1678,9 +1678,9 @@ } } } - } + ] } - }, + ], "metadata": { "model": { "timeRange": { @@ -1701,5 +1701,5 @@ "tags": { "hidden-title": "Arc - Deployment Progress" }, - "apiVersion": "2015-08-01-preview" + "apiVersion": "2022-12-01-preview" } \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/Arc - ESU.json b/samples/features/azure-arc/dashboard/Arc - ESU.json index b42ac4d951..df1473054b 100644 --- a/samples/features/azure-arc/dashboard/Arc - ESU.json +++ b/samples/features/azure-arc/dashboard/Arc - ESU.json @@ -1,10 +1,10 @@ { "properties": { - "lenses": { - "0": { + "lenses": [ + { "order": 0, - "parts": { - "0": { + "parts": [ + { "position": { "x": 0, "y": 0, @@ -25,7 +25,7 @@ } } }, - "1": { + { "position": { "x": 0, "y": 2, @@ -46,7 +46,7 @@ } } }, - "2": { + { "position": { "x": 6, "y": 2, @@ -67,7 +67,7 @@ } } }, - "3": { + { "position": { "x": 12, "y": 2, @@ -88,7 +88,7 @@ } } }, - "4": { + { "position": { "x": 0, "y": 3, @@ -141,7 +141,7 @@ } } }, - "5": { + { "position": { "x": 6, "y": 3, @@ -194,7 +194,7 @@ } } }, - "6": { + { "position": { "x": 12, "y": 3, @@ -247,7 +247,7 @@ } } }, - "7": { + { "position": { "x": 0, "y": 8, @@ -300,7 +300,7 @@ } } }, - "8": { + { "position": { "x": 6, "y": 8, @@ -353,7 +353,7 @@ } } }, - "9": { + { "position": { "x": 12, "y": 8, @@ -406,7 +406,7 @@ } } }, - "10": { + { "position": { "x": 0, "y": 13, @@ -458,7 +458,7 @@ } } }, - "11": { + { "position": { "x": 12, "y": 13, @@ -511,7 +511,7 @@ } } }, - "12": { + { "position": { "x": 0, "y": 18, @@ -564,7 +564,7 @@ } } }, - "13": { + { "position": { "x": 0, "y": 24, @@ -616,7 +616,7 @@ } } }, - "14": { + { "position": { "x": 12, "y": 24, @@ -669,7 +669,7 @@ } } }, - "15": { + { "position": { "x": 0, "y": 29, @@ -721,7 +721,7 @@ } } }, - "16": { + { "position": { "x": 12, "y": 29, @@ -774,9 +774,9 @@ } } } - } + ] } - }, + ], "metadata": { "model": { "timeRange": { @@ -797,5 +797,5 @@ "tags": { "hidden-title": "Arc - ESU" }, - "apiVersion": "2015-08-01-preview" + "apiVersion": "2022-12-01-preview" } \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/Arc - Estate Profile.json b/samples/features/azure-arc/dashboard/Arc - Estate Profile.json index b6df9548e0..91d888f0d9 100644 --- a/samples/features/azure-arc/dashboard/Arc - Estate Profile.json +++ b/samples/features/azure-arc/dashboard/Arc - Estate Profile.json @@ -1,10 +1,10 @@ { "properties": { - "lenses": { - "0": { + "lenses": [ + { "order": 0, - "parts": { - "0": { + "parts": [ + { "position": { "x": 0, "y": 0, @@ -25,7 +25,7 @@ } } }, - "1": { + { "position": { "x": 0, "y": 2, @@ -77,7 +77,7 @@ } } }, - "2": { + { "position": { "x": 2, "y": 2, @@ -129,7 +129,7 @@ } } }, - "3": { + { "position": { "x": 4, "y": 2, @@ -181,7 +181,7 @@ } } }, - "4": { + { "position": { "x": 6, "y": 2, @@ -233,7 +233,7 @@ } } }, - "5": { + { "position": { "x": 8, "y": 2, @@ -285,7 +285,7 @@ } } }, - "6": { + { "position": { "x": 10, "y": 2, @@ -337,7 +337,7 @@ } } }, - "7": { + { "position": { "x": 12, "y": 2, @@ -389,7 +389,7 @@ } } }, - "8": { + { "position": { "x": 14, "y": 2, @@ -441,7 +441,7 @@ } } }, - "9": { + { "position": { "x": 16, "y": 2, @@ -493,7 +493,7 @@ } } }, - "10": { + { "position": { "x": 18, "y": 2, @@ -545,7 +545,7 @@ } } }, - "11": { + { "position": { "x": 21, "y": 2, @@ -597,7 +597,7 @@ } } }, - "12": { + { "position": { "x": 0, "y": 5, @@ -650,7 +650,7 @@ } } }, - "13": { + { "position": { "x": 0, "y": 11, @@ -703,7 +703,7 @@ } } }, - "14": { + { "position": { "x": 0, "y": 17, @@ -756,7 +756,7 @@ } } }, - "15": { + { "position": { "x": 9, "y": 17, @@ -811,7 +811,7 @@ } } }, - "16": { + { "position": { "x": 18, "y": 17, @@ -864,7 +864,7 @@ } } }, - "17": { + { "position": { "x": 0, "y": 23, @@ -916,7 +916,7 @@ } } }, - "18": { + { "position": { "x": 13, "y": 23, @@ -970,7 +970,7 @@ } } }, - "19": { + { "position": { "x": 16, "y": 23, @@ -1022,7 +1022,7 @@ } } }, - "20": { + { "position": { "x": 13, "y": 26, @@ -1074,7 +1074,7 @@ } } }, - "21": { + { "position": { "x": 0, "y": 29, @@ -1127,7 +1127,7 @@ } } }, - "22": { + { "position": { "x": 0, "y": 34, @@ -1180,7 +1180,7 @@ } } }, - "23": { + { "position": { "x": 0, "y": 39, @@ -1201,7 +1201,7 @@ } } }, - "24": { + { "position": { "x": 0, "y": 40, @@ -1254,7 +1254,7 @@ } } }, - "25": { + { "position": { "x": 0, "y": 46, @@ -1307,7 +1307,7 @@ } } }, - "26": { + { "position": { "x": 0, "y": 52, @@ -1360,7 +1360,7 @@ } } }, - "27": { + { "position": { "x": 0, "y": 59, @@ -1413,7 +1413,7 @@ } } }, - "28": { + { "position": { "x": 13, "y": 59, @@ -1466,7 +1466,7 @@ } } }, - "29": { + { "position": { "x": 0, "y": 65, @@ -1519,7 +1519,7 @@ } } }, - "30": { + { "position": { "x": 0, "y": 71, @@ -1572,7 +1572,7 @@ } } }, - "31": { + { "position": { "x": 0, "y": 77, @@ -1625,9 +1625,9 @@ } } } - } + ] } - }, + ], "metadata": { "model": { "timeRange": { @@ -1667,5 +1667,5 @@ "tags": { "hidden-title": "Arc - Estate Profile" }, - "apiVersion": "2015-08-01-preview" + "apiVersion": "2022-12-01-preview" } \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json b/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json index f33f344780..7a10ebd428 100644 --- a/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json +++ b/samples/features/azure-arc/dashboard/Arc - SQL Server Inventory.json @@ -1,10 +1,10 @@ { "properties": { "lenses": [ - { + { "order": 0, "parts": [ - { + { "position": { "x": 0, "y": 0, @@ -25,7 +25,7 @@ } } }, - { + { "position": { "x": 0, "y": 2, @@ -77,7 +77,7 @@ } } }, - { + { "position": { "x": 3, "y": 2, @@ -181,7 +181,7 @@ } } }, - { + { "position": { "x": 0, "y": 6, @@ -234,7 +234,7 @@ } } }, - { + { "position": { "x": 0, "y": 11, @@ -287,7 +287,7 @@ } } }, - { + { "position": { "x": 0, "y": 16, @@ -336,11 +336,11 @@ "settings": {}, "partHeader": { "title": "Compatibility Level", - "subtitle": "Count of databases by compatibilty level" + "subtitle": "Count of databases by compatabilty level" } } }, - { + { "position": { "x": 0, "y": 21, @@ -446,7 +446,7 @@ } } }, - { + { "position": { "x": 12, "y": 21, @@ -499,7 +499,7 @@ } } }, - { + { "position": { "x": 0, "y": 27, @@ -548,11 +548,11 @@ "settings": {}, "partHeader": { "title": "SQL Server Edition Summary", - "subtitle": "Count of SQL Server instances by **instsance** license type and edition" + "subtitle": "Count of SQL Server instances by **instances** license type and edition" } } }, - { + { "position": { "x": 12, "y": 27, @@ -606,7 +606,7 @@ } } }, - { + { "position": { "x": 0, "y": 34, @@ -627,7 +627,7 @@ } } }, - { + { "position": { "x": 0, "y": 35, @@ -680,7 +680,7 @@ } } }, - { + { "position": { "x": 0, "y": 42, @@ -731,7 +731,7 @@ }, "partHeader": { "title": "SQL Server Instances by Location", - "subtitle": "SQL Servers instasnces by \"Location\" tag values" + "subtitle": "SQL Servers instances by \"Location\" tag values" } } }, @@ -785,7 +785,7 @@ "content": {} }, "partHeader": { - "title": "SQL Server Instasnces by Data Center", + "title": "SQL Server Instances by Data Center", "subtitle": "SQL Servers instances by \"Datacenter\" tag values." } } @@ -868,5 +868,5 @@ "tags": { "hidden-title": "Arc - SQL Server Inventory" }, - "apiVersion": "2015-08-01-preview" + "apiVersion": "2022-12-01-preview" } diff --git a/samples/features/azure-arc/dashboard/Arc - Server Deployment.json b/samples/features/azure-arc/dashboard/Arc - Server Deployment.json index a6033ae83d..b2067900f3 100644 --- a/samples/features/azure-arc/dashboard/Arc - Server Deployment.json +++ b/samples/features/azure-arc/dashboard/Arc - Server Deployment.json @@ -1,10 +1,10 @@ { "properties": { - "lenses": { - "0": { + "lenses": [ + { "order": 0, - "parts": { - "0": { + "parts": [ + { "position": { "x": 0, "y": 0, @@ -56,7 +56,7 @@ } } }, - "1": { + { "position": { "x": 3, "y": 0, @@ -108,7 +108,7 @@ } } }, - "2": { + { "position": { "x": 0, "y": 4, @@ -161,7 +161,7 @@ } } }, - "3": { + { "position": { "x": 3, "y": 4, @@ -213,7 +213,7 @@ } } }, - "4": { + { "position": { "x": 0, "y": 8, @@ -266,7 +266,7 @@ } } }, - "5": { + { "position": { "x": 3, "y": 8, @@ -318,7 +318,7 @@ } } }, - "6": { + { "position": { "x": 0, "y": 12, @@ -371,7 +371,7 @@ } } }, - "7": { + { "position": { "x": 3, "y": 12, @@ -424,7 +424,7 @@ } } }, - "8": { + { "position": { "x": 0, "y": 16, @@ -477,7 +477,7 @@ } } }, - "9": { + { "position": { "x": 10, "y": 16, @@ -531,7 +531,7 @@ } } }, - "10": { + { "position": { "x": 0, "y": 20, @@ -584,7 +584,7 @@ } } }, - "11": { + { "position": { "x": 10, "y": 20, @@ -638,7 +638,7 @@ } } }, - "12": { + { "position": { "x": 0, "y": 24, @@ -690,7 +690,7 @@ } } }, - "13": { + { "position": { "x": 0, "y": 28, @@ -744,7 +744,7 @@ } } }, - "14": { + { "position": { "x": 6, "y": 28, @@ -797,7 +797,7 @@ } } }, - "15": { + { "position": { "x": 12, "y": 28, @@ -851,7 +851,7 @@ } } }, - "16": { + { "position": { "x": 0, "y": 33, @@ -905,7 +905,7 @@ } } }, - "17": { + { "position": { "x": 6, "y": 33, @@ -959,7 +959,7 @@ } } }, - "18": { + { "position": { "x": 12, "y": 33, @@ -1012,7 +1012,7 @@ } } }, - "19": { + { "position": { "x": 0, "y": 38, @@ -1066,9 +1066,9 @@ } } } - } + ] } - }, + ], "metadata": { "model": { "timeRange": { @@ -1089,5 +1089,5 @@ "tags": { "hidden-title": "Arc Server Deployment" }, - "apiVersion": "2015-08-01-preview" -} + "apiVersion": "2022-12-01-preview" +} \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/SQL Server Estate Health.json b/samples/features/azure-arc/dashboard/SQL Server Estate Health.json new file mode 100644 index 0000000000..f0fcb93e33 --- /dev/null +++ b/samples/features/azure-arc/dashboard/SQL Server Estate Health.json @@ -0,0 +1,874 @@ +{ + "properties": { + "lenses": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 2, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "// Count of all resources\nresources\n| where type == \"microsoft.sql/managedinstances\" or \n type == \"microsoft.azurearcdata/sqlserverinstances\" or \n type == \"microsoft.sql/servers\" or \n type==\"microsoft.sqlvirtualmachine/sqlvirtualmachines\"\n| summarize Servers=count()\n", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile", + "settings": {}, + "partHeader": { + "title": "Number of Servers", + "subtitle": "" + } + } + }, + { + "position": { + "x": 2, + "y": 0, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.sql/managedinstances\" or \n type == \"microsoft.azurearcdata/sqlserverinstances\" or \n type == \"microsoft.sql/servers\" or \n type == \"microsoft.sqlvirtualmachine/sqlvirtualmachines\"\n| summarize ResourceCount=count() by iff( \n type==\"microsoft.sql/managedinstances\",\"Azure SQL Manage Instance\"\n ,iif(\n type==\"microsoft.azurearcdata/sqlserverinstances\",\"Arc Enable SQL Server\"\n ,iif(\n type==\"microsoft.sql/servers\",\"Azure SQL DB\"\n ,iif(\n type==\"microsoft.sqlvirtualmachine/sqlvirtualmachines\",\"Azure SQL Server On VM\",\"Not Found\"\n )\n )\n )\n )\n", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Sql Server Type Distributions", + "subtitle": "" + } + } + }, + { + "position": { + "x": 8, + "y": 0, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "// top ten resource types by number of resources\n// Count of all resources\nresources\n| where (type == \"microsoft.sql/managedinstances/databases\" or \n type == \"microsoft.azurearcdata/sqlserverinstances/databases\" or \n type == \"microsoft.sql/servers/databases\" or \n type==\"microsoft.sqlvirtualmachine/sqlvirtualmachines/databases\") and \n (name !in (\"master\",\"model\",\"msdb\") and \n name !contains \"tempdb\")\n| summarize ResourceCount=count() by iff( \n type==\"microsoft.sql/managedinstances/databases\",\"Azure SQL Manage Instance\"\n ,iif(\n type==\"microsoft.azurearcdata/sqlserverinstances/databases\",\"Arc Enable SQL Server\"\n ,iif(\n type==\"microsoft.sql/servers/databases\",\"Azure SQL DB\"\n ,iif(\n type==\"microsoft.sqlvirtualmachine/sqlvirtualmachines/databases\",\"Azure SQL Server On VM\",\"Not Found\"\n )\n )\n )\n )", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "User Databases per Type", + "subtitle": "Does Not Include System Databases" + } + } + }, + { + "position": { + "x": 14, + "y": 0, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where type == \"microsoft.sql/managedinstances\" or \r\n type == \"microsoft.azurearcdata/sqlserverinstances\" or \r\n type == \"microsoft.sql/servers\" or \r\n type == \"microsoft.sqlvirtualmachine/sqlvirtualmachines\"\r\n| summarize Count=sum(toint(properties['vCore'])) by tostring(properties['edition'])\r\n| where isnotempty (properties_edition)\r\n| order by Count desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Core Count by Edition", + "subtitle": "" + } + } + }, + { + "position": { + "x": 0, + "y": 3, + "colSpan": 2, + "rowSpan": 6 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "// Count of all resources\nresources\n| where (type == \"microsoft.sql/managedinstances/databases\" or \n type == \"microsoft.azurearcdata/sqlserverinstances/databases\" or \n type == \"microsoft.sql/servers/databases\" )\n| count ", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile", + "settings": {}, + "partHeader": { + "title": "Number of Databases", + "subtitle": "Includes all system databases" + } + } + }, + { + "position": { + "x": 2, + "y": 4, + "colSpan": 6, + "rowSpan": 5 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 2", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "// If distinct count is small (e.g. < 1000)\n// run next query to get count of each value\nresources\n| where type == \"microsoft.sql/managedinstances\" or \n type == \"microsoft.azurearcdata/sqlserverinstances\" or \n type == \"microsoft.sqlvirtualmachine/sqlvirtualmachines\"\n| summarize Count=count() by iif(type==\"microsoft.azurearcdata/sqlserverinstances\"\n,tostring(properties['edition'])\n, iif(type==\"microsoft.sql/managedinstances\", tostring(sku['tier'])\n,tostring(properties['sqlImageSku'])))\n| order by Count desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Servers per SQL Server Editions", + "subtitle": "" + } + } + }, + { + "position": { + "x": 8, + "y": 4, + "colSpan": 6, + "rowSpan": 5 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| summarize Count=sum(toint(properties['vCore'])) by tostring(properties['licenseType'])\r\n| order by Count desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Cores Per LicenseType", + "subtitle": "" + } + } + }, + { + "position": { + "x": 14, + "y": 4, + "colSpan": 6, + "rowSpan": 5 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.azurearcdata/sqlserverinstances/databases\"\n| extend prop_db=parse_xml(properties) \n| extend Recovery_Model = prop_db.recoveryMode\n| summarize Count = count() by tostring(Recovery_Model)", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Server Recovery Mode", + "subtitle": "" + } + } + }, + { + "position": { + "x": 0, + "y": 9, + "colSpan": 6, + "rowSpan": 6 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 2", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\n| summarize Count=count() by iff(tostring(properties['azureDefenderStatus'])==\"Unknown\", \"Not Protected\",tostring(properties['azureDefenderStatus']))\n| order by Count desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Defender for SQL", + "subtitle": "" + } + } + }, + { + "position": { + "x": 6, + "y": 9, + "colSpan": 6, + "rowSpan": 6 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 2", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "// If distinct count is small (e.g. < 1000)\n// run next query to get count of each value\nresources\n| where type == \"microsoft.azurearcdata/sqlserverinstances/databases\"\n|summarize Count=count() by tostring(properties['compatibilityLevel'])\n| order by Count desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Compatibility Mode", + "subtitle": "" + } + } + }, + { + "position": { + "x": 12, + "y": 9, + "colSpan": 7, + "rowSpan": 6 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\n| summarize Count=count() by tostring(properties['version'])", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Server Versions", + "subtitle": "" + } + } + }, + { + "position": { + "x": 0, + "y": 15, + "colSpan": 6, + "rowSpan": 5 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where (type == \"microsoft.sql/managedinstances/databases\" or \n type == \"microsoft.azurearcdata/sqlserverinstances/databases\" or \n type == \"microsoft.sql/servers/databases\" )\n| extend prop_db=parse_xml(properties) \n| extend prop_db_recoveryMode = prop_db.recoveryMode\n| extend prop_db_databaseCreationDate = todatetime(prop_db.databaseCreationDate)\n| extend prop_db_backupInformation = prop_db.backupInformation\n| extend prop_db_backupInformation_lastFullBackup = todatetime(prop_db.backupInformation.lastFullBackup)\n| extend calc_lastBackupAgeDays = iff(isnull(prop_db_backupInformation_lastFullBackup),\n datetime_diff('Day',now(),prop_db_databaseCreationDate),\n datetime_diff('Day',now(),prop_db_backupInformation_lastFullBackup)\n )\n| extend Backup_1day = iif( calc_lastBackupAgeDays <=1 , 1 , 0)\n| extend Backup_7day = iif( calc_lastBackupAgeDays >1 and calc_lastBackupAgeDays <=7 , 1 , 0)\n| extend Backup_over7day = iif( calc_lastBackupAgeDays >7 , 1 , 0)\n| extend Backup_desc = case(\n isnull(prop_db_backupInformation_lastFullBackup), \"no backups at all\", \n datetime_diff('Day',now(),prop_db_backupInformation_lastFullBackup) <= 1, \"1 day\", \n datetime_diff('Day',now(),prop_db_backupInformation_lastFullBackup) <= 7, \"7 days\", \n datetime_diff('Day',now(),prop_db_backupInformation_lastFullBackup) <= 30, \"1 Month\", \n \"older than a month\")\n| project database_name = name, RecoveryModel = prop_db_recoveryMode, Last_Full_Backup = prop_db_backupInformation_lastFullBackup , Backup_Age_Days = calc_lastBackupAgeDays ,Backup_1day ,Backup_7day ,Backup_over7day, Backup_desc\n| summarize Count=count() by Backup_desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Server Backups Intervals", + "subtitle": "" + } + } + }, + { + "position": { + "x": 6, + "y": 15, + "colSpan": 6, + "rowSpan": 5 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "chartType", + "value": 1, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where ['type'] ==\"microsoft.azurearcdata/sqlserverinstances/databases\"\n| summarize Count=count() by Encrypte=iif(tostring(properties['databaseOptions'].isEncrypted)==\"false\",\"No\", \"Yes\")", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Encrypted", + "subtitle": "" + } + } + }, + { + "position": { + "x": 12, + "y": 15, + "colSpan": 6, + "rowSpan": 5 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n | where type =~ 'microsoft.hybridcompute/machines/extensions'\r\n | where properties.type in ('WindowsAgent.SqlServer','LinuxAgent.SqlServer')\r\n | parse id with * '/providers/Microsoft.HybridCompute/machines/' machineName '/extensions/' *\r\n | parse properties with * 'uploadStatus : ' uploadStatus ';' *\r\n | project machineName, uploadStatus, subscriptionId, resourceGroup\r\n //| where uploadStatus !in ('OK') //comment this out to see all upload stats\r\n | order by uploadStatus desc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryGridTile", + "settings": {}, + "partHeader": { + "title": "SQL Extension Upload Status", + "subtitle": "" + } + } + }, + { + "position": { + "x": 0, + "y": 20, + "colSpan": 20, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where type == \"microsoft.hybridcompute/machines\"\r\n| where properties.detectedProperties.mssqldiscovered == \"true\"\r\n| extend machineIdHasSQLServerDiscovered = id\r\n| project name, machineIdHasSQLServerDiscovered, resourceGroup, subscriptionId\r\n| join kind= leftouter (\r\n resources\r\n | where type == \"microsoft.hybridcompute/machines/extensions\"\r\n | where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n | extend machineIdHasSQLServerExtensionInstalled = iff(id contains \"/extensions/WindowsAgent.SqlServer\" or id contains \"/extensions/LinuxAgent.SqlServer\", substring(id, 0, indexof(id, \"/extensions/\")), \"\")\r\n | project Provisioning_State = properties.provisioningState,\r\n License_Type = properties.settings.LicenseType,\r\n ESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), \"enabled\", \"\"),\r\n Extension_Version = properties.instanceView.typeHandlerVersion,\r\n Exlcuded_instaces = properties.ExcludedSqlInstances,\r\n Purview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization),\"enabled\",\"\"),\r\n Entra = iff(notnull(properties.settings.AzureAD),\"enabled\",\"\"),\r\n BPA = iff(notnull(properties.settings.AssessmentSettings),\"enabled\",\"\"),\r\n machineIdHasSQLServerExtensionInstalled)\r\non $left.machineIdHasSQLServerDiscovered == $right.machineIdHasSQLServerExtensionInstalled\r\n| where isnotempty(machineIdHasSQLServerExtensionInstalled)\r\n| project-away machineIdHasSQLServerDiscovered, machineIdHasSQLServerExtensionInstalled", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryGridTile", + "settings": {}, + "partHeader": { + "title": "Arc SQL details", + "subtitle": "" + } + } + }, + { + "position": { + "x": 0, + "y": 24, + "colSpan": 20, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where (type == \"microsoft.sql/managedinstances/databases\" or \r\n type == \"microsoft.azurearcdata/sqlserverinstances/databases\" or \r\n type == \"microsoft.sql/servers/databases\" ) and \r\n (name !in (\"master\",\"model\",\"msdb\") and \r\n name !contains \"tempdb\")\r\n| summarize Dbs=count(),Offline=sum(toint(iif(tostring(properties[\"state\"])!=\"Online\" and tostring(properties[\"status\"])!=\"Online\" and tostring(properties[\"status\"])!=\"Paused\" ,1,0)))\r\n,SizeMB=sum(toint(iif(tostring(properties[\"sizeMB\"])!=\"\",properties[\"sizeMB\"],0)))\r\n,Type=max(\r\n iff( type==\"microsoft.sql/managedinstances/databases\",\"Azure SQL Manage Instance\"\r\n ,iif(type==\"microsoft.azurearcdata/sqlserverinstances/databases\",\"Arc Enable SQL Server\"\r\n ,iif(type==\"microsoft.sql/servers/databases\",\"Azure SQL DB\"\r\n ,iif(type==\"microsoft.sqlvirtualmachine/sqlvirtualmachines/databases\",\"Azure SQL Server On VM\",\"Not Found\")\r\n )\r\n )\r\n )\r\n ) by Instances = tostring(split(tostring(id),\"/\")[8])\r\n| order by Offline", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryGridTile", + "settings": {}, + "partHeader": { + "title": "Dbs per Servers", + "subtitle": "" + } + } + } + ] + } + ], + "metadata": { + "model": { + "timeRange": { + "value": { + "relative": { + "duration": 24, + "timeUnit": 1 + } + }, + "type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange" + } + } + } + }, + "name": "SQL Data Estate Health", + "type": "Microsoft.Portal/dashboards", + "location": "INSERT LOCATION", + "tags": { + "hidden-title": "SQL Data Estate Health" + }, + "apiVersion": "2022-12-01-preview" +} \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/SQL Server Instances.json b/samples/features/azure-arc/dashboard/SQL Server Instances.json index 886cc07157..17e8b267e2 100644 --- a/samples/features/azure-arc/dashboard/SQL Server Instances.json +++ b/samples/features/azure-arc/dashboard/SQL Server Instances.json @@ -1,10 +1,10 @@ { "properties": { - "lenses": { - "0": { + "lenses": [ + { "order": 0, - "parts": { - "0": { + "parts": [ + { "position": { "x": 0, "y": 0, @@ -56,7 +56,7 @@ } } }, - "1": { + { "position": { "x": 3, "y": 0, @@ -109,7 +109,7 @@ } } }, - "2": { + { "position": { "x": 9, "y": 0, @@ -161,7 +161,7 @@ } } }, - "3": { + { "position": { "x": 12, "y": 0, @@ -214,7 +214,7 @@ } } }, - "4": { + { "position": { "x": 0, "y": 5, @@ -266,7 +266,7 @@ } } }, - "5": { + { "position": { "x": 0, "y": 9, @@ -318,7 +318,7 @@ } } }, - "6": { + { "position": { "x": 0, "y": 13, @@ -371,7 +371,7 @@ } } }, - "7": { + { "position": { "x": 6, "y": 13, @@ -424,7 +424,7 @@ } } }, - "8": { + { "position": { "x": 13, "y": 13, @@ -477,7 +477,7 @@ } } }, - "9": { + { "position": { "x": 0, "y": 19, @@ -530,7 +530,7 @@ } } }, - "10": { + { "position": { "x": 6, "y": 19, @@ -583,7 +583,7 @@ } } }, - "11": { + { "position": { "x": 12, "y": 19, @@ -636,7 +636,7 @@ } } }, - "12": { + { "position": { "x": 0, "y": 25, @@ -689,7 +689,7 @@ } } }, - "13": { + { "position": { "x": 6, "y": 25, @@ -742,7 +742,7 @@ } } }, - "14": { + { "position": { "x": 0, "y": 30, @@ -796,9 +796,9 @@ } } } - } + ] } - }, + ], "metadata": { "model": { "timeRange": { @@ -819,5 +819,5 @@ "tags": { "hidden-title": "SQL Server Instances" }, - "apiVersion": "2015-08-01-preview" + "apiVersion": "2022-12-01-preview" } From 8bffa8c20294976a4dfd862a52ccc8dd24747949 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:34:18 +0000 Subject: [PATCH 103/159] Bump serve-static and express Bumps [serve-static](https://github.com/expressjs/serve-static) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `serve-static` from 1.15.0 to 1.16.2 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2) Updates `express` from 4.19.2 to 4.21.1 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.1) --- updated-dependencies: - dependency-name: serve-static dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../lib/webcomponentsjs/package-lock.json | 373 ++++++++++++------ 1 file changed, 255 insertions(+), 118 deletions(-) diff --git a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json index 0f74db87ec..122fa6d35c 100644 --- a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json +++ b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json @@ -4319,6 +4319,17 @@ "dev": true, "optional": true }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -4744,6 +4755,42 @@ } } }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, "es5-ext": { "version": "0.10.30", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", @@ -5029,37 +5076,37 @@ } }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5068,9 +5115,9 @@ }, "dependencies": { "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "requires": { "bytes": "3.1.2", @@ -5081,7 +5128,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -5095,10 +5142,23 @@ } } }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true }, "debug": { @@ -5110,6 +5170,46 @@ "ms": "2.0.0" } }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + }, + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5119,6 +5219,33 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "requires": { + "side-channel": "^1.0.6" + } + }, "raw-body": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", @@ -5138,9 +5265,9 @@ "dev": true }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", @@ -5158,6 +5285,12 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5165,6 +5298,30 @@ "dev": true } } + }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } } } }, @@ -5340,32 +5497,6 @@ "repeat-string": "1.6.1" } }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, "find-port": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/find-port/-/find-port-1.0.1.tgz", @@ -6233,6 +6364,15 @@ } } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -6701,6 +6841,12 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -6767,6 +6913,23 @@ } } }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -8388,12 +8551,6 @@ } } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, "merge-stream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", @@ -9250,12 +9407,6 @@ "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -11581,64 +11732,6 @@ } } }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } - } - } - }, "server-destroy": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", @@ -11657,6 +11750,50 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + } + } + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", From daa13dc17aa031348c016ed3a2571ffe7332bb5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:34:40 +0000 Subject: [PATCH 104/159] Bump express Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.21.1. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.1) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../lib/webcomponentsjs/package-lock.json | 373 ++++++++++++------ 1 file changed, 255 insertions(+), 118 deletions(-) diff --git a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json index 0f74db87ec..122fa6d35c 100644 --- a/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json +++ b/samples/databases/wide-world-importers/wwi-app/wwwroot/lib/webcomponentsjs/package-lock.json @@ -4319,6 +4319,17 @@ "dev": true, "optional": true }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -4744,6 +4755,42 @@ } } }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + } + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, "es5-ext": { "version": "0.10.30", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", @@ -5029,37 +5076,37 @@ } }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5068,9 +5115,9 @@ }, "dependencies": { "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "requires": { "bytes": "3.1.2", @@ -5081,7 +5128,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -5095,10 +5142,23 @@ } } }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true }, "debug": { @@ -5110,6 +5170,46 @@ "ms": "2.0.0" } }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + }, + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5119,6 +5219,33 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "requires": { + "side-channel": "^1.0.6" + } + }, "raw-body": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", @@ -5138,9 +5265,9 @@ "dev": true }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", @@ -5158,6 +5285,12 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5165,6 +5298,30 @@ "dev": true } } + }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + } + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } } } }, @@ -5340,32 +5497,6 @@ "repeat-string": "1.6.1" } }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, "find-port": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/find-port/-/find-port-1.0.1.tgz", @@ -6233,6 +6364,15 @@ } } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -6701,6 +6841,12 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -6767,6 +6913,23 @@ } } }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + } + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -8388,12 +8551,6 @@ } } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, "merge-stream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", @@ -9250,12 +9407,6 @@ "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -11581,64 +11732,6 @@ } } }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } - } - } - }, "server-destroy": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", @@ -11657,6 +11750,50 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + } + } + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", From 9111f190112fce977d864ab61f712a89fb0043e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:06:57 +0000 Subject: [PATCH 105/159] Bump cookie and express Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `cookie` from 0.6.0 to 0.7.1 - [Release notes](https://github.com/jshttp/cookie/releases) - [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1) Updates `express` from 4.20.0 to 4.21.1 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md) - [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1) --- updated-dependencies: - dependency-name: cookie dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../ClientApp/package-lock.json | 265 +++++++++--------- 1 file changed, 140 insertions(+), 125 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 307df3b251..5d8b7d5431 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -4297,11 +4297,6 @@ "safe-buffer": "~5.1.1" } }, - "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" - }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -5873,23 +5868,23 @@ } }, "express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", @@ -5898,11 +5893,11 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5915,6 +5910,23 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5928,99 +5940,74 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, - "merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + }, "path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, - "send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "dependencies": { - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } - } + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } } } @@ -6134,35 +6121,6 @@ "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, "find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -9341,6 +9299,11 @@ } } }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -11059,14 +11022,6 @@ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -12131,6 +12086,48 @@ "lru-cache": "^6.0.0" } }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -12199,6 +12196,24 @@ } } }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "dependencies": { + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + } + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", From 1d381580244acb07c4f8b9c5c637953c205933b7 Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:01:47 -0700 Subject: [PATCH 106/159] Fix images --- .../security/azure-active-directory-auth/password/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/password/README.md b/samples/features/security/azure-active-directory-auth/password/README.md index 3d890c6a12..4655216943 100644 --- a/samples/features/security/azure-active-directory-auth/password/README.md +++ b/samples/features/security/azure-active-directory-auth/password/README.md @@ -15,8 +15,8 @@ Note: A contained user database must exist and a contained database user represe Please note that builder["Authentication"] method is set to SqlAuthenticationMethod.ActiveDirectoryPassword. -![screenshot of visual studio showing builder fields to change] (/samples/features/security/azure-active-directory-auth/img/vs-authentication-method-password.png) +![screenshot of visual studio showing builder fields to change](../img/vs-authentication-method-password.png) When running this program an execution window a prompt for the Azure AD password request for user bob@cqclinic.onmicrosoft.com will appear. Once the password is entered the message should indicate a successful connection to the database followed by “Please press any key to stop”: -![screenshot of application after successful authentication- "press any key to stop"] (/samples/features/security/azure-active-directory-auth/img/pwd-press-any-key-to-stop.png) +![screenshot of application after successful authentication- "press any key to stop"](../img/pwd-press-any-key-to-stop.png) From 25c2163cd19a7a3e41c02acc7ac4797e93c1ccf0 Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:05:26 -0700 Subject: [PATCH 107/159] Fix images --- .../azure-active-directory-auth/integrated/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/integrated/README.md b/samples/features/security/azure-active-directory-auth/integrated/README.md index a6519a0d14..239e343f16 100644 --- a/samples/features/security/azure-active-directory-auth/integrated/README.md +++ b/samples/features/security/azure-active-directory-auth/integrated/README.md @@ -10,7 +10,8 @@ builder["Initial Catalog"] = "demo"; // replace with your database name ``` 2. The builder["Authentication"] method must be set to SqlAuthenticationMethod.ActiveDirectoryIntegrated; -![screenshot of visual studio showing builder fields to change] (/samples/features/security/azure-active-directory-auth/img/vs-authentication-method-integrated.png) + + ![screenshot of visual studio showing builder fields to change](../img/vs-authentication-method-integrated.png) 3. Running this project on a machine joined to a domain that is federated with Azure Active Directory will automatically use your Windows credentials and no password is required. The execution window will indicate a successful connection to the database followed by “Please press any key to stop”: -![screenshot of application after successful authentication- "press any key to stop"] (/samples/features/security/azure-active-directory-auth/img/integrated-press-any-key-to-stop.png) + ![screenshot of application after successful authentication- "press any key to stop"](../img/integrated-press-any-key-to-stop.png) From ad4d73f6eb40be76803707d5e2766b44f5b8922c Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:09:36 -0700 Subject: [PATCH 108/159] Update README.md --- .../token/README.md | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/token/README.md b/samples/features/security/azure-active-directory-auth/token/README.md index 2e44d47194..a906069609 100644 --- a/samples/features/security/azure-active-directory-auth/token/README.md +++ b/samples/features/security/azure-active-directory-auth/token/README.md @@ -8,22 +8,22 @@ ## About this sample -The Token project contains a simple console application that connects to Azure SQL database using a self-signed certificate. +The Token project contains a simple console application that connects to Azure SQL Database using a self-signed certificate. **Software prerequisites:** 1. The `makecert.exe` utility, which is included in the Windows SDK + It is sometimes included in Visual Studio installations (depending on the selections made during installation). A search of your machine for `makecert.exe` would provide verification that the Windows SDK was installed. - + If the Windows SDK was not installed, you may [download it here](http://msdn.microsoft.com/en-US/windows/desktop/aa904949) + + If the Windows SDK was not installed, you may [download it here](https://learn.microsoft.com/windows/apps/windows-app-sdk/downloads) + You can learn more about the `makecert.exe` [utility here](https://msdn.microsoft.com/library/windows/desktop/aa386968.aspx) 2. PowerShell with Azure Active Directory Module - + To download the latest PowerShell version [see this page](https://azure.microsoft.com/en-us/documentation/articles/powershell-install-configure/#Install) - + [Install the Azure AD PowerShell Module](https://msdn.microsoft.com/en-us/library/azure/jj151815.aspx), if it is not already installed in your client machine. + + To download the latest PowerShell version [see this page](https://azure.microsoft.com/documentation/articles/powershell-install-configure/#Install) + + [Install the Microsoft Entra ID PowerShell Module](https://msdn.microsoft.com/en-us/library/azure/jj151815.aspx), if it is not already installed in your client machine. ## Run this sample -1. Create an application account in Azure AD for your service. +1. Create an application account in Microsoft Entra ID for your service. - Sign in to the Azure management portal. - Click on Azure Active Directory in the left hand navigation - Click the directory tenant where you wish to register the sample application. This must be the same directory that is associated with your database (the server hosting your database). @@ -31,16 +31,17 @@ The Token project contains a simple console application that connects to Azure S - In the drawer, click Add. - Click "Add an application my organization is developing". - Enter mytokentest as a friendly name for the application, select "Web Application and/or Web API", and click next. - - Assuming this application is a daemon/service and not a web application, it doesn't have a sign-in URL or app ID URI. For these two fields, enter http://mytokentest - - While still in the Azure portal, click the Configure tab of your application. - - Find the Client ID value and copy it into a text editor, you will need this later when configuring your application ( i.e. a4bbfe26-dbaa-4fec-8ef5-223d229f647d /see the snapshot below/) -![active directory portal Client ID image](/samples/features/security/azure-active-directory-auth/img/azure-active-directory-application-portal.png) + - Assuming this application is a daemon/service and not a web application, it doesn't have a sign-in URL or app ID URI. For these two fields, enter `http://mytokentest` + - While still in the Azure portal, select Configure in your application. + - Find the Client ID value and copy it into a text editor, you will need this later when configuring your application -2. Logon to your Azure SQL Server’s user database as an Azure AD admin and using a T-SQL command provision a contained database user for your application principal: + ![active directory portal Client ID image](../img/azure-active-directory-application-portal.png) + +2. Logon to your Azure SQL Server’s user database as an Microsoft Entra ID admin and using a T-SQL command provision a contained database user for your application principal: ```sql CREATE USER [mytokentest] FROM EXTERNAL PROVIDER ``` - - [See this link](https://azure.microsoft.com/en-us/documentation/articles/sql-database-aad-authentication/) for more details on how to create an Azure Ad admin and a contained database user. + - [See this link](https://azure.microsoft.com/documentation/articles/sql-database-aad-authentication/) for more details on how to create an Microsoft Entra ID admin and a contained database user. 3. On the machine you are going to run the project on, generate and install a self-signed certificate. - To complete this step, you will need to use `Makecert.exe` @@ -53,10 +54,10 @@ The Token project contains a simple console application that connects to Azure S ``` c:/"Program Files (x86)/Windows Kits/8.1/bin/x64"/makecert -r -pe -n "CN=mytokentestCert" -ss My -len 2048 mytokentestCert.cer ``` -4. Add the certificate as a key for the application you created in Azure AD. - - Click the Microsoft Azure Active Directory Module for Windows PowerShell shortcut on desktop to open a Windows PowerShell workspace that has the Azure AD cmdlets. +4. Add the certificate as a key for the application you created in Microsoft Entra ID. + - Click the Microsoft Azure Active Directory Module for Windows PowerShell shortcut on desktop to open a Windows PowerShell workspace that has the Microsoft Entra ID cmdlets. - Copy the following code snippet to a text editor. - - `connect-msolservice` will ask for you Azure AD credentials. Please be sure to use credentials that are part of Azure AD global admin to connect and to proceed with the scripts below. + - `connect-msolservice` will ask for you Microsoft Entra ID credentials. Please be sure to use credentials that are part of Microsoft Entra ID global admin to connect and to proceed with the scripts below. ``` connect-msolservice @@ -74,23 +75,23 @@ The Token project contains a simple console application that connects to Azure S 5. Configure the certificate and your application account in the *app.config* file in the project. + In Visual Studio, open *app.config* in the Solution Explorer - ![App.config file highlights](/samples/features/security/azure-active-directory-auth/img/app-config-key-value-example.png) + ![App.config file highlights](../img/app-config-key-value-example.png) - Find the app key `ida:Tenant` and replace the value with your AAD tenant name (your AAD domain) - Find the app key `ida:ClientID` and replace the value with the Client ID for the application registration from the Azure Portal (the value from step 1). - Find the app key `ida:Cert_Name` and replace the value with the subject name (CN) of the self-signed certificate you created - For example: ```csharp - //this is the AAD domain - //this is the Client ID + //this is the domain + //this is the Client ID //this is the Cert_name use by makecert.exe ``` + In Visual Studio, open *Program.cs* in the Solution Explorer - ![Program.cs field highlights](/samples/features/security/azure-active-directory-auth/img/program-cs-builder-highlight.png) + ![Program.cs field highlights](../img/program-cs-builder-highlight.png) - Make the following changes: ```csharp - builder["Data Source"] = "aad-managed-demo.database.windows.net"; // replace with your server name + builder["Data Source"] = ".database.windows.net"; // replace with your server name builder["Initial Catalog"] = "demo"; // replace with your database name ``` -6. Run the demo. (Click *Run* or press *F5*) +6. Run the demo. (Select *Run* or press *F5*) + A successful authorization should result in a message that states "Connected to the database" similar to the following: - ![succesful auth](/samples/features/security/azure-active-directory-auth/img/token-press-any-key-to-stop.png) + ![succesful auth](../img/token-press-any-key-to-stop.png) From 680615b60334abb0233143615a276aa3fd678a29 Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:10:51 -0700 Subject: [PATCH 109/159] Update README.md --- .../azure-active-directory-auth/password/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/password/README.md b/samples/features/security/azure-active-directory-auth/password/README.md index 4655216943..31a76fa14c 100644 --- a/samples/features/security/azure-active-directory-auth/password/README.md +++ b/samples/features/security/azure-active-directory-auth/password/README.md @@ -3,20 +3,19 @@ **Before building and running the Password project**: 1. In Program.cs, locate the following lines of code and replace the server/database name with your server/database name. ``` -builder["Data Source"] = "aad-managed-demo.database.windows.net "; // replace 'aad-managed-demo' with your server name +builder["Data Source"] = ".database.windows.net "; // replace '' with your server name builder["Initial Catalog"] = "demo"; // replace with your database name ``` -2. Locate the following line of code and replace username, with the name of the Azure AD user you want to connect as. +2. Locate the following line of code and replace username, with the name of the Microsoft Entra ID user you want to connect as. ``` -string username = "bob@cqclinic.onmicrosoft.com"; // replace with your username +string username = "bob@contoso.com"; // replace with your username ``` -Note: A contained user database must exist and a contained database user representing the specified Azure AD user or one of the groups, the specified Azure AD user belongs to, must exist in the database and must have the CONNECT permission (except for AAD server admin or group) +Note: A contained user database must exist and a contained database user representing the specified Microsoft Entra ID user or one of the groups, the specified Microsoft Entra ID user belongs to, must exist in the database and must have the CONNECT permission (except for AAD server admin or group) -Please note that -builder["Authentication"] method is set to SqlAuthenticationMethod.ActiveDirectoryPassword. +Please note that the `builder["Authentication"]` method is set to `SqlAuthenticationMethod.ActiveDirectoryPassword`. ![screenshot of visual studio showing builder fields to change](../img/vs-authentication-method-password.png) -When running this program an execution window a prompt for the Azure AD password request for user bob@cqclinic.onmicrosoft.com will appear. Once the password is entered the message should indicate a successful connection to the database followed by “Please press any key to stop”: +When running this program an execution window a prompt for the Microsoft Entra ID password request for user bob@cqclinic.onmicrosoft.com will appear. Once the password is entered the message should indicate a successful connection to the database followed by “Please press any key to stop”: ![screenshot of application after successful authentication- "press any key to stop"](../img/pwd-press-any-key-to-stop.png) From 99cd78377d2575faea24005089b0053fa481c44d Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:13:00 -0700 Subject: [PATCH 110/159] Update readme.md --- .../security/azure-active-directory-auth/readme.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/readme.md b/samples/features/security/azure-active-directory-auth/readme.md index e93226d252..48eb99a5a8 100644 --- a/samples/features/security/azure-active-directory-auth/readme.md +++ b/samples/features/security/azure-active-directory-auth/readme.md @@ -35,16 +35,15 @@ To run this sample, you need the following prerequisites: + ADALSQL.DLL enables applications to authenticate to Microsoft Azure SQL Database using Azure Active Directory. The ADALSQL.DLL is not installed with Visual Studio so download the DLL at http://www.microsoft.com/en-us/download/details.aspx?id=48742 + ADALSQL.DLL is automatically downloaded with Visual Studio 2015 Update 2, SQL Server Management Studio, and the newest version of SQL Server Data tools -1. Create Azure Active Directory (AD), or federate your domain with existing Azure AD - This allows either to use managed or federated accounts associated with a specific Azure AD -2. Create Azure AD administrator for Azure SQL DB using Azure portal, PowerShell command or Rest API -3. With help from T-SQL query interface (i.e. SSMS query editor), using Azure AD admin credentials for SQL DB & SQL DW, create an Azure AD user in a designated database. The database user represents your Azure AD principal (or one of the groups you belong to) and must exist in the database having CONNECT permission prior to executing a connection attempt +1. Create Microsoft Entra tenant (formerly known as Azure Active Directory), or federate your domain with existing Microsoft Entra ID. This allows either to use managed or federated accounts associated with a specific Microsoft Entra ID. +2. Create Microsoft Entra ID administrator for Azure SQL Database using the Azure portal, PowerShell command, or Rest API. +3. With help from T-SQL query interface (i.e. SSMS query editor), using Microsoft Entra ID admin credentials for Azure SQL Database and dedicated SQL pools in Azure Synapse, create an Microsoft Entra ID user in a designated database. The database user represents your Microsoft Entra ID principal (or one of the groups you belong to) and must exist in the database having CONNECT permission prior to executing a connection attempt. **Other Prerequisites** -1. For Azure AD integrated authentication a computer joined to a domain that is federated with Azure Active Directory is required -2. An existing database created before a connection attempt is required. The database can be created using credentials for SQL administrator, or Azure AD SQL administrator +1. For Microsoft Entra ID integrated authentication a computer joined to a domain that is federated with Azure Active Directory is required. +2. An existing database created before a connection attempt is required. The database can be created using credentials for SQL administrator, or Microsoft Entra SQL administrator. @@ -62,7 +61,7 @@ To run this sample, you need the following prerequisites: ## Sample details -This demo provides a simple tool for exploring Azure Active Directory authentication to Azure SQL DB or Azure SQL DW. +This demo provides a simple tool for exploring Azure Active Directory authentication to Azure SQL Database and dedicated SQL pools in Azure Synapse. Azure Active Directory authentication with Azure SQL Database V12 supports the following authentication methods: - User/password authentication From 0784a5f18df8c4dce42e28c99d5105c82e019a97 Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:16:51 -0700 Subject: [PATCH 111/159] Update README.md --- .../azure-active-directory-auth/integrated/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/integrated/README.md b/samples/features/security/azure-active-directory-auth/integrated/README.md index 239e343f16..0e66f9c90a 100644 --- a/samples/features/security/azure-active-directory-auth/integrated/README.md +++ b/samples/features/security/azure-active-directory-auth/integrated/README.md @@ -1,17 +1,17 @@ ## Run this sample -Note: Run this project on a machine joined to a domain that is federated with Azure Active Directory. A contained database user representing your Azure AD principal, or one of the groups, you belong to, must exist in the database and must have the CONNECT permission. +Note: Run this project on a machine joined to a domain that is federated with Microsoft Entra. A contained database user representing your Microsoft Entra ID principal, or one of the groups, you belong to, must exist in the database and must have the CONNECT permission. 1. Before building and running the Integrated project: + In Program.cs, locate the following lines of code and replace the server/database name with your server/database name. ``` -builder["Data Source"] = "aad-managed-demo.database.windows.net "; // replace 'aad-managed-demo' with your server name +builder["Data Source"] = ".database.windows.net "; // replace '' with your server name builder["Initial Catalog"] = "demo"; // replace with your database name ``` -2. The builder["Authentication"] method must be set to SqlAuthenticationMethod.ActiveDirectoryIntegrated; +2. The `builder["Authentication"]` method must be set to `SqlAuthenticationMethod.ActiveDirectoryIntegrated`; ![screenshot of visual studio showing builder fields to change](../img/vs-authentication-method-integrated.png) -3. Running this project on a machine joined to a domain that is federated with Azure Active Directory will automatically use your Windows credentials and no password is required. The execution window will indicate a successful connection to the database followed by “Please press any key to stop”: +3. Running this project on a machine joined to a domain that is federated with Microsoft Entra will automatically use your Windows credentials and no password is required. The execution window will indicate a successful connection to the database followed by “Please press any key to stop”: ![screenshot of application after successful authentication- "press any key to stop"](../img/integrated-press-any-key-to-stop.png) From c7433496e4ee7e09a26edb676e855ccf57423f2d Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:18:53 -0700 Subject: [PATCH 112/159] Update README.md --- .../security/azure-active-directory-auth/token/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/token/README.md b/samples/features/security/azure-active-directory-auth/token/README.md index a906069609..5ae1d9d3fc 100644 --- a/samples/features/security/azure-active-directory-auth/token/README.md +++ b/samples/features/security/azure-active-directory-auth/token/README.md @@ -17,8 +17,8 @@ The Token project contains a simple console application that connects to Azure S + If the Windows SDK was not installed, you may [download it here](https://learn.microsoft.com/windows/apps/windows-app-sdk/downloads) + You can learn more about the `makecert.exe` [utility here](https://msdn.microsoft.com/library/windows/desktop/aa386968.aspx) 2. PowerShell with Azure Active Directory Module - + To download the latest PowerShell version [see this page](https://azure.microsoft.com/documentation/articles/powershell-install-configure/#Install) - + [Install the Microsoft Entra ID PowerShell Module](https://msdn.microsoft.com/en-us/library/azure/jj151815.aspx), if it is not already installed in your client machine. + + To download the latest PowerShell version [see this page](https://learn.microsoft.com/powershell/azure/install-azure-powershell) + + [Install the Microsoft Entra ID PowerShell Module](https://learn.microsoft.com/powershell/entra-powershell/installation), if it is not already installed in your client machine. ## Run this sample @@ -89,7 +89,7 @@ The Token project contains a simple console application that connects to Azure S ![Program.cs field highlights](../img/program-cs-builder-highlight.png) - Make the following changes: ```csharp - builder["Data Source"] = ".database.windows.net"; // replace with your server name + builder["Data Source"] = ".database.windows.net"; // replace with your server name builder["Initial Catalog"] = "demo"; // replace with your database name ``` 6. Run the demo. (Select *Run* or press *F5*) From 5c15fbf513509ada1fd95ca1e21c408689f121ac Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:22:34 -0700 Subject: [PATCH 113/159] Update README.md --- .../security/azure-active-directory-auth/token/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/token/README.md b/samples/features/security/azure-active-directory-auth/token/README.md index 5ae1d9d3fc..38ab7b43b2 100644 --- a/samples/features/security/azure-active-directory-auth/token/README.md +++ b/samples/features/security/azure-active-directory-auth/token/README.md @@ -35,8 +35,6 @@ The Token project contains a simple console application that connects to Azure S - While still in the Azure portal, select Configure in your application. - Find the Client ID value and copy it into a text editor, you will need this later when configuring your application - ![active directory portal Client ID image](../img/azure-active-directory-application-portal.png) - 2. Logon to your Azure SQL Server’s user database as an Microsoft Entra ID admin and using a T-SQL command provision a contained database user for your application principal: ```sql CREATE USER [mytokentest] FROM EXTERNAL PROVIDER From 098d72131fbf665da2aa2338c7c9ca48144990da Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:23:29 -0700 Subject: [PATCH 114/159] Update README.md --- .../security/azure-active-directory-auth/token/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/features/security/azure-active-directory-auth/token/README.md b/samples/features/security/azure-active-directory-auth/token/README.md index 38ab7b43b2..de0f77a616 100644 --- a/samples/features/security/azure-active-directory-auth/token/README.md +++ b/samples/features/security/azure-active-directory-auth/token/README.md @@ -73,7 +73,6 @@ The Token project contains a simple console application that connects to Azure S 5. Configure the certificate and your application account in the *app.config* file in the project. + In Visual Studio, open *app.config* in the Solution Explorer - ![App.config file highlights](../img/app-config-key-value-example.png) - Find the app key `ida:Tenant` and replace the value with your AAD tenant name (your AAD domain) - Find the app key `ida:ClientID` and replace the value with the Client ID for the application registration from the Azure Portal (the value from step 1). - Find the app key `ida:Cert_Name` and replace the value with the subject name (CN) of the self-signed certificate you created From bf34b3a1406b86f0cfb2efdc930c64498131c8f7 Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:24:57 -0700 Subject: [PATCH 115/159] Update README.md --- .../security/azure-active-directory-auth/token/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/token/README.md b/samples/features/security/azure-active-directory-auth/token/README.md index de0f77a616..5a97951df4 100644 --- a/samples/features/security/azure-active-directory-auth/token/README.md +++ b/samples/features/security/azure-active-directory-auth/token/README.md @@ -90,5 +90,4 @@ The Token project contains a simple console application that connects to Azure S builder["Initial Catalog"] = "demo"; // replace with your database name ``` 6. Run the demo. (Select *Run* or press *F5*) - + A successful authorization should result in a message that states "Connected to the database" similar to the following: - ![succesful auth](../img/token-press-any-key-to-stop.png) + + A successful authorization should result in a message that includes "The access token obtained" and states "Connected to the database" and "Please press any key to stop". From 8df1863d2513afa24b75f7f61010894221171b4e Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:25:32 -0700 Subject: [PATCH 116/159] Delete samples/features/security/azure-active-directory-auth/img/token-press-any-key-to-stop.png --- .../img/token-press-any-key-to-stop.png | Bin 90860 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/features/security/azure-active-directory-auth/img/token-press-any-key-to-stop.png diff --git a/samples/features/security/azure-active-directory-auth/img/token-press-any-key-to-stop.png b/samples/features/security/azure-active-directory-auth/img/token-press-any-key-to-stop.png deleted file mode 100644 index 7bb127d779c07605f89e9a6bd7aa8975b566be71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90860 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 Date: Mon, 21 Oct 2024 18:25:41 -0700 Subject: [PATCH 117/159] Delete samples/features/security/azure-active-directory-auth/img/app-config-key-value-example.png --- .../img/app-config-key-value-example.png | Bin 88978 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/features/security/azure-active-directory-auth/img/app-config-key-value-example.png diff --git a/samples/features/security/azure-active-directory-auth/img/app-config-key-value-example.png b/samples/features/security/azure-active-directory-auth/img/app-config-key-value-example.png deleted file mode 100644 index f44eb0d07bc78d985b05305b5d8fc7f97476c938..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88978 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 From 1dec77f53cad8c509620b7203b308ca6a0bdd7b0 Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:25:48 -0700 Subject: [PATCH 118/159] Delete samples/features/security/azure-active-directory-auth/img/azure-active-directory-application-portal.png --- ...zure-active-directory-application-portal.png | Bin 26874 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/features/security/azure-active-directory-auth/img/azure-active-directory-application-portal.png diff --git a/samples/features/security/azure-active-directory-auth/img/azure-active-directory-application-portal.png b/samples/features/security/azure-active-directory-auth/img/azure-active-directory-application-portal.png deleted file mode 100644 index bad0f36ae3362e7a1845130e22353915c45909b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26874 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 R;J%`5C%k>V>O8|P{}WA=68!)G From 183bd1e1467509b6ba39d4cb7907504c5b5283ed Mon Sep 17 00:00:00 2001 From: William Assaf MSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:27:17 -0700 Subject: [PATCH 119/159] Delete samples/features/security/azure-active-directory-auth/img/vs-authentication-method-password.png --- .../img/vs-authentication-method-password.png | Bin 99265 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/features/security/azure-active-directory-auth/img/vs-authentication-method-password.png diff --git a/samples/features/security/azure-active-directory-auth/img/vs-authentication-method-password.png b/samples/features/security/azure-active-directory-auth/img/vs-authentication-method-password.png deleted file mode 100644 index b2f72737851f1ca0e67910935f18e5aac2941c43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99265 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%0DZt3l!G>bCSVnIC(54xc;X+KEUyn_PsWW+m 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

*OeI=57n&yRBRLax{!DSH;co+E{G+dt3^U%C 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 n@aE;Wd~Yzvp%raU Date: Mon, 21 Oct 2024 18:27:46 -0700 Subject: [PATCH 120/159] Update README.md --- .../security/azure-active-directory-auth/password/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/features/security/azure-active-directory-auth/password/README.md b/samples/features/security/azure-active-directory-auth/password/README.md index 31a76fa14c..23b823429f 100644 --- a/samples/features/security/azure-active-directory-auth/password/README.md +++ b/samples/features/security/azure-active-directory-auth/password/README.md @@ -14,8 +14,6 @@ Note: A contained user database must exist and a contained database user represe Please note that the `builder["Authentication"]` method is set to `SqlAuthenticationMethod.ActiveDirectoryPassword`. -![screenshot of visual studio showing builder fields to change](../img/vs-authentication-method-password.png) - When running this program an execution window a prompt for the Microsoft Entra ID password request for user bob@cqclinic.onmicrosoft.com will appear. Once the password is entered the message should indicate a successful connection to the database followed by “Please press any key to stop”: ![screenshot of application after successful authentication- "press any key to stop"](../img/pwd-press-any-key-to-stop.png) From 551fe208d1751447fff05684778074a0fa626e0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:25:10 +0000 Subject: [PATCH 121/159] Bump http-proxy-middleware Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.6 to 2.0.7. - [Release notes](https://github.com/chimurai/http-proxy-middleware/releases) - [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.7/CHANGELOG.md) - [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.6...v2.0.7) --- updated-dependencies: - dependency-name: http-proxy-middleware dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../SqlDbEdgeDemo.Web/ClientApp/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index 307df3b251..2854a7837c 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -6913,9 +6913,9 @@ } }, "http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "requires": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", From 7706d73fa98fb1fd5ab2e449d2967e4b063d0a41 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 8 Nov 2024 11:15:20 -0800 Subject: [PATCH 122/159] Add Arc SQL Server health dashboard --- .../ArcEnabledSQLServerHealth.dx.json | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json diff --git a/samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json b/samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json new file mode 100644 index 0000000000..bceaec6931 --- /dev/null +++ b/samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json @@ -0,0 +1,51 @@ +{ + "$schema": "<>", + "view": { + "kind": "Dashboard", + "export": true, + "properties": { + "title": "Arc Enabled SQL Server Health", + "pages": [ + { + "title": "New 1", + "tiles": [ + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\" \r\n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \r\n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.hybridcompute/machines\"\r\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , MachineStatus= properties.status , MachineProvisioningStatus= properties.provisioningState, MachineErrors = properties.errorDetails //Project relvant machine health information.\r\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\r\n| extend statusExpirationLengthRange = 3d // Change this value to change the acceptable range for the last time an extension should have reported its status.\r\n| extend startDate = startofday(now() - statusExpirationLengthRange), endDate = startofday(now()) // Get the start and end positon for the given range.\r\n| extend extractedDateString = extract(\"timestampUTC : (\\\\d{4}\\\\W\\\\d{2}\\\\W\\\\d{2})\", 1, tostring(properties.instanceView.status.message)) // Extracting the date string for the LastUploadTimestamp. Is empty if none is found.\r\n| extend extractedDateStringYear = split(extractedDateString, '/')[0], extractedDateStringMonth = split(extractedDateString, '/')[1], extractedDateStringDay = split(extractedDateString, '/')[2] // Identifying each of the parts of the date that was extracted from the message.\r\n| extend extractedDate = todatetime(strcat(extractedDateStringYear,\"-\",extractedDateStringMonth,\"-\",extractedDateStringDay,\"T00:00:00Z\")) // Converting to a datetime object and rewriting string into ISO format because todatetime() does not work using the previous format.\r\n| extend isNotInDateRange = not(extractedDate >= startDate and extractedDate <= endDate) // Created bool which is true if the date we extracted from the message is not within the specified range. This bool will also be true if the date was not found in the message.\r\n| where properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\" // Begin searching for unhealthy extensions using the following 1. Does extension report being healthy. 2. Is last upload within the given range. 3. Is the upload status in an OK state. 4. Is provisioning state not in a succeeded state.\r\n or isNotInDateRange\r\n or properties.instanceView.status.message !contains \"uploadStatus : OK\"\r\n or properties.provisioningState != \"Succeeded\"\r\n or MachineStatus != \"Connected\"\r\n| extend FailureReasons = strcat( // Makes a String to list all the reason that this resource got flagged for\r\n iif(MachineStatus != \"Connected\",strcat(\"- Machine's status is \", MachineStatus,\" -\"),\"\") ,\r\n iif(MachineErrors != \"[]\",\"- Machine reports errors -\", \"\"),\r\n iif(properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\",\"- Extension reported unhealthy -\",\"\"), \r\n iif(isNotInDateRange,\"- Last upload outside acceptable range -\",\"\"),\r\n iif(properties.instanceView.status.message !contains \"uploadStatus : OK\",\"- Upload status is not reported OK -\",\"\"), \r\n iif(properties.provisioningState != \"Succeeded\",strcat(\"- Extension provisiong state is \", properties.provisioningState,\" -\"),\"\") \r\n )\r\n| extend RecommendedAction = //Attempt to Identify RootCause based on information gathered, and point customer to what they should investigate first.\r\n iif(MachineStatus == \"Disconnected\", \"Machine is disconnected. Please reconnect the machine.\",\r\n iif(MachineStatus == \"Expired\", \"Machine cert is expired. Go to the machine on the Azure Portal for more information on how to resolve this issue.\",\r\n iif(MachineStatus != \"Connected\", strcat(\"Machine status is \", MachineStatus,\". Investigate and resolve this issue.\"),\r\n iif(MachineProvisioningStatus != \"Succeeded\", strcat(\"Machine provisioning status is \", MachineProvisioningStatus, \". Investigate and resolve machine provisioning status\"),\r\n iff(MachineErrors != \"[]\", \"Machine is reporting errors. Investigate and resolve machine errors\",\r\n iif(properties.provisioningState != \"Succeeded\", strcat(\"Extension provisioning status is \", properties.provisioningState,\". Investigate and resolve extension provisioning state.\"),\r\n iff(properties.instanceView.status.message !contains \"SQL Server Extension Agent:\" and properties.instanceView.status.message contains \"SQL Server Extension Agent Deployer\", \"SQL Server extension eeployer ran. However, SQL Server extension seems to not be running. Verify that the extension is currently running.\",\r\n iff(properties.instanceView.status.message !contains \"uploadStatus : OK\" or isNotInDateRange or properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\", \"Extension reported as unhealthy. View FailureReasons and LastExtensionStatusMessage for more information as to the cause of the failure.\",\r\n \"Unable to reccommend actions. Please view FailureReasons.\"\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n| project ID = id, MachineName, ResourceGroup = resourceGroup, SubscriptionID = subscriptionId, Location = location, RecommendedAction, FailureReasons, LicenseType = properties.settings.LicenseType, \r\n LastReportedExtensionHealth = iif(properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\", \"Unhealthy\", \"Healthy\"),\r\n LastExtensionUploadTimestamp = iif(indexof(properties.instanceView.status.message, \"timestampUTC : \") > 0,\r\n substring(properties.instanceView.status.message, indexof(properties.instanceView.status.message, \"timestampUTC : \") + 15, 10),\r\n \"no timestamp\"),\r\n LastExtensionUploadStatus = iif(indexof(properties.instanceView.status.message, \"uploadStatus : OK\") > 0, \"OK\", \"Unhealthy\"),\r\n ExtensionProvisioningState = properties.provisioningState,\r\n MachineStatus, MachineErrors, MachineProvisioningStatus,MachineId = machineId,\r\n LastExtensionStatusMessage = properties.instanceView.status.message", + "usedParameters": [] + }, + "visualization": { + "type": "table", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Arc SQL Server Resource Health", + "subtitle": "Health of Arc SQL Server extension and Arc machine", + "type": "QueryTile", + "layout": { + "x": 0, + "y": 0, + "width": 19, + "height": 11 + } + } + ] + } + ], + "parameters": [], + "provisioningState": "Succeeded" + } + } +} \ No newline at end of file From 937146858024dd222a3d6754ff321e71442a5c52 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 8 Nov 2024 15:50:51 -0800 Subject: [PATCH 123/159] Add Arc SQL Server Feature Status Dashboard --- .../Arc SQL Server Feature Status.json | 334 ++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json diff --git a/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json b/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json new file mode 100644 index 0000000000..50c9a89384 --- /dev/null +++ b/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json @@ -0,0 +1,334 @@ +{ + "properties": { + "title": "Arc SQL Server Feature Status", + "pages": [ + { + "title": "Feature Status", + "tiles": [ + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMigrationAssessment = iif(properties.migration.assessment.enabled == 'true', 'Enabled', 'Disabled'), \r\nMonitoring = iif(properties.monitoring.enabled == 'true', 'Enabled', 'Disabled'), \r\nBackupEnabled = iif(isempty(properties.backupPolicy.retentionPeriodDays),'Disabled', iif(properties.backupPolicy.retentionPeriodDays == 0,'Disabled','Enabled'))\r\n| order by id asc", + "usedParameters": [] + }, + "visualization": { + "type": "table", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "SQL Server instance features status", + "subtitle": "Shows enabled/disabled for each feature that is configured at the SQL Server instance level", + "type": "QueryTile", + "layout": { + "x": 0, + "y": 0, + "width": 8, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project\r\nid,\r\nESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\"),\r\nPurview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization),\"Enabled\",\"Disabled\"),\r\nEntra = iff(notnull(properties.settings.AzureAD),\"Enabled\",\"Disabled\"),\r\nBPA = iff(notnull(properties.settings.AssessmentSettings),\"Enabled\",\"Disabled\"),\r\nAutomaticUpdate = iff(properties.settings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate == true, \"Enabled\", \"Disabled\")\r\n| order by id asc", + "usedParameters": [] + }, + "visualization": { + "type": "table", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "SQL Server extension feature status", + "subtitle": "Shows the enabled and disabled state of each feature configured at the SQL Server extension level", + "type": "QueryTile", + "layout": { + "x": 0, + "y": 4, + "width": 8, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, ESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by ESU", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Extended Security Updates", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 8, + "y": 4, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, Purview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by Purview", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Purview", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 14, + "y": 4, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, Entra = iff(notnull(properties.settings.AzureAD), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by Entra", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Entra ID authentication", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 8, + "y": 8, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, BPA = iff(notnull(properties.settings.AssessmentSettings), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by BPA", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Best practices assessment", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 14, + "y": 8, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, AutomaticUpdates = iff(properties.settings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate == true, \"Enabled\", \"Disabled\")\r\n| summarize count(id) by AutomaticUpdates", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Automatic Updates", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 20, + "y": 4, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMigrationAssessment = iif(properties.migration.assessment.enabled == 'true', 'Enabled', 'Disabled')\r\n| summarize count(id) by MigrationAssessment", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Migration assessment", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 8, + "y": 0, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMonitoring = iif(properties.monitoring.enabled == 'true', 'Enabled', 'Disabled')\r\n| summarize count(id) by Monitoring", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Monitoring", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 14, + "y": 0, + "width": 6, + "height": 4 + } + }, + { + "data": { + "kind": "arg", + "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nBackupEnabled = iif(isempty(properties.backupPolicy.retentionPeriodDays),'Disabled', iif(properties.backupPolicy.retentionPeriodDays == 0,'Disabled','Enabled'))\r\n| summarize count(id) by BackupEnabled", + "usedParameters": [] + }, + "visualization": { + "type": "pie", + "options": { + "hideTileTitle": false, + "table__enableFormatting": true, + "table__enableRenderLinks": true, + "table__renderLinksForColumns": [], + "colorRules": [], + "colorRulesDisabled": true, + "colorStyle": "light", + "crossFilter": [], + "crossFilterDisabled": false, + "drillthrough": [], + "drillthroughDisabled": false + } + }, + "title": "Backups", + "subtitle": "", + "type": "QueryTile", + "layout": { + "x": 20, + "y": 0, + "width": 6, + "height": 4 + } + } + ] + } + ], + "parameters": [], + "provisioningState": "Succeeded" + } +} \ No newline at end of file From 2951352142f63babf8a09d778072a649dbed7905 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Tue, 12 Nov 2024 01:40:25 -0800 Subject: [PATCH 124/159] Updating v2 format to v1 format for dashboards --- .../Arc SQL Server Feature Status.json | 779 +++++++++++------- .../Arc-enabled SQL Server Health.json | 83 ++ .../ArcEnabledSQLServerHealth.dx.json | 51 -- sql-server-samples | 1 + 4 files changed, 586 insertions(+), 328 deletions(-) create mode 100644 samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json delete mode 100644 samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json create mode 160000 sql-server-samples diff --git a/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json b/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json index 50c9a89384..d3183d58fa 100644 --- a/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json +++ b/samples/features/azure-arc/dashboard/Arc SQL Server Feature Status.json @@ -1,334 +1,559 @@ { "properties": { - "title": "Arc SQL Server Feature Status", - "pages": [ + "lenses": [ { - "title": "Feature Status", - "tiles": [ + "order": 0, + "parts": [ { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMigrationAssessment = iif(properties.migration.assessment.enabled == 'true', 'Enabled', 'Disabled'), \r\nMonitoring = iif(properties.monitoring.enabled == 'true', 'Enabled', 'Disabled'), \r\nBackupEnabled = iif(isempty(properties.backupPolicy.retentionPeriodDays),'Disabled', iif(properties.backupPolicy.retentionPeriodDays == 0,'Disabled','Enabled'))\r\n| order by id asc", - "usedParameters": [] - }, - "visualization": { - "type": "table", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false - } - }, - "title": "SQL Server instance features status", - "subtitle": "Shows enabled/disabled for each feature that is configured at the SQL Server instance level", - "type": "QueryTile", - "layout": { + "position": { "x": 0, "y": 0, - "width": 8, - "height": 4 + "colSpan": 11, + "rowSpan": 7 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMigrationAssessment = iif(properties.migration.assessment.enabled == 'true', 'ENABLED', 'disabled'), \r\nMonitoring = iif(properties.monitoring.enabled == 'true', 'ENABLED', 'disabled'), \r\nBackupEnabled = iif(isempty(properties.backupPolicy.retentionPeriodDays),'disabled', iif(properties.backupPolicy.retentionPeriodDays == 0,'disabled','ENABLED'))\r\n| order by id asc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryGridTile", + "settings": {}, + "partHeader": { + "title": "SQL Server instance features status", + "subtitle": "Shows enabled/disabled for each feature that is configured at the SQL Server instance level" + } } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project\r\nid,\r\nESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\"),\r\nPurview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization),\"Enabled\",\"Disabled\"),\r\nEntra = iff(notnull(properties.settings.AzureAD),\"Enabled\",\"Disabled\"),\r\nBPA = iff(notnull(properties.settings.AssessmentSettings),\"Enabled\",\"Disabled\"),\r\nAutomaticUpdate = iff(properties.settings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate == true, \"Enabled\", \"Disabled\")\r\n| order by id asc", - "usedParameters": [] + "position": { + "x": 11, + "y": 0, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "table", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\n| project \nid, \nMigrationAssessment = iif(properties.migration.assessment.enabled == 'true', 'Enabled', 'Disabled')\n| summarize count(id) by MigrationAssessment", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Migration assessment", + "subtitle": "" } - }, - "title": "SQL Server extension feature status", - "subtitle": "Shows the enabled and disabled state of each feature configured at the SQL Server extension level", - "type": "QueryTile", - "layout": { - "x": 0, - "y": 4, - "width": 8, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, ESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by ESU", - "usedParameters": [] + "position": { + "x": 17, + "y": 0, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\n| project \nid, \nMonitoring = iif(properties.monitoring.enabled == 'true', 'Enabled', 'Disabled')\n| summarize count(id) by Monitoring", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Monitoring dashboards", + "subtitle": "" } - }, - "title": "Extended Security Updates", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 8, - "y": 4, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, Purview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by Purview", - "usedParameters": [] + "position": { + "x": 23, + "y": 0, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\n| project \nid, \nBackupEnabled = iif(isempty(properties.backupPolicy.retentionPeriodDays),'Disabled', iif(properties.backupPolicy.retentionPeriodDays == 0,'Disabled','Enabled'))\n| summarize count(id) by BackupEnabled", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Backups", + "subtitle": "" } - }, - "title": "Purview", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 14, - "y": 4, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, Entra = iff(notnull(properties.settings.AzureAD), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by Entra", - "usedParameters": [] + "position": { + "x": 0, + "y": 7, + "colSpan": 11, + "rowSpan": 14 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project\r\nid,\r\nESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,\"ENABLED\",\"disabled\"), \"disabled\"),\r\nPurview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization),\"ENABLED\",\"disabled\"),\r\nEntra = iff(notnull(properties.settings.AzureAD),\"ENABLED\",\"disabled\"),\r\nBPA = iff(notnull(properties.settings.AssessmentSettings),\"ENABLED\",\"disabled\"),\r\nAutomaticUpdate = iff(properties.settings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate == true, \"ENABLED\", \"disabled\")\r\n| order by id asc", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryGridTile", + "settings": {}, + "partHeader": { + "title": "SQL Server extension feature status", + "subtitle": "Shows the enabled and disabled status of each feature at the SQL Server extension level" } - }, - "title": "Entra ID authentication", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 8, - "y": 8, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, BPA = iff(notnull(properties.settings.AssessmentSettings), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\r\n| summarize count(id) by BPA", - "usedParameters": [] + "position": { + "x": 11, + "y": 7, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\n| project id, ESU = iff(notnull(properties.settings.enableExtendedSecurityUpdates), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\n| summarize count(id) by ESU\n", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Extended Security Updates", + "subtitle": "" } - }, - "title": "Best practices assessment", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 14, - "y": 8, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\"\r\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\r\n| project id, AutomaticUpdates = iff(properties.settings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate == true, \"Enabled\", \"Disabled\")\r\n| summarize count(id) by AutomaticUpdates", - "usedParameters": [] + "position": { + "x": 17, + "y": 7, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\n| project id, AutomaticUpdates = iff(properties.settings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate == true, \"Enabled\", \"Disabled\")\n| summarize count(id) by AutomaticUpdates", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Automatic Updates", + "subtitle": "" } - }, - "title": "Automatic Updates", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 20, - "y": 4, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMigrationAssessment = iif(properties.migration.assessment.enabled == 'true', 'Enabled', 'Disabled')\r\n| summarize count(id) by MigrationAssessment", - "usedParameters": [] + "position": { + "x": 23, + "y": 7, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\n| project id, Purview = iff(notnull(properties.settings.ExternalPolicyBasedAuthorization), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\n| summarize count(id) by Purview", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Purview", + "subtitle": "" } - }, - "title": "Migration assessment", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 8, - "y": 0, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nMonitoring = iif(properties.monitoring.enabled == 'true', 'Enabled', 'Disabled')\r\n| summarize count(id) by Monitoring", - "usedParameters": [] + "position": { + "x": 11, + "y": 14, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\n| project id, Entra = iff(notnull(properties.settings.AzureAD), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\n| summarize count(id) by Entra", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Entra ID authentication", + "subtitle": "" } - }, - "title": "Monitoring", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 14, - "y": 0, - "width": 6, - "height": 4 } }, { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.azurearcdata/sqlserverinstances\"\r\n| project \r\nid, \r\nBackupEnabled = iif(isempty(properties.backupPolicy.retentionPeriodDays),'Disabled', iif(properties.backupPolicy.retentionPeriodDays == 0,'Disabled','Enabled'))\r\n| summarize count(id) by BackupEnabled", - "usedParameters": [] + "position": { + "x": 17, + "y": 14, + "colSpan": 6, + "rowSpan": 7 }, - "visualization": { - "type": "pie", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\",\"LinuxAgent.SqlServer\")\n| project id, BPA = iff(notnull(properties.settings.AssessmentSettings), iff(properties.settings.enableExtendedSecurityUpdates == true,\"Enabled\",\"Disabled\"), \"Disabled\")\n| summarize count(id) by BPA", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Best practices assessment", + "subtitle": "" } - }, - "title": "Backups", - "subtitle": "", - "type": "QueryTile", - "layout": { - "x": 20, - "y": 0, - "width": 6, - "height": 4 } } ] } ], - "parameters": [], - "provisioningState": "Succeeded" - } + "metadata": { + "model": { + "timeRange": { + "value": { + "relative": { + "duration": 24, + "timeUnit": 1 + } + }, + "type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange" + } + } + } + }, + "name": "Arc-enabled SQL Server Features", + "type": "Microsoft.Portal/dashboards", + "location": "INSERT LOCATION", + "tags": { + "hidden-title": "Arc-enabled SQL Server Features" + }, + "apiVersion": "2022-12-01-preview" } \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json b/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json new file mode 100644 index 0000000000..bbb053cc04 --- /dev/null +++ b/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json @@ -0,0 +1,83 @@ +{ + "properties": { + "lenses": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 20, + "rowSpan": 11 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\" \r\n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \r\n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.hybridcompute/machines\"\r\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , MachineStatus= properties.status , MachineProvisioningStatus= properties.provisioningState, MachineErrors = properties.errorDetails //Project relvant machine health information.\r\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\r\n| extend statusExpirationLengthRange = 3d // Change this value to change the acceptable range for the last time an extension should have reported its status.\r\n| extend startDate = startofday(now() - statusExpirationLengthRange), endDate = startofday(now()) // Get the start and end positon for the given range.\r\n| extend extractedDateString = extract(\"timestampUTC : (\\\\d{4}\\\\W\\\\d{2}\\\\W\\\\d{2})\", 1, tostring(properties.instanceView.status.message)) // Extracting the date string for the LastUploadTimestamp. Is empty if none is found.\r\n| extend extractedDateStringYear = split(extractedDateString, '/')[0], extractedDateStringMonth = split(extractedDateString, '/')[1], extractedDateStringDay = split(extractedDateString, '/')[2] // Identifying each of the parts of the date that was extracted from the message.\r\n| extend extractedDate = todatetime(strcat(extractedDateStringYear,\"-\",extractedDateStringMonth,\"-\",extractedDateStringDay,\"T00:00:00Z\")) // Converting to a datetime object and rewriting string into ISO format because todatetime() does not work using the previous format.\r\n| extend isNotInDateRange = not(extractedDate >= startDate and extractedDate <= endDate) // Created bool which is true if the date we extracted from the message is not within the specified range. This bool will also be true if the date was not found in the message.\r\n| where properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\" // Begin searching for unhealthy extensions using the following 1. Does extension report being healthy. 2. Is last upload within the given range. 3. Is the upload status in an OK state. 4. Is provisioning state not in a succeeded state.\r\n or isNotInDateRange\r\n or properties.instanceView.status.message !contains \"uploadStatus : OK\"\r\n or properties.provisioningState != \"Succeeded\"\r\n or MachineStatus != \"Connected\"\r\n| extend FailureReasons = strcat( // Makes a String to list all the reason that this resource got flagged for\r\n iif(MachineStatus != \"Connected\",strcat(\"- Machine's status is \", MachineStatus,\" -\"),\"\") ,\r\n iif(MachineErrors != \"[]\",\"- Machine reports errors -\", \"\"),\r\n iif(properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\",\"- Extension reported unhealthy -\",\"\"), \r\n iif(isNotInDateRange,\"- Last upload outside acceptable range -\",\"\"),\r\n iif(properties.instanceView.status.message !contains \"uploadStatus : OK\",\"- Upload status is not reported OK -\",\"\"), \r\n iif(properties.provisioningState != \"Succeeded\",strcat(\"- Extension provisiong state is \", properties.provisioningState,\" -\"),\"\") \r\n )\r\n| extend RecommendedAction = //Attempt to Identify RootCause based on information gathered, and point customer to what they should investigate first.\r\n iif(MachineStatus == \"Disconnected\", \"Machine is disconnected. Please reconnect the machine.\",\r\n iif(MachineStatus == \"Expired\", \"Machine cert is expired. Go to the machine on the Azure Portal for more information on how to resolve this issue.\",\r\n iif(MachineStatus != \"Connected\", strcat(\"Machine status is \", MachineStatus,\". Investigate and resolve this issue.\"),\r\n iif(MachineProvisioningStatus != \"Succeeded\", strcat(\"Machine provisioning status is \", MachineProvisioningStatus, \". Investigate and resolve machine provisioning status\"),\r\n iff(MachineErrors != \"[]\", \"Machine is reporting errors. Investigate and resolve machine errors\",\r\n iif(properties.provisioningState != \"Succeeded\", strcat(\"Extension provisioning status is \", properties.provisioningState,\". Investigate and resolve extension provisioning state.\"),\r\n iff(properties.instanceView.status.message !contains \"SQL Server Extension Agent:\" and properties.instanceView.status.message contains \"SQL Server Extension Agent Deployer\", \"SQL Server extension eeployer ran. However, SQL Server extension seems to not be running. Verify that the extension is currently running.\",\r\n iff(properties.instanceView.status.message !contains \"uploadStatus : OK\" or isNotInDateRange or properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\", \"Extension reported as unhealthy. View FailureReasons and LastExtensionStatusMessage for more information as to the cause of the failure.\",\r\n \"Unable to reccommend actions. Please view FailureReasons.\"\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n| project ID = id, MachineName, ResourceGroup = resourceGroup, SubscriptionID = subscriptionId, Location = location, RecommendedAction, FailureReasons, LicenseType = properties.settings.LicenseType, \r\n LastReportedExtensionHealth = iif(properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\", \"Unhealthy\", \"Healthy\"),\r\n LastExtensionUploadTimestamp = iif(indexof(properties.instanceView.status.message, \"timestampUTC : \") > 0,\r\n substring(properties.instanceView.status.message, indexof(properties.instanceView.status.message, \"timestampUTC : \") + 15, 10),\r\n \"no timestamp\"),\r\n LastExtensionUploadStatus = iif(indexof(properties.instanceView.status.message, \"uploadStatus : OK\") > 0, \"OK\", \"Unhealthy\"),\r\n ExtensionProvisioningState = properties.provisioningState,\r\n MachineStatus, MachineErrors, MachineProvisioningStatus,MachineId = machineId,\r\n LastExtensionStatusMessage = properties.instanceView.status.message", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryGridTile", + "settings": {}, + "partHeader": { + "title": "Arc-enabled SQL Server Health", + "subtitle": "" + } + } + } + ] + } + ], + "metadata": { + "model": { + "timeRange": { + "value": { + "relative": { + "duration": 24, + "timeUnit": 1 + } + }, + "type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange" + } + } + } + }, + "name": "Arc-enabled SQL Server Health", + "type": "Microsoft.Portal/dashboards", + "location": "INSERT LOCATION", + "tags": { + "hidden-title": "Arc-enabled SQL Server Health" + }, + "apiVersion": "2022-12-01-preview" +} \ No newline at end of file diff --git a/samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json b/samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json deleted file mode 100644 index bceaec6931..0000000000 --- a/samples/features/azure-arc/dashboard/ArcEnabledSQLServerHealth.dx.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "$schema": "<>", - "view": { - "kind": "Dashboard", - "export": true, - "properties": { - "title": "Arc Enabled SQL Server Health", - "pages": [ - { - "title": "New 1", - "tiles": [ - { - "data": { - "kind": "arg", - "query": "resources\r\n| where type == \"microsoft.hybridcompute/machines/extensions\" \r\n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \r\n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.hybridcompute/machines\"\r\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , MachineStatus= properties.status , MachineProvisioningStatus= properties.provisioningState, MachineErrors = properties.errorDetails //Project relvant machine health information.\r\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\r\n| extend statusExpirationLengthRange = 3d // Change this value to change the acceptable range for the last time an extension should have reported its status.\r\n| extend startDate = startofday(now() - statusExpirationLengthRange), endDate = startofday(now()) // Get the start and end positon for the given range.\r\n| extend extractedDateString = extract(\"timestampUTC : (\\\\d{4}\\\\W\\\\d{2}\\\\W\\\\d{2})\", 1, tostring(properties.instanceView.status.message)) // Extracting the date string for the LastUploadTimestamp. Is empty if none is found.\r\n| extend extractedDateStringYear = split(extractedDateString, '/')[0], extractedDateStringMonth = split(extractedDateString, '/')[1], extractedDateStringDay = split(extractedDateString, '/')[2] // Identifying each of the parts of the date that was extracted from the message.\r\n| extend extractedDate = todatetime(strcat(extractedDateStringYear,\"-\",extractedDateStringMonth,\"-\",extractedDateStringDay,\"T00:00:00Z\")) // Converting to a datetime object and rewriting string into ISO format because todatetime() does not work using the previous format.\r\n| extend isNotInDateRange = not(extractedDate >= startDate and extractedDate <= endDate) // Created bool which is true if the date we extracted from the message is not within the specified range. This bool will also be true if the date was not found in the message.\r\n| where properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\" // Begin searching for unhealthy extensions using the following 1. Does extension report being healthy. 2. Is last upload within the given range. 3. Is the upload status in an OK state. 4. Is provisioning state not in a succeeded state.\r\n or isNotInDateRange\r\n or properties.instanceView.status.message !contains \"uploadStatus : OK\"\r\n or properties.provisioningState != \"Succeeded\"\r\n or MachineStatus != \"Connected\"\r\n| extend FailureReasons = strcat( // Makes a String to list all the reason that this resource got flagged for\r\n iif(MachineStatus != \"Connected\",strcat(\"- Machine's status is \", MachineStatus,\" -\"),\"\") ,\r\n iif(MachineErrors != \"[]\",\"- Machine reports errors -\", \"\"),\r\n iif(properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\",\"- Extension reported unhealthy -\",\"\"), \r\n iif(isNotInDateRange,\"- Last upload outside acceptable range -\",\"\"),\r\n iif(properties.instanceView.status.message !contains \"uploadStatus : OK\",\"- Upload status is not reported OK -\",\"\"), \r\n iif(properties.provisioningState != \"Succeeded\",strcat(\"- Extension provisiong state is \", properties.provisioningState,\" -\"),\"\") \r\n )\r\n| extend RecommendedAction = //Attempt to Identify RootCause based on information gathered, and point customer to what they should investigate first.\r\n iif(MachineStatus == \"Disconnected\", \"Machine is disconnected. Please reconnect the machine.\",\r\n iif(MachineStatus == \"Expired\", \"Machine cert is expired. Go to the machine on the Azure Portal for more information on how to resolve this issue.\",\r\n iif(MachineStatus != \"Connected\", strcat(\"Machine status is \", MachineStatus,\". Investigate and resolve this issue.\"),\r\n iif(MachineProvisioningStatus != \"Succeeded\", strcat(\"Machine provisioning status is \", MachineProvisioningStatus, \". Investigate and resolve machine provisioning status\"),\r\n iff(MachineErrors != \"[]\", \"Machine is reporting errors. Investigate and resolve machine errors\",\r\n iif(properties.provisioningState != \"Succeeded\", strcat(\"Extension provisioning status is \", properties.provisioningState,\". Investigate and resolve extension provisioning state.\"),\r\n iff(properties.instanceView.status.message !contains \"SQL Server Extension Agent:\" and properties.instanceView.status.message contains \"SQL Server Extension Agent Deployer\", \"SQL Server extension eeployer ran. However, SQL Server extension seems to not be running. Verify that the extension is currently running.\",\r\n iff(properties.instanceView.status.message !contains \"uploadStatus : OK\" or isNotInDateRange or properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\", \"Extension reported as unhealthy. View FailureReasons and LastExtensionStatusMessage for more information as to the cause of the failure.\",\r\n \"Unable to reccommend actions. Please view FailureReasons.\"\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n )\r\n| project ID = id, MachineName, ResourceGroup = resourceGroup, SubscriptionID = subscriptionId, Location = location, RecommendedAction, FailureReasons, LicenseType = properties.settings.LicenseType, \r\n LastReportedExtensionHealth = iif(properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\", \"Unhealthy\", \"Healthy\"),\r\n LastExtensionUploadTimestamp = iif(indexof(properties.instanceView.status.message, \"timestampUTC : \") > 0,\r\n substring(properties.instanceView.status.message, indexof(properties.instanceView.status.message, \"timestampUTC : \") + 15, 10),\r\n \"no timestamp\"),\r\n LastExtensionUploadStatus = iif(indexof(properties.instanceView.status.message, \"uploadStatus : OK\") > 0, \"OK\", \"Unhealthy\"),\r\n ExtensionProvisioningState = properties.provisioningState,\r\n MachineStatus, MachineErrors, MachineProvisioningStatus,MachineId = machineId,\r\n LastExtensionStatusMessage = properties.instanceView.status.message", - "usedParameters": [] - }, - "visualization": { - "type": "table", - "options": { - "hideTileTitle": false, - "table__enableFormatting": true, - "table__enableRenderLinks": true, - "table__renderLinksForColumns": [], - "colorRules": [], - "colorRulesDisabled": true, - "colorStyle": "light", - "crossFilter": [], - "crossFilterDisabled": false, - "drillthrough": [], - "drillthroughDisabled": false - } - }, - "title": "Arc SQL Server Resource Health", - "subtitle": "Health of Arc SQL Server extension and Arc machine", - "type": "QueryTile", - "layout": { - "x": 0, - "y": 0, - "width": 19, - "height": 11 - } - } - ] - } - ], - "parameters": [], - "provisioningState": "Succeeded" - } - } -} \ No newline at end of file diff --git a/sql-server-samples b/sql-server-samples new file mode 160000 index 0000000000..9371468580 --- /dev/null +++ b/sql-server-samples @@ -0,0 +1 @@ +Subproject commit 937146858024dd222a3d6754ff321e71442a5c52 From dff1a5320296d557bb41963602b18fdc9b347b1c Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 15 Nov 2024 11:28:37 -0600 Subject: [PATCH 125/159] adding patch-SQLServerInstance script --- .../configuration/Patch-SQLServerInstance.ps1 | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 diff --git a/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 b/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 new file mode 100644 index 0000000000..f9025f4055 --- /dev/null +++ b/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 @@ -0,0 +1,57 @@ +param ( + [string]$resourceGroupName = 'myResourceGroup', + [string]$subscriptionId = '00000000-0000-0000-0000-000000000000', + [switch]$WhatIf = $false, + [string]$propertiesJSON = @" +{ + "backupPolicy": null, + "upgradeLockedUntil": null, + "monitoring": { + "enabled": false + }, + "migration": { + "assessment": { + "enabled": false + } + } +} +"@ +) + +Write-Verbose "Resource Group Name: $resourceGroupName" +Write-Verbose "Subscription ID: $subscriptionId" +Write-Verbose "WhatIf: $WhatIf" +Write-Verbose "Properties JSON: $propertiesJSON" + +$properties = $propertiesJSON | ConvertFrom-Json + +try { + Write-Verbose "Connecting to Azure with subscription ID: $subscriptionId" + $defaultProfile = Connect-AzAccount -SubscriptionId $subscriptionId -ErrorAction Stop + + if ([string]::IsNullOrEmpty($resourceGroupName)) { + Write-Verbose "Fetching resources for subscription ID: $subscriptionId" + $resources = Get-AzResource -ResourceType "Microsoft.AzureArcData/SqlServerInstances" -ErrorAction Stop -Pre -ExpandProperties + } else { + Write-Verbose "Fetching resources for subscription ID: $subscriptionId and resource group: $resourceGroupName" + $resources = Get-AzResource -ResourceType "Microsoft.AzureArcData/SqlServerInstances" -ErrorAction Stop -Pre -ExpandProperties -ResourceGroupName $resourceGroupName + } + $resources = $resources | Where-Object { 'SSIS','SSAS','SSRS' -notcontains $_.Properties.serviceType } + + foreach ($resource in $resources) { + try { + if ($WhatIf) { + Write-Verbose "Performing dry-run patch for resource: $($resource.Id)" + $resource | Set-AzResource -Properties $properties -UsePatchSemantics -Pre -Force -DefaultProfile $defaultProfile -ErrorAction Stop -WhatIf + } else { + Write-Verbose "Patching resource: $($resource.Id)" + $resource | Set-AzResource -Properties $properties -UsePatchSemantics -Pre -Force -DefaultProfile $defaultProfile -ErrorAction Stop + Write-Host("Resource patched: $($resource.Id)") + } + } catch { + Write-Error "Failed to patch resource: $($resource.Id). Error: $_" + } + } +} catch { + Write-Error "An error occurred: $_" +} \ No newline at end of file From 76fa8893f1b2e650ef5a565d8bba0d73defda781 Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 15 Nov 2024 11:50:22 -0600 Subject: [PATCH 126/159] small changes to script params --- .../azure-arc/configuration/Patch-SQLServerInstance.ps1 | 3 ++- sql-server-samples | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 160000 sql-server-samples diff --git a/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 b/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 index f9025f4055..cd99abc20d 100644 --- a/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 +++ b/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 @@ -1,5 +1,6 @@ param ( - [string]$resourceGroupName = 'myResourceGroup', + [string]$resourceGroupName = '', + [Parameter(Mandatory=$true)] [string]$subscriptionId = '00000000-0000-0000-0000-000000000000', [switch]$WhatIf = $false, [string]$propertiesJSON = @" diff --git a/sql-server-samples b/sql-server-samples deleted file mode 160000 index 9371468580..0000000000 --- a/sql-server-samples +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 937146858024dd222a3d6754ff321e71442a5c52 From c90edfa8abda396159e09b4a440188017404972f Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Fri, 15 Nov 2024 12:03:28 -0600 Subject: [PATCH 127/159] tweak json --- .../features/azure-arc/configuration/Patch-SQLServerInstance.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 b/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 index cd99abc20d..f7c3e7749b 100644 --- a/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 +++ b/samples/features/azure-arc/configuration/Patch-SQLServerInstance.ps1 @@ -6,7 +6,6 @@ param ( [string]$propertiesJSON = @" { "backupPolicy": null, - "upgradeLockedUntil": null, "monitoring": { "enabled": false }, From 68d479f0b853bd126e0614cd32ec6c65242617ac Mon Sep 17 00:00:00 2001 From: Charmaine Chan Date: Mon, 18 Nov 2024 14:44:37 -0800 Subject: [PATCH 128/159] Add host level script --- .../Patch-ComputeMachineDisableFeatures | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures diff --git a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures new file mode 100644 index 0000000000..138c3d9c1e --- /dev/null +++ b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures @@ -0,0 +1,128 @@ +$subscriptionId = "" +$resourceGroupName = "" +$whatIf = $null + +if ([string]::IsNullOrEmpty($subscriptionId)) { + $subscriptionId = Read-Host -Prompt "Please enter the subscription ID" +} + +if ([string]::IsNullOrEmpty($resourceGroupName)) { + $resourceGroupName = Read-Host -Prompt "Please enter the resource group name" +} + +if ([string]::IsNullOrEmpty($whatIf)) { + $dryRun = Read-Host -Prompt "Would you like to run this as a dry run? (yes/no)" + if ($dryRun -eq "yes") { + $whatIf = $true + } else { + $whatIf = $false + } +} + +if ([string]::IsNullOrEmpty($resourceGroupName) -or [string]::IsNullOrEmpty($subscriptionId)) { + Write-Host "Either the resource group or subscription ID is not specified. Please provide both to proceed." + exit +} else { + Write-Host "Performing actions on ResourceGroup: $($resourceGroupName) in Subscription:$($subscriptionId)" +} + +$query = @" +Resources +| where type == 'microsoft.azurearcdata/sqlserverinstances' +| where resourceGroup == '$resourceGroupName' +| where subscriptionId == '$subscriptionId' +| project name, resourceGroup +"@ + +$minSupportedApiVersion = '2024-07-10' + +$resources = Search-AzGraph -Query $query + +if ([string]::IsNullOrEmpty($resources)) { + Write-Host "No resources were found in this resource group." + exit +} + +$resources = $resources | ForEach-Object { + [pscustomobject]@{ + ResourceGroup = $_.resourceGroup + SqlArcResource = $_.name + } +} +Write-Host $resources +$arcMachineResourceIds = @() +foreach ($resource in $resources) { + Write-Host "ResourceGroup: $($resource.ResourceGroup), Sql Arc resource: $($resource.SqlArcResource)" + + $hybridComputeResourceId = Get-AzResource -ResourceName $resource.SqlArcResource -ResourceGroupName $resource.ResourceGroup -ResourceType "Microsoft.AzureArcData/sqlServerInstances" | Select-Object -ExpandProperty Properties | Select-Object -ExpandProperty containerResourceId + $arcMachineResourceIds += $hybridComputeResourceId +} + +$arcMachineUniqueResourceIds = $arcMachineResourceIds | Get-Unique +Write-Output "Arc Machine Resource Ids:" +Write-Output $arcMachineUniqueResourceIds + +foreach ($arcMachineUniqueResourceId in $arcMachineUniqueResourceIds) { + Write-Host "----- Attempting to remove settings from machine: $($arcMachineUniqueResourceId) -----" + $computeMachineResource = Get-AzResource -ResourceId "$arcMachineUniqueResourceId" + $extensionResource = Get-AzResource -ResourceId "$arcMachineUniqueResourceId/extensions/WindowsAgent.SqlServer" -ApiVersion $minSupportedApiVersion + $currentSettings = $extensionResource.properties.settings + + $parsedData = @{ + "ExtensionAgentStatus" = $null + "TimestampUTC" = $null + } + + if ($extensionResource.properties.instanceView.status -match "SQL Server Extension Agent: (\w+);") { + $parsedData["ExtensionAgentStatus"] = $matches[1] + } + + if ($extensionResource.properties.instanceView.status -match "timestampUTC : ([\d\/:., ]+);") { + $parsedData["TimestampUTC"] = [datetime]::ParseExact($matches[1], "yyyy/MM/dd, HH:mm:ss.fff", $null) + } + + # Check if the Extension Agent is healthy and the timestamp is within the last 24 hours + $extensionAgentHealthy = $parsedData["ExtensionAgentStatus"] -eq "Healthy" + $timestampWithin24Hours = ($parsedData["TimestampUTC"] -gt (Get-Date).AddHours(-24)) + + if ($computeMachineResource.properties.status -ne "Connected") { + Write-Host "This machine has status: $($computeMachineResource.properties.status). We will skip removing the configurations on this machine." + continue + } elseif (-not ($extensionAgentHealthy -and $timestampWithin24Hours)) { + Write-Host "The extension agent status is: $($parsedData["ExtensionAgentStatus"]) and was last updated: $($($parsedData["TimestampUTC"]))." + Write-Host "The extension status must be healthy and updated within 24hrs for us to proceed. We will skip removing the configurations on this machine." + continue + } else { + Write-Host "This machine has status: $($computeMachineResource.properties.status). We will proceed to remove the configurations." + } + + # Disable ESU + if ($currentSettings.PSobject.Properties.Name -contains "EnableExtendedSecurityUpdates") { + $currentSettings.EnableExtendedSecurityUpdates = $false + } + # Disable Microsoft Updates + if ($currentSettings.PSobject.Properties.Name -contains "MicrosoftUpdateConfiguration") { + $currentSettings.MicrosoftUpdateConfiguration.EnableMicrosoftUpdate = $false + } + # Disable BPA + if ($currentSettings.PSobject.Properties.Name -contains "AssessmentSettings") { + $currentSettings.AssessmentSettings.Enable = $false + } + + $newProperties = $extensionResource.properties + $newProperties.settings = $currentSettings + + $newProperties | ConvertTo-Json | Out-File "settingsInFile.json" + + try { + if ($whatIf) { + $extensionResource | Set-AzResource -Properties $newProperties -UsePatchSemantics -Pre -ErrorAction Stop -WhatIf -AsJob + } else { + $extensionResource | Set-AzResource -Properties $newProperties -UsePatchSemantics -Pre -ErrorAction Stop -Force -AsJob + } + Write-Host "Command executed." + } catch { + Write-Host "Command failed with the following error:" + Write-Host $_.Exception.Message + } +} \ No newline at end of file From d2f0ddac334172df962cac30e187e58a8039df3f Mon Sep 17 00:00:00 2001 From: Charmaine Chan Date: Mon, 18 Nov 2024 15:08:31 -0800 Subject: [PATCH 129/159] Use params --- .../configuration/Patch-ComputeMachineDisableFeatures | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures index 138c3d9c1e..7dff0173e0 100644 --- a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures +++ b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures @@ -1,6 +1,8 @@ -$subscriptionId = "" -$resourceGroupName = "" -$whatIf = $null +param ( +[string]$subscriptionId, +[string]$resourceGroupName, +[bool]$whatIf = $false +) if ([string]::IsNullOrEmpty($subscriptionId)) { $subscriptionId = Read-Host -Prompt "Please enter the subscription ID" From 3b4e3920f9e8dc6c496e8e2ffa6b5a3bfb0e182c Mon Sep 17 00:00:00 2001 From: Charmaine Chan Date: Mon, 18 Nov 2024 15:28:56 -0800 Subject: [PATCH 130/159] Rename file and make not case sensitive --- ...ableFeatures => Patch-ComputeMachineDisableFeatures.ps1} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename samples/features/azure-arc/configuration/{Patch-ComputeMachineDisableFeatures => Patch-ComputeMachineDisableFeatures.ps1} (97%) diff --git a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 similarity index 97% rename from samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures rename to samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 index 7dff0173e0..0d7a15d00f 100644 --- a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures +++ b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 @@ -30,9 +30,9 @@ if ([string]::IsNullOrEmpty($resourceGroupName) -or [string]::IsNullOrEmpty($sub $query = @" Resources -| where type == 'microsoft.azurearcdata/sqlserverinstances' -| where resourceGroup == '$resourceGroupName' -| where subscriptionId == '$subscriptionId' +| where type =~ 'microsoft.azurearcdata/sqlserverinstances' +| where resourceGroup =~ '$resourceGroupName' +| where subscriptionId =~ '$subscriptionId' | project name, resourceGroup "@ From 6ed88d20d6f01bd645b974e53b27b3de4afccd2e Mon Sep 17 00:00:00 2001 From: Charmaine Chan Date: Mon, 18 Nov 2024 17:09:38 -0800 Subject: [PATCH 131/159] Make RG optional --- .../Patch-ComputeMachineDisableFeatures.ps1 | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 index 0d7a15d00f..f86be2d4a7 100644 --- a/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 +++ b/samples/features/azure-arc/configuration/Patch-ComputeMachineDisableFeatures.ps1 @@ -1,6 +1,7 @@ param ( -[string]$subscriptionId, [string]$resourceGroupName, +[Parameter(Mandatory=$true)] +[string]$subscriptionId, [bool]$whatIf = $false ) @@ -8,9 +9,9 @@ if ([string]::IsNullOrEmpty($subscriptionId)) { $subscriptionId = Read-Host -Prompt "Please enter the subscription ID" } -if ([string]::IsNullOrEmpty($resourceGroupName)) { - $resourceGroupName = Read-Host -Prompt "Please enter the resource group name" -} +# if ([string]::IsNullOrEmpty($resourceGroupName)) { +# $resourceGroupName = Read-Host -Prompt "Please enter the resource group name" +# } if ([string]::IsNullOrEmpty($whatIf)) { $dryRun = Read-Host -Prompt "Would you like to run this as a dry run? (yes/no)" @@ -21,27 +22,40 @@ if ([string]::IsNullOrEmpty($whatIf)) { } } -if ([string]::IsNullOrEmpty($resourceGroupName) -or [string]::IsNullOrEmpty($subscriptionId)) { - Write-Host "Either the resource group or subscription ID is not specified. Please provide both to proceed." - exit -} else { - Write-Host "Performing actions on ResourceGroup: $($resourceGroupName) in Subscription:$($subscriptionId)" -} +Write-Host "Resource Group Name: $resourceGroupName" +Write-Host "Subscription ID: $subscriptionId" +Write-Host "WhatIf: $WhatIf" -$query = @" -Resources -| where type =~ 'microsoft.azurearcdata/sqlserverinstances' -| where resourceGroup =~ '$resourceGroupName' -| where subscriptionId =~ '$subscriptionId' -| project name, resourceGroup -"@ +if ([string]::IsNullOrEmpty($subscriptionId)) { + Write-Host "The subscription ID is required." + exit +} $minSupportedApiVersion = '2024-07-10' +$query = $null +$resources = $null + +if ([string]::IsNullOrEmpty($resourceGroupName)){ + $query =" + Resources + | where type =~ 'microsoft.azurearcdata/sqlserverinstances' + | where subscriptionId =~ '$subscriptionId' + | project name, resourceGroup + " +} else { + $query =" + Resources + | where type =~ 'microsoft.azurearcdata/sqlserverinstances' + | where resourceGroup =~ '$resourceGroupName' + | where subscriptionId =~ '$subscriptionId' + | project name, resourceGroup + " +} $resources = Search-AzGraph -Query $query if ([string]::IsNullOrEmpty($resources)) { - Write-Host "No resources were found in this resource group." + Write-Host "No SQL Server Instances were found in this scope." exit } @@ -51,7 +65,7 @@ $resources = $resources | ForEach-Object { SqlArcResource = $_.name } } -Write-Host $resources + $arcMachineResourceIds = @() foreach ($resource in $resources) { Write-Host "ResourceGroup: $($resource.ResourceGroup), Sql Arc resource: $($resource.SqlArcResource)" From cc6c038a2000e7592552f21b0268c13ac8052731 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:23:44 +0000 Subject: [PATCH 132/159] Bump cross-spawn Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6. - [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md) - [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6) --- updated-dependencies: - dependency-name: cross-spawn dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../SqlDbEdgeDemo.Web/ClientApp/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json index a3348ec317..7d8d18149d 100644 --- a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/webappsrc/SqlDbEdgeDemoWeb/SqlDbEdgeDemo.Web/ClientApp/package-lock.json @@ -4338,9 +4338,9 @@ } }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", From 6a1bea3337fe7e7ab2ac1b93f4b78d9a069353ce Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Sun, 1 Dec 2024 15:14:24 -0800 Subject: [PATCH 133/159] Updated to support UsePcoreLicense --- .../modify-license-type.ps1 | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 29906728d0..430e0d1508 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -6,13 +6,15 @@ # If not specified, all subscriptions your role has access to are scanned. # # The script accepts the following command line parameters: -# +#. # -SubId [subscription_id] | [csv_file_name] (Optional. Limits the scope to specific subscriptions. Accepts a .csv file with the list of subscriptions. # If not specified all subscriptions will be scanned) # -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group) # -MachineName [machine_name] (Optional. Limits the scope to a specific machine) # -LicenseType [license_type_value] (Optional. Sets the license type to the specified value) -# -EnableESU [Yes or No] (Optional. Enables the ESU policy the value is "Yes" or disables it if the value is "No" +# -EnableESU [Yes or No] (Optional. Enables the ESU policy if the value is "Yes" or disables it if the value is "No" +# To enable, the license type must be "Paid" or "PAYG" +# -UsePcoreLicense [Yes or 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" # -Force (Optional. Forces the chnahge 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 @@ -36,6 +38,9 @@ param ( [ValidateSet("Yes","No", IgnoreCase=$false)] [string] $EnableESU, [Parameter (Mandatory= $false)] + [ValidateSet("Yes","No", IgnoreCase=$false)] + [string] $UsePcoreLicense, + [Parameter (Mandatory= $false)] [switch] $Force ) @@ -243,11 +248,24 @@ foreach ($sub in $subscriptions){ write-host "The configured license type does not support ESUs" } } - + + # Enable UsePcoreLicense for qualified license types or disable + if ($UsePcoreLicense) { + if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($UsePcoreLicense -eq "No")) { + $settings["UsePhysicalCoreLicense"] = @{ + "IsApplied" = ($UsePcoreLicense -eq "Yes"); + "LastUpdatedTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') + } + $WriteSettings = $true + } else { + write-host "The configured license type does not support ESUs" + } + } If ($WriteSettings) { - Write-Host "Resource group: [$($r.resourceGroup)] Connected machine: [$($r.MachineName)] : License type: [$($settings["LicenseType"])] : Enable ESU: [$($settings["enableExtendedSecurityUpdates"])]" + try { Set-AzConnectedMachineExtension @setId -Settings $settings -NoWait | Out-Null + Write-Host "Updated -- Resource group: [$($r.resourceGroup)], Connected machine: [$($r.MachineName)]" } catch { write-host "The request to modify the extenion object failed with the following error:" write-host $_.Exception.Message From d836e167a4c68775532ffa4712f235fc79313847 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Sun, 1 Dec 2024 15:28:15 -0800 Subject: [PATCH 134/159] Modified README --- .../modify-license-type/README.md | 7 ++++--- .../modify-license-type/modify-license-type.ps1 | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) 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 e0282d4038..8173433c93 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 @@ -3,7 +3,7 @@ services: Azure Arc-enabled SQL Server platforms: Azure author: anosov1960 ms.author: sashan -ms.date: 9/22/2023 +ms.date: 12/01/2024 --- @@ -31,6 +31,7 @@ The script accepts the following command line parameters: |-ResourceGroup |resource_group_name|Optional: Limits the scope to a specific resource group| |-MachineName |machine_name|Optional: Limits the scope to a specific machine| |-LicenseType | "Paid", "PAYG" or "LicenseOnly"| Optional: Sets the license type to the specified value | +|-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| @@ -57,10 +58,10 @@ The following command will scan the subscription `` and set the license ## Example 3 -The following command will scan resource group `` in the subscription `` and set the license type value to "PAYG" on all servers. +The following command will scan resource group `` in the subscription `` and set the license type value to "PAYG" and enable unlimited virtualization license on all servers in the specified resource group. ```PowerShell -.\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType PAYG -Force +.\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType PAYG -UsePcoreLicense Yes -Force ``` ## Example 4 diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 430e0d1508..62873d8fd4 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -12,10 +12,10 @@ # -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group) # -MachineName [machine_name] (Optional. Limits the scope to a specific machine) # -LicenseType [license_type_value] (Optional. Sets the license type to the specified value) -# -EnableESU [Yes or No] (Optional. Enables the ESU policy if the value is "Yes" or disables it if the value is "No" -# To enable, the license type must be "Paid" or "PAYG" # -UsePcoreLicense [Yes or 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 or No] (Optional. Enables the ESU policy if 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 chnahge 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 # @@ -36,10 +36,10 @@ param ( [string] $LicenseType, [Parameter (Mandatory= $false)] [ValidateSet("Yes","No", IgnoreCase=$false)] - [string] $EnableESU, + [string] $UsePcoreLicense, [Parameter (Mandatory= $false)] [ValidateSet("Yes","No", IgnoreCase=$false)] - [string] $UsePcoreLicense, + [string] $EnableESU, [Parameter (Mandatory= $false)] [switch] $Force ) From bafb8e95e3fcb17e635fab377e3bf2e8e68e78c4 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Sun, 1 Dec 2024 15:59:42 -0800 Subject: [PATCH 135/159] Update README.md Minor text edit --- .../azure-arc-enabled-sql-server/modify-license-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8173433c93..3429fa14a2 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 @@ -58,7 +58,7 @@ The following command will scan the subscription `` and set the license ## Example 3 -The following command will scan resource group `` in the subscription `` and set the license type value to "PAYG" and enable unlimited virtualization license on all servers in the specified resource group. +The following command will scan resource group `` in the subscription ``, set the license type value to "PAYG" and enable unlimited virtualization license on all servers in the specified resource group. ```PowerShell .\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType PAYG -UsePcoreLicense Yes -Force From e74af02add614d7ec764dd2a68bce3364250a3ff Mon Sep 17 00:00:00 2001 From: Travis Wright Date: Sat, 18 Jan 2025 21:56:02 -0800 Subject: [PATCH 136/159] adding more charts to health dashboard --- .../Arc-enabled SQL Server Health.json | 637 +++++++++++++++++- sql-server-samples | 1 + 2 files changed, 636 insertions(+), 2 deletions(-) create mode 160000 sql-server-samples diff --git a/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json b/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json index bbb053cc04..518ea88ae6 100644 --- a/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json +++ b/samples/features/azure-arc/dashboard/Arc-enabled SQL Server Health.json @@ -8,8 +8,641 @@ "position": { "x": 0, "y": 0, - "colSpan": 20, - "rowSpan": 11 + "colSpan": 6, + "rowSpan": 2 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines\"\n| where properties.detectedProperties.mssqldiscovered =~ 'true' or properties.mssqldiscovered =~ 'true'\n| summarize SqlServerMachines = count()", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile", + "settings": {}, + "partHeader": { + "title": "Machines Hosting SQL Server", + "subtitle": "The count of machines that have SQL Server installed" + } + } + }, + { + "position": { + "x": 6, + "y": 0, + "colSpan": 6, + "rowSpan": 2 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\" \n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\")\n| summarize SQLServerExtensions = count()", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile", + "settings": {}, + "partHeader": { + "title": "SQL Server Extensions", + "subtitle": "The count of SQL Server extensions. Should be the same as the count of Machines Hosting SQL Server." + } + } + }, + { + "position": { + "x": 12, + "y": 0, + "colSpan": 6, + "rowSpan": 2 + }, + "metadata": { + "inputs": [ + { + "name": "chartType", + "isOptional": true + }, + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\")\n| extend targetMachineName = tolower(tostring(split(id, '/')[8]))\n| join kind=leftouter (\n resources\n | where type == \"microsoft.hybridcompute/machines\"\n | project machineId = id, MachineName = name, subscriptionId, resourceGroup, MachineStatus = properties.status, MachineProvisioningStatus = properties.provisioningState, MachineErrors = properties.errorDetails\n) on $left.targetMachineName == $right.MachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId\n| extend extractedDate = todatetime(extract(\"timestampUTC : (\\\\d{4}-\\\\d{2}-\\\\d{2})\", 1, tostring(properties.instanceView.status.message)))\n| extend isNotInDateRange = extractedDate < ago(3d) or isnull(extractedDate)\n| where properties.instanceView.status.message !contains \"SQL Server Extension Agent: Healthy\"\n or isNotInDateRange\n or properties.instanceView.status.message !contains \"uploadStatus : OK\"\n or properties.provisioningState != \"Succeeded\"\n or MachineStatus != \"Connected\"\n| project ID = id, MachineName, ResourceGroup = resourceGroup, SubscriptionID = subscriptionId, Location = location, \n LastReportedExtensionHealth = iif(properties.instanceView.status.message contains \"SQL Server Extension Agent: Healthy\", \"Healthy\", \"Unhealthy\"),\n LastExtensionUploadTimestamp = tostring(extractedDate),\n LastExtensionUploadStatus = iif(properties.instanceView.status.message contains \"uploadStatus : OK\", \"OK\", \"Unhealthy\"),\n ExtensionProvisioningState = properties.provisioningState,\n MachineStatus, MachineErrors, MachineProvisioningStatus\n| project OverallHealth = iif(LastReportedExtensionHealth == \"Healthy\" and LastExtensionUploadStatus == \"OK\" and ExtensionProvisioningState == \"Succeeded\" and MachineStatus == \"Connected\" and MachineProvisioningStatus == \"Succeeded\", \"Healthy\", \"Unhealthy\")\n| where OverallHealth == \"Healthy\"\n| summarize HealthyExtensions = count()", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQuerySingleValueTile", + "settings": {}, + "partHeader": { + "title": "Overall Healthy SQL Server Extensions", + "subtitle": "The count of overall healthy SQL Server extensions should be the same as the count of SQL Server extensions." + } + } + }, + { + "position": { + "x": 0, + "y": 2, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n | where type =~ 'microsoft.hybridcompute/machines/extensions'\n | where properties.type in ('WindowsAgent.SqlServer','LinuxAgent.SqlServer')\n | parse id with * '/providers/Microsoft.HybridCompute/machines/' machineName '/extensions/' *\n | parse properties with * 'uploadStatus : ' uploadStatus ';' *\n | project uploadStatus, subscriptionId, resourceGroup, machineName\n | summarize count() by uploadStatus", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Extension DPS Upload Status", + "subtitle": "'OK' is good. Anaything else should be investigated." + } + } + }, + { + "position": { + "x": 6, + "y": 2, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type =~ 'microsoft.hybridcompute/machines/extensions'\n| where properties.type in ('WindowsAgent.SqlServer', 'LinuxAgent.SqlServer')\n| parse id with * '/providers/Microsoft.HybridCompute/machines/' machineName '/extensions/' *\n| extend extractedDateString = extract(\"timestampUTC : (\\\\d{4}-\\\\d{2}-\\\\d{2})\", 1, tostring(properties.instanceView.status.message))\n| extend extractedDateString = case(\n isnull(extractedDateString) or extractedDateString == '', \n '1900-01-01T00:00:00Z', \n extractedDateString\n)\n| extend extractedDate = todatetime(extractedDateString)\n| extend isRecent = case(extractedDate > ago(1d), \"Less than 1 day ago\", extractedDate > ago(3d), \"1 to 3 days ago\", \"More than 3 days ago\")\n| summarize count() by isRecent", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Extension Status Update Time", + "subtitle": "Status should be updated every 5 minutes." + } + } + }, + { + "position": { + "x": 12, + "y": 2, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\")\n| summarize count() by tostring(properties.provisioningState)", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Extension Provisioning State", + "subtitle": "Provisioning State should normally be 'Succeeded'" + } + } + }, + { + "position": { + "x": 0, + "y": 6, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\" \n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\")\n| summarize count() by tostring(properties.typeHandlerVersion)", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Extension Versions", + "subtitle": "Extension versions should be on a recent version, at least within one year. https://aka.ms/arcsqlreleasenotes" + } + } + }, + { + "position": { + "x": 6, + "y": 6, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\"\n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\")\n| project GeneralHealth = iif(properties.instanceView.status.message contains \"SQL Server Extension Agent: Healthy\", \"Healthy\", \"Unhealthy\")\n| summarize count() by GeneralHealth", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "SQL Extension General Health", + "subtitle": "The health as reported in the extension of the extension itself." + } + } + }, + { + "position": { + "x": 12, + "y": 6, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\" \n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\n| join kind=leftouter (\n resources\n | where type == \"microsoft.hybridcompute/machines\"\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , MachineStatus= properties.status , MachineProvisioningStatus= properties.provisioningState\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\n| summarize count() by tostring(MachineProvisioningStatus)", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Machine Provisioning State", + "subtitle": "Machines should have a provisioning state of 'Succeeded'" + } + } + }, + { + "position": { + "x": 0, + "y": 10, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\" \n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\n| join kind=leftouter (\n resources\n | where type == \"microsoft.hybridcompute/machines\"\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , MachineStatus= properties.status , MachineProvisioningStatus= properties.provisioningState\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\n| summarize count() by tostring(MachineStatus)", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Machine Connectivity Status", + "subtitle": "Machines should have a state of 'Connected'" + } + } + }, + { + "position": { + "x": 6, + "y": 10, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + }, + { + "name": "query", + "value": "resources\n| where type == \"microsoft.hybridcompute/machines/extensions\" \n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\n| join kind=leftouter (\n resources\n | where type == \"microsoft.hybridcompute/machines\"\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , MachineExtensionServiceStatus = properties.serviceStatuses.extensionService.status\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\n| summarize count() by tostring(MachineExtensionServiceStatus)", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Machine Extension Service Status", + "subtitle": "The Machine Extension Service status should be 'Running'" + } + } + }, + { + "position": { + "x": 12, + "y": 10, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "isShared", + "isOptional": true + }, + { + "name": "queryId", + "isOptional": true + }, + { + "name": "formatResults", + "isOptional": true + }, + { + "name": "partTitle", + "value": "Query 1", + "isOptional": true + }, + { + "name": "query", + "value": "//Machine Guest Configuration Service Status\nresources\n| where type == \"microsoft.hybridcompute/machines/extensions\" \n| where properties.type in (\"WindowsAgent.SqlServer\", \"LinuxAgent.SqlServer\") \n| extend targetMachineName = tolower(tostring(split(id, '/')[8])) // Extract the machine name from the extension's id\n| join kind=leftouter (\n resources\n | where type == \"microsoft.hybridcompute/machines\"\n | project machineId = id, MachineName = name, subscriptionId, LowerMachineName = tolower(name), resourceGroup , GuestConfigurationService = properties.serviceStatuses.guestConfigurationService.status\n) on $left.targetMachineName == $right.LowerMachineName and $left.resourceGroup == $right.resourceGroup and $left.subscriptionId == $right.subscriptionId // Join Based on MachineName in the id and the machine's name, the resource group, and the subscription. This join allows us to present the data of the machine as well as the extension in the final output.\n| summarize count() by tostring(GuestConfigurationService)", + "isOptional": true + }, + { + "name": "chartType", + "value": 2, + "isOptional": true + }, + { + "name": "queryScope", + "value": { + "scope": 0, + "values": [] + }, + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/ArgQueryChartTile", + "settings": {}, + "partHeader": { + "title": "Machine Guest Configuration Service Status", + "subtitle": "The Machine Guest Configuration Status should be 'Running'" + } + } + }, + { + "position": { + "x": 0, + "y": 14, + "colSpan": 18, + "rowSpan": 12 }, "metadata": { "inputs": [ diff --git a/sql-server-samples b/sql-server-samples new file mode 160000 index 0000000000..bafb8e95e3 --- /dev/null +++ b/sql-server-samples @@ -0,0 +1 @@ +Subproject commit bafb8e95e3fcb17e635fab377e3bf2e8e68e78c4 From 8dc1b7163affda4b03a5aec37d47fa97affdb39c Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 25 Mar 2025 19:06:50 -0700 Subject: [PATCH 137/159] Added modify-license-type for Azure SQL --- .../get-sqlvm-inventory.ps1 | 262 ++++++------------ .../modify-license-type/README.md | 121 ++++++++ .../modify-license-type.ps1 | 179 ++++++++++++ 3 files changed, 388 insertions(+), 174 deletions(-) create mode 100644 samples/manage/azure-hybrid-benefit/modify-license-type/README.md create mode 100644 samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 diff --git a/samples/manage/azure-hybrid-benefit/get-sqlvm-inventory.ps1 b/samples/manage/azure-hybrid-benefit/get-sqlvm-inventory.ps1 index 591cd8f04c..94bf5b71db 100644 --- a/samples/manage/azure-hybrid-benefit/get-sqlvm-inventory.ps1 +++ b/samples/manage/azure-hybrid-benefit/get-sqlvm-inventory.ps1 @@ -1,32 +1,10 @@ -# -# This script scan each VM in scope to detect if SQL server insstalled and if it is regsitered with IaaS extension. -# The report includes the following information for each VM. -# -# Subscription Name -# Subscription ID -# ResourceGroupName -# Server Name -# Location -# Server SKU -# Size in vCores -# OS Type -# OS Version -# SQL Version -# SQL Edition -# IaaS registration status -# -# The script accepts the following command line parameters: -# -# -SubId [subscription_id] (Optional. If not specified all subscription the user has access to Accepts a .csv file with the list of subscriptions) -# -FilePath [csv_file_name] (Optional. Sprcifies a .csv file to save the data. if not specified, saves it in sql-vcm-inventory.csv) -# - -param ( +param ( [Parameter (Mandatory= $false)] [string] $SubId, [Parameter (Mandatory= $false)] + [PSCredential] $Cred, + [Parameter (Mandatory= $false)] [string] $FilePath - ) function CheckModule ($m) { @@ -56,76 +34,10 @@ function CheckModule ($m) { } } -function GetVCores { - # This function translates each VM or Host sku type and name into vCores - - [CmdletBinding()] - param ( - [Parameter(Mandatory)] - [string]$type, - [Parameter(Mandatory)] - [string]$name - ) - - if ($global:VM_SKUs.Count -eq 0){ - $global:VM_SKUs = Get-AzComputeResourceSku "westus" | where-object {$_.ResourceType -in 'virtualMachines','hostGroups/hosts'} - } - # Select first size and get the VCPus available - $size_info = $global:VM_SKUs | Where-Object {$_.ResourceType.Contains($type) -and ($_.Name -eq $name)} | Select-Object -First 1 - - # Save the VCPU count - switch ($type) { - "hosts" {$vcpu = $size_info.Capabilities | Where-Object {$_.name -eq "Cores"} } - "virtualMachines" {$vcpu = $size_info.Capabilities | Where-Object {$_.name -eq "vCPUsAvailable"} } - } - - if ($vcpu){ - return $vcpu.Value - } - else { - return 0 - } - } - -function DiscoveryOnWindows { - -# This script checks if SQL Server is installed on Windows - - [string] $SqlInstalled = "" - $regPath = 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' - if (Test-Path $regPath) { - $inst = (get-itemproperty $regPath).InstalledInstances - #$SqlInstalled = ($inst.Count -gt 0) - foreach ($i in $inst) { - # Read registry data - # - $p = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$i - $setupValues = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\Setup") - $edition = ($setupValues.Edition -split ' ')[0] - $version = ($setupValues.Version) - $SqlInstalled = $version, $edition -join ':' - } - } - Write-Output $SqlInstalled -} - -# -# This script checks if SQL Server is installed on Linux # +# Suppress warnings # -$DiscoveryOnLinux = - 'if ! systemctl is-active --quiet mssql-server.service; then dir - - echo "False" - exit - else - echo "True" - fi' - - - -# Ensure that the required modules are imported -# In Runbooks these modules must be added to the automation account manually +Update-AzConfig -DisplayBreakingChangeWarning $false $requiredModules = @( "Az.Accounts", @@ -137,37 +49,27 @@ $requiredModules = @( ) $requiredModules | Foreach-Object {CheckModule $_} -# Save the function definitions to run in parallel loops -$GetVCoresDef = $function:GetVCores.ToString() - -# Create a script file with the SQL server discovery logic -New-Item -ItemType file -path DiscoverSql.ps1 -value $function:DiscoveryOnWindows.ToString() -Force | Out-Null -New-Item -ItemType file -path DiscoverSql.sh -value $DiscoveryOnLinux -Force | Out-Null - # Subscriptions to scan - if ($SubId -like "*.csv") { $subscriptions = Import-Csv $SubId -}elseif($SubId.length -gt 0){ +}elseif($SubId -ne $null){ $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription }else{ $subscriptions = Get-AzSubscription } - -#File setup +#Log file setup if (!$PSBoundParameters.ContainsKey("FilePath")) { - $FilePath = '.\sql-vm-inventory.csv' + $FilePath = '.\sql-change-log.csv' } -[System.Collections.ArrayList]$inventoryTable = @() -$inventoryTable += ,(@("Subscription Name", "Subscription ID", "ResourceGroupName", "Name", "Location", "SKU", "vCores", "OS Type", "OS Version", "SQL Version", "SQL Edition", "IaaS registration")) - -$global:VM_SKUs = @{} # To hold the VM SKU table for future use - Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --") +# Record the start time +$startTime = Get-Date +Write-Host ("Script execution started at: $startTime") + # Calculate usage for each subscription foreach ($sub in $subscriptions){ @@ -178,78 +80,90 @@ foreach ($sub in $subscriptions){ Set-AzContext -SubscriptionId $sub.Id }catch { write-host "Invalid subscription: " $sub.Id - {continue} + continue } - # Reset the subtotals - #$subtotal.psobject.properties.name | Foreach-object {$subtotal.$_ = 0} - # Get all resource groups in the subscription - #$rgs = Get-AzResourceGroup - - # Scan all VMs with SQL server installed using a parallel loop (up to 10 at a time). - # NOTE: ForEach-Object -Parallel requires PS v7.1 or higher - if ($PSVersionTable.PSVersion.Major -ge 7){ - #Get-AzVM -Status | Where-Object { $_.powerstate -eq 'VM running' } | ForEach-Object -ThrottleLimit 10 -Parallel { - Get-AzVM -Status | Where-Object { $_.powerstate -eq 'VM running' } | ForEach-Object { - #$function:GetVCores = $using:GetVCoresDef - $SqlEdition = '' - $SqlVersion = '' - $vCores = GetVCores -type 'virtualMachines' -name $_.HardwareProfile.VmSize - $sql_vm = Get-AzSqlVm -ResourceGroupName $_.ResourceGroupName -Name $_.Name -ErrorAction Ignore - - - if ($sql_vm) { - $RegStatus = 'SQL Server registered' - $SqlEdition = $Sql_vm.Sku - $SqlVersion = $Sql_vm.Offer - } - else { - if ($_.StorageProfile.OSDisk.OSType -eq "Windows"){ - $params =@{ - ResourceGroupName = $_.ResourceGroupName - Name = $_.Name - CommandId = 'RunPowerShellScript' - ScriptPath = 'DiscoverSql.ps1' - ErrorAction = 'Stop' - } - } - else { - $params =@{ - ResourceGroupName = $_.ResourceGroupName - Name = $_.Name - CommandId = 'RunShellScript' - ScriptPath = 'DiscoverSql.sh' - ErrorAction = 'Stop' - } - } - try { - $out = Invoke-AzVMRunCommand @params - if (!$out.Value[0].Message){ - $RegStatus = 'SQL Server not installed' - } - else { - $SqlVersion, $SqlEdition = $out.Value[0].Message -split ':', 2 - $RegStatus = 'SQL Server not registered' - } - } - catch { - $RegStatus = 'No VM access' - } + $rgs = Get-AzResourceGroup + + # Get all logical servers + $servers = Get-AzSqlServer + + # Scan all vCore-based SQL database resources in the subscription + $servers | Get-AzSqlDatabase | Where-Object { $_.SkuName -ne "ElasticPool" -and $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { + if ($_.LicenseType -ne "LicenseIncluded") { + Set-AzSqlDatabase -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -DatabaseName $_.DatabaseName -LicenseType "LicenseIncluded" + Write-Host ([Environment]::NewLine + "-- Database $_.DatabaseName is set to \"LicenseIncluded\"") + } + } + [system.gc]::Collect() + + # Scan all vCore-based SQL elastic pool resources in the subscription + $servers | Get-AzSqlElasticPool | Where-Object { $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { + if ($_.LicenseType -ne "LicenseIncluded") { + Set-AzSqlElasticPool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -ElasticPoolName $_.ElasticPoolName -LicenseType "LicenseIncluded" + Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to \"LicenseIncluded\"") + } + } + [system.gc]::Collect() + + # Scan all SQL managed instance resources in the subscription + Get-AzSqlInstance | Where-Object { $_.InstancePoolName -eq $null } | ForEach-Object { + if ($_.LicenseType -ne "LicenseIncluded") { + Set-AzSqlInstance -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType "LicenseIncluded" + Write-Host ([Environment]::NewLine + "-- Instance $_.InstanceName is set to \"LicenseIncluded\"") + } + } + [system.gc]::Collect() + + # Scan all instance pool resources in the subscription + Get-AzSqlInstancePool | Foreach-Object { + if ($_.LicenseType -ne "LicenseIncluded") { + Set-AzSqlInstancePool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType "LicenseIncluded" + Write-Host ([Environment]::NewLine + "-- InstancePool $_.InstanceName is set to \"LicenseIncluded\"") + } + } + [system.gc]::Collect() + + # Scan all SSIS integration runtime resources in the subscription + $rgs | Get-AzDataFactoryV2 | Get-AzDataFactoryV2IntegrationRuntime | Where-Object { $_.State -eq "Started" -and $_.NodeSize -ne $null } | ForEach-Object { + if ($_.LicenseType -ne "LicenseIncluded") { + # Set the license type to "LicenseIncluded" + Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType "LicenseIncluded" + Write-Host ([Environment]::NewLine + "-- DataFactory $_.DataFactoryName is set to \"LicenseIncluded\"") + } + } + [system.gc]::Collect() + + # Scan all SQL VMs in the subscription + $rgs | Get-AzVM | Where-Object { $_.StorageProfile.ImageReference.Offer -like "*sql*" -and $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { + $vmName = $_.Name + $resourceGroupName = $_.ResourceGroupName + + # Get the SQL configuration for the VM + $sqlConfig = Get-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" + + if ($sqlConfig -ne $null) { + $licenseType = $sqlConfig.Settings.LicenseType + + if ($licenseType -ne "LicenseIncluded") { + # Set the license type to "LicenseIncluded" + Set-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" -Publisher "Microsoft.SqlServer.Management" -ExtensionType "SqlIaaSAgent" -TypeHandlerVersion "1.5" -Settings @{ "LicenseType" = "LicenseIncluded" } + Write-Host ([Environment]::NewLine + "-- SQL VM $vmName is set to \"LicenseIncluded\"") } - $inventoryTable += ,(@( $sub.Name, $sub.Id, $_.ResourceGroupName, $_.Name, $_.Location, $_.HardwareProfile.VmSize, $vCores, $_.StorageProfile.ImageReference.Offer, $_.StorageProfile.ImageReference.Sku, $SqlVersion, $SqlEdition, $RegStatus)) - #write-host $_.ResourceGroupName $_.Name $_.Location $_.HardwareProfile.VmSize $vCores $_.StorageProfile.ImageReference.Offer $_.StorageProfile.ImageReference.Sku $SqlVersion $SqlEdition $RegStatus + } } [system.gc]::Collect() + } +# Record the end time +$endTime = Get-Date +Write-Host ("Script execution ended at: $endTime") -# Write usage data to the .csv file -if ($FilePath){ - (ConvertFrom-Csv ($inventoryTable | %{$_ -join ','})) | Export-Csv $FilePath -NoType #-Append - Write-Host ([Environment]::NewLine + "-- Added the usage data to $FilePath --") -} else { - Write-Host $inventoryTable -} +# Calculate the duration of script execution +$executionDuration = $endTime - $startTime +Write-Host ("Script execution duration: $executionDuration") +Write-Host ([Environment]::NewLine + "-- Script execution completed --") diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md new file mode 100644 index 0000000000..896ea0f6e5 --- /dev/null +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -0,0 +1,121 @@ +--- +services: Azure SQL +platforms: Azure +author: anosov1960 +ms.author: sashan +ms.date: 03/25/2025 +--- + + +# Overview + +This script provides a scaleable solution to set or change the license type on all Azure SQL Servers resources in a specified scope. + +You can specify a single subscription to scan, or provide a list of subscriptions as a .CSV file. +If not specified, all subscriptions your role has access to are scanned. + +# Prerequisites + +- The following minimum RBAC premissions are required to set the licesne type on the individual Azure SQL resources: +1. **Azure SQL Databases**: *SQL DB Contributor role*. +1. **Azure SQL Elastic Pools**: *SQL DB Contributor* +1. **Azure SQL Managed Instances**: *SQL Managed Instance Contributor* +1. **Azure SQL Instance Pools**: *SQL Managed Instance Contributor* +1. **Azure Data Factory SSIS Integration Runtimes**: *Data Factory Contributor role*. +1. **SQL Servers in Azure Virtual Machines**: *Virtual Machine Contributor role*. + +A *Subscriptin Contributor* role has sufficient permissions to mdify any of the above resources. + +# Launching the script + +The script accepts the following command line parameters: + +| **Parameter**                                         | **Value**                                                                       | **Description** | +|:--|:--|:--| +|-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| +|-LicenseType | "LicenseIncluded" or "BasePrice"| Optional: Sets the license type to the specified value. If not specified, "LicenseIncluded" is set | + +1You can create a .csv file using the following command and then edit to remove the subscriptions you don't want to scan. +```PowerShell +Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation +``` + +## Example 1 + +The following command will scan all the subscriptions to which the user has access to, and set the license type to "LicenseIncluded" on all servers where license type is undefined. + +```PowerShell +.\modify-license-type.ps1 -LicenseType LicenseIncluded +``` + +## Example 2 + +The following command will scan the subscription `` and set the license type value to "LicenseIncluded" on all servers. + +```PowerShell +.\modify-license-type.ps1 -SubId -LicenseType LicenseIncluded``` + +## Example 3 + +The following command will scan resource group `` in the subscription ``, set the license type value to "BasePrice". + +```PowerShell +.\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType BasePrice +``` + +# Running the script using Cloud Shell + +This option is recommended because Cloud shell has the Azure PowerShell modules pre-installed and you are automatically authenticated. Use the following steps to run the script in Cloud Shell. + +1. Launch the [Cloud Shell](https://shell.azure.com/). For details, [read more about PowerShell in Cloud Shell](https://aka.ms/pscloudshell/docs). + +1. Connect to Azure AD. You must specify `` if you have access to more than one AAD tenants. + + ```console + Connect-AzureAD -TenantID + ``` + +1. Upload the script to your cloud shell using the following command: + + ```console + curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 -o modify-license-type.ps1 + ``` + +1. Run the script. + +> [!NOTE] +> - To paste the commands into the shell, use `Ctrl-Shift-V` on Windows or `Cmd-v` on MacOS. +> - The script will be uploaded directly to the home folder associated with your Cloud Shell session. + +# Running the script from a PC + +Use the following steps to run the script in a PowerShell session on your PC. + +1. Copy the script to your current folder: + + ```console + curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 -o modify-license-type.ps1 + ``` + +1. Make sure the NuGet package provider is installed: + + ```console + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + Install-packageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force + ``` + +1. Make sure the the Az module is installed. For more information, see [Install the Azure Az PowerShell module](https://learn.microsoft.com/powershell/azure/install-az-ps): + + ```console + Install-Module Az -Scope CurrentUser -Repository PSGallery -Force + ``` + +1. Connect to Azure AD and log in to your Azure account. You must specify `` if you have access to more than one AAD tenants. + + ```console + Connect-AzureAD -TenantID + Connect-AzAccount -TenantID (Get-AzureADTenantDetail).ObjectId + ``` + +1. Run the script. diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 new file mode 100644 index 0000000000..961b90f8e3 --- /dev/null +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -0,0 +1,179 @@ +# +# 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 +# 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 list of resources that have been affected by the change. +# +# The following resources are in scope for the license utilization analysis: +# - Azure SQL databases (vCore-based purchasing model only) +# - Azure SQL elastic pools (vCore-based purchasing model only) +# - Azure SQL managed instances +# - Azure SQL instance pools +# - Azure Data Factory SSIS integration runtimes +# - SQL Servers in Azure virtual machines +# +# The script accepts the following command line parameters: +# +# -SubId [subscription_id] | [csv_file_name] (Accepts a .csv file with the list of subscriptions) +# -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group) +# -LicenseType [license_type_value] (Optional. Sets the license type to the specified value. Ifnot specified, "LicenseIncluded" is set) +# -FilePath [csv_file_name] (Required to save data in a .csv format. Ignored if database parameters are specified) +# + +param ( + [Parameter (Mandatory= $false)] + [string] $SubId, + [Parameter (Mandatory= $false)] + [string] $ResourceGroup, + [Parameter (Mandatory= $false)] + [ValidateSet("LicenseIncluded", "BasePrice", IgnoreCase=$false)] + [string] $LicenseType = "LicenseIncluded" +) + +function CheckModule ($m) { + + # This function ensures that the specified module is imported into the session + # If module is already imported - do nothing + + if (!(Get-Module | Where-Object {$_.Name -eq $m})) { + # If module is not imported, but available on disk then import + if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { + Import-Module $m + } + else { + + # If module is not imported, not available on disk, but is in online gallery then install and import + if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { + Install-Module -Name $m -Force -Verbose -Scope CurrentUser + Import-Module $m + } + else { + + # If module is not imported, not available and not in online gallery then abort + write-host "Module $m not imported, not available and not in online gallery, exiting." + EXIT 1 + } + } + } +} + +# +# Suppress warnings +# +Update-AzConfig -DisplayBreakingChangeWarning $false + +$requiredModules = @( + "Az.Accounts", + "Az.Compute", + "Az.DataFactory", + "Az.Resources", + "Az.Sql", + "Az.SqlVirtualMachine" +) +$requiredModules | Foreach-Object {CheckModule $_} + +# Subscriptions to scan + +if ($SubId -like "*.csv") { + $subscriptions = Import-Csv $SubId +}elseif($SubId -ne $null){ + $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription +}else{ + $subscriptions = Get-AzSubscription +} + +# Record the start time +$startTime = Get-Date +Write-Host ("Script execution started at: $startTime") + +# 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 + } + + # Get all resource groups in the subscription + $rgs = Get-AzResourceGroup + + # Get all logical servers + $servers = Get-AzSqlServer + + # Scan all vCore-based SQL database resources in the subscription + $servers | Get-AzSqlDatabase | Where-Object { $_.SkuName -ne "ElasticPool" -and $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlDatabase -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -DatabaseName $_.DatabaseName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- Database $_.DatabaseName is set to $LicenseType") + } + } + [system.gc]::Collect() + + # Scan all vCore-based SQL elastic pool resources in the subscription + $servers | Get-AzSqlElasticPool | Where-Object { $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlElasticPool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -ElasticPoolName $_.ElasticPoolName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to $LicenseType") + } + } + [system.gc]::Collect() + + # Scan all SQL managed instance resources in the subscription + Get-AzSqlInstance | Where-Object { $_.InstancePoolName -eq $null } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlInstance -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- Instance $_.InstanceName is set to $LicenseType") + } + } + [system.gc]::Collect() + + # Scan all instance pool resources in the subscription + Get-AzSqlInstancePool | Foreach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlInstancePool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- InstancePool $_.InstanceName is set to $LicenseType") + } + } + [system.gc]::Collect() + + # Scan all SSIS integration runtime resources in the subscription + $rgs | Get-AzDataFactoryV2 | Get-AzDataFactoryV2IntegrationRuntime | Where-Object { $_.State -eq "Started" -and $_.NodeSize -ne $null } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + # Set the license type to $LicenseType + Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- DataFactory $_.DataFactoryName is set to $LicenseType") + } + } + [system.gc]::Collect() + + # Scan all SQL VMs in the subscription + $rgs | Get-AzVM | Where-Object { $_.StorageProfile.ImageReference.Offer -like "*sql*" -and $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { + $vmName = $_.Name + $resourceGroupName = $_.ResourceGroupName + + # Get the SQL configuration for the VM + $sqlConfig = Get-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" + + if ($sqlConfig -ne $null) { + $licenseType = $sqlConfig.Settings.LicenseType + + if ($licenseType -ne $LicenseType) { + # Set the license type to $LicenseType + Set-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" -Publisher "Microsoft.SqlServer.Management" -ExtensionType "SqlIaaSAgent" -TypeHandlerVersion "1.5" -Settings @{ "LicenseType" = $LicenseType } + Write-Host ([Environment]::NewLine + "-- SQL VM $vmName is set to $LicenseType") + } + + } + } + [system.gc]::Collect() + +} + +# Record the end time +$endTime = Get-Date +Write-Host ("Script execution ended at: $endTime") + From d815c201482a958e1ee3e3c304697d04990da9f5 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 25 Mar 2025 19:24:25 -0700 Subject: [PATCH 138/159] added resourc group option to Azure SQL modify-license-type --- .../modify-license-type.ps1 | 149 +++++++++--------- 1 file changed, 77 insertions(+), 72 deletions(-) diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 index 961b90f8e3..a983613d43 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -35,19 +35,17 @@ function CheckModule ($m) { # If module is already imported - do nothing if (!(Get-Module | Where-Object {$_.Name -eq $m})) { - # If module is not imported, but available on disk then import + # If module is not imported, but available on disk then import if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { Import-Module $m } else { - # If module is not imported, not available on disk, but is in online gallery then install and import if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { Install-Module -Name $m -Force -Verbose -Scope CurrentUser Import-Module $m } else { - # If module is not imported, not available and not in online gallery then abort write-host "Module $m not imported, not available and not in online gallery, exiting." EXIT 1 @@ -73,12 +71,14 @@ $requiredModules | Foreach-Object {CheckModule $_} # Subscriptions to scan +$tenantID = (Get-AzureADTenantDetail).ObjectId + if ($SubId -like "*.csv") { $subscriptions = Import-Csv $SubId -}elseif($SubId -ne $null){ - $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -}else{ - $subscriptions = Get-AzSubscription +}elseif($SubId -ne "") { + $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -TenantID $tenantID +} else { + $subscriptions = Get-AzSubscription -TenantID $tenantID } # Record the start time @@ -87,93 +87,98 @@ Write-Host ("Script execution started at: $startTime") # Calculate usage for each subscription -foreach ($sub in $subscriptions){ +foreach ($sub in $subscriptions) { - if ($sub.State -ne "Enabled") {continue} + if ($sub.State -ne "Enabled") { continue } try { Set-AzContext -SubscriptionId $sub.Id - }catch { + } catch { write-host "Invalid subscription: " $sub.Id continue } - # Get all resource groups in the subscription - $rgs = Get-AzResourceGroup + # Get the resource groups + if ($ResourceGroup) { + $rgs = Get-AzResourceGroup -Name $ResourceGroup + } else { + $rgs = Get-AzResourceGroup + } - # Get all logical servers - $servers = Get-AzSqlServer + foreach ($rg in $rgs) { + # Get all logical servers + $servers = Get-AzSqlServer -ResourceGroupName $rg.ResourceGroupName - # Scan all vCore-based SQL database resources in the subscription - $servers | Get-AzSqlDatabase | Where-Object { $_.SkuName -ne "ElasticPool" -and $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlDatabase -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -DatabaseName $_.DatabaseName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- Database $_.DatabaseName is set to $LicenseType") + # Scan all vCore-based SQL database resources in the subscription + $servers | Get-AzSqlDatabase | Where-Object { $_.SkuName -ne "ElasticPool" -and $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlDatabase -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -DatabaseName $_.DatabaseName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- Database $_.DatabaseName is set to $LicenseType") + } } - } - [system.gc]::Collect() + [system.gc]::Collect() - # Scan all vCore-based SQL elastic pool resources in the subscription - $servers | Get-AzSqlElasticPool | Where-Object { $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlElasticPool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -ElasticPoolName $_.ElasticPoolName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to $LicenseType") + # Scan all vCore-based SQL elastic pool resources in the subscription + $servers | Get-AzSqlElasticPool | Where-Object { $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlElasticPool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -ElasticPoolName $_.ElasticPoolName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to $LicenseType") + } + } + [system.gc]::Collect() + + # Scan all SQL managed instance resources in the subscription + Get-AzSqlInstance | Where-Object { $_.InstancePoolName -eq $null } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlInstance -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- Instance $_.InstanceName is set to $LicenseType") + } } - } - [system.gc]::Collect() - - # Scan all SQL managed instance resources in the subscription - Get-AzSqlInstance | Where-Object { $_.InstancePoolName -eq $null } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlInstance -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- Instance $_.InstanceName is set to $LicenseType") - } - } - [system.gc]::Collect() + [system.gc]::Collect() - # Scan all instance pool resources in the subscription - Get-AzSqlInstancePool | Foreach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlInstancePool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- InstancePool $_.InstanceName is set to $LicenseType") + # Scan all instance pool resources in the subscription + Get-AzSqlInstancePool | Foreach-Object { + if ($_.LicenseType -ne $LicenseType) { + Set-AzSqlInstancePool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- InstancePool $_.InstanceName is set to $LicenseType") + } } - } - [system.gc]::Collect() - - # Scan all SSIS integration runtime resources in the subscription - $rgs | Get-AzDataFactoryV2 | Get-AzDataFactoryV2IntegrationRuntime | Where-Object { $_.State -eq "Started" -and $_.NodeSize -ne $null } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - # Set the license type to $LicenseType - Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- DataFactory $_.DataFactoryName is set to $LicenseType") + [system.gc]::Collect() + + # Scan all SSIS integration runtime resources in the subscription + Get-AzDataFactoryV2IntegrationRuntime | Where-Object { $_.State -eq "Started" -and $_.NodeSize -ne $null } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + # Set the license type to $LicenseType + Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType $LicenseType + Write-Host ([Environment]::NewLine + "-- DataFactory $_.DataFactoryName is set to $LicenseType") + } } - } - [system.gc]::Collect() - - # Scan all SQL VMs in the subscription - $rgs | Get-AzVM | Where-Object { $_.StorageProfile.ImageReference.Offer -like "*sql*" -and $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { - $vmName = $_.Name - $resourceGroupName = $_.ResourceGroupName - - # Get the SQL configuration for the VM - $sqlConfig = Get-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" + [system.gc]::Collect() + + # Scan all SQL VMs in the subscription + Get-AzVM | Where-Object { $_.StorageProfile.ImageReference.Offer -like "*sql*" -and $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { + $vmName = $_.Name + $resourceGroupName = $_.ResourceGroupName + + # Get the SQL configuration for the VM + $sqlConfig = Get-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" + + if ($sqlConfig -ne $null) { + $licenseType = $sqlConfig.Settings.LicenseType + + if ($licenseType -ne $LicenseType) { + # Set the license type to $LicenseType + Set-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" -Publisher "Microsoft.SqlServer.Management" -ExtensionType "SqlIaaSAgent" -TypeHandlerVersion "1.5" -Settings @{ "LicenseType" = $LicenseType } + Write-Host ([Environment]::NewLine + "-- SQL VM $vmName is set to $LicenseType") + } - if ($sqlConfig -ne $null) { - $licenseType = $sqlConfig.Settings.LicenseType - - if ($licenseType -ne $LicenseType) { - # Set the license type to $LicenseType - Set-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" -Publisher "Microsoft.SqlServer.Management" -ExtensionType "SqlIaaSAgent" -TypeHandlerVersion "1.5" -Settings @{ "LicenseType" = $LicenseType } - Write-Host ([Environment]::NewLine + "-- SQL VM $vmName is set to $LicenseType") } - } - } - [system.gc]::Collect() + [system.gc]::Collect() + } } # Record the end time $endTime = Get-Date Write-Host ("Script execution ended at: $endTime") - From af8a3a01b988ccda74753bdf0f450defabb92ade Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 25 Mar 2025 19:35:12 -0700 Subject: [PATCH 139/159] Minor edit --- .../manage/azure-hybrid-benefit/modify-license-type/README.md | 3 +-- .../modify-license-type/modify-license-type.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) 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 896ea0f6e5..5c14b71a4b 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -11,8 +11,7 @@ ms.date: 03/25/2025 This script provides a scaleable solution to set or change the license type on all Azure SQL Servers resources in a specified scope. -You can specify a single subscription to scan, or provide a list of subscriptions as a .CSV file. -If not specified, all subscriptions your role has access to are scanned. +By default, the script scans all subscriptions the user account has access or a .CSV file with a list of subscriptions. Alternatively, you can specify a single subscription or and a specific resource group. The sript enumerates the specific resources that have been affected by the change. # Prerequisites diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 index a983613d43..dcd0829dbb 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -1,7 +1,7 @@ # # 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 -# 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 list of resources that have been affected by the change. +# all subscriptions the user account has access or a .CSV file with a list of subscriptions. Alternatively, you can specify a single subscription or and a specific resource group. The sripts enumerates te specific +# resources that have been affected by the change. # # The following resources are in scope for the license utilization analysis: # - Azure SQL databases (vCore-based purchasing model only) From 570aa22f63042fe6262389a3c6d08eaabb07b01c Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 25 Mar 2025 19:36:11 -0700 Subject: [PATCH 140/159] spelling --- .../modify-license-type/modify-license-type.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 index dcd0829dbb..e4cc935a16 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -1,6 +1,6 @@ # # 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 -# all subscriptions the user account has access or a .CSV file with a list of subscriptions. Alternatively, you can specify a single subscription or and a specific resource group. The sripts enumerates te specific +# all subscriptions the user account has access or a .CSV file with a list of subscriptions. Alternatively, you can specify a single subscription or and a specific resource group. The sripts enumerates the specific # resources that have been affected by the change. # # The following resources are in scope for the license utilization analysis: From af9a402f3a483f0744ffeee8b1ab7a3c09300c59 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 1 Apr 2025 17:45:26 -0700 Subject: [PATCH 141/159] Added the consent tag for the CSP subs --- .../modify-license-type.ps1 | 96 ++++++------------- 1 file changed, 30 insertions(+), 66 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 62873d8fd4..9b4aa6fafe 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -52,82 +52,52 @@ function ConvertTo-Hashtable { $InputObject ) process { - ## Return null if the input is null. This can happen when calling the function - ## recursively and a property is null if ($null -eq $InputObject) { return $null } - ## Check if the input is an array or collection. If so, we also need to convert - ## those types into hash tables as well. This function will convert all child - ## objects into hash tables (if applicable) - if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { - $collection = @( - foreach ($object in $InputObject) { - ConvertTo-Hashtable -InputObject $object - } - ) - ## Return the array but don't enumerate it because the object may be pretty complex - Write-Output -NoEnumerate $collection - } elseif ($InputObject -is [psobject]) { - ## If the object has properties that need enumeration, cxonvert it to its own hash table and return it + if ($InputObject -is [System.Collections.ICollection]) { $hash = @{} - foreach ($property in $InputObject.PSObject.Properties) { + foreach ($property in $InputObject) { $hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value } $hash } else { - ## If the object isn't an array, collection, or other object, it's already a hash table - ## So just return it. $InputObject } } } -# This function checks if the specified module is imported into the session and if not installes and/or imports it -function LoadModule -{ +function LoadModule { param ( [parameter(Mandatory = $true)][string] $name ) $retVal = $true - if (!(Get-Module -Name $name)) - { + if (!(Get-Module -Name $name)) { $retVal = Get-Module -ListAvailable | Where-Object {$_.Name -eq $name} - if ($retVal) - { - try - { + if ($retVal) { + try { Import-Module $name -ErrorAction SilentlyContinue } - catch - { - write-host "The request to lload module $($name) failed with the following error:" + catch { + write-host "The request to load 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 + } else { if (Find-Module -Name $name) { Install-Module -Name $name -Force -Verbose -Scope CurrentUser - try - { - Import-Module $name -ErrorAction SilentlyContinue + try { + Import-Module $name -ErrorAction SilentlyContinue } - catch - { + catch { write-host "The request to load 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 + } else { write-host "Module $($name) not imported, not available and not in online gallery, exiting." EXIT 1 } @@ -137,12 +107,8 @@ function LoadModule return $retVal } -# -# Suppress warnings -# Update-AzConfig -DisplayBreakingChangeWarning $false -# Load required modules $requiredModules = @( "AzureAD", "Az.Accounts", @@ -151,25 +117,19 @@ $requiredModules = @( ) $requiredModules | Foreach-Object {LoadModule $_} -# Subscriptions to scan - $tenantID = (Get-AzureADTenantDetail).ObjectId if ($SubId -like "*.csv") { $subscriptions = Import-Csv $SubId -}elseif($SubId -ne ""){ +}elseif($SubId -ne "") { $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -TenantID $tenantID -}else{ +}else { $subscriptions = Get-AzSubscription -TenantID $tenantID } - Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --") -# Scan arc-enabled servers in each subscription - -foreach ($sub in $subscriptions){ - +foreach ($sub in $subscriptions) { if ($sub.State -ne "Enabled") {continue} try { @@ -179,6 +139,18 @@ foreach ($sub in $subscriptions){ {continue} } + if ($LicenseType -eq "PAYG") { + $offers = @("MS-AZR-0145P", "MS-AZR-DE-0145P", "MS-AZR-0017G", "MS-AZR-159P", "MS-AZR-USGOV-0145P") + $subscriptionOffers = Get-AzSubscription -SubscriptionId $sub.Id | Select-Object -ExpandProperty OfferId + if ($subscriptionOffers -contains $offers) { + $tags = Get-AzTag -ResourceId "/subscriptions/$($sub.Id)" + if ($tags.Tags["SQLPerpetualPaygBilling"] -ne "Enabled") { + write-host "Error: Subscription $($sub.Id) does not have the consent tag 'SQLPerpetualPaygBilling' enabled." + continue + } + } + } + $query = " resources | where type =~ 'microsoft.hybridcompute/machines/extensions' @@ -203,7 +175,6 @@ foreach ($sub in $subscriptions){ $resources = Search-AzGraph -Query "$($query)" foreach ($r in $resources) { - $setID = @{ MachineName = $r.MachineName Name = $r.extensionName @@ -218,7 +189,6 @@ foreach ($sub in $subscriptions){ $settings = @{} $settings = $r.properties.settings | ConvertTo-Json | ConvertFrom-Json | ConvertTo-Hashtable - # set the license type or update (if -Force). ESU must be disabled to set to LicenseOnly. $LO_Allowed = (!$settings["enableExtendedSecurityUpdates"] -and !$EnableESU) -or ($EnableESU -eq "No") if ($LicenseType) { @@ -235,10 +205,8 @@ foreach ($sub in $subscriptions){ $WriteSettings = $true } } - } - # Enable ESU for qualified license types or disable if ($EnableESU) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($EnableESU -eq "No")) { $settings["enableExtendedSecurityUpdates"] = ($EnableESU -eq "Yes") @@ -249,7 +217,6 @@ foreach ($sub in $subscriptions){ } } - # Enable UsePcoreLicense for qualified license types or disable if ($UsePcoreLicense) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($UsePcoreLicense -eq "No")) { $settings["UsePhysicalCoreLicense"] = @{ @@ -262,17 +229,14 @@ foreach ($sub in $subscriptions){ } } If ($WriteSettings) { - try { - Set-AzConnectedMachineExtension @setId -Settings $settings -NoWait | Out-Null + Set-AzConnectedMachineExtension @setID -Settings $settings -NoWait | Out-Null Write-Host "Updated -- Resource group: [$($r.resourceGroup)], Connected machine: [$($r.MachineName)]" } catch { - write-host "The request to modify the extenion object failed with the following error:" + write-host "The request to modify the extension object failed with the following error:" write-host $_.Exception.Message {continue} } } } } - - From 87d68d8cae4814f375c41e3d8843de069584890a Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 1 Apr 2025 17:49:51 -0700 Subject: [PATCH 142/159] Added forced PAYG at scale example --- .../modify-license-type/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 3429fa14a2..fa16837a01 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 @@ -50,10 +50,10 @@ The following command will scan all the subscriptions to which the user has acce ## Example 2 -The following command will scan the subscription `` and set the license type value to "Paid" on all servers. +The following command will scan all all the subscriptions to which the user has access to, and set the license type to "PAYG" on all servers . ```PowerShell -.\modify-license-type.ps1 -SubId -LicenseType Paid -Force +.\modify-license-type.ps1 -SubId -LicenseType PAYG -Force ``` ## Example 3 From 4aaa18f7f94ea5c586856832197d3dd6d33af9a0 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 1 Apr 2025 18:22:45 -0700 Subject: [PATCH 143/159] Added a note re CSP subs. --- .../azure-arc-enabled-sql-server/modify-license-type/README.md | 2 ++ 1 file changed, 2 insertions(+) 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 fa16837a01..5bba2e4a1c 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 @@ -39,6 +39,8 @@ The script accepts the following command line parameters: ```PowerShell Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation ``` +> [!IMPORTANT] +> If you are setting License type to PAYG in the CSP subscription(s), the subscription resource must have a consent tag enabling perperual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be adding using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). ## Example 1 From 3a4d3dd467272ad1a6b2bd3628bd55e4c80402c2 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 1 Apr 2025 18:24:32 -0700 Subject: [PATCH 144/159] Typo --- .../azure-arc-enabled-sql-server/modify-license-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5bba2e4a1c..2fb462a40a 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 @@ -40,7 +40,7 @@ The script accepts the following command line parameters: Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation ``` > [!IMPORTANT] -> If you are setting License type to PAYG in the CSP subscription(s), the subscription resource must have a consent tag enabling perperual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be adding using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). +> If you are setting License type to "PAYG" in the CSP subscription(s), the subscription resource must have a consent tag enabling perpetual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be adding using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). ## Example 1 From 73b8f554a8a9c0eeb986d53a9f68ccfeb447ef94 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 1 Apr 2025 18:25:39 -0700 Subject: [PATCH 145/159] Typo --- .../azure-arc-enabled-sql-server/modify-license-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2fb462a40a..c9e2358ba0 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 @@ -40,7 +40,7 @@ The script accepts the following command line parameters: Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation ``` > [!IMPORTANT] -> If you are setting License type to "PAYG" in the CSP subscription(s), the subscription resource must have a consent tag enabling perpetual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be adding using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). +> If you are setting License type to "PAYG" in the CSP subscription(s), the subscription resource must have a consent tag enabling perpetual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be added using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). ## Example 1 From 8019289085f015b733897e9b3692e7f54cef6bae Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 2 Apr 2025 11:57:43 -0700 Subject: [PATCH 146/159] Added the reader role to prereqs --- .../azure-arc-enabled-sql-server/modify-license-type/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 c9e2358ba0..186ec9b5c3 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 @@ -16,11 +16,10 @@ If not specified, all subscriptions your role has access to are scanned. # Prerequisites -- You must have at least a *Azure Connected Machine Resource Administrator* role in each subscription you modify. +- You must have least *Azure Connected Machine Resource Administrator* role and subscription *Reader* role. - The Azure extension for SQL Server is updated to version 1.1.2230.58 or newer. - You must be connected to Azure AD and logged in to your Azure account. If your account have access to multiple tenants, make sure to log in with a specific tenant ID. - # Launching the script The script accepts the following command line parameters: From 989c8fee7256378762ebad9a522073a94c5720f2 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 2 Apr 2025 11:58:06 -0700 Subject: [PATCH 147/159] Typo --- .../azure-arc-enabled-sql-server/modify-license-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 186ec9b5c3..66258777f7 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 @@ -16,7 +16,7 @@ If not specified, all subscriptions your role has access to are scanned. # Prerequisites -- You must have least *Azure Connected Machine Resource Administrator* role and subscription *Reader* role. +- You must have at least *Azure Connected Machine Resource Administrator* role and subscription *Reader* role. - The Azure extension for SQL Server is updated to version 1.1.2230.58 or newer. - You must be connected to Azure AD and logged in to your Azure account. If your account have access to multiple tenants, make sure to log in with a specific tenant ID. From b21d644916f9e3c6a6789c987800d84d2a77f0e0 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 2 Apr 2025 12:08:25 -0700 Subject: [PATCH 148/159] Cleaned up the consent tag logic --- .../modify-license-type/modify-license-type.ps1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 9b4aa6fafe..081caa01d6 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -143,9 +143,13 @@ foreach ($sub in $subscriptions) { $offers = @("MS-AZR-0145P", "MS-AZR-DE-0145P", "MS-AZR-0017G", "MS-AZR-159P", "MS-AZR-USGOV-0145P") $subscriptionOffers = Get-AzSubscription -SubscriptionId $sub.Id | Select-Object -ExpandProperty OfferId if ($subscriptionOffers -contains $offers) { - $tags = Get-AzTag -ResourceId "/subscriptions/$($sub.Id)" - if ($tags.Tags["SQLPerpetualPaygBilling"] -ne "Enabled") { - write-host "Error: Subscription $($sub.Id) does not have the consent tag 'SQLPerpetualPaygBilling' enabled." + if ($tags.Tags.ContainsKey("SQLPerpetualPaygBilling")) { + if ($tags.Tags["SQLPerpetualPaygBilling"] -ne "Enabled") { + write-host "Error: Subscription $($sub.Id) has an incorrect value $($tags.Tags["SQLPerpetualPaygBilling"]) of the consent tag 'SQLPerpetualPaygBilling' ." + continue + } + } else { + write-host "Error: Subscription $($sub.Id) does not have the consent tag 'SQLPerpetualPaygBilling'." continue } } From 864df369d450698c273b82d0b64585cb54d7d1cb Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 2 Apr 2025 12:09:44 -0700 Subject: [PATCH 149/159] Added a comment --- .../modify-license-type/modify-license-type.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 081caa01d6..a14c96111b 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -139,6 +139,7 @@ foreach ($sub in $subscriptions) { {continue} } + # Consent tag enforcement on the CSP subscriptions if ($LicenseType -eq "PAYG") { $offers = @("MS-AZR-0145P", "MS-AZR-DE-0145P", "MS-AZR-0017G", "MS-AZR-159P", "MS-AZR-USGOV-0145P") $subscriptionOffers = Get-AzSubscription -SubscriptionId $sub.Id | Select-Object -ExpandProperty OfferId From a00fde401066d17f64a47b6ac7c7e30520e479eb Mon Sep 17 00:00:00 2001 From: Rodrigo Monteiro Date: Tue, 8 Apr 2025 13:56:28 -0400 Subject: [PATCH 150/159] Updates the license type for Azure SQL resources (SQL DBs, Elastic Pools, Managed Instances, Instance Pools, SQL VMs) to a specified model ("LicenseIncluded" or "BasePrice"). Optionally starts resources if needed. --- .../modify-license-type/README.md | 164 +++--- .../modify-license-type.ps1 | 525 +++++++++++++----- 2 files changed, 455 insertions(+), 234 deletions(-) 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 5c14b71a4b..c3990ead1a 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -1,21 +1,33 @@ --- services: Azure SQL platforms: Azure -author: anosov1960 -ms.author: sashan -ms.date: 03/25/2025 +author: anosov1960,rodrigomonteiro-gbb +ms.author: sashan.romontei +ms.date: 04/08/2025 --- - # Overview -This script provides a scaleable solution to set or change the license type on all Azure SQL Servers resources in a specified scope. +This Azure Runbook updates the license type for various Azure SQL resources using Azure CLI and PowerShell commands. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -Force_Start_On_Resources parameter is enabled). + +This script is designed to help administrators standardize SQL licensing across their Azure environment by automating license updates. In summary, the script: -By default, the script scans all subscriptions the user account has access or a .CSV file with a list of subscriptions. Alternatively, you can specify a single subscription or and a specific resource group. The sript enumerates the specific resources that have been affected by the change. +Targets Multiple Resource Types: +SQL Virtual Machines: Updates license types after checking if the VM is running. If not, it can optionally start the VM to perform the update. +SQL Managed Instances: Detects instances that are stopped or not in the "Ready" state and can force them to start before updating. +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. +Flexible Subscription Targeting: +The script accepts a subscription ID or CSV file (for a list of subscriptions). If no subscription is specified, it defaults to updating resources in all accessible subscriptions. +Interactive Reporting: +The script logs steps along the process and compiles a final report summarizing which resources were updated in each category. +Seamless Integration with Azure Authentication: +It uses managed identity authentication (via Connect-AzAccount -Identity and az login --identity) to connect to your Azure environment securely. -# Prerequisites +# 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: -- The following minimum RBAC premissions are required to set the licesne type on the individual Azure SQL resources: 1. **Azure SQL Databases**: *SQL DB Contributor role*. 1. **Azure SQL Elastic Pools**: *SQL DB Contributor* 1. **Azure SQL Managed Instances**: *SQL Managed Instance Contributor* @@ -23,98 +35,64 @@ By default, the script scans all subscriptions the user account has access or a 1. **Azure Data Factory SSIS Integration Runtimes**: *Data Factory Contributor role*. 1. **SQL Servers in Azure Virtual Machines**: *Virtual Machine Contributor role*. -A *Subscriptin Contributor* role has sufficient permissions to mdify any of the above resources. - -# Launching the script - -The script accepts the following command line parameters: - -| **Parameter**                                         | **Value**                                                                       | **Description** | -|:--|:--|:--| -|-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| -|-LicenseType | "LicenseIncluded" or "BasePrice"| Optional: Sets the license type to the specified value. If not specified, "LicenseIncluded" is set | - -1You can create a .csv file using the following command and then edit to remove the subscriptions you don't want to scan. -```PowerShell -Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation -``` +A *Subscription Contributor* role has sufficient permissions to mdify any of the above resources. -## Example 1 +# Additional Information -The following command will scan all the subscriptions to which the user has access to, and set the license type to "LicenseIncluded" on all servers where license type is undefined. +Script Parameters: +- SubId: A single subscription ID or the filename of a CSV file containing multiple subscriptions. +- ResourceGroup: (Optional) Limits the script’s operations to a specific resource group. +- LicenseType: (Optional) Defines the target license type. Valid values are "LicenseIncluded" (default) or "BasePrice". +- Force_Start_On_Resources: (Optional) When enabled, the script will attempt to start SQL VMs and SQL Managed Instances if they are not running before applying the update. +Logging & Error Handling: -```PowerShell -.\modify-license-type.ps1 -LicenseType LicenseIncluded -``` +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. -## Example 2 +# Customizations: +You might want to customize the script’s logging or incorporate additional logging (e.g., writing to a file or Azure Log Analytics) to integrate seamlessly with your monitoring and reporting workflow. -The following command will scan the subscription `` and set the license type value to "LicenseIncluded" on all servers. +# Creating an Azure Runbook -```PowerShell -.\modify-license-type.ps1 -SubId -LicenseType LicenseIncluded``` +You can schedule the command to run as a runbook. Follow these steps using the Azure Portal: -## Example 3 +### 1. Download the Script -The following command will scan resource group `` in the subscription ``, set the license type value to "BasePrice". +Open a command shell on your device and run the command below. This will copy the script to your local folder. -```PowerShell -.\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType BasePrice +```console +curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 ``` - -# Running the script using Cloud Shell - -This option is recommended because Cloud shell has the Azure PowerShell modules pre-installed and you are automatically authenticated. Use the following steps to run the script in Cloud Shell. - -1. Launch the [Cloud Shell](https://shell.azure.com/). For details, [read more about PowerShell in Cloud Shell](https://aka.ms/pscloudshell/docs). - -1. Connect to Azure AD. You must specify `` if you have access to more than one AAD tenants. - - ```console - Connect-AzureAD -TenantID - ``` - -1. Upload the script to your cloud shell using the following command: - - ```console - curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 -o modify-license-type.ps1 - ``` - -1. Run the script. - -> [!NOTE] -> - To paste the commands into the shell, use `Ctrl-Shift-V` on Windows or `Cmd-v` on MacOS. -> - The script will be uploaded directly to the home folder associated with your Cloud Shell session. - -# Running the script from a PC - -Use the following steps to run the script in a PowerShell session on your PC. - -1. Copy the script to your current folder: - - ```console - curl https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 -o modify-license-type.ps1 - ``` - -1. Make sure the NuGet package provider is installed: - - ```console - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - Install-packageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force - ``` - -1. Make sure the the Az module is installed. For more information, see [Install the Azure Az PowerShell module](https://learn.microsoft.com/powershell/azure/install-az-ps): - - ```console - Install-Module Az -Scope CurrentUser -Repository PSGallery -Force - ``` - -1. Connect to Azure AD and log in to your Azure account. You must specify `` if you have access to more than one AAD tenants. - - ```console - Connect-AzureAD -TenantID - Connect-AzAccount -TenantID (Get-AzureADTenantDetail).ObjectId - ``` - -1. Run the script. +### 2. Create or Use an Existing Automation Account +[Create a new automation account](https://ms.portal.azure.com/#create/Microsoft.AutomationAccount) or open an existing one. +In the Advanced section, ensure that System assigned identity is selected. +### 3. Import the Runbook +Navigate to the Process Automation group and select Runbooks. +Click on the Import a runbook tab and configure it: +File: Select the file you downloaded in Step 1. +Name: Enter a name for the runbook. +Type: Set to PowerShell. +Runtime Version: Choose 7.2. +Click Import. +### 4. Publish the Runbook +After the runbook is imported, click the Publish button to make it available for scheduling. + +### 5. Link the Runbook to a Schedule +Once the runbook status is Published, click on the Link to schedule button. +Select Link a schedule to your runbook and click + Add a schedule. +Configure the schedule: +Name: Provide a name for the schedule. +Start Time: Set the desired start time. +Recurrence: Choose the recurrence need it. +Click Create. +### 6. Configure Runbook Parameters +Return to the Schedule runbook page. +Click on Parameters and run settings. +Paste the license ID value into the appropriate field. +Click OK to link the schedule, then OK again to create the job. +### 7. Verify the Runbook Execution +On the runbook Overview page, open a recent job that was completed after the scheduled start time. +Click on the Output tab and verify that you see: +Properties.activationState=Activated +Your license is now active. + +For more information about the runbooks, see the [Runbook tutorial](https://docs.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual-powershell) \ No newline at end of file diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 index e4cc935a16..6999669c5e 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -1,184 +1,427 @@ -# -# 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 -# all subscriptions the user account has access or a .CSV file with a list of subscriptions. Alternatively, you can specify a single subscription or and a specific resource group. The sripts enumerates the specific -# resources that have been affected by the change. -# -# The following resources are in scope for the license utilization analysis: -# - Azure SQL databases (vCore-based purchasing model only) -# - Azure SQL elastic pools (vCore-based purchasing model only) -# - Azure SQL managed instances -# - Azure SQL instance pools -# - Azure Data Factory SSIS integration runtimes -# - SQL Servers in Azure virtual machines -# -# The script accepts the following command line parameters: -# -# -SubId [subscription_id] | [csv_file_name] (Accepts a .csv file with the list of subscriptions) -# -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group) -# -LicenseType [license_type_value] (Optional. Sets the license type to the specified value. Ifnot specified, "LicenseIncluded" is set) -# -FilePath [csv_file_name] (Required to save data in a .csv format. Ignored if database parameters are specified) -# +<# +.SYNOPSIS + Updates the license type for Azure SQL resources (SQL DBs, Elastic Pools, Managed Instances, Instance Pools, SQL VMs) + to a specified model ("LicenseIncluded" or "BasePrice"). Optionally starts resources if needed. + +.DESCRIPTION + In a quest to bring harmony to the Azure realms, our script journeys across subscriptions, + updating the license types of various SQL resources. It supports processing a single subscription, + a CSV list of subscriptions, or all accessible subscriptions. For SQL VMs and SQL Managed Instances, + it can even start the resource if it's stopped (when -Force_Start_On_Resources is enabled). + +.PARAMETER SubId + A single subscription ID or a CSV file name containing a list of subscriptions. + +.PARAMETER ResourceGroup + Optional. Limit the scope to a specific resource group. + +.PARAMETER LicenseType + Optional. License type to set. Allowed values: "LicenseIncluded" (default) or "BasePrice". + +.PARAMETER Force_Start_On_Resources + Optional. If true, starts SQL VMs and SQL Managed Instances before updating their license type. +#> param ( - [Parameter (Mandatory= $false)] + [Parameter(Mandatory = $false)] [string] $SubId, - [Parameter (Mandatory= $false)] + + [Parameter(Mandatory = $false)] [string] $ResourceGroup, - [Parameter (Mandatory= $false)] - [ValidateSet("LicenseIncluded", "BasePrice", IgnoreCase=$false)] - [string] $LicenseType = "LicenseIncluded" + + [Parameter(Mandatory = $false)] + [ValidateSet("LicenseIncluded", "BasePrice", IgnoreCase = $false)] + [string] $LicenseType = "LicenseIncluded", + + [Parameter(Mandatory = $false)] + [bool] $Force_Start_On_Resources = $false ) -function CheckModule ($m) { +# Suppress unnecessary logging output +$VerbosePreference = "SilentlyContinue" +$DebugPreference = "SilentlyContinue" +$ProgressPreference = "SilentlyContinue" +$InformationPreference = "SilentlyContinue" +$WarningPreference = "SilentlyContinue" +function Connect-Azure { + <# + .SYNOPSIS + Connects to Azure using either Managed Identity or interactive user login. + + .DESCRIPTION + This function first attempts to authenticate to Azure using a Managed Identity by calling + Connect-AzAccount with the -Identity switch. If the Managed Identity login is successful, + it then connects the Azure CLI using the --identity option. If any of the Managed Identity + login attempts fail, the function falls back to interactive (user) login for both Azure + PowerShell and the Azure CLI. - # This function ensures that the specified module is imported into the session - # If module is already imported - do nothing + .EXAMPLE + PS C:\> Connect-Azure + Attempts to connect using Managed Identity; if not available, it will prompt for interactive login. + #> - if (!(Get-Module | Where-Object {$_.Name -eq $m})) { - # If module is not imported, but available on disk then import - if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { - Import-Module $m + # Variable to track if Managed Identity authentication was successful. + $ManagedIdentityLoginSuccessful = $false + + Write-Output "Attempting to connect using Managed Identity for Azure PowerShell..." + try { + Connect-AzAccount -Identity -ErrorAction Stop | Out-Null + Write-Output "Azure PowerShell connected using Managed Identity." + $ManagedIdentityLoginSuccessful = $true + } + catch { + Write-Output "Managed Identity login failed for Azure PowerShell. Falling back to interactive login..." + try { + Connect-AzAccount -ErrorAction Stop | Out-Null + Write-Output "Azure PowerShell connected using interactive login." } - else { - # If module is not imported, not available on disk, but is in online gallery then install and import - if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { - Install-Module -Name $m -Force -Verbose -Scope CurrentUser - Import-Module $m + catch { + Write-Error "Failed to connect to Azure PowerShell: $_" + return + } + } + + # Attempt Azure CLI connection. + if ($ManagedIdentityLoginSuccessful) { + Write-Output "Attempting to connect Azure CLI using Managed Identity..." + try { + az login --identity --output none + Write-Output "Azure CLI connected using Managed Identity." + } + catch { + Write-Output "Managed Identity login failed for Azure CLI. Falling back to interactive login..." + try { + az login --output none + Write-Output "Azure CLI connected using interactive login." } - else { - # If module is not imported, not available and not in online gallery then abort - write-host "Module $m not imported, not available and not in online gallery, exiting." - EXIT 1 + catch { + Write-Error "Failed to connect to Azure CLI interactively: $_" } } } + else { + Write-Output "Attempting to connect Azure CLI using interactive login..." + try { + az login --output none + Write-Output "Azure CLI connected using interactive login." + } + catch { + Write-Error "Failed to connect to Azure CLI interactively: $_" + } + } } -# -# Suppress warnings -# -Update-AzConfig -DisplayBreakingChangeWarning $false - -$requiredModules = @( - "Az.Accounts", - "Az.Compute", - "Az.DataFactory", - "Az.Resources", - "Az.Sql", - "Az.SqlVirtualMachine" -) -$requiredModules | Foreach-Object {CheckModule $_} +# Initialize final status and report counters. +$finalStatus = @() +$report = @{ + "SQLVMUpdated" = @() + "SQLMIUpdated" = @() + "SQLDBUpdated" = @() + "ElasticPoolUpdated" = @() + "InstancePoolUpdated" = @() + "ADFSSISUpdated" = @() +} -# Subscriptions to scan +# Ensure connection with both PowerShell and CLI. +Connect-Azure +$context = Get-AzContext -ErrorAction SilentlyContinue +Write-Output "Connected to Azure as: $($context.Account)" -$tenantID = (Get-AzureADTenantDetail).ObjectId +# Map License Types for SQL VMs: LicenseIncluded -> PAYG, BasePrice -> AHUB. +$SqlVmLicenseType = if ($LicenseType -eq "LicenseIncluded") { "PAYG" } else { "AHUB" } -if ($SubId -like "*.csv") { - $subscriptions = Import-Csv $SubId -}elseif($SubId -ne "") { - $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -TenantID $tenantID -} else { - $subscriptions = Get-AzSubscription -TenantID $tenantID +# Determine the subscriptions to process: CSV file, single subscription, or all accessible subscriptions. +try { + if ($SubId -and $SubId -like "*.csv") { + Write-Output "Gathering subscriptions from CSV file: $SubId" + $subscriptions = Import-Csv -Path $SubId + } + elseif ($SubId) { + Write-Output "Gathering subscription details for: $SubId" + $subscriptions = @(az account show --subscription $SubId --output json | ConvertFrom-Json) + } + else { + Write-Output "Gathering all accessible subscriptions..." + $subscriptions = az account list --output json | ConvertFrom-Json + } +} +catch { + Write-Error "Error determining subscriptions: $_" + exit 1 } -# Record the start time -$startTime = Get-Date -Write-Host ("Script execution started at: $startTime") - -# Calculate usage for each subscription +# Build resource group filter if specified. +$rgFilter = if ($ResourceGroup) { "resourceGroup=='$ResourceGroup'" } else { "" } +$scriptStartTime = Get-Date +Write-Output "Our adventure begins at: $scriptStartTime`n" +# Process each subscription. foreach ($sub in $subscriptions) { + try { + Write-Output "===== Entering the realm of Subscription: $($sub.name) =====" + Write-Output "Switching context to subscription: $($sub.name)" + az account set --subscription $sub.id - if ($sub.State -ne "Enabled") { continue } + # --- Section: Update SQL Virtual Machines --- + try { + Write-Output "Seeking SQL Virtual Machines that require a license update..." + $sqlVmQuery = if ($rgFilter) { + "[?sqlServerLicenseType!='${SqlVmLicenseType}' && $rgFilter]" + } + else { + "[?sqlServerLicenseType!='${SqlVmLicenseType}']" + } + $sqlVMs = az sql vm list --query $sqlVmQuery -o json | ConvertFrom-Json + $sqlVmsToUpdate = [System.Collections.ArrayList]::new() - try { - Set-AzContext -SubscriptionId $sub.Id - } catch { - write-host "Invalid subscription: " $sub.Id - continue - } + foreach ($sqlvm in $sqlVMs) { + $vmStatus = az vm get-instance-view --resource-group $sqlvm.resourceGroup --name $sqlvm.name --query "{Name:name, ResourceGroup:resourceGroup, PowerState:instanceView.statuses[?starts_with(code, 'PowerState/')].displayStatus | [0]}" -o json | ConvertFrom-Json + if ($vmStatus.PowerState -eq "VM running") { + Write-Output "Updating SQL VM '$($sqlvm.name)' in RG '$($sqlvm.resourceGroup)' to license type '$SqlVmLicenseType'..." + $result = az sql vm update -n $sqlvm.name -g $sqlvm.resourceGroup --license-type $SqlVmLicenseType -o json | ConvertFrom-Json + $finalStatus += $result + $report["SQLVMUpdated"] += $sqlvm.name + } + else { + if ($Force_Start_On_Resources) { + Write-Output "SQL VM '$($sqlvm.name)' is not running. Forcing start to update license..." + az vm start --resource-group $sqlvm.resourceGroup --name $sqlvm.name --no-wait yes + $sqlVmsToUpdate.Add($sqlvm) | Out-Null + } + } + } + } + catch { + Write-Error "An error occurred while updating SQL VMs: $_" + } - # Get the resource groups - if ($ResourceGroup) { - $rgs = Get-AzResourceGroup -Name $ResourceGroup - } else { - $rgs = Get-AzResourceGroup - } + # --- Section: Update SQL Managed Instances (Stopped then Ready) --- + $sqlMIsToUpdate = [System.Collections.ArrayList]::new() + try { + if ($Force_Start_On_Resources) { + Write-Output "Seeking SQL Managed Instances that are stopped and require an update..." + $miQuery = if ($rgFilter) { + "[?licenseType!='${LicenseType}' && state!='Ready' && $rgFilter].{Name:name, State:state, ResourceGroup:resourceGroup}" + } + else { + "[?licenseType!='${LicenseType}' && state!='Ready'].{Name:name, State:state, ResourceGroup:resourceGroup}" + } + $offSQLMIs = az sql mi list --query $miQuery -o json | ConvertFrom-Json + foreach ($mi in $offSQLMIs) { + if ($mi.State -eq "Stopped") { + Write-Output "Starting SQL Managed Instance '$($mi.Name)' in RG '$($mi.ResourceGroup)'..." + az sql mi start --mi $mi.Name -g $mi.ResourceGroup --no-wait yes + } + $sqlMIsToUpdate.Add($mi) | Out-Null + } + } - foreach ($rg in $rgs) { - # Get all logical servers - $servers = Get-AzSqlServer -ResourceGroupName $rg.ResourceGroupName + Write-Output "Processing SQL Managed Instances that are running..." + $miRunningQuery = if ($rgFilter) { + "[?licenseType!='${LicenseType}' && state=='Ready' && $rgFilter]" + } + else { + "[?licenseType!='${LicenseType}' && state=='Ready']" + } + $runningMIs = az sql mi list --query $miRunningQuery -o json | ConvertFrom-Json + foreach ($mi in $runningMIs) { + Write-Output "Updating SQL Managed Instance '$($mi.name)' in RG '$($mi.resourceGroup)' to license type '$LicenseType'..." + $result = az sql mi update --name $mi.name --resource-group $mi.resourceGroup --license-type $LicenseType -o json | ConvertFrom-Json + $finalStatus += $result + $report["SQLMIUpdated"] += $mi.name + } + } + catch { + Write-Error "An error occurred while updating SQL Managed Instances: $_" + } + + # --- Section: Update SQL Databases and Elastic Pools --- + try { + Write-Output "Querying SQL Servers within this subscription..." + $serverQuery = if ($rgFilter) { "[?$rgFilter]" } else { "[]" } + $servers = az sql server list --query $serverQuery -o json | ConvertFrom-Json - # Scan all vCore-based SQL database resources in the subscription - $servers | Get-AzSqlDatabase | Where-Object { $_.SkuName -ne "ElasticPool" -and $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlDatabase -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -DatabaseName $_.DatabaseName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- Database $_.DatabaseName is set to $LicenseType") + foreach ($server in $servers) { + # Update SQL Databases + Write-Output "Scanning SQL Databases on server '$($server.name)'..." + $dbs = az sql db list --resource-group $server.resourceGroup --server $server.name --query "[?licenseType!='$($LicenseType)' && licenseType!=null]" -o json | ConvertFrom-Json + foreach ($db in $dbs) { + Write-Output "Updating SQL Database '$($db.name)' on server '$($server.name)' to license type '$LicenseType'..." + $result = az sql db update --name $db.name --server $server.name --resource-group $server.resourceGroup --set licenseType=$LicenseType -o json | ConvertFrom-Json + $finalStatus += $result + $report["SQLDBUpdated"] += $db.name + } + + # Update Elastic Pools + try { + Write-Output "Scanning Elastic Pools on server '$($server.name)'..." + $elasticPools = az sql elastic-pool list --resource-group $server.resourceGroup --server $server.name --query "[?licenseType!='$($LicenseType)' && licenseType!=null]" --only-show-errors -o json | ConvertFrom-Json + foreach ($pool in $elasticPools) { + Write-Output "Updating Elastic Pool '$($pool.name)' on server '$($server.name)' to license type '$LicenseType'..." + $result = az sql elastic-pool update --name $pool.name --server $server.name --resource-group $server.resourceGroup --set licenseType=$LicenseType --only-show-errors -o json | ConvertFrom-Json -ErrorAction SilentlyContinue + $finalStatus += $result + $report["ElasticPoolUpdated"] += $pool.name + } + } + catch { + Write-Output "Encountered an issue while updating Elastic Pools on server '$($server.name)'. Continuing..." + } } } - [system.gc]::Collect() + catch { + Write-Error "An error occurred while processing SQL Databases or Elastic Pools: $_" + } - # Scan all vCore-based SQL elastic pool resources in the subscription - $servers | Get-AzSqlElasticPool | Where-Object { $_.Edition -in @("GeneralPurpose", "BusinessCritical", "Hyperscale") } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlElasticPool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -ElasticPoolName $_.ElasticPoolName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- ElasticPool $_.ElasticPoolName is set to $LicenseType") + # --- Section: Update SQL Instance Pools --- + try { + Write-Output "Searching for SQL Instance Pools that require a license update..." + $instancePoolsQuery = if ($rgFilter) { "[?$rgFilter]" } else { "[]" } + $instancePools = az sql instance-pool list --query $instancePoolsQuery -o json | ConvertFrom-Json + $poolsToUpdate = $instancePools | Where-Object { $_.licenseType -ne $LicenseType } + foreach ($pool in $poolsToUpdate) { + Write-Output "Updating SQL Instance Pool '$($pool.name)' in RG '$($pool.resourceGroup)' to license type '$LicenseType'..." + $result = az sql instance-pool update --name $pool.name --resource-group $pool.resourceGroup --license-type $LicenseType -o json | ConvertFrom-Json + $finalStatus += $result + $report["InstancePoolUpdated"] += $pool.name } - } - [system.gc]::Collect() - - # Scan all SQL managed instance resources in the subscription - Get-AzSqlInstance | Where-Object { $_.InstancePoolName -eq $null } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlInstance -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- Instance $_.InstanceName is set to $LicenseType") - } - } - [system.gc]::Collect() - - # Scan all instance pool resources in the subscription - Get-AzSqlInstancePool | Foreach-Object { - if ($_.LicenseType -ne $LicenseType) { - Set-AzSqlInstancePool -ResourceGroupName $_.ResourceGroupName -ServerName $_.ServerName -InstanceName $_.InstanceName -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- InstancePool $_.InstanceName is set to $LicenseType") + } + catch { + Write-Error "An error occurred while updating SQL Instance Pools: $_" + } + + # --- Section: Update DataFactory SSIS Integration Runtimes --- + try { + Write-Output "Processing DataFactory SSIS Integration Runtime resources..." + Get-AzDataFactoryV2 | Where-Object { $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { + Get-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName | Where-Object { $_.Type -eq "Managed" -and $_.State -ne "Starting" } | ForEach-Object { + if ($_.LicenseType -ne $LicenseType) { + # Update the license type to $LicenseType. + $result = Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType $LicenseType -Force + $finalStatus += $result + $report["ADFSSISUpdated"] += $_.Name + Write-Host ([Environment]::NewLine + "-- DataFactory '$($_.DataFactoryName)' integration runtime updated to license type $LicenseType") + } + } } } - [system.gc]::Collect() + catch { + Write-Error "An error occurred while updating DataFactory SSIS Integration Runtimes: $_" + } - # Scan all SSIS integration runtime resources in the subscription - Get-AzDataFactoryV2IntegrationRuntime | Where-Object { $_.State -eq "Started" -and $_.NodeSize -ne $null } | ForEach-Object { - if ($_.LicenseType -ne $LicenseType) { - # Set the license type to $LicenseType - Set-AzDataFactoryV2IntegrationRuntime -ResourceGroupName $_.ResourceGroupName -DataFactoryName $_.DataFactoryName -Name $_.Name -LicenseType $LicenseType - Write-Host ([Environment]::NewLine + "-- DataFactory $_.DataFactoryName is set to $LicenseType") + # --- Section: Finalize SQL VM updates for those that were started on-demand --- + $sqlvm = "" + try { + $updated = $true + while ($sqlVmsToUpdate.Count -gt 0) { + $sqlvm = $sqlVmsToUpdate[0] + $vmStatus = az vm get-instance-view --resource-group $sqlvm.resourceGroup --name $sqlvm.name --query "{PowerState:instanceView.statuses[?starts_with(code, 'PowerState/')].displayStatus | [0]}" -o json | ConvertFrom-Json + if ($vmStatus.PowerState -eq "VM running") { + Write-Output "Now updating SQL VM '$($sqlvm.name)' after forced start..." + $result = az sql vm update -n $sqlvm.name -g $sqlvm.resourceGroup --license-type $SqlVmLicenseType -o json | ConvertFrom-Json + $finalStatus += $result + $report["SQLVMUpdated"] += $sqlvm.name + Write-Output "Deallocating SQL VM '$($sqlvm.name)' post-update..." + az vm deallocate --resource-group $sqlvm.resourceGroup --name $sqlvm.name --no-wait yes + $sqlVmsToUpdate.RemoveAt(0) + $updated = $true + } + else { + if ($updated) { + Write-Host "Waiting for SQL VM '$($sqlvm.name)' to start..." + $updated = $false + } + else { + Write-Host "." -NoNewline + } + Start-Sleep -Seconds 30 + } } } - [system.gc]::Collect() - - # Scan all SQL VMs in the subscription - Get-AzVM | Where-Object { $_.StorageProfile.ImageReference.Offer -like "*sql*" -and $_.ProvisioningState -eq "Succeeded" } | ForEach-Object { - $vmName = $_.Name - $resourceGroupName = $_.ResourceGroupName - - # Get the SQL configuration for the VM - $sqlConfig = Get-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" - - if ($sqlConfig -ne $null) { - $licenseType = $sqlConfig.Settings.LicenseType - - if ($licenseType -ne $LicenseType) { - # Set the license type to $LicenseType - Set-AzVMExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "SqlIaaSAgent" -Publisher "Microsoft.SqlServer.Management" -ExtensionType "SqlIaaSAgent" -TypeHandlerVersion "1.5" -Settings @{ "LicenseType" = $LicenseType } - Write-Host ([Environment]::NewLine + "-- SQL VM $vmName is set to $LicenseType") + catch { + Write-Error "An error occurred while finalizing SQL VM updates in subscription '$($sub.name)': $sqlvm" + } + + # --- Section: Finalize SQL Managed Instance updates for those that were forced-start --- + $mi = "" + try { + $updated = $true + while ($sqlMIsToUpdate.Count -gt 0) { + $mi = $sqlMIsToUpdate[0] + $miStatus = az sql mi show --resource-group $mi.ResourceGroup --name $mi.Name -o json | ConvertFrom-Json + if ($miStatus.state -eq "Ready") { + Write-Output "Updating SQL Managed Instance '$($mi.Name)' after forced start..." + $result = az sql mi update --name $mi.Name --resource-group $mi.ResourceGroup --license-type $LicenseType -o json | ConvertFrom-Json + $finalStatus += $result + $report["SQLMIUpdated"] += $mi.Name + Write-Output "Stopping SQL Managed Instance '$($mi.Name)' post-update..." + az sql mi stop --resource-group $mi.ResourceGroup --mi $mi.Name --no-wait yes + $sqlMIsToUpdate.RemoveAt(0) + $updated = $true + } + else { + if ($updated) { + Write-Host "Waiting for SQL Managed Instance '$($mi.Name)' to be ready..." + $updated = $false + } + else { + Write-Host "." -NoNewline + } + Start-Sleep -Seconds 30 } - } } - [system.gc]::Collect() + catch { + Write-Error "An error occurred while finalizing SQL Managed Instance updates in subscription '$($sub.name)': $mi" + } } + catch { + Write-Error "An error occurred while processing subscription '$($sub.name)': $_" + } +} + +$scriptEndTime = Get-Date +$totalDuration = $scriptEndTime - $scriptStartTime + +# --- Final Report --- +Write-Output "`n===== Final Report =====" +Write-Output "Script started at: $scriptStartTime" +Write-Output "Script ended at: $scriptEndTime" +Write-Output "Total duration: $($totalDuration.ToString())" +Write-Output "`nResources updated by category:" + +if ($report["SQLVMUpdated"].Count -gt 0) { + Write-Output "SQL VMs Updated: $($report["SQLVMUpdated"] -join ', ')" +} else { + Write-Output "SQL VMs Updated: None" +} + +if ($report["SQLMIUpdated"].Count -gt 0) { + Write-Output "SQL Managed Instances Updated: $($report["SQLMIUpdated"] -join ', ')" +} else { + Write-Output "SQL Managed Instances Updated: None" } -# Record the end time -$endTime = Get-Date -Write-Host ("Script execution ended at: $endTime") +if ($report["SQLDBUpdated"].Count -gt 0) { + Write-Output "SQL Databases Updated: $($report["SQLDBUpdated"] -join ', ')" +} else { + Write-Output "SQL Databases Updated: None" +} + +if ($report["ElasticPoolUpdated"].Count -gt 0) { + Write-Output "Elastic Pools Updated: $($report["ElasticPoolUpdated"] -join ', ')" +} else { + Write-Output "Elastic Pools Updated: None" +} + +if ($report["InstancePoolUpdated"].Count -gt 0) { + Write-Output "SQL Instance Pools Updated: $($report["InstancePoolUpdated"] -join ', ')" +} else { + Write-Output "SQL Instance Pools Updated: None" +} + +if ($report["ADFSSISUpdated"].Count -gt 0) { + Write-Output "SQL ADF SSIS: $($report["ADFSSISUpdated"] -join ', ')" +} else { + Write-Output "SQL ADF SSIS Updated: None" +} \ No newline at end of file From e935c4e116b1ca06bdeeceaa34b0de772cde1a08 Mon Sep 17 00:00:00 2001 From: Rodrigo Monteiro Date: Tue, 8 Apr 2025 13:59:05 -0400 Subject: [PATCH 151/159] Updates the license type for Azure SQL resources (SQL DBs, Elastic Pools, Managed Instances, Instance Pools, SQL VMs) to a specified model ("LicenseIncluded" or "BasePrice"). Optionally starts resources if needed. --- .../modify-license-type.ps1 | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 index 6999669c5e..af765ea4bd 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -4,10 +4,25 @@ to a specified model ("LicenseIncluded" or "BasePrice"). Optionally starts resources if needed. .DESCRIPTION - In a quest to bring harmony to the Azure realms, our script journeys across subscriptions, - updating the license types of various SQL resources. It supports processing a single subscription, - a CSV list of subscriptions, or all accessible subscriptions. For SQL VMs and SQL Managed Instances, - it can even start the resource if it's stopped (when -Force_Start_On_Resources is enabled). + The script updates Azure SQL License types across subscriptions by modifying the license settings for a variety of SQL resources. It supports processing resources in one of the following ways: + +Single Subscription: +Run against a specified subscription ID. +CSV List of Subscriptions: +Process multiple subscriptions provided in a CSV file. +All Accessible Subscriptions: +Automatically detect and update all subscriptions that you have access to. +For specific resource types like SQL Virtual Machines and SQL Managed Instances, the script can optionally start the resource if it is in a stopped state (when the -Force_Start_On_Resources parameter is enabled) before applying the license update. + +The script processes several types of Azure SQL resources including: + +SQL Virtual Machines (SQL VMs) +SQL Managed Instances +SQL Databases +Elastic Pools +SQL Instance Pools +DataFactory SSIS Integration Runtimes +This automation helps ensure that your licensing configuration is consistent across your environment without manual intervention. .PARAMETER SubId A single subscription ID or a CSV file name containing a list of subscriptions. From 478a6447b9b7c7ed2d6d77e67dd9fd3014905c16 Mon Sep 17 00:00:00 2001 From: Rodrigo Monteiro Date: Tue, 8 Apr 2025 14:04:47 -0400 Subject: [PATCH 152/159] Fix the requirements --- .../modify-license-type/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 c3990ead1a..0eed35f291 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -28,12 +28,12 @@ It uses managed identity authentication (via Connect-AzAccount -Identity and az # 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: -1. **Azure SQL Databases**: *SQL DB Contributor role*. -1. **Azure SQL Elastic Pools**: *SQL DB Contributor* -1. **Azure SQL Managed Instances**: *SQL Managed Instance Contributor* -1. **Azure SQL Instance Pools**: *SQL Managed Instance Contributor* -1. **Azure Data Factory SSIS Integration Runtimes**: *Data Factory Contributor role*. -1. **SQL Servers in Azure Virtual Machines**: *Virtual Machine Contributor role*. +1. **SQL DB Contributor**: *SQL DB Contributor role*. +1. **SQL Managed Instance Contributor**: *SQL Managed Instance Contributor* +1. **SQL Server Contributor**: *SQL Managed Instance Contributor* +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. From db3721dbc969bcd7a13cfe08afea5adb0312e405 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 8 Apr 2025 15:11:15 -0700 Subject: [PATCH 153/159] Modified readme --- .../modify-license-type/README.md | 180 +++++++++++++----- .../modify-license-type.ps1 | 10 +- 2 files changed, 134 insertions(+), 56 deletions(-) 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 0eed35f291..a7487844b3 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -8,22 +8,17 @@ ms.date: 04/08/2025 # Overview -This Azure Runbook updates the license type for various Azure SQL resources using Azure CLI and PowerShell commands. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -Force_Start_On_Resources parameter is enabled). - -This script is designed to help administrators standardize SQL licensing across their Azure environment by automating license updates. In summary, the script: - -Targets Multiple Resource Types: -SQL Virtual Machines: Updates license types after checking if the VM is running. If not, it can optionally start the VM to perform the update. -SQL Managed Instances: Detects instances that are stopped or not in the "Ready" state and can force them to start before updating. -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. -Flexible Subscription Targeting: -The script accepts a subscription ID or CSV file (for a list of subscriptions). If no subscription is specified, it defaults to updating resources in all accessible subscriptions. -Interactive Reporting: -The script logs steps along the process and compiles a final report summarizing which resources were updated in each category. -Seamless Integration with Azure Authentication: -It uses managed identity authentication (via Connect-AzAccount -Identity and az login --identity) to connect to your Azure environment securely. +This Azure Runbook updates the license type for various Azure SQL resources using Azure CLI and PowerShell commands. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -ForceStartOnResources parameter is enabled). + +This script is designed to help administrators standardize SQL licensing across their Azure environment by automating license updates. It accepts a subscription ID or CSV file (for a list of subscriptions). If no subscription is specified, it defaults to updating resources in all accessible subscriptions. + +# Target Resource Types + +- SQL Virtual Machines: Updates license types after checking if the VM is running. If not, it can optionally start the VM to perform the update. +- SQL Managed Instances: Detects instances that are stopped or not in the "Ready" state and can force them to start before updating. +- 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. # 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: @@ -34,65 +29,148 @@ 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. -# Additional Information +# Interactive Reporting + +The script logs steps along the process and compiles a final report summarizing which resources were updated in each category. -Script Parameters: -- SubId: A single subscription ID or the filename of a CSV file containing multiple subscriptions. -- ResourceGroup: (Optional) Limits the script’s operations to a specific resource group. -- LicenseType: (Optional) Defines the target license type. Valid values are "LicenseIncluded" (default) or "BasePrice". -- Force_Start_On_Resources: (Optional) When enabled, the script will attempt to start SQL VMs and SQL Managed Instances if they are not running before applying the update. -Logging & Error Handling: +# Integration with Azure Authentication + +The scripts is seamlessly integrated with Azure Authentication. It uses managed identity authentication (via Connect-AzAccount -Identity and az login --identity) to connect to your Azure environment securely. + +# Script parameters + + +| **Parameter**                                         | **Value**                                                                       | **Description** | +|:--|:--|:--| +|-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| +|-LicenseType | "LicenseIncluded" (default) or "BasePrice" | Optional: Sets the license type to the specified value | +|-ForceStartOnResources| |(Optional) When enabled, the script will attempt to start SQL VMs and SQL Managed Instances if they are not running before applying the update.| + +# 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. -# Customizations: +# Customizations + You might want to customize the script’s logging or incorporate additional logging (e.g., writing to a file or Azure Log Analytics) to integrate seamlessly with your monitoring and reporting workflow. -# Creating an Azure Runbook +# Script execution examples + +## Example 1 + +The following command will scan all the subscriptions to which the user has access to, and set the license type to pay-as-you-go on all SQL resources in each subscription that the user has access to. + +```PowerShell +.\modify-license-type.ps1 -LicenseType LicenseIncluded +``` + +## Example 2 + +The following command will scan a specific subscription, and set the license type to pay-as-you-go on all SQL resources. + +```PowerShell +.\modify-license-type.ps1 -SubId -LicenseType LicenseIncluded +``` + +## Example 3 + +The following command will scan the resource group `` in the subscription ``, set the license type value to pay-as-you-go. If the resource group has SQL VMs in the offline state, it will start each VM before applying the change, and then stop it. + +```PowerShell +.\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType LicenseIncluded -ForceStartOnResources +``` + +# Running the script from your PC + +1. Connect to Azure AD. You must specify `` if you have access to more than one AAD tenants. + + ```console + Connect-AzureAD -TenantID + ``` +1. Open a command shell on your device and download the script the script to your local folder. + +```console +curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +``` +1. Execute the command as shown by the examples + +# Running the script using Cloud Shell + +This option is recommended because Cloud shell has the Azure PowerShell modules pre-installed and you are automatically authenticated. Use the following steps to run the script in Cloud Shell. + +1. Launch the [Cloud Shell](https://shell.azure.com/). For details, [read more about PowerShell in Cloud Shell](https://aka.ms/pscloudshell/docs). + +1. Connect to Azure AD. You must specify `` if you have access to more than one AAD tenants. + + ```console + Connect-AzureAD -TenantID + ``` + +1. Upload the script to your cloud shell using the following command: + + ```console + curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 + ``` + +1. Execute the command as shown by the examples. + +> [!NOTE] +> - To paste the commands into the shell, use `Ctrl-Shift-V` on Windows or `Cmd-v` on MacOS. +> - The script will be uploaded directly to the home folder associated with your Cloud Shell session. + +# Schedule the script execution using Azure Runbook You can schedule the command to run as a runbook. Follow these steps using the Azure Portal: ### 1. Download the Script -Open a command shell on your device and run the command below. This will copy the script to your local folder. +Open a command shell on your device and dowload the script to to your current folder. ```console curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 ``` ### 2. Create or Use an Existing Automation Account -[Create a new automation account](https://ms.portal.azure.com/#create/Microsoft.AutomationAccount) or open an existing one. -In the Advanced section, ensure that System assigned identity is selected. +[Create a new automation account](https://ms.portal.azure.com/#create/Microsoft.AutomationAccount) or open an existing one. In the Advanced section, ensure that System assigned identity is selected. + ### 3. Import the Runbook -Navigate to the Process Automation group and select Runbooks. -Click on the Import a runbook tab and configure it: -File: Select the file you downloaded in Step 1. -Name: Enter a name for the runbook. -Type: Set to PowerShell. -Runtime Version: Choose 7.2. -Click Import. +- Navigate to the Process Automation group and select **Runbooks**. + +- Click on the **Import a runbook** tab and configure it: + + **File**: Select the file you downloaded in Step 1. + **Name**: Enter a name for the runbook. + **Type**: Set to PowerShell. + **Runtime Version**: Choose 7.2. + +- Click **Import**. + ### 4. Publish the Runbook -After the runbook is imported, click the Publish button to make it available for scheduling. +After the runbook is imported, click the **Publish** button to make it available for scheduling. ### 5. Link the Runbook to a Schedule -Once the runbook status is Published, click on the Link to schedule button. -Select Link a schedule to your runbook and click + Add a schedule. -Configure the schedule: -Name: Provide a name for the schedule. -Start Time: Set the desired start time. -Recurrence: Choose the recurrence need it. -Click Create. + +- Once the runbook status is *Published*, click on the **Link to schedule** button. +- Select *Link a schedule to your runbook* and click **+ Add**. +- Configure the schedule: + **Name**: Provide a name for the schedule. + **Start Time**: Set the desired start time. + **Recurrence**: Choose the recurrence need it. +- Click **Create**. + ### 6. Configure Runbook Parameters -Return to the Schedule runbook page. -Click on Parameters and run settings. -Paste the license ID value into the appropriate field. -Click OK to link the schedule, then OK again to create the job. +- Return to the **Schedule runbook** page. +- Click on **Parameters** and run settings. +- Paste the license type value into the appropriate field. +- Click **OK** to link the schedule, then **OK** again to create the job. + ### 7. Verify the Runbook Execution -On the runbook Overview page, open a recent job that was completed after the scheduled start time. -Click on the Output tab and verify that you see: -Properties.activationState=Activated +On the runbook Overview page: +- Open a recent job that was completed after the scheduled start time. +- Click on the **Output tab** and verify that you see: `Properties.activationState=Activated ` + Your license is now active. For more information about the runbooks, see the [Runbook tutorial](https://docs.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual-powershell) \ No newline at end of file diff --git a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 index af765ea4bd..4aa1c9e0a1 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/modify-license-type.ps1 @@ -12,7 +12,7 @@ CSV List of Subscriptions: Process multiple subscriptions provided in a CSV file. All Accessible Subscriptions: Automatically detect and update all subscriptions that you have access to. -For specific resource types like SQL Virtual Machines and SQL Managed Instances, the script can optionally start the resource if it is in a stopped state (when the -Force_Start_On_Resources parameter is enabled) before applying the license update. +For specific resource types like SQL Virtual Machines and SQL Managed Instances, the script can optionally start the resource if it is in a stopped state (when the -ForceStartOnResources parameter is enabled) before applying the license update. The script processes several types of Azure SQL resources including: @@ -33,7 +33,7 @@ This automation helps ensure that your licensing configuration is consistent acr .PARAMETER LicenseType Optional. License type to set. Allowed values: "LicenseIncluded" (default) or "BasePrice". -.PARAMETER Force_Start_On_Resources +.PARAMETER ForceStartOnResources Optional. If true, starts SQL VMs and SQL Managed Instances before updating their license type. #> @@ -49,7 +49,7 @@ param ( [string] $LicenseType = "LicenseIncluded", [Parameter(Mandatory = $false)] - [bool] $Force_Start_On_Resources = $false + [bool] $ForceStartOnResources = $false ) # Suppress unnecessary logging output @@ -198,7 +198,7 @@ foreach ($sub in $subscriptions) { $report["SQLVMUpdated"] += $sqlvm.name } else { - if ($Force_Start_On_Resources) { + if ($ForceStartOnResources) { Write-Output "SQL VM '$($sqlvm.name)' is not running. Forcing start to update license..." az vm start --resource-group $sqlvm.resourceGroup --name $sqlvm.name --no-wait yes $sqlVmsToUpdate.Add($sqlvm) | Out-Null @@ -213,7 +213,7 @@ foreach ($sub in $subscriptions) { # --- Section: Update SQL Managed Instances (Stopped then Ready) --- $sqlMIsToUpdate = [System.Collections.ArrayList]::new() try { - if ($Force_Start_On_Resources) { + if ($ForceStartOnResources) { Write-Output "Seeking SQL Managed Instances that are stopped and require an update..." $miQuery = if ($rgFilter) { "[?licenseType!='${LicenseType}' && state!='Ready' && $rgFilter].{Name:name, State:state, ResourceGroup:resourceGroup}" From 0897b6ed3acb6ba714625752939659653a733284 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 8 Apr 2025 15:14:46 -0700 Subject: [PATCH 154/159] more tweaks --- .../manage/azure-hybrid-benefit/modify-license-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a7487844b3..fa0e966fe7 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -8,7 +8,7 @@ ms.date: 04/08/2025 # Overview -This Azure Runbook updates the license type for various Azure SQL resources using Azure CLI and PowerShell commands. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -ForceStartOnResources parameter is enabled). +This script provides a scaleable solution to change the license type of various Azure SQL resources with the selected scope. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -ForceStartOnResources parameter is enabled). This script is designed to help administrators standardize SQL licensing across their Azure environment by automating license updates. It accepts a subscription ID or CSV file (for a list of subscriptions). If no subscription is specified, it defaults to updating resources in all accessible subscriptions. From 15668e0e370af1264acd1be53c4620cec02cdea2 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Tue, 8 Apr 2025 15:15:19 -0700 Subject: [PATCH 155/159] typo --- .../manage/azure-hybrid-benefit/modify-license-type/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fa0e966fe7..8c5bdc84e0 100644 --- a/samples/manage/azure-hybrid-benefit/modify-license-type/README.md +++ b/samples/manage/azure-hybrid-benefit/modify-license-type/README.md @@ -8,7 +8,7 @@ ms.date: 04/08/2025 # Overview -This script provides a scaleable solution to change the license type of various Azure SQL resources with the selected scope. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -ForceStartOnResources parameter is enabled). +This script provides a scaleable solution to change the license type of various Azure SQL resources within the selected scope. It automates the process of modifying license settings for SQL Databases, Elastic Pools, SQL Managed Instances, SQL Instance Pools, SQL Virtual Machines, and DataFactory SSIS Integration Runtimes. The script supports targeting a single subscription, a list of subscriptions defined in a CSV file, or all accessible subscriptions. Optionally, it can also start resources that are stopped (if the -ForceStartOnResources parameter is enabled). This script is designed to help administrators standardize SQL licensing across their Azure environment by automating license updates. It accepts a subscription ID or CSV file (for a list of subscriptions). If no subscription is specified, it defaults to updating resources in all accessible subscriptions. From 56b627144bed06c1c1c0e4771217e0185e1f120b Mon Sep 17 00:00:00 2001 From: zoran-rilak-msft <81432157+zoran-rilak-msft@users.noreply.github.com> Date: Wed, 9 Apr 2025 17:49:17 +0200 Subject: [PATCH 156/159] Bump VPN SKU to AZ to match the public IP --- .../attach-vpn-gateway/azuredeploy.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json index d785c1d268..ea933aa994 100644 --- a/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json +++ b/samples/manage/azure-sql-db-managed-instance/attach-vpn-gateway/azuredeploy.json @@ -78,8 +78,8 @@ } ], "sku": { - "name": "VpnGw1", - "tier": "VpnGw1" + "name": "VpnGw1AZ", + "tier": "VpnGw1AZ" }, "gatewayType": "Vpn", "vpnType": "RouteBased", From 79e88a9db76f3db56e8bad1b650e5c5707286f6c Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Wed, 9 Apr 2025 14:25:39 -0700 Subject: [PATCH 157/159] reverted to Dec 1, 2024 --- .../modify-license-type/README.md | 7 +- .../modify-license-type.ps1 | 101 ++++++++++++------ 2 files changed, 68 insertions(+), 40 deletions(-) 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 66258777f7..fe527719f1 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 @@ -38,15 +38,12 @@ The script accepts the following command line parameters: ```PowerShell Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation ``` -> [!IMPORTANT] -> If you are setting License type to "PAYG" in the CSP subscription(s), the subscription resource must have a consent tag enabling perpetual pay-as-you-go billing. Without the tag, the command will fail. The consent tag is `SQLPerpetualPaygBilling`:`Enabled` and can be added using [Azure portal](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal), [PowerShell](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-powershell) or [CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-cli). - ## Example 1 -The following command will scan all the subscriptions to which the user has access to, and set the license type to "Paid" on all servers where license type is undefined. +The following command will scan all the subscriptions to which the user has access to, and set the license type to "PAYG" on all servers where license type is undefined. ```PowerShell -.\modify-license-type.ps1 -LicenseType Paid +.\modify-license-type.ps1 -LicenseType PAYG ``` ## Example 2 diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index a14c96111b..d6b4159c6b 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -52,52 +52,82 @@ function ConvertTo-Hashtable { $InputObject ) process { + ## Return null if the input is null. This can happen when calling the function + ## recursively and a property is null if ($null -eq $InputObject) { return $null } - if ($InputObject -is [System.Collections.ICollection]) { + ## Check if the input is an array or collection. If so, we also need to convert + ## those types into hash tables as well. This function will convert all child + ## objects into hash tables (if applicable) + if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { + $collection = @( + foreach ($object in $InputObject) { + ConvertTo-Hashtable -InputObject $object + } + ) + ## Return the array but don't enumerate it because the object may be pretty complex + Write-Output -NoEnumerate $collection + } elseif ($InputObject -is [psobject]) { + ## If the object has properties that need enumeration, cxonvert it to its own hash table and return it $hash = @{} - foreach ($property in $InputObject) { + foreach ($property in $InputObject.PSObject.Properties) { $hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value } $hash } else { + ## If the object isn't an array, collection, or other object, it's already a hash table + ## So just return it. $InputObject } } } -function LoadModule { +# 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)) { + if (!(Get-Module -Name $name)) + { $retVal = Get-Module -ListAvailable | Where-Object {$_.Name -eq $name} - if ($retVal) { - try { + if ($retVal) + { + try + { Import-Module $name -ErrorAction SilentlyContinue } - catch { - write-host "The request to load module $($name) failed with the following error:" + catch + { + write-host "The request to lload module $($name) failed with the following error:" write-host $_.Exception.Message $retVal = $false } - } else { + } + 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 + try + { + Import-Module $name -ErrorAction SilentlyContinue } - catch { + catch + { write-host "The request to load module $($name) failed with the following error:" write-host $_.Exception.Message $retVal = $false } - } else { + } + 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 } @@ -107,8 +137,12 @@ function LoadModule { return $retVal } +# +# Suppress warnings +# Update-AzConfig -DisplayBreakingChangeWarning $false +# Load required modules $requiredModules = @( "AzureAD", "Az.Accounts", @@ -117,19 +151,25 @@ $requiredModules = @( ) $requiredModules | Foreach-Object {LoadModule $_} +# Subscriptions to scan + $tenantID = (Get-AzureADTenantDetail).ObjectId if ($SubId -like "*.csv") { $subscriptions = Import-Csv $SubId -}elseif($SubId -ne "") { +}elseif($SubId -ne ""){ $subscriptions = [PSCustomObject]@{SubscriptionId = $SubId} | Get-AzSubscription -TenantID $tenantID -}else { +}else{ $subscriptions = Get-AzSubscription -TenantID $tenantID } + Write-Host ([Environment]::NewLine + "-- Scanning subscriptions --") -foreach ($sub in $subscriptions) { +# Scan arc-enabled servers in each subscription + +foreach ($sub in $subscriptions){ + if ($sub.State -ne "Enabled") {continue} try { @@ -139,23 +179,6 @@ foreach ($sub in $subscriptions) { {continue} } - # Consent tag enforcement on the CSP subscriptions - if ($LicenseType -eq "PAYG") { - $offers = @("MS-AZR-0145P", "MS-AZR-DE-0145P", "MS-AZR-0017G", "MS-AZR-159P", "MS-AZR-USGOV-0145P") - $subscriptionOffers = Get-AzSubscription -SubscriptionId $sub.Id | Select-Object -ExpandProperty OfferId - if ($subscriptionOffers -contains $offers) { - if ($tags.Tags.ContainsKey("SQLPerpetualPaygBilling")) { - if ($tags.Tags["SQLPerpetualPaygBilling"] -ne "Enabled") { - write-host "Error: Subscription $($sub.Id) has an incorrect value $($tags.Tags["SQLPerpetualPaygBilling"]) of the consent tag 'SQLPerpetualPaygBilling' ." - continue - } - } else { - write-host "Error: Subscription $($sub.Id) does not have the consent tag 'SQLPerpetualPaygBilling'." - continue - } - } - } - $query = " resources | where type =~ 'microsoft.hybridcompute/machines/extensions' @@ -180,6 +203,7 @@ foreach ($sub in $subscriptions) { $resources = Search-AzGraph -Query "$($query)" foreach ($r in $resources) { + $setID = @{ MachineName = $r.MachineName Name = $r.extensionName @@ -194,6 +218,7 @@ foreach ($sub in $subscriptions) { $settings = @{} $settings = $r.properties.settings | ConvertTo-Json | ConvertFrom-Json | ConvertTo-Hashtable + # set the license type or update (if -Force). ESU must be disabled to set to LicenseOnly. $LO_Allowed = (!$settings["enableExtendedSecurityUpdates"] -and !$EnableESU) -or ($EnableESU -eq "No") if ($LicenseType) { @@ -210,8 +235,10 @@ foreach ($sub in $subscriptions) { $WriteSettings = $true } } + } + # Enable ESU for qualified license types or disable if ($EnableESU) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($EnableESU -eq "No")) { $settings["enableExtendedSecurityUpdates"] = ($EnableESU -eq "Yes") @@ -222,6 +249,7 @@ foreach ($sub in $subscriptions) { } } + # Enable UsePcoreLicense for qualified license types or disable if ($UsePcoreLicense) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($UsePcoreLicense -eq "No")) { $settings["UsePhysicalCoreLicense"] = @{ @@ -234,14 +262,17 @@ foreach ($sub in $subscriptions) { } } If ($WriteSettings) { + try { - Set-AzConnectedMachineExtension @setID -Settings $settings -NoWait | Out-Null + Set-AzConnectedMachineExtension @setId -Settings $settings -NoWait | Out-Null Write-Host "Updated -- Resource group: [$($r.resourceGroup)], Connected machine: [$($r.MachineName)]" } catch { - write-host "The request to modify the extension object failed with the following error:" + write-host "The request to modify the extenion object failed with the following error:" write-host $_.Exception.Message {continue} } } } } + + \ No newline at end of file From b31c28aefe1a29b61826bc0d097d998e0afe1e65 Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Thu, 1 May 2025 18:06:02 -0700 Subject: [PATCH 158/159] updated modify-license-type to support PAYG-R consent --- .../modify-license-type/README.md | 41 ++++++++++++------- .../modify-license-type.ps1 | 23 +++++++++-- 2 files changed, 47 insertions(+), 17 deletions(-) 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 fe527719f1..2a86d27636 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 @@ -3,7 +3,7 @@ services: Azure Arc-enabled SQL Server platforms: Azure author: anosov1960 ms.author: sashan -ms.date: 12/01/2024 +ms.date: 05/01/2025 --- @@ -16,42 +16,45 @@ If not specified, all subscriptions your role has access to are scanned. # Prerequisites -- You must have at least *Azure Connected Machine Resource Administrator* role and subscription *Reader* role. +- You must have at least a *Azure Connected Machine Resource Administrator* role in each subscription you modify. - The Azure extension for SQL Server is updated to version 1.1.2230.58 or newer. - You must be connected to Azure AD and logged in to your Azure account. If your account have access to multiple tenants, make sure to log in with a specific tenant ID. + # Launching the script The script accepts the following command line parameters: | **Parameter**                                         | **Value**                                                                       | **Description** | |:--|:--|:--| -|-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| -|-MachineName |machine_name|Optional: Limits the scope to a specific machine| -|-LicenseType | "Paid", "PAYG" or "LicenseOnly"| Optional: Sets the license type to the specified value | -|-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| +|`-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| +|`-MachineName` |machine_name|*Optional*: Limits the scope to a specific machine| +|`-LicenseType` | "Paid", "PAYG" or "LicenseOnly"| *Optional*: Sets the license type to the specified value | +|`-ConsentToRecurringPAYG` | "Yes" or "No" |*Optional*. Consents to enabling the recurring PAYG billing. LicenseType must be "PAYG". Applies to CSP subscriptions only.| +|`-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| 1You can create a .csv file using the following command and then edit to remove the subscriptions you don't want to scan. ```PowerShell Get-AzSubscription | Export-Csv .\mysubscriptions.csv -NoTypeInformation ``` + ## Example 1 -The following command will scan all the subscriptions to which the user has access to, and set the license type to "PAYG" on all servers where license type is undefined. +The following command will scan all the subscriptions to which the user has access to, and set the license type to "Paid" on all servers where license type is undefined. ```PowerShell -.\modify-license-type.ps1 -LicenseType PAYG +.\modify-license-type.ps1 -LicenseType Paid ``` ## Example 2 -The following command will scan all all the subscriptions to which the user has access to, and set the license type to "PAYG" on all servers . +The following command will scan the subscription `` and set the license type value to "Paid" on all servers. ```PowerShell -.\modify-license-type.ps1 -SubId -LicenseType PAYG -Force +.\modify-license-type.ps1 -SubId -LicenseType Paid -Force ``` ## Example 3 @@ -64,7 +67,7 @@ The following command will scan resource group `` in the su ## Example 4 -The following command will set License Type to 'Paid" and enables ESU on all servers in the subscriptions `` and the resource group ``. +The following command will set License Type to "Paid" and enables ESU on all servers in the subscriptions `` and the resource group ``. ```console .\modify-license-type.ps1 -SubId -ResourceGroup -LicenseType Paid -EnableESU Yes -Force @@ -78,6 +81,16 @@ The following command will disable ESU on all servers in the subscriptions ` -EnableESU No ``` +## Example 6 + +The following command will scan all subscriptions in the account, set the license type value to "PAYG" and consents to enabling recurring billing on all servers in the account. + +```PowerShell +.\modify-license-type.ps1 -LicenseType PAYG -ConsentToRecurringPAYG Yes -Force +``` +> [!NOTE] +> The recurring billing only supported in the CSP accounts. + # Running the script using Cloud Shell This option is recommended because Cloud shell has the Azure PowerShell modules pre-installed and you are automatically authenticated. Use the following steps to run the script in Cloud Shell. diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index d6b4159c6b..96cc0ec271 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -12,6 +12,7 @@ # -ResourceGroup [resource_goup] (Optional. Limits the scope to a specific resoure group) # -MachineName [machine_name] (Optional. Limits the scope to a specific machine) # -LicenseType [license_type_value] (Optional. Sets the license type to the specified value) +# -ConsentToRecurringPAYG [Yes or No] (Optional. Consents to enabling the recurring PAYG billing. LicenseType must be "PAYG". Applies to CSP subscriptions only. # -UsePcoreLicense [Yes or 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 or No] (Optional. Enables the ESU policy if the value is "Yes" or disables it if the value is "No" @@ -34,6 +35,8 @@ param ( [Parameter (Mandatory= $false)] [ValidateSet("PAYG","Paid","LicenseOnly", IgnoreCase=$false)] [string] $LicenseType, + [ValidateSet("Yes","No", IgnoreCase=$false)] + [string] $ConsentToRecurringPAYG, [Parameter (Mandatory= $false)] [ValidateSet("Yes","No", IgnoreCase=$false)] [string] $UsePcoreLicense, @@ -234,8 +237,7 @@ foreach ($sub in $subscriptions){ $settings["LicenseType"] = $LicenseType $WriteSettings = $true } - } - + } } # Enable ESU for qualified license types or disable @@ -261,6 +263,21 @@ foreach ($sub in $subscriptions){ write-host "The configured license type does not support ESUs" } } + + # Add or update ConsentToRecurringPAYG setting if applicable + if ($ConsentToRecurringPAYG -eq "Yes") { + $isPayg = ($LicenseType -eq "PAYG") -or ($settings["LicenseType"] -eq "PAYG") + if ($isPayg) { + if (-not $settings.ContainsKey("ConsentToRecurringPAYG") -or -not $settings["ConsentToRecurringPAYG"]["Consented"]) { + $settings["ConsentToRecurringPAYG"] = @{ + "Consented" = $true; + "ConsentTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') + } + $WriteSettings = $true + } + } + } + If ($WriteSettings) { try { @@ -275,4 +292,4 @@ foreach ($sub in $subscriptions){ } } - \ No newline at end of file + From f3dc8c476d27982c6169ff3cdf41751098be5f8a Mon Sep 17 00:00:00 2001 From: "Alexander (Sasha) Nosov" Date: Mon, 5 May 2025 10:21:41 -0700 Subject: [PATCH 159/159] Removed milliseconds --- .../modify-license-type/modify-license-type.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 index 96cc0ec271..62e686655c 100644 --- a/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 +++ b/samples/manage/azure-arc-enabled-sql-server/modify-license-type/modify-license-type.ps1 @@ -244,7 +244,7 @@ foreach ($sub in $subscriptions){ if ($EnableESU) { if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($EnableESU -eq "No")) { $settings["enableExtendedSecurityUpdates"] = ($EnableESU -eq "Yes") - $settings["esuLastUpdatedTimestamp"] = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') + $settings["esuLastUpdatedTimestamp"] = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ssZ') $WriteSettings = $true } else { write-host "The configured license type does not support ESUs" @@ -256,7 +256,7 @@ foreach ($sub in $subscriptions){ if (($settings["LicenseType"] | select-string "Paid","PAYG") -or ($UsePcoreLicense -eq "No")) { $settings["UsePhysicalCoreLicense"] = @{ "IsApplied" = ($UsePcoreLicense -eq "Yes"); - "LastUpdatedTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') + "LastUpdatedTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ssZ') } $WriteSettings = $true } else { @@ -271,7 +271,7 @@ foreach ($sub in $subscriptions){ if (-not $settings.ContainsKey("ConsentToRecurringPAYG") -or -not $settings["ConsentToRecurringPAYG"]["Consented"]) { $settings["ConsentToRecurringPAYG"] = @{ "Consented" = $true; - "ConsentTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') + "ConsentTimestamp" = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ssZ') } $WriteSettings = $true }