Skip to content

Commit c61aafb

Browse files
Export-DbaDacPackage - Add thread-safe database enumeration and SQL Server version check
- Replace SMO-based Get-DbaDatabase with T-SQL query using Invoke-DbaQuery - Fixes thread-safety issues in parallel PowerShell runspaces (100% vs 26.7% success) - Add SQL Server 2008 R2+ (Version 10.50) minimum version validation - Update documentation to reflect DAC Framework requirements Fixes #9980 (do Export-DbaDacPackage) Co-authored-by: Chrissy LeMaire <[email protected]>
1 parent a5e2fc0 commit c61aafb

File tree

1 file changed

+45
-7
lines changed

1 file changed

+45
-7
lines changed

public/Export-DbaDacPackage.ps1

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function Export-DbaDacPackage {
1313
For help with the extract action parameters and properties, refer to https://learn.microsoft.com/en-us/sql/tools/sqlpackage/sqlpackage-extract
1414
1515
.PARAMETER SqlInstance
16-
The target SQL Server instance or instances.
16+
The target SQL Server instance or instances. Must be SQL Server 2008 R2 or higher (DAC Framework minimum version 10.50).
1717
1818
.PARAMETER SqlCredential
1919
Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential).
@@ -73,6 +73,8 @@ function Export-DbaDacPackage {
7373
Copyright: (c) 2018 by dbatools, licensed under MIT
7474
License: MIT https://opensource.org/licenses/MIT
7575
76+
Minimum SQL Server Version: SQL Server 2008 R2 (10.50) - DAC Framework requirement
77+
7678
.LINK
7779
https://dbatools.io/Export-DbaDacPackage
7880
@@ -199,16 +201,52 @@ function Export-DbaDacPackage {
199201
} catch {
200202
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue
201203
}
204+
205+
# Check SQL Server version - DAC Framework requires SQL Server 2008 R2+ (Version 10.50+)
206+
if ($server.VersionMajor -lt 10 -or ($server.VersionMajor -eq 10 -and $server.VersionMinor -lt 50)) {
207+
Stop-Function -Message "Export-DbaDacPackage requires SQL Server 2008 R2 or higher (DAC Framework minimum version 10.50). Server $instance is version $($server.VersionString)." -Target $instance -Continue
208+
}
209+
210+
# ============================================================
211+
# THREAD-SAFE DATABASE ENUMERATION
212+
# Use Invoke-DbaQuery instead of Get-DbaDatabase to avoid SMO thread-safety issues
213+
# Get-DbaDatabase uses $server.Databases enumeration which is NOT thread-safe in parallel runspaces
214+
# Note: Export-DbaDacPackage requires SQL Server 2008 R2+ (DAC Framework minimum version)
215+
# ============================================================
216+
217+
# Build query to enumerate databases (equivalent to Get-DbaDatabase -OnlyAccessible -ExcludeSystem)
218+
$query = @"
219+
SELECT name
220+
FROM sys.databases
221+
WHERE database_id > 4 -- Exclude system databases (master=1, tempdb=2, model=3, msdb=4)
222+
AND state = 0 -- Only ONLINE databases (OnlyAccessible equivalent)
223+
"@
224+
225+
# Add ExcludeDatabase filter if specified
226+
if ($ExcludeDatabase) {
227+
$excludedDatabaseList = $ExcludeDatabase | ForEach-Object { "'$_'" }
228+
$query += "`n AND name NOT IN ($($excludedDatabaseList -join ","))"
229+
}
230+
231+
$query += "`nORDER BY name"
232+
233+
Write-Message -Level Verbose -Message "Executing query: $query"
234+
$dbNames = Invoke-DbaQuery -SqlInstance $server -Query $query -EnableException | Select-Object -ExpandProperty name
235+
236+
# Apply Database filter if specified
202237
if ($Database) {
203-
$dbs = Get-DbaDatabase -SqlInstance $server -OnlyAccessible -Database $Database -ExcludeDatabase $ExcludeDatabase
204-
} else {
205-
# all user databases by default
206-
$dbs = Get-DbaDatabase -SqlInstance $server -OnlyAccessible -ExcludeSystem -ExcludeDatabase $ExcludeDatabase
238+
$dbNames = $dbNames | Where-Object { $_ -in $Database }
207239
}
208-
if (-not $dbs) {
209-
Stop-Function -Message "Databases not found on $instance"-Target $instance -Continue
240+
241+
if (-not $dbNames) {
242+
Stop-Function -Message "Databases not found on $instance" -Target $instance -Continue
210243
}
211244

245+
Write-Message -Level Verbose -Message "Found $($dbNames.Count) databases: $($dbNames -join ", ")"
246+
247+
# Convert database names to objects for compatibility with rest of function
248+
$dbs = $dbNames | ForEach-Object { [PSCustomObject]@{ name = $_ } }
249+
212250
foreach ($db in $dbs) {
213251
$resultstime = [diagnostics.stopwatch]::StartNew()
214252
$dbName = $db.name

0 commit comments

Comments
 (0)