-
-
Notifications
You must be signed in to change notification settings - Fork 785
/
New-DbaReplSubscription.ps1
300 lines (231 loc) 路 16.7 KB
/
New-DbaReplSubscription.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
function New-DbaReplSubscription {
<#
.SYNOPSIS
Creates a subscription for the database on the target SQL instances.
.DESCRIPTION
Creates a subscription for the database on the target SQL instances.
.PARAMETER SqlInstance
The target publishing SQL Server instance or instances.
.PARAMETER SqlCredential
Login to the target publishing instance using alternative credentials. Accepts PowerShell credentials (Get-Credential).
Windows Authentication, SQL Server Authentication, Active Directory - Password, and Active Directory - Integrated are all supported.
For MFA support, please use Connect-DbaInstance.
.PARAMETER Database
The database on the publisher that will be replicated.
.PARAMETER SubscriberSqlInstance
The subscriber SQL instance.
.PARAMETER SubscriberSqlCredential
Login to the subscriber instance using alternative credentials. Accepts PowerShell credentials (Get-Credential).
Windows Authentication, SQL Server Authentication, Active Directory - Password, and Active Directory - Integrated are all supported.
For MFA support, please use Connect-DbaInstance.
.PARAMETER SubscriptionDatabase
The database on the subscriber that will be the target of the replicated data.
.PARAMETER PublicationName
The name of the replication publication
.PARAMETER SubscriptionSqlCredential
Credential object that will be saved as the 'subscriber credential' in the subscription properties.
.PARAMETER Type
The flavour of the subscription. Push or Pull.
.PARAMETER EnableException
By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message.
This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting.
Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch.
.PARAMETER WhatIf
If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
.PARAMETER Confirm
If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
.NOTES
Tags: repl, Replication
Author: Jess Pomfret (@jpomfret), jesspomfret.com
Website: https://dbatools.io
Copyright: (c) 2023 by dbatools, licensed under MIT
License: MIT https://opensource.org/licenses/MIT
.LINK
https://dbatools.io/New-DbaReplSubscription
.EXAMPLE
PS C:\> New-DbaReplSubscription -SqlInstance sql2017 -Database pubs -SubscriberSqlInstance sql2019 -SubscriptionDatabase pubs -PublicationName testPub -Type Push
Creates a push subscription from sql2017 to sql2019 for the pubs database.
.EXAMPLE
PS C:\> New-DbaReplSubscription -SqlInstance sql2017 -Database pubs -SubscriberSqlInstance sql2019 -SubscriptionDatabase pubs -PublicationName testPub -Type Pull
Creates a pull subscription from sql2017 to sql2019 for the pubs database.
#>
[CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')]
param (
[Parameter(Mandatory, ValueFromPipeline)]
[DbaInstanceParameter]$SqlInstance,
[PSCredential]$SqlCredential,
[String]$Database,
[Parameter(Mandatory)]
[DbaInstanceParameter[]]$SubscriberSqlInstance,
[PSCredential]$SubscriberSqlCredential,
[String]$SubscriptionDatabase,
[Parameter(Mandatory)]
[String]$PublicationName,
[PSCredential]
$SubscriptionSqlCredential,
[Parameter(Mandatory)]
[ValidateSet("Push", "Pull")]
[String]$Type,
[Switch]$EnableException
)
begin {
Write-Message -Level Verbose -Message "Connecting to publisher: $SqlInstance"
# connect to publisher and get the publication
try {
$pubReplServer = Get-DbaReplServer -SqlInstance $SqlInstance -SqlCredential $SqlCredential -EnableException:$EnableException
} catch {
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $SqlInstance -Continue
}
try {
$pub = Get-DbaReplPublication -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Name $PublicationName -EnableException:$EnableException
} catch {
Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $SqlInstance) -ErrorRecord $_ -Target $SqlInstance -Continue
}
}
process {
# for each subscription SqlInstance we need to create a subscription
foreach ($instance in $SubscriberSqlInstance) {
try {
$subReplServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -EnableException:$EnableException
if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -EnableException:$EnableException)) {
Write-Message -Level Verbose -Message "Subscription database $SubscriptionDatabase not found on $instance - will create it - but you should check the settings!"
if ($PSCmdlet.ShouldProcess($instance, "Creating subscription database")) {
$newSubDb = @{
SqlInstance = $instance
SqlCredential = $SubscriberSqlCredential
Name = $SubscriptionDatabase
EnableException = $EnableException
}
$null = New-DbaDatabase @newSubDb
}
}
} catch {
Stop-Function -Message ("Couldn't create the subscription database {0}.{1}" -f $instance, $SubscriptionDatabase) -ErrorRecord $_ -Target $instance -Continue
}
try {
Write-Message -Level Verbose -Message "Creating subscription on $instance"
if ($PSCmdlet.ShouldProcess($instance, "Creating subscription on $instance")) {
# check if needed schemas exist
foreach ($schema in $pub.articles.DestinationObjectOwner) {
if ($schema -ne 'dbo' -and -not (Get-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema)) {
Write-Message -Level Verbose -Message "Subscription database $SubscriptionDatabase does not contain the $schema schema on $instance - will create it!"
$null = New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema -EnableException
}
}
if ($pub.Type -in ('Transactional', 'Snapshot')) {
$transPub = New-Object Microsoft.SqlServer.Replication.TransPublication
$transPub.ConnectionContext = $pubReplServer.ConnectionContext
$transPub.DatabaseName = $Database
$transPub.Name = $PublicationName
# if LoadProperties returns then the publication was found
if ( $transPub.LoadProperties() ) {
if ($type -eq 'Push') {
# Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPush.
if (($transPub.Attributes -band [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowPush) -ne [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowPush) {
# # Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPush.
# if ($transPub.Attributes -band 'AllowPush' -eq 'None' ) {
# If the result is None, set Attributes to the result of a bitwise logical OR (| in Visual C# and Or in Visual Basic) between Attributes and AllowPush.
$transPub.Attributes = $transPub.Attributes -bor 'AllowPush'
# Then, call CommitPropertyChanges to enable push subscriptions.
$transPub.CommitPropertyChanges()
}
} else {
#TODO: Fix pull subscriptions in New-DbaReplSubscription command - this still creates a PUSH
# Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull.
if (($transPub.Attributes -band [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowPull) -ne [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowPull) {
# If the result is None, set Attributes to the result of a bitwise logical OR (| in Visual C# and Or in Visual Basic) between Attributes and AllowPull.
$transPub.Attributes = $transPub.Attributes -bor 'AllowPull'
# Then, call CommitPropertyChanges to enable pull subscriptions.
$transPub.CommitPropertyChanges()
}
}
# create the subscription
$transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription
$transSub.ConnectionContext = $pubReplServer.ConnectionContext
$transSub.SubscriptionDBName = $SubscriptionDatabase
$transSub.SubscriberName = $instance
$transSub.DatabaseName = $Database
$transSub.PublicationName = $PublicationName
#TODO:
<#
The Login and Password fields of SynchronizationAgentProcessSecurity to provide the credentials for the
Microsoft Windows account under which the Distribution Agent runs at the Distributor. This account is used to make local connections to the Distributor and to make
remote connections by using Windows Authentication.
Note
Setting SynchronizationAgentProcessSecurity is not required when the subscription is created by a member of the sysadmin fixed server role, but we recommend it.
In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent security model.
(Optional) A value of true (the default) for CreateSyncAgentByDefault to create an agent job that is used to synchronize the subscription.
If you specify false, the subscription can only be synchronized programmatically.
#>
if ($SubscriptionSqlCredential) {
$transSub.SubscriberSecurity.WindowsAuthentication = $false
$transSub.SubscriberSecurity.SqlStandardLogin = $SubscriptionSqlCredential.UserName
$transSub.SubscriberSecurity.SecureSqlStandardPassword = $SubscriptionSqlCredential.Password
}
$transSub.Create()
} else {
Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -Target $instance -Continue
}
} elseif ($pub.Type -eq 'Merge') {
$mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication
$mergePub.ConnectionContext = $pubReplServer.ConnectionContext
$mergePub.DatabaseName = $Database
$mergePub.Name = $PublicationName
if ( $mergePub.LoadProperties() ) {
if ($type = 'Push') {
# Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPush.
if ($mergePub.Attributes -band 'AllowPush' -eq 'None' ) {
# If the result is None, set Attributes to the result of a bitwise logical OR (| in Visual C# and Or in Visual Basic) between Attributes and AllowPush.
$mergePub.Attributes = $mergePub.Attributes -bor 'AllowPush'
# Then, call CommitPropertyChanges to enable push subscriptions.
$mergePub.CommitPropertyChanges()
}
} else {
# Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull.
if ($mergePub.Attributes -band 'AllowPull' -eq 'None' ) {
# If the result is None, set Attributes to the result of a bitwise logical OR (| in Visual C# and Or in Visual Basic) between Attributes and AllowPull.
$mergePub.Attributes = $mergePub.Attributes -bor 'AllowPull'
# Then, call CommitPropertyChanges to enable pull subscriptions.
$mergePub.CommitPropertyChanges()
}
}
# create the subscription
if ($type = 'Push') {
$mergeSub = New-Object Microsoft.SqlServer.Replication.MergeSubscription
} else {
$mergeSub = New-Object Microsoft.SqlServer.Replication.MergePullSubscription
}
$mergeSub.ConnectionContext = $pubReplServer.ConnectionContext
$mergeSub.SubscriptionDBName = $SubscriptionDatabase
$mergeSub.SubscriberName = $instance
$mergeSub.DatabaseName = $Database
$mergeSub.PublicationName = $PublicationName
#TODO:
<#
The Login and Password fields of SynchronizationAgentProcessSecurity to provide the credentials for the
Microsoft Windows account under which the Distribution Agent runs at the Distributor. This account is used to make local connections to the Distributor and to make
remote connections by using Windows Authentication.
Note
Setting SynchronizationAgentProcessSecurity is not required when the subscription is created by a member of the sysadmin fixed server role, but we recommend it.
In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent security model.
(Optional) A value of true (the default) for CreateSyncAgentByDefault to create an agent job that is used to synchronize the subscription.
If you specify false, the subscription can only be synchronized programmatically.
#>
if ($SubscriptionSqlCredential) {
$mergeSub.SubscriberSecurity.WindowsAuthentication = $false
$mergeSub.SubscriberSecurity.SqlStandardLogin = $SubscriptionSqlCredential.UserName
$mergeSub.SubscriberSecurity.SecureSqlStandardPassword = $SubscriptionSqlCredential.Password
}
$mergeSub.Create()
}
} else {
Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -Target $instance -Continue
}
}
} catch {
Stop-Function -Message ("Unable to create subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue
}
#TODO: call Get-DbaReplSubscription when it's done
}
}
}