Skip to content

Commit 821987b

Browse files
Registered server commands - Leave the connection of the caller alone (#10577)
1 parent 17674dc commit 821987b

16 files changed

Lines changed: 354 additions & 18 deletions
Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
function Disconnect-Regserver ($Server) {
2+
<#
3+
.SYNOPSIS
4+
Internal function. Closes the connection behind a registered server object, but only if we opened it.
5+
6+
.DESCRIPTION
7+
Takes any object of the registered server tree - a store, a group or a registered server - and walks up
8+
to the RegisteredServersStore, which is the object that holds the connection.
9+
10+
The connection is only closed when Get-DbaRegServerStore opened it itself, which it records as
11+
IsNewConnection on the store. A connection that was handed in belongs to the caller, and closing it takes
12+
their session, their temp tables and their database context with it. See #10572.
13+
#>
214
$i = 0
3-
do { $server = $server.Parent }
4-
until ($null -ne $server.ServerConnection -or $i++ -gt 20)
5-
if ($server.ServerConnection) {
6-
$server.ServerConnection.Disconnect()
15+
while ($null -ne $Server -and $null -eq $Server.ServerConnection -and $i++ -le 20) {
16+
$Server = $Server.Parent
717
}
8-
}
18+
19+
if ($Server.ServerConnection -and $Server.IsNewConnection) {
20+
$Server.ServerConnection.Disconnect()
21+
}
22+
}

public/Add-DbaRegServerGroup.ps1

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,7 @@ function Add-DbaRegServerGroup {
151151
$newgroup.Alter()
152152

153153
Get-DbaRegServerGroup -SqlInstance $currentInstance -Group (Get-RegServerGroupReverseParse -object $newgroup)
154-
if ($currentInstance.ConnectionContext) {
155-
$currentInstance.ConnectionContext.Disconnect()
156-
}
154+
Disconnect-RegServer -Server $newgroup
157155
} catch {
158156
Stop-Function -Message "Failed to add $reggroup" -ErrorRecord $_ -Continue
159157
}

public/Get-DbaRegServer.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ function Get-DbaRegServer {
219219
}
220220
} else {
221221
$servers += ($serverstore.DatabaseEngineServerGroup.GetDescendantRegisteredServers())
222-
$serverstore.ServerConnection.Disconnect()
222+
Disconnect-RegServer -Server $serverstore
223223
}
224224

225225
# save the $serverstore for later usage

public/Get-DbaRegServerGroup.ps1

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,7 @@ function Get-DbaRegServerGroup {
177177
$groups = $serverstore.DatabaseEngineServerGroup.GetDescendantRegisteredServers().Parent | Where-Object Id -In $Id
178178
}
179179
}
180-
if ($serverstore.ServerConnection) {
181-
$serverstore.ServerConnection.Disconnect()
182-
}
180+
Disconnect-RegServer -Server $serverstore
183181

