diff --git a/.github/workflows/gallery.yml b/.github/workflows/gallery.yml index 512404e88e..0ce64ca72a 100644 --- a/.github/workflows/gallery.yml +++ b/.github/workflows/gallery.yml @@ -24,7 +24,7 @@ jobs: - name: Install and cache PowerShell modules uses: potatoqualitee/psmodulecache@v5.2 with: - modules-to-cache: dbatools.library:2024.3.9 + modules-to-cache: dbatools.library:2024.4.12 - name: Download dbatools from Gallery run: | diff --git a/bin/dbatools-buildref-index.json b/bin/dbatools-buildref-index.json index d7b2b96a5d..8d68193030 100644 --- a/bin/dbatools-buildref-index.json +++ b/bin/dbatools-buildref-index.json @@ -1,5 +1,5 @@ { - "LastUpdated": "2024-04-11T00:00:00", + "LastUpdated": "2024-05-16T00:00:00", "Data": [ { "Version": "8.0.47", @@ -4683,6 +4683,11 @@ { "Version": "16.0.4120", "KBList": "5036343" + }, + { + "CU": "CU13", + "Version": "16.0.4125", + "KBList": "5036432" } ] } diff --git a/bin/dbatools-index.json b/bin/dbatools-index.json index ac19f7f5aa..fa075fd97b 100644 Binary files a/bin/dbatools-index.json and b/bin/dbatools-index.json differ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2012.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2012.sql index eb0a45199c..8e87e2c58b 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2012.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2012.sql @@ -1,7 +1,7 @@ -- SQL Server 2012 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 1, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1380,6 +1380,7 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 52) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], @@ -1387,12 +1388,13 @@ qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -qs.creation_time AS [Creation Time] +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2014.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2014.sql index 9181d2b006..36f5960379 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2014.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2014.sql @@ -1,7 +1,7 @@ -- SQL Server 2014 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 1, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1406,20 +1406,21 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 53) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], -CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -CONVERT(nvarchar(25), qs.last_execution_time, 20) AS [Last Execution Time], -CONVERT(nvarchar(25), qs.creation_time, 20) AS [Plan Cached Time] +CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2016.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2016.sql index 6fa6ef6500..445be6a9ac 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2016.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2016.sql @@ -1,7 +1,7 @@ -- SQL Server 2016 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 1, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1470,20 +1470,21 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 54) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], -CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -FORMAT(qs.last_execution_time, 'yyyy-MM-dd HH:mm:ss', 'en-US') AS [Last Execution Time], -FORMAT(qs.creation_time, 'yyyy-MM-dd HH:mm:ss', 'en-US') AS [Plan Cached Time] +CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2016SP2.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2016SP2.sql index db89811e4d..639d7ad2d8 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2016SP2.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2016SP2.sql @@ -1,7 +1,7 @@ -- SQL Server 2016 SP2 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 1, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1485,20 +1485,21 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 57) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], -CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -CONVERT(nvarchar(25), qs.last_execution_time, 20) AS [Last Execution Time], -CONVERT(nvarchar(25), qs.creation_time, 20) AS [Plan Cached Time] +CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2017.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2017.sql index 410ed3605c..90c9e603c3 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2017.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2017.sql @@ -1,7 +1,7 @@ -- SQL Server 2017 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 1, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1521,20 +1521,21 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 58) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], -CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -CONVERT(nvarchar(25), qs.last_execution_time, 20) AS [Last Execution Time], -CONVERT(nvarchar(25), qs.creation_time, 20) AS [Plan Cached Time] +CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2019.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2019.sql index a77daae461..f51d37b2d8 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2019.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2019.sql @@ -1,7 +1,7 @@ -- SQL Server 2019 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 11, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1596,20 +1596,21 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 60) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], -CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -CONVERT(nvarchar(25), qs.last_execution_time, 20) AS [Last Execution Time], -CONVERT(nvarchar(25), qs.creation_time, 20) AS [Plan Cached Time] +CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/bin/diagnosticquery/SQLServerDiagnosticQueries_2022.sql b/bin/diagnosticquery/SQLServerDiagnosticQueries_2022.sql index 3d9ab485a6..b73f294600 100644 --- a/bin/diagnosticquery/SQLServerDiagnosticQueries_2022.sql +++ b/bin/diagnosticquery/SQLServerDiagnosticQueries_2022.sql @@ -1,7 +1,7 @@ -- SQL Server 2022 Diagnostic Information Queries -- Glenn Berry --- Last Modified: April 9, 2024 +-- Last Modified: May 2, 2024 -- https://glennsqlperformance.com/ -- https://sqlserverperformance.wordpress.com/ -- YouTube: https://bit.ly/2PkoAM1 @@ -1666,20 +1666,21 @@ ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE); -- Get most frequently executed queries for this database (Query 62) (Query Execution Counts) SELECT TOP(50) LEFT(t.[text], 50) AS [Short Query Text], qs.execution_count AS [Execution Count], +ISNULL(qs.execution_count/DATEDIFF(Minute, qs.creation_time, GETDATE()), 0) AS [Calls/Minute], qs.total_logical_reads AS [Total Logical Reads], qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], qs.total_worker_time AS [Total Worker Time], qs.total_worker_time/qs.execution_count AS [Avg Worker Time], qs.total_elapsed_time AS [Total Elapsed Time], qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], -CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], -CONVERT(nvarchar(25), qs.last_execution_time, 20) AS [Last Execution Time], -CONVERT(nvarchar(25), qs.creation_time, 20) AS [Plan Cached Time] +CASE WHEN CONVERT(nvarchar(max), qp.query_plan) COLLATE Latin1_General_BIN2 LIKE N'%%' THEN 1 ELSE 0 END AS [Has Missing Index], +qs.last_execution_time AS [Last Execution Time], qs.creation_time AS [Creation Time] --,t.[text] AS [Complete Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp WHERE t.dbid = DB_ID() +AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0 ORDER BY qs.execution_count DESC OPTION (RECOMPILE); ------ diff --git a/dbatools.psd1 b/dbatools.psd1 index 26d6a45018..998f59aac6 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -11,7 +11,7 @@ RootModule = 'dbatools.psm1' # Version number of this module. - ModuleVersion = '2.1.14' + ModuleVersion = '2.1.15' # ID used to uniquely identify this module GUID = '9d139310-ce45-41ce-8e8b-d76335aa1789' diff --git a/public/Backup-DbaDatabase.ps1 b/public/Backup-DbaDatabase.ps1 index f7038b29a2..bf8a2d5d2f 100644 --- a/public/Backup-DbaDatabase.ps1 +++ b/public/Backup-DbaDatabase.ps1 @@ -54,6 +54,9 @@ function Backup-DbaDatabase { timestamp - will be replaced with the timestamp (either the default, or the format provided) backuptype - will be replaced with Full, Log or Differential as appropriate + .PARAMETER NoAppendDbNameInPath + A switch that will prevent to systematically appended dbname to the path when creating the backup file path + .PARAMETER CopyOnly If this switch is enabled, CopyOnly backups will be taken. By default function performs a normal backup, these backups interfere with the restore chain of the database. CopyOnly backups will not interfere with the restore chain of the database. @@ -217,6 +220,7 @@ function Backup-DbaDatabase { [string]$FilePath, [switch]$IncrementPrefix, [switch]$ReplaceInName, + [switch]$NoAppendDbNameInPath, [switch]$CopyOnly, [ValidateSet('Full', 'Log', 'Differential', 'Diff', 'Database')] [string]$Type = 'Database', @@ -661,7 +665,11 @@ function Backup-DbaDatabase { for ($i = 0; $i -lt $FinalBackupPath.Count; $i++) { $parent = [IO.Path]::GetDirectoryName($FinalBackupPath[$i]) $leaf = [IO.Path]::GetFileName($FinalBackupPath[$i]) - $FinalBackupPath[$i] = [IO.Path]::Combine($parent, $dbName, $leaf) + if ($NoAppendDbNameInPath) { + $FinalBackupPath[$i] = [IO.Path]::Combine($parent, $leaf) + } else { + $FinalBackupPath[$i] = [IO.Path]::Combine($parent, $dbName, $leaf) + } } } diff --git a/public/ConvertTo-DbaDataTable.ps1 b/public/ConvertTo-DbaDataTable.ps1 index bf2adf3ff5..c0bbecd772 100644 --- a/public/ConvertTo-DbaDataTable.ps1 +++ b/public/ConvertTo-DbaDataTable.ps1 @@ -166,6 +166,11 @@ function ConvertTo-DbaDataTable { } } $specialType = 'Size' + } elseif ($type -eq 'Dataplat.Dbatools.Utility.DbaDateTime') { + $special = $true + $value = [System.DateTime]$value.DateTime + $type = 'System.DateTime' + $specialType = 'DateTime' } elseif (-not ($type -in $types)) { # All types which are not found in the array will be converted into strings. # In this way we don't ignore it completely and it will be clear in the end why it looks as it does. @@ -217,6 +222,9 @@ function ConvertTo-DbaDataTable { $Value.$TimeSpanType } } + 'DateTime' { + return [System.DateTime]$Value.DateTime + } } } diff --git a/public/New-DbaAvailabilityGroup.ps1 b/public/New-DbaAvailabilityGroup.ps1 index 5e82eb0271..f4f6621130 100644 --- a/public/New-DbaAvailabilityGroup.ps1 +++ b/public/New-DbaAvailabilityGroup.ps1 @@ -56,6 +56,14 @@ function New-DbaAvailabilityGroup { .PARAMETER Name The name of the Availability Group. + .PARAMETER IsContained + Builds the Availability Group as contained. Only supported in SQL Server 2022 or higher. + + https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/contained-availability-groups-overview + + .PARAMETER ReuseSystemDatabases + Used when rebuilding an availability group with the same name, where system databases already exist for the contained availability group. + .PARAMETER DtcSupport Indicates whether the DtcSupport is enabled @@ -219,6 +227,11 @@ function New-DbaAvailabilityGroup { Creates a basic availability group named BAG1 on sql2016std and does not confirm when setting up + .EXAMPLE + PS C:\> New-DbaAvailabilityGroup -Primary sql2022n01 -Secondary sql2022n02 -Name AgContained -IsContained + + Creates a contained availability group named AgContained on nodes sql2022n01 and sql2022n02 + .EXAMPLE PS C:\> New-DbaAvailabilityGroup -Primary sql2016b -Name AG1 -Dhcp -Database db1 -UseLastBackup @@ -268,6 +281,8 @@ function New-DbaAvailabilityGroup { [parameter(Mandatory)] [string]$Name, + [switch]$IsContained, + [switch]$ReuseSystemDatabases, [switch]$DtcSupport, [ValidateSet('Wsfc', 'External', 'None')] [string]$ClusterType = (Get-DbatoolsConfigValue -FullName 'AvailabilityGroups.Default.ClusterType' -Fallback 'Wsfc'), @@ -366,6 +381,16 @@ function New-DbaAvailabilityGroup { return } + if ($IsContained -and $server.VersionMajor -lt 16) { + Stop-Function -Message "Contained availability groups are only supported in SQL Server 2022 and above" -Target $Primary + return + } + + if ($ReuseSystemDatabases -and $IsContained -eq $false) { + Stop-Function -Message "Reuse system databases is only applicable in contained availability groups" -Target $Primary + return + } + Write-ProgressHelper -StepNumber ($stepCounter++) -Message "Checking requirements" $requirementsFailed = $false @@ -499,6 +524,11 @@ function New-DbaAvailabilityGroup { $ag.ClusterType = $ClusterType } + if ($server.VersionMajor -ge 16) { + $ag.IsContained = $IsContained + $ag.ReuseSystemDatabases = $ReuseSystemDatabases + } + if ($PassThru) { $defaults = 'LocalReplicaRole', 'Name as AvailabilityGroup', 'PrimaryReplicaServerName as PrimaryReplica', 'AutomatedBackupPreference', 'AvailabilityReplicas', 'AvailabilityDatabases', 'AvailabilityGroupListeners' return (Select-DefaultView -InputObject $ag -Property $defaults) diff --git a/public/Set-DbaNetworkCertificate.ps1 b/public/Set-DbaNetworkCertificate.ps1 index 3b56babf62..faea32361e 100644 --- a/public/Set-DbaNetworkCertificate.ps1 +++ b/public/Set-DbaNetworkCertificate.ps1 @@ -168,7 +168,11 @@ function Set-DbaNetworkCertificate { if ($null -ne $cert.PrivateKey) { $keyPath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\" - $keyName = $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName + $keyName = switch ($PSEdition) { + Core { $cert.PrivateKey.Key.UniqueName } + Desktop { $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName } + default { $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName } # for PowerShell v3 and earlier which does not return $PSEdition + } $keyFullPath = $keyPath + $keyName } else { $keyPath = $env:ProgramData + '\Microsoft\Crypto\Keys\' diff --git a/tests/Backup-DbaDatabase.Tests.ps1 b/tests/Backup-DbaDatabase.Tests.ps1 index e4b736b283..26889a9db6 100644 --- a/tests/Backup-DbaDatabase.Tests.ps1 +++ b/tests/Backup-DbaDatabase.Tests.ps1 @@ -5,7 +5,7 @@ Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan Describe "$CommandName Unit Tests" -Tag 'UnitTests' { Context "Validate parameters" { [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object { $_ -notin ('whatif', 'confirm') } - [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'ExcludeDatabase', 'Path', 'FilePath', 'ReplaceInName', 'CopyOnly', 'Type', 'InputObject', 'CreateFolder', 'FileCount', 'CompressBackup', 'Checksum', 'Verify', 'MaxTransferSize', 'BlockSize', 'BufferCount', 'AzureBaseUrl', 'AzureCredential', 'NoRecovery', 'BuildPath', 'WithFormat', 'Initialize', 'SkipTapeHeader', 'TimeStampFormat', 'IgnoreFileChecks', 'OutputScriptOnly', 'EnableException', 'EncryptionAlgorithm', 'EncryptionCertificate', 'IncrementPrefix', 'Description' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'ExcludeDatabase', 'Path', 'FilePath', 'ReplaceInName', 'NoAppendDbNameInPath', 'CopyOnly', 'Type', 'InputObject', 'CreateFolder', 'FileCount', 'CompressBackup', 'Checksum', 'Verify', 'MaxTransferSize', 'BlockSize', 'BufferCount', 'AzureBaseUrl', 'AzureCredential', 'NoRecovery', 'BuildPath', 'WithFormat', 'Initialize', 'SkipTapeHeader', 'TimeStampFormat', 'IgnoreFileChecks', 'OutputScriptOnly', 'EnableException', 'EncryptionAlgorithm', 'EncryptionCertificate', 'IncrementPrefix', 'Description' $knownParameters += [System.Management.Automation.PSCmdlet]::CommonParameters It "Should only contain our specific parameters" { (@(Compare-Object -ReferenceObject ($knownParameters | Where-Object { $_ }) -DifferenceObject $params).Count ) | Should Be 0 diff --git a/tests/New-DbaAvailabilityGroup.Tests.ps1 b/tests/New-DbaAvailabilityGroup.Tests.ps1 index 691713ef8d..7f218a624c 100644 --- a/tests/New-DbaAvailabilityGroup.Tests.ps1 +++ b/tests/New-DbaAvailabilityGroup.Tests.ps1 @@ -5,7 +5,7 @@ Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan Describe "$commandname Unit Tests" -Tag 'UnitTests' { Context "Validate parameters" { [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object { $_ -notin ('whatif', 'confirm') } - [object[]]$knownParameters = 'Primary', 'PrimarySqlCredential', 'Secondary', 'SecondarySqlCredential', 'Name', 'DtcSupport', 'ClusterType', 'AutomatedBackupPreference', 'FailureConditionLevel', 'HealthCheckTimeout', 'Basic', 'DatabaseHealthTrigger', 'Passthru', 'Database', 'SharedPath', 'UseLastBackup', 'Force', 'AvailabilityMode', 'FailoverMode', 'BackupPriority', 'ConnectionModeInPrimaryRole', 'ConnectionModeInSecondaryRole', 'SeedingMode', 'Endpoint', 'EndpointUrl', 'Certificate', 'ConfigureXESession', 'IPAddress', 'SubnetMask', 'Port', 'Dhcp', 'EnableException' + [object[]]$knownParameters = 'Primary', 'PrimarySqlCredential', 'Secondary', 'SecondarySqlCredential', 'Name', 'ReuseSystemDatabases', 'IsContained', 'DtcSupport', 'ClusterType', 'AutomatedBackupPreference', 'FailureConditionLevel', 'HealthCheckTimeout', 'Basic', 'DatabaseHealthTrigger', 'Passthru', 'Database', 'SharedPath', 'UseLastBackup', 'Force', 'AvailabilityMode', 'FailoverMode', 'BackupPriority', 'ConnectionModeInPrimaryRole', 'ConnectionModeInSecondaryRole', 'SeedingMode', 'Endpoint', 'EndpointUrl', 'Certificate', 'ConfigureXESession', 'IPAddress', 'SubnetMask', 'Port', 'Dhcp', 'EnableException' $knownParameters += [System.Management.Automation.PSCmdlet]::CommonParameters It "Should only contain our specific parameters" { (@(Compare-Object -ReferenceObject ($knownParameters | Where-Object { $_ }) -DifferenceObject $params).Count ) | Should Be 0