184182
foreach ($groupobject in $groups) {
185183
Add-Member -Force -InputObject $groupobject -MemberType NoteProperty -Name ComputerName -Value $serverstore.ComputerName

public/Get-DbaRegServerStore.ps1

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ function Get-DbaRegServerStore {
4848
- RegisteredServers: Collection of registered servers at the root level
4949
5050
Properties excluded from default display (internal/technical properties):
51-
- ServerConnection, DomainInstanceName, DomainName, Urn, Properties, Metadata, Parent, ConnectionContext, PropertyMetadataChanged, PropertyChanged, ParentServer
51+
- ServerConnection, DomainInstanceName, DomainName, Urn, Properties, Metadata, Parent, ConnectionContext, PropertyMetadataChanged, PropertyChanged, ParentServer, IsNewConnection
52+
53+
IsNewConnection records whether the connection behind the store was opened here or handed in by the caller. The registered server commands use it to decide whether they may close the connection when they are done.
5254
5355
All SMO RegisteredServersStore properties are accessible using Select-Object *, including the excluded properties if needed for advanced operations.
5456
@@ -72,8 +74,17 @@ function Get-DbaRegServerStore {
7274
)
7375
process {
7476
foreach ($instance in $SqlInstance) {
77+
# Connect-DbaInstance tells us whether it opened a connection for us. The whole registered server
78+
# family closes the connection through Disconnect-RegServer, which reads the answer back off the
79+
# store, so that only a connection this module opened is ever closed. See #10572.
80+
$isNewConnection = $false
81+
$splatConnect = @{
82+
SqlInstance = $instance
83+
SqlCredential = $SqlCredential
84+
IsNewConnectionReference = [ref]$isNewConnection
85+
}
7586
try {
76-
$server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential
87+
$server = Connect-DbaInstance @splatConnect
7788
} catch {
7889
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue
7990
}
@@ -88,7 +99,8 @@ function Get-DbaRegServerStore {
8899
Add-Member -Force -InputObject $store -MemberType NoteProperty -Name InstanceName -value $server.ServiceName
89100
Add-Member -Force -InputObject $store -MemberType NoteProperty -Name SqlInstance -value $server.DomainInstanceName
90101
Add-Member -Force -InputObject $store -MemberType NoteProperty -Name ParentServer -value $server
91-
Select-DefaultView -InputObject $store -ExcludeProperty ServerConnection, DomainInstanceName, DomainName, Urn, Properties, Metadata, Parent, ConnectionContext, PropertyMetadataChanged, PropertyChanged, ParentServer
102+
Add-Member -Force -InputObject $store -MemberType NoteProperty -Name IsNewConnection -value $isNewConnection
103+
Select-DefaultView -InputObject $store -ExcludeProperty ServerConnection, DomainInstanceName, DomainName, Urn, Properties, Metadata, Parent, ConnectionContext, PropertyMetadataChanged, PropertyChanged, ParentServer, IsNewConnection
92104
}
93105

94106
# Magic courtesy of Mathias Jessen and David Shifflet

public/Move-DbaRegServer.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ function Move-DbaRegServer {
126126
try {
127127
$null = $parentserver.ServerConnection.ExecuteNonQuery($regserver.ScriptMove($movetogroup).GetScript())
128128
Get-DbaRegServer -SqlInstance $server -Name $regserver.Name -ServerName $regserver.ServerName
129-
$parentserver.ServerConnection.Disconnect()
129+
Disconnect-RegServer -Server $parentserver
130130
} catch {
131131
Stop-Function -Message "Failed to move $($regserver.Name) to $Group on $($regserver.SqlInstance)" -ErrorRecord $_ -Continue
132132
}

public/Move-DbaRegServerGroup.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ function Move-DbaRegServerGroup {
130130
Write-Message -Level Verbose -Message "Executing $($regservergroup.ScriptMove($groupobject).GetScript())"
131131
$null = $parentserver.ServerConnection.ExecuteNonQuery($regservergroup.ScriptMove($groupobject).GetScript())
132132
Get-DbaRegServerGroup -SqlInstance $server -Group $newname
133-
$parentserver.ServerConnection.Disconnect()
133+
Disconnect-RegServer -Server $parentserver
134134
} catch {
135135
Stop-Function -Message "Failed to move $($regserver.Name) to $NewGroup on $($regserver.SqlInstance)" -ErrorRecord $_ -Continue
136136
}

public/Remove-DbaRegServerGroup.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ function Remove-DbaRegServerGroup {
115115
# try to avoid 'Collection was modified after the enumerator was instantiated' issue
116116
if ($regservergroup.ID) {
117117
$null = $parentserver.ServerConnection.ExecuteNonQuery($regservergroup.ScriptDrop().GetScript())
118-
$parentserver.ServerConnection.Disconnect()
118+
Disconnect-RegServer -Server $parentserver
119119
} else {
120120
$regservergroup.Drop()
121121
}

tests/Add-DbaRegServerGroup.Tests.ps1

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,39 @@ Describe $CommandName -Tag IntegrationTests {
108108
$results.SqlInstance | Should -Not -BeNullOrEmpty
109109
}
110110
}
111+
112+
Context "The connection of the caller is left alone (#10572)" {
113+
BeforeAll {
114+
# We want to run all commands in the BeforeAll block with EnableException to ensure that the test fails if the setup fails.
115+
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true
116+
117+
# Only a non-pooled connection can show this. SMO silently reopens a pooled connection, so the test
118+
# would pass even with the disconnect this is about.
119+
$callerServer = Connect-DbaInstance -SqlInstance $TestConfig.InstanceSingle -NonPooledConnection
120+
$null = $callerServer.ConnectionContext.ExecuteNonQuery("CREATE TABLE #dbatoolsci_marker (id INT)")
121+
122+
$callerGroupName = "dbatoolsci-caller-group"
123+
$callerResult = Add-DbaRegServerGroup -SqlInstance $callerServer -Name $callerGroupName
124+
125+
# We want to run all commands outside of the BeforeAll block without EnableException to be able to test for specific warnings.
126+
$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
127+
}
128+
129+
AfterAll {
130+
# We want to run all commands in the AfterAll block with EnableException to ensure that the test fails if the cleanup fails.
131+
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true
132+
133+
$null = $callerServer | Disconnect-DbaInstance
134+
135+
$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
136+
}
137+
138+
It "still adds the group" {
139+
$callerResult.Name | Should -Be $callerGroupName
140+
}
141+
142+
It "leaves the connection open, so the session survives" {
143+
{ $callerServer.ConnectionContext.ExecuteScalar("SELECT COUNT(*) FROM #dbatoolsci_marker") } | Should -Not -Throw
144+
}
145+
}
111146
}

tests/Get-DbaRegServer.Tests.ps1

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,44 @@ Describe $CommandName -Tag IntegrationTests {
197197

198198
# Property Comparisons will come later when we have the commands
199199
}
200+
201+
Context "The connection of the caller is left alone (#10572)" {
202+
BeforeAll {
203+
# We want to run all commands in the BeforeAll block with EnableException to ensure that the test fails if the setup fails.
204+
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true
205+
206+
# This context brings its own registered server, because the one of the context above is cleaned up
207+
# by the time this runs.
208+
$callerRegSrvName = "dbatoolsci-caller-server"
209+
$null = Add-DbaRegServer -SqlInstance $TestConfig.InstanceSingle -ServerName $callerRegSrvName -Name $callerRegSrvName
210+
211+
# Only a non-pooled connection can show this. SMO silently reopens a pooled connection, so the test
212+
# would pass even with the disconnect this is about.
213+
$callerServer = Connect-DbaInstance -SqlInstance $TestConfig.InstanceSingle -NonPooledConnection
214+
$null = $callerServer.ConnectionContext.ExecuteNonQuery("CREATE TABLE #dbatoolsci_marker (id INT)")
215+
216+
$callerResult = Get-DbaRegServer -SqlInstance $callerServer
217+
218+
# We want to run all commands outside of the BeforeAll block without EnableException to be able to test for specific warnings.
219+
$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
220+
}
221+
222+
AfterAll {
223+
# We want to run all commands in the AfterAll block with EnableException to ensure that the test fails if the cleanup fails.
224+
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true
225+
226+
$null = $callerServer | Disconnect-DbaInstance
227+
Get-DbaRegServer -SqlInstance $TestConfig.InstanceSingle -Name $callerRegSrvName | Remove-DbaRegServer -ErrorAction SilentlyContinue
228+
229+
$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
230+
}
231+
232+
It "still returns the registered servers" {
233+
$callerResult.Name | Should -Contain $callerRegSrvName
234+
}
235+
236+
It "leaves the connection open, so the session survives" {
237+
{ $callerServer.ConnectionContext.ExecuteScalar("SELECT COUNT(*) FROM #dbatoolsci_marker") } | Should -Not -Throw
238+
}
239+
}
200240
}

0 commit comments

Comments
 (0)