From d6f902a4e94c530c8f8e9f9b11084ca3b3b4c9ee Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 11:51:23 +0000 Subject: [PATCH 001/226] repl testing --- ReplicationCommands.md | 75 ++++++++++++++++++++++++++++++++ testing.ps1 | 98 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 ReplicationCommands.md create mode 100644 testing.ps1 diff --git a/ReplicationCommands.md b/ReplicationCommands.md new file mode 100644 index 0000000000..adf1bc1ee2 --- /dev/null +++ b/ReplicationCommands.md @@ -0,0 +1,75 @@ +# Replication Work + +## Commands to Create + +List to keep track of commands we need and who's working on them, most of the names are being pulled from thin air so if you don't agree with new vs add they can all be discussed\changed. + +Meaning of the checkmarks: +- [X] Done +- [ ] not done +- [-] in progress by... + + +### General + +- [X] Get-DbaReplServer +- [X] Export-DbaReplServerSetting + +### Distribution + +- [X] Get-DbaReplDistributor +- [X] Disable-DbaReplDistributor +- [X] Enable-DbaReplDistributor +- [ ] Set-DbaReplDistributor (updating properties?) + +### Publishing + +- [-] Get-DbaReplPublisher - Mikey +- [ ] Set-DbaReplPublisher (updating properties?) +- [X] Get-DbaReplPublication -- #TODO: Exists but needs some love +- [X] Disable-DbaReplPublishing +- [X] Enable-DbaReplPublishing +- [-] New-DbaReplPublication - Jess +- [ ] Remove-DbaReplPublication + +### Articles +- [-] Add-DbaReplArticle - Jess +- [ ] Remove-DbaReplArticle +- [-] Get-DbaReplArticle - Cláudio +- [ ] Set-DbaReplArticle + +### Columns +- [-] Get-DbaReplArticleColumn +- [ ] Add-DbaReplArticleColumn +- [ ] Remove-DbaReplArticleColumn + +### Subscriptions +- [ ] Get-DbaDbSubscription +- [ ] New-DbaDbSubscription +- [ ] Set-DbaReplDistributor (update properties) + +### Monitoring\Troubleshooting + +- [X] Test-DbaReplLatency +- [ ] Run-DbaReplSnapshotAgent ? +- [ ] Get-DbaReplSnapshotAgentStatus +- [ ] Get-DbaReplLogReaderAgentStatus +- [ ] Test-DbaReplSnapFolder - similiar to Test-DbaPath but from replication service account perspective or something similiar to check If the share (UNC or Local) is accesable from both, publisher and subscriber side + +## How to run pester tests locally + +```PowerShell + # run this against fresh containers to setup replication as it would be in gh action + #.\bin\Replication\Invoke-ReplicationSetup.ps1 + # commented out + + #run the tests -Show All will caus + invoke-pester .\tests\gh-actions-repl.ps1 + +``` + +## Testing + +Some additional scenarios for us to test commands against. + +- how the commands work when we have a "third site" involved , i mean if we have the distribution db not on the Publication-Server and not on the Subscriber-Server (thats not so common, but it is a thing imo) - I saw some unusual behaviour with replcation commands when the setup is with a seperate Distribution-DB-Server. diff --git a/testing.ps1 b/testing.ps1 new file mode 100644 index 0000000000..6c07458884 --- /dev/null +++ b/testing.ps1 @@ -0,0 +1,98 @@ +############################## +# create docker environment +############################## +# create a shared network +docker network create localnet + +# Expose engines and setup shared path for migrations +docker run -p 2500:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance +docker run -p 2600:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + +# create the repl folder +docker exec mssql1 mkdir /var/opt/mssql/ReplData + +# also need these folders for setting up replication +docker exec mssql1 mkdir /shared/data /shared/repldata + +############################## +# import our working module +############################## +Import-Module .\dbatools.psd1 -Force +Get-module dbatools* + +############################## +# create alias +############################## +New-DbaClientAlias -ServerName 'localhost,2500' -Alias mssql1 +New-DbaClientAlias -ServerName 'localhost,2600' -Alias mssql2 + + +############################## +# save the password for ease +############################## +$securePassword = ('dbatools.IO' | ConvertTo-SecureString -AsPlainText -Force) +$credential = New-Object System.Management.Automation.PSCredential('sqladmin', $securePassword) + +$PSDefaultParameterValues = @{ + "*:SqlCredential" = $credential + "*:DestinationCredential" = $credential + "*:DestinationSqlCredential" = $credential + "*:SourceSqlCredential" = $credential +} + + +############################## +# change silly defaults +############################## +Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig #-Scope SystemMandatory +Set-DbatoolsConfig -FullName sql.connection.EncryptConnection -Value optional -PassThru | Register-DbatoolsConfig #-Scope SystemMandatory + +############################## +# test things :) +############################## + + +## already existing commands +<# +Get-DbaReplServer +Get-DbaReplDistributor +Get-DbaReplPublication +Test-DbaReplLatency + +Export-DbaReplServerSetting +#> + +$sqlInstance = Connect-DbaInstance -SqlInstance mssql1 + +Get-DbaReplServer -SqlInstance mssql1 +Get-DbaReplDistributor -SqlInstance mssql1 +Get-DbaReplPublication -SqlInstance mssql1 + +# enable\disable distribution +Enable-DbaReplDistributor -SqlInstance mssql1 +Disable-DbaReplDistributor -SqlInstance mssql1 + +# enable publishing +Enable-DbaReplPublishing -SqlInstance mssql1 +Disable-DbaReplPublishing -SqlInstance mssql1 + +# add a publication +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Type = 'Transactional' + +} +New-DbaReplPublication @pub + +# add an article + +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'publishers' + Filter = "where city = 'seattle'" ## not working? +} +Add-DbaReplArticle @article \ No newline at end of file From b18ea53185f0c19c9655d1451546d628653a45c7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 11:51:39 +0000 Subject: [PATCH 002/226] tests --- .github/workflows/integration-tests-repl.yml | 110 ++++++++++++ bin/Replication/Invoke-ReplicationSetup.ps1 | 13 ++ bin/Replication/setup-test-replication.sql | 40 +++++ ...s.ps1 => Get-DbaReplDistributor.Tests.ps1} | 2 +- tests/Get-DbaReplPublication.Tests.ps1 | 80 +++++++++ tests/Get-DbaReplServer.Tests.ps1 | 19 ++ tests/Test-DbaReplLatency.Tests.ps1 | 14 ++ tests/gh-actions-repl.ps1 | 170 ++++++++++++++++++ 8 files changed, 447 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/integration-tests-repl.yml create mode 100644 bin/Replication/Invoke-ReplicationSetup.ps1 create mode 100644 bin/Replication/setup-test-replication.sql rename tests/{Get-DbaRepDistributor.Tests.ps1 => Get-DbaReplDistributor.Tests.ps1} (93%) create mode 100644 tests/Get-DbaReplPublication.Tests.ps1 create mode 100644 tests/Get-DbaReplServer.Tests.ps1 create mode 100644 tests/Test-DbaReplLatency.Tests.ps1 create mode 100644 tests/gh-actions-repl.ps1 diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml new file mode 100644 index 0000000000..a64a6c1da9 --- /dev/null +++ b/.github/workflows/integration-tests-repl.yml @@ -0,0 +1,110 @@ +name: Run Cross Platform Tests - repl +on: [push] +defaults: + run: + shell: pwsh +jobs: + linux-tests: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + steps: + - uses: actions/checkout@v3 + + - name: Install and cache PowerShell modules + uses: potatoqualitee/psmodulecache@v5.1 + with: + modules-to-cache: dbatools-core-library:2022.10.27 + modules-to-cache-prerelease: dbatools-library:2022.10.28-preview + + - name: Install and cache dbatools-library + run: | + Import-Module ./dbatools.psd1 -Force + Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register + Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -Register + Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + + - name: Setup docker images + run: | + # create a shared network + docker network create localnet + # Expose engine and endpoint then setup a shared path for migrations + docker run -p 1433:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance + # Expose second engine and endpoint on different port + docker run -p 14333:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + + - name: 👥 Clone appveyor repo + working-directory: /tmp + run: | + gh repo clone sqlcollaborative/appveyor-lab + + - name: Setup Replication + run: | + Import-Module ./dbatools.psd1 -Force + # need some folders for our repl stuff + docker exec mssql1 mkdir /shared/data /shared/repldata /var/opt/mssql/ReplData + # setup distribution, 1xPublication with 1xSubscription + # $null = .\bin\Replication\Invoke-ReplicationSetup.ps1 + + - name: Run tests + run: | + Import-Module ./dbatools.psd1 -Force + Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning + Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru + + + +# windows-tests: +# runs-on: windows-latest +# env: +# GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} +# +# steps: +# - name: Checkout dbatools repo +# uses: actions/checkout@v3 +# +# - name: Install and cache PowerShell modules +# uses: potatoqualitee/psmodulecache@v5.1 +# with: +# shell: powershell, pwsh +# modules-to-cache: dbatools-core-library:2022.10.27 +# modules-to-cache-prerelease: dbatools-library:2022.10.28-preview +# +# - name: Install SQL Server localdb +# uses: potatoqualitee/mssqlsuite@v1.3 +# with: +# install: localdb +# +# - name: Connect to localdb instance powershell +# shell: powershell +# run: | +# Import-Module ./dbatools -Force +# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" +# +# - name: Connect to localdb instance pwsh +# shell: pwsh +# run: | +# Import-Module ./dbatools -Force +# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" +# +# - name: Run pwsh tests +# env: +# TENANTID: ${{secrets.TENANTID}} +# CLIENTID: ${{secrets.CLIENTID}} +# CLIENTSECRET: ${{secrets.CLIENTSECRET}} +# shell: pwsh +# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru +# +# - name: Run PowerShell tests +# env: +# TENANTID: ${{secrets.TENANTID}} +# CLIENTID: ${{secrets.CLIENTID}} +# CLIENTSECRET: ${{secrets.CLIENTSECRET}} +# shell: powershell +# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru \ No newline at end of file diff --git a/bin/Replication/Invoke-ReplicationSetup.ps1 b/bin/Replication/Invoke-ReplicationSetup.ps1 new file mode 100644 index 0000000000..0636a538b9 --- /dev/null +++ b/bin/Replication/Invoke-ReplicationSetup.ps1 @@ -0,0 +1,13 @@ +$password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force +$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password + +$PSDefaultParameterValues["*:SqlInstance"] = "localhost" +$PSDefaultParameterValues["*:SqlCredential"] = $cred +$PSDefaultParameterValues["*:Confirm"] = $false +$PSDefaultParameterValues["*:SharedPath"] = "/shared" +##$PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" +#$global:ProgressPreference = "SilentlyContinue" + + + +Invoke-DbaQuery -File .\bin\Replication\setup-test-replication.sql \ No newline at end of file diff --git a/bin/Replication/setup-test-replication.sql b/bin/Replication/setup-test-replication.sql new file mode 100644 index 0000000000..9ac6fcb442 --- /dev/null +++ b/bin/Replication/setup-test-replication.sql @@ -0,0 +1,40 @@ +-- Set up distribution + use master + exec sp_adddistributor @distributor = N'mssql1', @password = N'dbatools.IO' + GO + exec sp_adddistributiondb @database = N'distribution', @data_folder = N'/shared/data/', @log_folder = N'/shared/data/', @log_file_size = 2, @min_distretention = 0, @max_distretention = 72, @history_retention = 48, @deletebatchsize_xact = 5000, @deletebatchsize_cmd = 2000, @security_mode = 1 + GO + + use [distribution] + if (not exists (select * from sysobjects where name = 'UIProperties' and type = 'U ')) + create table UIProperties(id int) + if (exists (select * from ::fn_listextendedproperty('SnapshotFolder', 'user', 'dbo', 'table', 'UIProperties', null, null))) + EXEC sp_updateextendedproperty N'SnapshotFolder', N'/shared/ReplData', 'user', dbo, 'table', 'UIProperties' + else + EXEC sp_addextendedproperty N'SnapshotFolder', N'/shared/ReplData', 'user', dbo, 'table', 'UIProperties' + GO + + exec sp_adddistpublisher @publisher = N'mssql1', @distribution_db = N'distribution', @security_mode = 0, @login = N'sqladmin', @password = N'', @working_directory = N'/shared/ReplData', @trusted = N'false', @thirdparty_flag = 0, @publisher_type = N'MSSQLSERVER' + GO + +-- set up publication + use [pubs] + exec sp_replicationdboption @dbname = N'pubs', @optname = N'publish', @value = N'true' + GO + -- Adding the transactional publication + use [pubs] + exec sp_addpublication @publication = N'DMMRepl', @description = N'Transactional publication of database ''pubs'' from Publisher ''mssql1''.', @sync_method = N'concurrent', @retention = 0, @allow_push = N'true', @allow_pull = N'true', @allow_anonymous = N'true', @enabled_for_internet = N'false', @snapshot_in_defaultfolder = N'true', @compress_snapshot = N'false', @ftp_port = 21, @allow_subscription_copy = N'false', @add_to_active_directory = N'false', @repl_freq = N'continuous', @status = N'active', @independent_agent = N'true', @immediate_sync = N'true', @allow_sync_tran = N'false', @allow_queued_tran = N'false', @allow_dts = N'false', @replicate_ddl = 1, @allow_initialize_from_backup = N'false', @enabled_for_p2p = N'false', @enabled_for_het_sub = N'false' + exec sp_addpublication_snapshot @publication = N'DMMRepl', @frequency_type = 1, @frequency_interval = 1, @frequency_relative_interval = 1, @frequency_recurrence_factor = 0, @frequency_subday = 8, @frequency_subday_interval = 1, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 0, @active_end_date = 0, @job_login = null, @job_password = null, @publisher_security_mode = 1 + exec sp_addarticle @publication = N'DMMRepl', @article = N'authors', @source_owner = N'dbo', @source_object = N'authors', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'authors', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dboauthors', @del_cmd = N'CALL sp_MSdel_dboauthors', @upd_cmd = N'SCALL sp_MSupd_dboauthors' + exec sp_addarticle @publication = N'DMMRepl', @article = N'employee', @source_owner = N'dbo', @source_object = N'employee', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'employee', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dboemployee', @del_cmd = N'CALL sp_MSdel_dboemployee', @upd_cmd = N'SCALL sp_MSupd_dboemployee' + exec sp_addarticle @publication = N'DMMRepl', @article = N'jobs', @source_owner = N'dbo', @source_object = N'jobs', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'jobs', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbojobs', @del_cmd = N'CALL sp_MSdel_dbojobs', @upd_cmd = N'SCALL sp_MSupd_dbojobs' + exec sp_addarticle @publication = N'DMMRepl', @article = N'pub_info', @source_owner = N'dbo', @source_object = N'pub_info', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'pub_info', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbopub_info', @del_cmd = N'CALL sp_MSdel_dbopub_info', @upd_cmd = N'SCALL sp_MSupd_dbopub_info' + exec sp_addarticle @publication = N'DMMRepl', @article = N'publishers', @source_owner = N'dbo', @source_object = N'publishers', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'publishers', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbopublishers', @del_cmd = N'CALL sp_MSdel_dbopublishers', @upd_cmd = N'SCALL sp_MSupd_dbopublishers' + GO + +-- add a subscription + use [pubs] + exec sp_addsubscription @publication = N'DMMRepl', @subscriber = N'mssql2', @destination_db = N'pubs', @subscription_type = N'Push', @sync_type = N'automatic', @article = N'all', @update_mode = N'read only', @subscriber_type = 0 + exec sp_addpushsubscription_agent @publication = N'DMMRepl', @subscriber = N'mssql2', @subscriber_db = N'pubs', @job_login = null, @job_password = null, @subscriber_security_mode = 0, @subscriber_login = N'sqladmin', @subscriber_password = 'dbatools.IO', @frequency_type = 64, @frequency_interval = 0, @frequency_relative_interval = 0, @frequency_recurrence_factor = 0, @frequency_subday = 0, @frequency_subday_interval = 0, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 20221101, @active_end_date = 99991231, @enabled_for_syncmgr = N'False', @dts_package_location = N'Distributor' + GO + diff --git a/tests/Get-DbaRepDistributor.Tests.ps1 b/tests/Get-DbaReplDistributor.Tests.ps1 similarity index 93% rename from tests/Get-DbaRepDistributor.Tests.ps1 rename to tests/Get-DbaReplDistributor.Tests.ps1 index 2d4231cb8a..dded7c7e9d 100644 --- a/tests/Get-DbaRepDistributor.Tests.ps1 +++ b/tests/Get-DbaReplDistributor.Tests.ps1 @@ -15,7 +15,7 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { Describe "$CommandName Integration Tests" -Tags "IntegrationTests" { Context "ensuring accuracy of results" { - $results = Get-DbaRepDistributor -SqlInstance $script:instance1 + $results = Get-DbaReplDistributor -SqlInstance $script:instance1 It "accurately reports that the distributor is not installed" { $results.DistributorInstalled | Should Be $false } diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 new file mode 100644 index 0000000000..3e1a3096e5 --- /dev/null +++ b/tests/Get-DbaReplPublication.Tests.ps1 @@ -0,0 +1,80 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +Describe "$commandname Unit Tests" -Tag 'UnitTests' { + Context "Validate parameters" { + [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'PublicationType', '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 + } + } + + InModuleScope dbatools { + Context "Code Validation" { + + Mock Connect-ReplicationDB -MockWith { + [object]@{ + Name = 'TestDB' + TransPublications = @{ + Name = 'TestDB_pub' + Type = 'Transactional' + } + MergePublications = @{} + } + } + + Mock Connect-DbaInstance -MockWith { + [object]@{ + Name = "MockServerName" + ComputerName = 'MockComputerName' + Databases = @{ + Name = 'TestDB' + #state + #status + ID = 5 + ReplicationOptions = 'Published' + } + ConnectionContext = @{ + SqlConnectionObject = 'FakeConnectionContext' + } + } + } + + It "Honors the SQLInstance parameter" { + $Results = Get-DbaReplPublication -SqlInstance MockServerName + $Results.Server | Should Be "MockServerName" + } + + It "Honors the Database parameter" { + $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB + $Results.Database | Should Be "TestDB" + } + + It "Honors the PublicationType parameter" { + + Mock Connect-ReplicationDB -MockWith { + [object]@{ + Name = 'TestDB' + TransPublications = @{ + Name = 'TestDB_pub' + Type = 'Snapshot' + } + MergePublications = @{} + } + } + + $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB -PublicationType Snapshot + $Results.PublicationType | Should Be "Snapshot" + } + + It "Stops if validate set for PublicationType is not met" { + + { Get-DbaReplPublication -SqlInstance MockServerName -PublicationType NotAPubType } | should Throw + + } + } + } +} \ No newline at end of file diff --git a/tests/Get-DbaReplServer.Tests.ps1 b/tests/Get-DbaReplServer.Tests.ps1 new file mode 100644 index 0000000000..43b16dc2ce --- /dev/null +++ b/tests/Get-DbaReplServer.Tests.ps1 @@ -0,0 +1,19 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +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', '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 + } + } +} +<# + Integration test should appear below and are custom to the command you are writing. + Read https://github.com/dataplat/dbatools/blob/development/contributing.md#tests + for more guidence. +#> \ No newline at end of file diff --git a/tests/Test-DbaReplLatency.Tests.ps1 b/tests/Test-DbaReplLatency.Tests.ps1 new file mode 100644 index 0000000000..de02df1513 --- /dev/null +++ b/tests/Test-DbaReplLatency.Tests.ps1 @@ -0,0 +1,14 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +Describe "$commandname Unit Tests" -Tag 'UnitTests' { + Context "Validate parameters" { + [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'PublicationName', 'TimeToLive', 'RetainToken', 'DisplayTokenHistory', '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 + } + } +} \ No newline at end of file diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 new file mode 100644 index 0000000000..12b63b6ea3 --- /dev/null +++ b/tests/gh-actions-repl.ps1 @@ -0,0 +1,170 @@ +Describe "Integration Tests" -Tag "IntegrationTests" { + BeforeAll { + $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force + $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password + + $PSDefaultParameterValues["*:SqlInstance"] = "localhost" + $PSDefaultParameterValues["*:SqlCredential"] = $cred + $PSDefaultParameterValues["*:Confirm"] = $false + $PSDefaultParameterValues["*:SharedPath"] = "/shared" + $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" + $global:ProgressPreference = "SilentlyContinue" + + #$null = Get-XPlatVariable | Where-Object { $PSItem -notmatch "Copy-", "Migration" } | Sort-Object + # load dbatools-lib + #Import-Module dbatools-core-library + Import-Module ./dbatools.psd1 -Force + } + + Context "Get-DbaReplDistributor works" { + BeforeAll { + + # if distribution is enabled, disable it & enable it with defaults + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + Enable-DbaReplDistributor + } + + It "gets a distributor" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution database name is correct" { + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + } + } + + Context "Enable-DbaReplDistributor works" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + + It "distribution is enabled" { + Enable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + } + + Context "Enable-DbaReplDistributor works with specified database name" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + AfterAll { + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + + It "distribution is enabled with specific database" { + $distDb = ('distdb-{0}' -f (Get-Random)) + Enable-DbaReplDistributor -DistributionDatabase $distDb + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + } + } + + Context "Disable-DbaReplDistributor works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + } + + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + } + + Context "Enable-DbaReplPublishing works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if Publishing is enabled - disable it + if ((Get-DbaReplServer).IsPublisher) { + Disable-DbaReplPublishing + } + } + + It "publishing starts disabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $false + } + + It "publishing is enabled" { + Enable-DbaReplPublishing -EnableException + (Get-DbaReplServer).IsPublisher | Should -Be $true + } + } + + Context "Disable-DbaReplPublishing works" { + BeforeAll { + + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + write-output -message 'I should enable publishing' + Enable-DbaReplPublishing -EnableException + } + + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + } + + It "publishing starts enabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $true + } + + It "publishing is disabled" { + Disable-DbaReplPublishing -EnableException + (Get-DbaReplServer).IsPublisher | Should -Be $false + } + } + + Context "Get-DbaReplPublisher works" -skip { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + + } +} From b778e4b6dade95441711517460b536628cf0b75a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 11:51:47 +0000 Subject: [PATCH 003/226] functions --- public/Add-DbaReplArticle.ps1 | 152 ++++++++++++++ public/Disable-DbaReplDistributor.ps1 | 102 ++++++++++ public/Disable-DbaReplPublishing.ps1 | 106 ++++++++++ public/Enable-DbaReplDistributor.ps1 | 94 +++++++++ public/Enable-DbaReplPublishing.ps1 | 118 +++++++++++ public/Export-DbaInstance.ps1 | 2 +- ...ng.ps1 => Export-DbaReplServerSetting.ps1} | 12 +- public/Get-DbaReplArticle.ps1 | 124 ++++++++++++ public/Get-DbaReplArticleColumn.ps1 | 103 ++++++++++ ...ributor.ps1 => Get-DbaReplDistributor.ps1} | 6 +- ...ication.ps1 => Get-DbaReplPublication.ps1} | 36 ++-- public/Get-DbaReplPublisher.ps1 | 85 ++++++++ ...DbaRepServer.ps1 => Get-DbaReplServer.ps1} | 23 ++- public/New-DbaReplPublication.ps1 | 185 ++++++++++++++++++ public/Remove-DbaReplArticle.ps1 | 152 ++++++++++++++ ...RepLatency.ps1 => Test-DbaReplLatency.ps1} | 12 +- 16 files changed, 1272 insertions(+), 40 deletions(-) create mode 100644 public/Add-DbaReplArticle.ps1 create mode 100644 public/Disable-DbaReplDistributor.ps1 create mode 100644 public/Disable-DbaReplPublishing.ps1 create mode 100644 public/Enable-DbaReplDistributor.ps1 create mode 100644 public/Enable-DbaReplPublishing.ps1 rename public/{Export-DbaRepServerSetting.ps1 => Export-DbaReplServerSetting.ps1} (91%) create mode 100644 public/Get-DbaReplArticle.ps1 create mode 100644 public/Get-DbaReplArticleColumn.ps1 rename public/{Get-DbaRepDistributor.ps1 => Get-DbaReplDistributor.ps1} (95%) rename public/{Get-DbaRepPublication.ps1 => Get-DbaReplPublication.ps1} (70%) create mode 100644 public/Get-DbaReplPublisher.ps1 rename public/{Get-DbaRepServer.ps1 => Get-DbaReplServer.ps1} (64%) create mode 100644 public/New-DbaReplPublication.ps1 create mode 100644 public/Remove-DbaReplArticle.ps1 rename public/{Test-DbaRepLatency.ps1 => Test-DbaReplLatency.ps1} (95%) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 new file mode 100644 index 0000000000..51ceb60f51 --- /dev/null +++ b/public/Add-DbaReplArticle.ps1 @@ -0,0 +1,152 @@ +function Add-DbaReplArticle { + <# + .SYNOPSIS + Adds an article to a publication for the database on the target SQL instances. + + .DESCRIPTION + Adds an article to a publication for the database on the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 contains the article to be replicated. + + .PARAMETER PublicationName + The name of the replication publication. + + .PARAMETER Type + The flavour of replication. + + Currently supported 'Transactional' + + Coming soon 'Snapshot', 'Merge' + + .PARAMETER LogReaderAgentCredential + Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs + + Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + TODO: Implement & test this + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [parameter(Mandatory)] + [String]$Database, + + [parameter(Mandatory)] + [String]$PublicationName, + + [String]$Schema = 'dbo', + + [parameter(Mandatory)] + [String]$Name, + + [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Adding article $Name to publication $PublicationName on $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { + + # based off this + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + + #TODO: add name field to Get-DbaReplPublication so don't have to where + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName + $pub + if ($pub.PublicationType -eq 'Transactional') { + + $article = New-Object Microsoft.SqlServer.Replication.TransArticle + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.DatabaseName = $Database + $article.SourceObjectName = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + + # think this is the default + #$article.Type = ArticleOptions.LogBased + + if ($articleFilter) { + article.FilterClause = $Filter #TODO: This doesn't seem to be working + } + + if (-not ($article.IsExistingObject)) { + $article.Create() + } else { + Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + } + # TODO: what if it's not transactional + + # TODO: Does the schema exist on the subscriber? + <# + // Ensure that we create the schema owner at the Subscriber. + article.SchemaOption |= CreationScriptOptions.Schema; + #> + + } + } catch { + Stop-Function -Message "Unable to add article $ArticleName to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + + #TODO: What should we return + Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name + + } + } +} + + + diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 new file mode 100644 index 0000000000..c2d325f673 --- /dev/null +++ b/public/Disable-DbaReplDistributor.ps1 @@ -0,0 +1,102 @@ +function Disable-DbaReplDistributor { + <# + .SYNOPSIS + Disables replication distribution for the target SQL instances. + + .DESCRIPTION + Disables replication distribution for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 Force + Boolean value that specifies whether or not replication objects are removed from the server, + even if a remote Distributor cannot be reached. + + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or + not dependent publishing and distribution objects are uninstalled. + + If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Disable-DbaReplDistributor + + .EXAMPLE + PS C:\> Disable-DbaReplDistributor -SqlInstance mssql1 + + Disables replication distribution for the mssql1 instance. + + .EXAMPLE + PS C:\> $cred = Get-Credential sqladmin + PS C:\> Disable-DbaReplDistributor -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force + + Disables replication distribution for the mssql1 and mssql2 instances using a sql login. + Specifies force so the publishing and Distributor configuration at the current server is uninstalled + regardless of whether or not dependent publishing and distribution objects are uninstalled. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + + [switch]$force, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Disabling replication distribution for $instance" + + if ($replServer.IsDistributor) { + try { + if ($PSCmdlet.ShouldProcess($instance, "Disabling distribution on $instance")) { + # remove any connections to the distribution database + Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess + # uninstall distribution + $replServer.UninstallDistributor($force) + } + } catch { + Stop-Function -Message "Unable to disable replication distribution" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } else { + Stop-Function -Message "$instance isn't currently enabled for distributing." -ErrorRecord $_ -Target $instance -Continue + } + } + } +} diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 new file mode 100644 index 0000000000..39d500924c --- /dev/null +++ b/public/Disable-DbaReplPublishing.ps1 @@ -0,0 +1,106 @@ +function Disable-DbaReplPublishing { + <# + .SYNOPSIS + Disables publication for the target SQL instances. + + .DESCRIPTION + Disables publication for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 Force + Boolean value that specifies whether or not replication objects are removed from the server, + even if a remote Distributor cannot be reached. + + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or + not dependent publishing and distribution objects are uninstalled. + + If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Disable-DbaReplPublishing + + .EXAMPLE + PS C:\> Disable-DbaReplPublishing -SqlInstance mssql1 + + Disables replication distribution for the mssql1 instance. + + .EXAMPLE + PS C:\> $cred = Get-Credential sqladmin + PS C:\> Disable-DbaReplPublishing -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force + + Disables replication distribution for the mssql1 and mssql2 instances using a sql login. + Specifies force so the publishing and Distributor configuration at the current server is uninstalled + regardless of whether or not dependent publishing and distribution objects are uninstalled. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [switch]$force, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Disabling publishing for $instance" + + if ($replServer.IsPublisher) { + try { + if ($PSCmdlet.ShouldProcess($instance, "Disabling publishing on $instance")) { + #Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess + # uninstall distribution + $replServer.DistributionPublishers.Remove($Force) + } + } catch { + Stop-Function -Message "Unable to disable replication publishing" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } else { + Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category InvalidData + } + + #$replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force + #$replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force + #$replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force + #Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name + + } + } +} diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 new file mode 100644 index 0000000000..1cba0e42a4 --- /dev/null +++ b/public/Enable-DbaReplDistributor.ps1 @@ -0,0 +1,94 @@ +function Enable-DbaReplDistributor { + <# + .SYNOPSIS + Enables replication distribution for the target SQL instances. + + .DESCRIPTION + Enables replication distribution for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 DistributionDatabase + Name of the distribution database that will be created. + + Default is 'distribution'. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Enable-DbaReplDistributor + + .EXAMPLE + PS C:\> Enable-DbaReplDistributor -SqlInstance mssql1 + + Enables distribution for the mssql1 instance. + + .EXAMPLE + PS C:\> Enable-DbaReplDistributor -SqlInstance mssql1 -DistributionDatabase repDatabase + + Enables distribution for the mssql1 instance and names the distribution database repDatabase. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [string]$DistributionDatabase = 'distribution', + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Enabling replication distribution for $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Enabling distributor for $instance")) { + $distributionDb = New-Object Microsoft.SqlServer.Replication.DistributionDatabase + $distributionDb.ConnectionContext = $replServer.ConnectionContext + $distributionDb.Name = $DistributionDatabase + # lots more properties to add as params + $replServer.InstallDistributor($null, $distributionDb) + } + } catch { + Stop-Function -Message "Unable to enable replication distributor" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } + } +} + + + diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 new file mode 100644 index 0000000000..409da62131 --- /dev/null +++ b/public/Enable-DbaReplPublishing.ps1 @@ -0,0 +1,118 @@ +function Enable-DbaReplPublishing { + <# + .SYNOPSIS + Enables replication publishing for the target SQL instances. + + .DESCRIPTION + Enables replication publishing for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 SnapshotShare + The share used to access snapshot files. + + .PARAMETER PublisherSqlLogin + If this is used the PublisherSecurity will be set to use this. + If not specified WindowsAuthentication can will used - this is the default, and recommended method. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Enable-DbaReplPublishing + + .EXAMPLE + PS C:\> Enable-DbaReplPublishing -SqlInstance SqlBox1\Instance2 -StartupProcedure '[dbo].[StartUpProc1]' + + Attempts to set the procedure '[dbo].[StartUpProc1]' in the master database of SqlBox1\Instance2 for automatic execution when the instance is started. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + $SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? + [PSCredential]$PublisherSqlLogin, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Enabling replication publishing for $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Enabling publishing on $instance")) { + + if ($replServer.IsDistributor) { + + $distPublisher = New-Object Microsoft.SqlServer.Replication.DistributionPublisher + $distPublisher.ConnectionContext = $replServer.ConnectionContext + $distPublisher.Name = $instance #- name of the Publisher. + $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name #- the name of the database created in step 5. + + #TODO: test snapshot path and warn\error? + #if (Test-DbaPath -SqlInstance mssql1 -Path $SnapshotShare) { + # Stop-Function -Message ("Snapshot path '{0}' does not exist - will attempt to create it" -f $SnapshotShare) -ErrorRecord $_ -Target $instance -Continue + #} + $distPublisher.WorkingDirectory = $SnapshotShare + + if ($PublisherSqlLogin) { + Write-Message -Level Verbose -Message "Configuring with a SQLLogin for PublisherSecurity" + $distPublisher.PublisherSecurity.WindowsAuthentication = $false + $distPublisher.PublisherSecurity.SqlStandardLogin = $PublisherSqlLogin.UserName + $distPublisher.PublisherSecurity.SecureSqlStandardPassword = $PublisherSqlLogin.Password + + } else { + Write-Message -Level Verbose -Message "Configuring with WindowsAuth for PublisherSecurity" + $distPublisher.PublisherSecurity.WindowsAuthentication = $true # TODO: test with windows auth + } + + Write-Message -Level Debug -Message $distPublisher + # lots more properties to add as params + $distPublisher.Create() + } else { + Stop-Function -Message "$instance isn't currently enabled for distributing. Please enable that first." -ErrorRecord $_ -Target $instance -Continue + } + } + } catch { + Stop-Function -Message "Unable to enable replication publishing" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer # TODO: Standard output + + } + } +} + + + diff --git a/public/Export-DbaInstance.ps1 b/public/Export-DbaInstance.ps1 index 625e272ffc..b5229e3431 100644 --- a/public/Export-DbaInstance.ps1 +++ b/public/Export-DbaInstance.ps1 @@ -385,7 +385,7 @@ function Export-DbaInstance { Write-ProgressHelper -StepNumber ($stepCounter++) -Message "Exporting replication settings" try { - $null = Export-DbaRepServerSetting -SqlInstance $instance -SqlCredential $SqlCredential -FilePath "$exportPath\replication.sql" -EnableException + $null = Export-DbaReplServerSetting -SqlInstance $instance -SqlCredential $SqlCredential -FilePath "$exportPath\replication.sql" -EnableException Get-ChildItem -ErrorAction Ignore -Path "$exportPath\replication.sql" } catch { Write-Message -Level Verbose -Message "Replication failed, skipping" diff --git a/public/Export-DbaRepServerSetting.ps1 b/public/Export-DbaReplServerSetting.ps1 similarity index 91% rename from public/Export-DbaRepServerSetting.ps1 rename to public/Export-DbaReplServerSetting.ps1 index 7ab3ecc52d..8ab1b71a23 100644 --- a/public/Export-DbaRepServerSetting.ps1 +++ b/public/Export-DbaReplServerSetting.ps1 @@ -1,4 +1,4 @@ -function Export-DbaRepServerSetting { +function Export-DbaReplServerSetting { <# .SYNOPSIS Exports replication server settings to file. @@ -51,7 +51,7 @@ function Export-DbaRepServerSetting { Not real sure how to use this yet .PARAMETER InputObject - Allows piping from Get-DbaRepServer + Allows piping from Get-DbaReplServer .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -67,15 +67,15 @@ function Export-DbaRepServerSetting { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Export-DbaRepServerSetting + https://dbatools.io/Export-DbaReplServerSetting .EXAMPLE - PS C:\> Export-DbaRepServerSetting -SqlInstance sql2017 -Path C:\temp\replication.sql + PS C:\> Export-DbaReplServerSetting -SqlInstance sql2017 -Path C:\temp\replication.sql Exports the replication settings on sql2017 to the file C:\temp\replication.sql .EXAMPLE - PS C:\> Get-DbaRepServer -SqlInstance sql2017 | Export-DbaRepServerSettings -Path C:\temp\replication.sql + PS C:\> Get-DbaReplServer -SqlInstance sql2017 | Export-DbaReplServerSetting -Path C:\temp\replication.sql Exports the replication settings on sql2017 to the file C:\temp\replication.sql @@ -104,7 +104,7 @@ function Export-DbaRepServerSetting { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - $InputObject += Get-DbaRepServer -SqlInstance $instance -SqlCredential $SqlCredential + $InputObject += Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } foreach ($repserver in $InputObject) { diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 new file mode 100644 index 0000000000..2fddf5e3f1 --- /dev/null +++ b/public/Get-DbaReplArticle.ps1 @@ -0,0 +1,124 @@ +function Get-DbaReplArticle { + <# + .SYNOPSIS + Gets the information about publication articles. + + .DESCRIPTION + This function locates and enumerates articles' information for a given publication. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 + Specifies one or more database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER PublicationName + Specifies one or more publication(s) to process. If unspecified, all publications will be processed. + + .PARAMETER PublicationType + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + + .PARAMETER Article + Specifies one or more article(s) to process. If unspecified, all articles will be processed. + + .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. + + .NOTES + Tags: Replication + Author: Cláudio Silva (@claudioessilva), claudioessilva.eu + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplArticle + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + + Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + + #> + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [object[]]$Database, + [parameter(ValueFromPipeline)] + [object[]]$Publication, + [String]$PublicationType, # Snapshot, Transactional, Merge + [string[]]$Article, + [switch]$EnableException + ) + begin { + #TODO - Still needed? + Add-ReplicationLibrary + } + process { + if (Test-FunctionInterrupt) { return } + + foreach ($instance in $SqlInstance) { + # Connect to the distributor of the instance + try { + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + $databases = $server.Databases | Where-Object IsAccessible -eq $true + if ($Database) { + $databases = $databases | Where-Object Name -In $Database + } + + foreach ($db in $databases) { + + $RMOdb = Connect-ReplicationDB -Server $server -Database $db + + #TODO - Check if database has replication options + #if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { + # Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + #} + + if ($PublicationType -eq 'Transactional') { + $publications = $RMOdb.TransPublications + } else { + $publications = $RMOdb.MergePublications + } + + if ($Publication) { + $publications = $publications | Where-Object Name -in $Publication + } + + if ($PublicationType -eq 'Transactional') { + $articles = $publications.TransArticles + } else { + $articles = $publications.MergeArticles + } + + if ($Article) { + $articles = $articles | Where-Object Name -In $Article + } + + foreach ($art in $articles) { + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + } + } + } + } +} \ No newline at end of file diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 new file mode 100644 index 0000000000..46ec46bd52 --- /dev/null +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -0,0 +1,103 @@ +function Get-DbaReplArticleColumn { + <# + .SYNOPSIS + Gets the information about publication article columns. + + .DESCRIPTION + This function enumerates columns information for a given articles. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 + Specifies one or more database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER PublicationName + Specifies one or more publication(s) to process. If unspecified, all publications will be processed. + + .PARAMETER PublicationType + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + + .PARAMETER Article + Specifies one or more article(s) to process. If unspecified, all articles will be processed. + + .PARAMETER Column + Specifies one or more column(s) to process. If unspecified, all columns will be processed. + + .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. + + .NOTES + Tags: Replication + Author: Cláudio Silva (@claudioessilva), claudioessilva.eu + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplArticleColumn + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + + Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + + #> + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [object[]]$Database, + [parameter(ValueFromPipeline)] + [object[]]$Publication, + [String]$PublicationType, # Snapshot, Transactional, Merge + [string[]]$Article, + [string[]]$Column, + [switch]$EnableException + ) + begin { + #TODO - Still needed? + Add-ReplicationLibrary + } + process { + if (Test-FunctionInterrupt) { return } + + $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -PublicationType $PublicationType -Article $Article + + foreach ($art in $articles) { + $columns = $art.ListReplicatedColumns() + + if ($Column) { + $columns = $columns | Where-Object { $_ -In $Column } + } + + foreach ($col in $columns) { + + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $art.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $art.InstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $art.SqlInstance + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleName -Value $art.Name + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleId -Value $art.ArticleId + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Description -Value $art.Description + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Type -Value $art.Type + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name VerticalPartition -Value $art.VerticalPartition + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectOwner -Value $art.SourceObjectOwner + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectName -Value $art.SourceObjectName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ColumnName -Value $col + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, ArticleName, ArticleId, Description, ColumnName #, DestinationObjectOwner, DestinationObjectName + } + } + } +} \ No newline at end of file diff --git a/public/Get-DbaRepDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 similarity index 95% rename from public/Get-DbaRepDistributor.ps1 rename to public/Get-DbaReplDistributor.ps1 index c5657c688e..a93522df7c 100644 --- a/public/Get-DbaRepDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -1,4 +1,4 @@ -function Get-DbaRepDistributor { +function Get-DbaReplDistributor { <# .SYNOPSIS Gets the information about a replication distributor for a given SQL Server instance. @@ -33,10 +33,10 @@ function Get-DbaRepDistributor { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaRepDistributor + https://dbatools.io/Get-DbaReplDistributor .EXAMPLE - PS C:\> Get-DbaRepDistributor -SqlInstance sql2008, sqlserver2012 + PS C:\> Get-DbaReplDistributor -SqlInstance sql2008, sqlserver2012 Retrieve distributor information for servers sql2008 and sqlserver2012. diff --git a/public/Get-DbaRepPublication.ps1 b/public/Get-DbaReplPublication.ps1 similarity index 70% rename from public/Get-DbaRepPublication.ps1 rename to public/Get-DbaReplPublication.ps1 index 8a04b05640..783c15c7bb 100644 --- a/public/Get-DbaRepPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -1,4 +1,4 @@ -function Get-DbaRepPublication { +function Get-DbaReplPublication { <# .SYNOPSIS Displays all publications for a server or database. @@ -26,7 +26,9 @@ function Get-DbaRepPublication { Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER EnableException - byng this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. + 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. .NOTES Tags: Replication @@ -37,20 +39,20 @@ function Get-DbaRepPublication { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaRepPublication + https://dbatools.io/Get-DbaReplPublication .EXAMPLE - PS C:\> Get-DbaRepPublication -SqlInstance sql2008, sqlserver2012 + PS C:\> Get-DbaReplPublication -SqlInstance sql2008, sqlserver2012 Return all publications for servers sql2008 and sqlserver2012. .EXAMPLE - PS C:\> Get-DbaRepPublication -SqlInstance sql2008 -Database TestDB + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Database TestDB Return all publications on server sql2008 for only the TestDB database .EXAMPLE - PS C:\> Get-DbaRepPublication -SqlInstance sql2008 -PublicationType Transactional + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -PublicationType Transactional Return all publications on server sql2008 for all databases that have Transactional publications @@ -62,8 +64,9 @@ function Get-DbaRepPublication { [object[]]$Database, [PSCredential]$SqlCredential, [ValidateSet("Transactional", "Merge", "Snapshot")] - [object[]]$PublicationType, + [object[]]$PublicationType, #TODO: change to just Type [switch]$EnableException + #TODO: add a name parameter ) begin { Add-ReplicationLibrary @@ -79,16 +82,13 @@ function Get-DbaRepPublication { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $dbList = $server.Databases - + $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } if ($Database) { - $dbList = $dbList | Where-Object name -in $Database + $databases = $databases | Where-Object Name -In $Database } - $dbList = $dbList | Where-Object { ($_.ID -gt 4) -and ($_.status -ne "Offline") } - - foreach ($db in $dbList) { + foreach ($db in $databases) { if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." @@ -106,12 +106,14 @@ function Get-DbaRepPublication { [PSCustomObject]@{ ComputerName = $server.ComputerName - InstanceName = $server.InstanceName - SqlInstance = $server.SqlInstance + InstanceName = $server.ServiceName + SqlInstance = $server.Name Server = $server.name Database = $db.name - PublicationName = $pub.Name - PublicationType = $pub.Type + PublicationName = $pub.Name #TODO: change to just name + PublicationType = $pub.Type #TODO: change to just Type + Articles = $pub.TransArticles #TODO what about merge articles? + } } } diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 new file mode 100644 index 0000000000..1c3e2acd14 --- /dev/null +++ b/public/Get-DbaReplPublisher.ps1 @@ -0,0 +1,85 @@ +function Get-DbaReplPublisher { + <# + .SYNOPSIS + Gets publisher for the target SQL instances. + + .DESCRIPTION + Gets publisher for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 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: Replication + Author: Mikey Bronowski (@MikeyBronowski), bronowski.it + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplPublisher + + .EXAMPLE + PS C:\> Get-DbaReplPublisher -SqlInstance mssql1 + + Gets publisher for the mssql1 instance. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $server + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue + } + Write-Message -Level Verbose -Message "Getting publisher for $server" + + try { + if ($PSCmdlet.ShouldProcess($server, "Getting publisher for $server")) { + $publisher = $replServer.DistributionPublishers + $publisher + } + } catch { + Stop-Function -Message "Unable to get publisher for" -ErrorRecord $_ -Target $server -Continue + } + + # fails if there isn't any + if ($publisher) { + $publisher | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force + $publisher | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force + $publisher | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force + } + + + Select-DefaultView -InputObject $publisher -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name + + } + } +} diff --git a/public/Get-DbaRepServer.ps1 b/public/Get-DbaReplServer.ps1 similarity index 64% rename from public/Get-DbaRepServer.ps1 rename to public/Get-DbaReplServer.ps1 index 9a9d692110..ca50bf70f6 100644 --- a/public/Get-DbaRepServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -1,4 +1,4 @@ -function Get-DbaRepServer { +function Get-DbaReplServer { <# .SYNOPSIS Gets a replication server object @@ -33,15 +33,15 @@ function Get-DbaRepServer { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaRepServer + https://dbatools.io/Get-DbaReplServer .EXAMPLE - PS C:\> Get-DbaRepServer -SqlInstance sql2016 + PS C:\> Get-DbaReplServer -SqlInstance sql2016 Gets the replication server object for sql2016 using Windows authentication .EXAMPLE - PS C:\> Get-DbaRepServer -SqlInstance sql2016 -SqlCredential repadmin + PS C:\> Get-DbaReplServer -SqlInstance sql2016 -SqlCredential repadmin Gets the replication server object for sql2016 using SQL authentication @@ -61,11 +61,20 @@ function Get-DbaRepServer { foreach ($instance in $SqlInstance) { try { # use System.Data instead of Microsoft.Data - $sqlconn = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential - New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlconn + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + $sqlCon = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlCon + + $replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force + $replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force + $replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force + + Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, DistributorInstalled, DistributorAvailable, IsDistributor, IsPublisher, HasRemotePublisher, DistributionServer, DistributionDatabase, WorkingDirectory, AgentCheckupInterval, DistributionDatabases, DistributionPublishers, ReplicationDatabases, RegisteredSubscribers } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } } } -} \ No newline at end of file +} + +# TODO: Replication databases are shown even if they have no pubs \ No newline at end of file diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 new file mode 100644 index 0000000000..232955d5c2 --- /dev/null +++ b/public/New-DbaReplPublication.ps1 @@ -0,0 +1,185 @@ +function New-DbaReplPublication { + <# + .SYNOPSIS + Creates a publication for the database on the target SQL instances. + + .DESCRIPTION + Creates a publication for the database on the target SQL instances. + + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 that will be replicated. + + .PARAMETER PublicationName + The name of the replication publication + + .PARAMETER Type + The flavour of replication. + + Currently supported 'Transactional' + + Coming soon 'Snapshot', 'Merge' + + .PARAMETER LogReaderAgentCredential + Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs + + Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + TODO: Implement & test this + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [String]$Database, + + [parameter(Mandatory)] + [String]$PublicationName, + + [parameter(Mandatory)] + [ValidateSet("Snapshot", "Transactional", "Merge")] + [String]$Type, + + [PSCredential]$LogReaderAgentCredential, + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Creating a new publication on $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Enabling distribution on $instance")) { + + # based off this + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 + + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $pubDatabase.ConnectionContext = $replServer.ConnectionContext + $pubDatabase.Name = $Database + if (-not $pubDatabase.LoadProperties()) { + throw "Database $Database not found on $instance" + } + + if ($Type -eq 'Transactional') { + $pubDatabase.EnabledTransPublishing = $true + } elseif ($Type -eq 'Merge') { + $pubDatabase.EnabledMergePublishing = $true + $pubDatabase.CommitPropertyChanges + } + #TODO: snapshot repl? + + if (-not $pubDatabase.LogReaderAgentExists) { + #TODO: if this needed for merge? + + Write-Message -Level Verbose -Message "Create Log Read Agent job for $Database on $instance" + if ($LogReaderAgentCredential) { + #TODO: Test this + $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName + $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password + } + + #(Optional) Set the SqlStandardLogin and SqlStandardPassword or + # SecureSqlStandardPassword fields of LogReaderAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. + + $pubDatabase.CreateLogReaderAgent() + } else { + Write-Message -Level Verbose -Message "Log Read Agent job already exists for $Database on $instance" + } + + if ($Type -eq 'Transactional') { + + $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication + $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.DatabaseName = $Database + $transPub.Name = $PublicationName + $transPub.Type = $Type + $transPub.Create() + + # create the Snapshot Agent job + #TODO: also for snapshot pub? + $transPub.CreateSnapshotAgent() + + #$transPub.CreateSnapshotAgent + + <# + TODO: add these in? + + The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. + This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. + + Note + Setting SnapshotGenerationAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + (Optional) The SqlStandardLogin and SqlStandardPassword or + SecureSqlStandardPassword fields of SnapshotGenerationAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. + #> + } + + #TODO: merge? + + + + } + } catch { + Stop-Function -Message "Unable to enable replication distribution" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } + } +} + + + diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 new file mode 100644 index 0000000000..b838bdb784 --- /dev/null +++ b/public/Remove-DbaReplArticle.ps1 @@ -0,0 +1,152 @@ +function Remove-DbaReplArticle { + <# + .SYNOPSIS + Removes an article from a publication for the database on the target SQL instances. + + .DESCRIPTION + Removes an article from a publication for the database on the target SQL instances. + + Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. + Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this ClearUpSubObject + +For snapshot or transactional publications, articles can be dropped with no special considerations prior to subscriptions being created. +If an article is dropped after one or more subscriptions is created, the subscriptions must be dropped, recreated, and synchronized. + +Dropping an article from a publication involves dropping the article and creating a new snapshot for the publication. +Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. + + +https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 + + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 contains the article to be removed from replication. + + .PARAMETER PublicationName + The name of the replication publication. + + .PARAMETER Type + The flavour of replication. + + Currently supported 'Transactional' + + Coming soon 'Snapshot', 'Merge' + + .PARAMETER LogReaderAgentCredential + Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs + + Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + TODO: Implement & test this + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [parameter(Mandatory)] + [String]$Database, + + [parameter(Mandatory)] + [String]$PublicationName, + + [String]$Schema = 'dbo', + + [parameter(Mandatory)] + [String]$Name, + + [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Removing article $Name from publication $PublicationName on $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { + + # based off this + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + + #TODO: add name field to Get-DbaReplPublication so don't have to where + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName + + if ($pub.PublicationType -eq 'Transactional') { + + $article = New-Object Microsoft.SqlServer.Replication.TransArticle + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + $article.DatabaseName = $Database + + # think this is the default + #$article.Type = ArticleOptions.LogBased + + if (($article.IsExistingObject)) { + $article.Remove() + } else { + Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + } + # TODO: what if it's not transactional + } + } catch { + Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + + #TODO: What should we return anything? + + } + } +} + + + diff --git a/public/Test-DbaRepLatency.ps1 b/public/Test-DbaReplLatency.ps1 similarity index 95% rename from public/Test-DbaRepLatency.ps1 rename to public/Test-DbaReplLatency.ps1 index 6224e0041a..a1e4cbdc0c 100644 --- a/public/Test-DbaRepLatency.ps1 +++ b/public/Test-DbaReplLatency.ps1 @@ -1,4 +1,4 @@ -function Test-DbaRepLatency { +function Test-DbaReplLatency { <# .SYNOPSIS Displays replication latency for all transactional publications for a server or database. @@ -50,20 +50,20 @@ function Test-DbaRepLatency { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Test-DbaRepLatency + https://dbatools.io/Test-DbaReplLatency .EXAMPLE - PS C:\> Test-DbaRepLatency -SqlInstance sql2008, sqlserver2012 + PS C:\> Test-DbaReplLatency -SqlInstance sql2008, sqlserver2012 Return replication latency for all transactional publications for servers sql2008 and sqlserver2012. .EXAMPLE - PS C:\> Test-DbaRepLatency -SqlInstance sql2008 -Database TestDB + PS C:\> Test-DbaReplLatency -SqlInstance sql2008 -Database TestDB Return replication latency for all transactional publications on server sql2008 for only the TestDB database .EXAMPLE - PS C:\> Test-DbaRepLatency -SqlInstance sql2008 -Database TestDB -PublicationName TestDB_Pub + PS C:\> Test-DbaReplLatency -SqlInstance sql2008 -Database TestDB -PublicationName TestDB_Pub Return replication latency for the TestDB_Pub publication for the TestDB database located on the server sql2008. @@ -94,7 +94,7 @@ function Test-DbaRepLatency { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $publicationNames = Get-DbaRepPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -PublicationType "Transactional" + $publicationNames = Get-DbaReplPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -PublicationType "Transactional" if ($PublicationName) { $publicationNames = $publicationNames | Where-Object PublicationName -in $PublicationName From 11f5682f764356245607d4841dc949ae6217818b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:01:26 +0000 Subject: [PATCH 004/226] psd1\psm1 merging --- dbatools.psd1 | 33 ++++++++++++++++++++++++++------- dbatools.psm1 | 23 +++++++++++++++++------ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index 880aeafff1..31e849ecef 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -139,7 +139,7 @@ 'Export-DbaLogin', 'Export-DbaPfDataCollectorSetTemplate', 'Export-DbaRegServer', - 'Export-DbaRepServerSetting', + 'Export-DbaReplServerSetting', 'Export-DbaScript', 'Export-DbaServerRole', 'Export-DbaSpConfigure', @@ -350,9 +350,10 @@ 'Get-DbaRegServer', 'Get-DbaRegServerGroup', 'Get-DbaRegServerStore', - 'Get-DbaRepDistributor', - 'Get-DbaRepPublication', - 'Get-DbaRepServer', + 'Get-DbaReplDistributor', + 'Get-DbaReplPublication', + 'Get-DbaReplPublisher', + 'Get-DbaReplServer', 'Get-DbaResourceGovernor', 'Get-DbaRgClassifierFunction', 'Get-DbaRgResourcePool', @@ -693,7 +694,7 @@ 'Test-DbaOptimizeForAdHoc', 'Test-DbaPath', 'Test-DbaPowerPlan', - 'Test-DbaRepLatency', + 'Test-DbaReplLatency', 'Test-DbaSpn', 'Test-DbaTempDbConfig', 'Test-DbaWindowsLogin', @@ -728,7 +729,18 @@ 'New-DbaLinkedServerLogin', 'Remove-DbaLinkedServerLogin', 'Remove-DbaCredential', - 'Remove-DbaAgentProxy' + 'Remove-DbaAgentProxy', + + # NEW REPLICATION STUFF + 'Disable-DbaReplDistributor', + 'Enable-DbaReplDistributor', + 'Disable-DbaReplPublishing', + 'Enable-DbaReplPublishing', + 'New-DbaReplPublication', + 'Get-DbaReplArticle', + 'Get-DbaReplArticleColumn', + 'Add-DbaReplArticle', + 'Remove-DbaReplArticle' ) # Cmdlets to export from this module @@ -751,9 +763,16 @@ 'Write-DbaDataTable', 'Get-DbaDbModule', 'Get-DbaBuildReference', - 'Copy-DbaSysDbUserObject' + 'Copy-DbaSysDbUserObject', + + # replication aliases - these existed before the repl overhaul in 2.0+ + 'Get-DbaRepServer', + 'Export-DbaRepServerSetting', + 'Get-DbaRepDistributor', + 'Test-DbaRepLatency' ) + # List of all modules packaged with this module ModuleList = @() diff --git a/dbatools.psm1 b/dbatools.psm1 index 55fd649f59..3e4390a21e 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -295,9 +295,19 @@ $forever = @{ foreach ($_ in $forever.GetEnumerator()) { Set-Alias -Name $_.Key -Value $_.Value } + +# Replication Aliases +$replAliases = @{ + 'Get-DbaRepServer' = 'Get-DbaReplServer' + 'Export-DbaRepServerSetting' = 'Export-DbaReplServerSetting' + 'Get-DbaRepDistributor' = 'Get-DbaReplDistributor' + 'Test-DbaRepLatency' = 'Test-DbaReplLatency' +} +foreach ($_ in $replAliases.GetEnumerator()) { + Set-Alias -Name $_.Key -Value $_.Value +} #endregion Aliases -# apparently this is no longer required? :O if ($PSVersionTable.PSVersion.Major -lt 5) { # region Commands $script:xplat = @( @@ -844,9 +854,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Remove-DbaCredential', 'Remove-DbaAgentProxy' ) + #TODO: can repl commands be removed here? $script:noncoresmo = @( # SMO issues - 'Get-DbaRepDistributor', + 'Get-DbaReplDistributor', 'Copy-DbaPolicyManagement', 'Copy-DbaDataCollector', 'Get-DbaPbmCategory', @@ -855,10 +866,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Get-DbaPbmObjectSet', 'Get-DbaPbmPolicy', 'Get-DbaPbmStore', - 'Get-DbaRepPublication', - 'Test-DbaRepLatency', - 'Export-DbaRepServerSetting', - 'Get-DbaRepServer' + 'Get-DbaReplPublication', + 'Test-DbaReplLatency', + 'Export-DbaReplServerSetting', + 'Get-DbaReplServer' ) $script:windowsonly = @( # filesystem (\\ related), From dd981d6601a62b4404cac8ca1cb4629ef584bd32 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:32:58 +0000 Subject: [PATCH 005/226] update wf --- .github/workflows/integration-tests-repl.yml | 64 ++------------------ 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index a64a6c1da9..a199934b3e 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -13,12 +13,11 @@ jobs: - uses: actions/checkout@v3 - name: Install and cache PowerShell modules - uses: potatoqualitee/psmodulecache@v5.1 + uses: potatoqualitee/psmodulecache@v5.2 with: - modules-to-cache: dbatools-core-library:2022.10.27 - modules-to-cache-prerelease: dbatools-library:2022.10.28-preview + modules-to-cache: dbatools.library:2023.1.29 - - name: Install and cache dbatools-library + - name: Set encryption values run: | Import-Module ./dbatools.psd1 -Force Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register @@ -37,7 +36,7 @@ jobs: - name: 👥 Clone appveyor repo working-directory: /tmp run: | - gh repo clone sqlcollaborative/appveyor-lab + gh repo clone dataplat/appveyor-lab - name: Setup Replication run: | @@ -53,58 +52,3 @@ jobs: Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru - - - -# windows-tests: -# runs-on: windows-latest -# env: -# GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} -# -# steps: -# - name: Checkout dbatools repo -# uses: actions/checkout@v3 -# -# - name: Install and cache PowerShell modules -# uses: potatoqualitee/psmodulecache@v5.1 -# with: -# shell: powershell, pwsh -# modules-to-cache: dbatools-core-library:2022.10.27 -# modules-to-cache-prerelease: dbatools-library:2022.10.28-preview -# -# - name: Install SQL Server localdb -# uses: potatoqualitee/mssqlsuite@v1.3 -# with: -# install: localdb -# -# - name: Connect to localdb instance powershell -# shell: powershell -# run: | -# Import-Module ./dbatools -Force -# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" -# -# - name: Connect to localdb instance pwsh -# shell: pwsh -# run: | -# Import-Module ./dbatools -Force -# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" -# -# - name: Run pwsh tests -# env: -# TENANTID: ${{secrets.TENANTID}} -# CLIENTID: ${{secrets.CLIENTID}} -# CLIENTSECRET: ${{secrets.CLIENTSECRET}} -# shell: pwsh -# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru -# -# - name: Run PowerShell tests -# env: -# TENANTID: ${{secrets.TENANTID}} -# CLIENTID: ${{secrets.CLIENTID}} -# CLIENTSECRET: ${{secrets.CLIENTSECRET}} -# shell: powershell -# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru \ No newline at end of file From 39914f8b4d225d3974dc5e74179ad755e22a7847 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:44:31 +0000 Subject: [PATCH 006/226] Swap order of pub dist --- tests/gh-actions-repl.ps1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 12b63b6ea3..f2234d63bd 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -97,14 +97,14 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Enable-DbaReplPublishing works" { BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } } It "publishing starts disabled" { @@ -123,18 +123,18 @@ Describe "Integration Tests" -Tag "IntegrationTests" { write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - write-output -message 'I should enable distribution' - Enable-DbaReplDistributor -EnableException - } - # if publishing is disabled - enable it if (-not (Get-DbaReplServer).IsPublisher) { write-output -message 'I should enable publishing' Enable-DbaReplPublishing -EnableException } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) } From d22510f6c02c390b1e5db3ebe7e2f59ed4c04df9 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:45:48 +0000 Subject: [PATCH 007/226] rename --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index a199934b3e..d7bb4b3f84 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -1,4 +1,4 @@ -name: Run Cross Platform Tests - repl +name: Run Replication Tests on: [push] defaults: run: From dc96c0e311c006ab487fa66c3f3f4c61d8c78ea7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 15:05:13 +0000 Subject: [PATCH 008/226] debug --- tests/gh-actions-repl.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index f2234d63bd..fb4b3f4fee 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -100,10 +100,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing + write-output 'DISABLE PUB' } # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { Enable-DbaReplDistributor + write-output 'ENABLE DIST' } } @@ -112,7 +114,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - Enable-DbaReplPublishing -EnableException + write-output 'work on enable' + Enable-DbaReplPublishing -EnableException -Outvariable test + $test (Get-DbaReplServer).IsPublisher | Should -Be $true } } From b4ed6644c192ebf93a943ce1ecf8325d07d2416e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 17 Feb 2023 13:47:49 +0000 Subject: [PATCH 009/226] add name to get-dbareplpublication --- public/Get-DbaReplPublication.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 783c15c7bb..b9501b12dd 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -15,6 +15,9 @@ function Get-DbaReplPublication { .PARAMETER Database The database(s) to process. If unspecified, all databases will be processed. + .PARAMETER Name + The name of the publication. + .PARAMETER SqlCredential Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). @@ -56,6 +59,10 @@ function Get-DbaReplPublication { Return all publications on server sql2008 for all databases that have Transactional publications + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey + + Returns the Mergey publications on server mssql1 #> [CmdletBinding()] param ( @@ -63,10 +70,10 @@ function Get-DbaReplPublication { [DbaInstanceParameter[]]$SqlInstance, [object[]]$Database, [PSCredential]$SqlCredential, + [String]$Name, [ValidateSet("Transactional", "Merge", "Snapshot")] [object[]]$PublicationType, #TODO: change to just Type [switch]$EnableException - #TODO: add a name parameter ) begin { Add-ReplicationLibrary @@ -96,12 +103,17 @@ function Get-DbaReplPublication { $repDB = Connect-ReplicationDB -Server $server -Database $db + $pubTypes = $repDB.TransPublications + $repDB.MergePublications if ($PublicationType) { $pubTypes = $pubTypes | Where-Object Type -in $PublicationType } + if ($Name) { + $pubTypes = $pubTypes | Where-Object Name -in $Name + } + foreach ($pub in $pubTypes) { [PSCustomObject]@{ From 87001eea55f8fdfb15ef27b4cddb61552017f0b7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 17 Feb 2023 13:48:49 +0000 Subject: [PATCH 010/226] add support for merge and snapshot --- public/Add-DbaReplArticle.ps1 | 61 +++++++++++++--------------- public/New-DbaReplPublication.ps1 | 41 +++++++++++++------ public/Remove-DbaReplArticle.ps1 | 66 ++++++++++++------------------- 3 files changed, 83 insertions(+), 85 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 51ceb60f51..e114d65946 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -56,6 +56,8 @@ function Add-DbaReplArticle { Copyright: (c) 2022 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + .LINK https://dbatools.io/New-DbaReplPublication @@ -99,51 +101,42 @@ function Add-DbaReplArticle { try { if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { - # based off this - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName - #TODO: add name field to Get-DbaReplPublication so don't have to where - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName - $pub - if ($pub.PublicationType -eq 'Transactional') { + $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - $article = New-Object Microsoft.SqlServer.Replication.TransArticle - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.DatabaseName = $Database - $article.SourceObjectName = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName - - # think this is the default - #$article.Type = ArticleOptions.LogBased - - if ($articleFilter) { - article.FilterClause = $Filter #TODO: This doesn't seem to be working - } - - if (-not ($article.IsExistingObject)) { - $article.Create() - } else { - Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } + if ($pub.PublicationType -eq 'Transactional') { + $article = New-Object Microsoft.SqlServer.Replication.TransArticle + $article.Type = $ArticleOptions::LogBased + } elseif ($pub.PublicationType -eq 'Merge') { + $article = New-Object Microsoft.SqlServer.Replication.MergeArticle + $article.Type = $ArticleOptions::TableBased + } else { + Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue } - # TODO: what if it's not transactional - # TODO: Does the schema exist on the subscriber? - <# - // Ensure that we create the schema owner at the Subscriber. - article.SchemaOption |= CreationScriptOptions.Schema; - #> + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.DatabaseName = $Database + $article.SourceObjectName = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + + if ($articleFilter) { + article.FilterClause = $Filter #TODO: This doesn't seem to be working + } + if (-not ($article.IsExistingObject)) { + $article.Create() + } else { + Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } } } catch { Stop-Function -Message "Unable to add article $ArticleName to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } - #TODO: What should we return Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name - } } } diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 232955d5c2..1aaa44786f 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -97,7 +97,7 @@ function New-DbaReplPublication { Write-Message -Level Verbose -Message "Creating a new publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Enabling distribution on $instance")) { + if ($PSCmdlet.ShouldProcess($instance, "Creating a new publication on $instance")) { # based off this # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 @@ -109,7 +109,7 @@ function New-DbaReplPublication { throw "Database $Database not found on $instance" } - if ($Type -eq 'Transactional') { + if ($Type -in ('Transactional', 'Snapshot')) { $pubDatabase.EnabledTransPublishing = $true } elseif ($Type -eq 'Merge') { $pubDatabase.EnabledMergePublishing = $true @@ -135,7 +135,7 @@ function New-DbaReplPublication { Write-Message -Level Verbose -Message "Log Read Agent job already exists for $Database on $instance" } - if ($Type -eq 'Transactional') { + if ($Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication $transPub.ConnectionContext = $replServer.ConnectionContext @@ -145,11 +145,8 @@ function New-DbaReplPublication { $transPub.Create() # create the Snapshot Agent job - #TODO: also for snapshot pub? $transPub.CreateSnapshotAgent() - #$transPub.CreateSnapshotAgent - <# TODO: add these in? @@ -163,19 +160,41 @@ function New-DbaReplPublication { (Optional) The SqlStandardLogin and SqlStandardPassword or SecureSqlStandardPassword fields of SnapshotGenerationAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. #> - } + } elseif ($Type -eq 'Merge') { + $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication + $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.DatabaseName = $Database + $mergePub.Name = $PublicationName + $mergePub.Create() + + # create the Snapshot Agent job + $mergePub.CreateSnapshotAgent() + + <# + TODO: add these in? + + The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. + This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. + + Note + Setting SnapshotGenerationAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + For more information, see Replication Agent Security Model. - #TODO: merge? + (Optional) Use the inclusive logical OR operator (| in Visual C# and Or in Visual Basic) and the exclusive logical OR operator (^ in Visual C# and Xor in Visual Basic) + to set the PublicationAttributes values for the Attributes property. + + #> + + } } } catch { - Stop-Function -Message "Unable to enable replication distribution" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message ("Unable to create publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } - $replServer.Refresh() - $replServer + #TODO: What to return } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index b838bdb784..cc796b6aa3 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -18,7 +18,6 @@ Dropping an article invalidates the current snapshot; therefore a new snapshot m https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 - .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -35,20 +34,11 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a .PARAMETER PublicationName The name of the replication publication. - .PARAMETER Type - The flavour of replication. - - Currently supported 'Transactional' - - Coming soon 'Snapshot', 'Merge' + .PARAMETER Schema + Source schema of the replicated object to remove from the publication. - .PARAMETER LogReaderAgentCredential - Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs - - Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. - In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - - TODO: Implement & test this + .PARAMETER Name + The name of the article to remove. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -69,13 +59,15 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a Copyright: (c) 2022 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-an-article?view=sql-server-ver16 + .LINK - https://dbatools.io/New-DbaReplPublication + https://dbatools.io/Remove-DbaReplArticle .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> Remove-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName PubFromPosh -Name 'publishers' - Creates a publication called PubFromPosh for the Northwind database on mssql1 + Removes the publishers article from a publication called PubFromPosh on mssql1 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] @@ -96,8 +88,6 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a [parameter(Mandatory)] [String]$Name, - [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; - [Switch]$EnableException ) process { @@ -112,31 +102,27 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a try { if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { - # based off this - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure - - #TODO: add name field to Get-DbaReplPublication so don't have to where - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName if ($pub.PublicationType -eq 'Transactional') { - $article = New-Object Microsoft.SqlServer.Replication.TransArticle - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName - $article.DatabaseName = $Database - - # think this is the default - #$article.Type = ArticleOptions.LogBased - - if (($article.IsExistingObject)) { - $article.Remove() - } else { - Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } + } elseif ($pub.PublicationType -eq 'Merge') { + $article = New-Object Microsoft.SqlServer.Replication.MergeArticle + } else { + Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue + } + + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + $article.DatabaseName = $Database + + if (($article.IsExistingObject)) { + $article.Remove() + } else { + Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } - # TODO: what if it's not transactional } } catch { Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue From 7263dfd7630afc3c6a787d08240e0e46df7b324a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 23 Feb 2023 16:15:54 +0000 Subject: [PATCH 011/226] change publicationtype --> type --- public/Add-DbaReplArticle.ps1 | 6 +++--- public/Get-DbaReplPublication.ps1 | 21 ++++++++++----------- public/Remove-DbaReplArticle.ps1 | 6 +++--- public/Test-DbaReplLatency.ps1 | 6 +++--- tests/Get-DbaReplPublication.Tests.ps1 | 12 ++++++------ 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index e114d65946..59c6826a14 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -101,14 +101,14 @@ function Add-DbaReplArticle { try { if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - if ($pub.PublicationType -eq 'Transactional') { + if ($pub.Type -eq 'Transactional') { $article = New-Object Microsoft.SqlServer.Replication.TransArticle $article.Type = $ArticleOptions::LogBased - } elseif ($pub.PublicationType -eq 'Merge') { + } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle $article.Type = $ArticleOptions::TableBased } else { diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index b9501b12dd..5a8662b06e 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -71,8 +71,9 @@ function Get-DbaReplPublication { [object[]]$Database, [PSCredential]$SqlCredential, [String]$Name, + [Alias("PublicationType")] [ValidateSet("Transactional", "Merge", "Snapshot")] - [object[]]$PublicationType, #TODO: change to just Type + [object[]]$Type, [switch]$EnableException ) begin { @@ -94,7 +95,6 @@ function Get-DbaReplPublication { $databases = $databases | Where-Object Name -In $Database } - foreach ($db in $databases) { if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { @@ -103,7 +103,6 @@ function Get-DbaReplPublication { $repDB = Connect-ReplicationDB -Server $server -Database $db - $pubTypes = $repDB.TransPublications + $repDB.MergePublications if ($PublicationType) { @@ -117,14 +116,14 @@ function Get-DbaReplPublication { foreach ($pub in $pubTypes) { [PSCustomObject]@{ - ComputerName = $server.ComputerName - InstanceName = $server.ServiceName - SqlInstance = $server.Name - Server = $server.name - Database = $db.name - PublicationName = $pub.Name #TODO: change to just name - PublicationType = $pub.Type #TODO: change to just Type - Articles = $pub.TransArticles #TODO what about merge articles? + ComputerName = $server.ComputerName + InstanceName = $server.ServiceName + SqlInstance = $server.Name + Server = $server.name + Database = $db.name + Name = $pub.Name #TODO: breaking change from PublicationName to Name + Type = $pub.Type #TODO: breaking change from PublicationType to Type + Articles = $pub.TransArticles #TODO what about merge articles? } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index cc796b6aa3..b76f2e3cce 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -102,11 +102,11 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a try { if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - if ($pub.PublicationType -eq 'Transactional') { + if ($pub.Type -eq 'Transactional') { $article = New-Object Microsoft.SqlServer.Replication.TransArticle - } elseif ($pub.PublicationType -eq 'Merge') { + } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle } else { Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/Test-DbaReplLatency.ps1 b/public/Test-DbaReplLatency.ps1 index a1e4cbdc0c..aff54d33a1 100644 --- a/public/Test-DbaReplLatency.ps1 +++ b/public/Test-DbaReplLatency.ps1 @@ -94,7 +94,7 @@ function Test-DbaReplLatency { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $publicationNames = Get-DbaReplPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -PublicationType "Transactional" + $publicationNames = Get-DbaReplPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -Type "Transactional" if ($PublicationName) { $publicationNames = $publicationNames | Where-Object PublicationName -in $PublicationName @@ -205,7 +205,7 @@ function Test-DbaReplLatency { PublicationServer = $publication.Server PublicationDB = $publication.Database PublicationName = $publication.PublicationName - PublicationType = $publication.PublicationType + PublicationType = $publication.Type DistributionServer = $distributionServer DistributionDB = $distributionDatabase SubscriberServer = $info.subscriber @@ -213,7 +213,7 @@ function Test-DbaReplLatency { PublisherToDistributorLatency = $info.distributor_latency DistributorToSubscriberLatency = $info.subscriber_latency TotalLatency = $totalLatency - } | Select-DefaultView -ExcludeProperty PublicationType + } | Select-DefaultView -ExcludeProperty Type if (!$RetainToken) { diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 index 3e1a3096e5..7b303a7a4b 100644 --- a/tests/Get-DbaReplPublication.Tests.ps1 +++ b/tests/Get-DbaReplPublication.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', 'Database', 'SqlCredential', 'PublicationType', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'Type', '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 @@ -53,7 +53,7 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { $Results.Database | Should Be "TestDB" } - It "Honors the PublicationType parameter" { + It "Honors the Type parameter" { Mock Connect-ReplicationDB -MockWith { [object]@{ @@ -66,13 +66,13 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { } } - $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB -PublicationType Snapshot - $Results.PublicationType | Should Be "Snapshot" + $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB -Type Snapshot + $Results.Type | Should Be "Snapshot" } - It "Stops if validate set for PublicationType is not met" { + It "Stops if validate set for Type is not met" { - { Get-DbaReplPublication -SqlInstance MockServerName -PublicationType NotAPubType } | should Throw + { Get-DbaReplPublication -SqlInstance MockServerName -Type NotAPubType } | should Throw } } From 9bf954cefe06f235575222f834294d22f4826c62 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 23 Feb 2023 16:16:47 +0000 Subject: [PATCH 012/226] change pubtype --> type --- public/Get-DbaReplArticle.ps1 | 2 ++ public/Get-DbaReplPublication.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 2fddf5e3f1..351aa422e9 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -20,9 +20,11 @@ function Get-DbaReplArticle { Specifies one or more database(s) to process. If unspecified, all databases will be processed. .PARAMETER PublicationName + #TODO change to Name Specifies one or more publication(s) to process. If unspecified, all publications will be processed. .PARAMETER PublicationType + #TODO change to Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER Article diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 5a8662b06e..e13b77159e 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -25,7 +25,7 @@ function Get-DbaReplPublication { For MFA support, please use Connect-DbaInstance. - .PARAMETER PublicationType + .PARAMETER Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER EnableException @@ -55,7 +55,7 @@ function Get-DbaReplPublication { Return all publications on server sql2008 for only the TestDB database .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -PublicationType Transactional + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional Return all publications on server sql2008 for all databases that have Transactional publications From 3492beab70bf4bfa0a89efcca93718751163d2de Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 31 Mar 2023 17:16:17 +0100 Subject: [PATCH 013/226] working --- ReplicationCommands.md | 17 +- dbatools.psd1 | 5 +- public/Add-DbaReplArticle.ps1 | 46 ++--- public/Get-DbaReplArticle.ps1 | 23 ++- public/Get-DbaReplPublication.ps1 | 12 +- public/Get-DbaReplSubscription.ps1 | 134 +++++++++++++ public/New-DbaReplPublication.ps1 | 9 +- public/New-DbaReplSubscription.ps1 | 275 ++++++++++++++++++++++++++ public/Remove-DbaReplPublication.ps1 | 152 ++++++++++++++ public/Remove-DbaReplSubscription.ps1 | 156 +++++++++++++++ testing.ps1 | 169 +++++++++++++++- tests/Get-DbaRepPublication.Tests.ps1 | 12 +- tests/gh-actions-repl.ps1 | 117 ++++++++++- 13 files changed, 1073 insertions(+), 54 deletions(-) create mode 100644 public/Get-DbaReplSubscription.ps1 create mode 100644 public/New-DbaReplSubscription.ps1 create mode 100644 public/Remove-DbaReplPublication.ps1 create mode 100644 public/Remove-DbaReplSubscription.ps1 diff --git a/ReplicationCommands.md b/ReplicationCommands.md index adf1bc1ee2..fdd790c96b 100644 --- a/ReplicationCommands.md +++ b/ReplicationCommands.md @@ -29,12 +29,12 @@ Meaning of the checkmarks: - [X] Get-DbaReplPublication -- #TODO: Exists but needs some love - [X] Disable-DbaReplPublishing - [X] Enable-DbaReplPublishing -- [-] New-DbaReplPublication - Jess -- [ ] Remove-DbaReplPublication +- [X] New-DbaReplPublication - Jess +- [X] Remove-DbaReplPublication ### Articles -- [-] Add-DbaReplArticle - Jess -- [ ] Remove-DbaReplArticle +- [X] Add-DbaReplArticle - Jess +- [X] Remove-DbaReplArticle - Jess - [-] Get-DbaReplArticle - Cláudio - [ ] Set-DbaReplArticle @@ -45,8 +45,9 @@ Meaning of the checkmarks: ### Subscriptions - [ ] Get-DbaDbSubscription -- [ ] New-DbaDbSubscription - [ ] Set-DbaReplDistributor (update properties) +- [X] New-DbaDbSubscription +- [X] Remove-DbaReplSubscription ### Monitoring\Troubleshooting @@ -54,7 +55,7 @@ Meaning of the checkmarks: - [ ] Run-DbaReplSnapshotAgent ? - [ ] Get-DbaReplSnapshotAgentStatus - [ ] Get-DbaReplLogReaderAgentStatus -- [ ] Test-DbaReplSnapFolder - similiar to Test-DbaPath but from replication service account perspective or something similiar to check If the share (UNC or Local) is accesable from both, publisher and subscriber side +- [ ] Test-DbaReplSnapFolder - similar to Test-DbaPath but from replication service account perspective or something similar to check If the share (UNC or Local) is accessible from both, publisher and subscriber side ## How to run pester tests locally @@ -73,3 +74,7 @@ Meaning of the checkmarks: Some additional scenarios for us to test commands against. - how the commands work when we have a "third site" involved , i mean if we have the distribution db not on the Publication-Server and not on the Subscriber-Server (thats not so common, but it is a thing imo) - I saw some unusual behaviour with replcation commands when the setup is with a seperate Distribution-DB-Server. + +## Questions + +- Should parameter be `PublicationType` or `Type` and `PublicationName` or `Name` diff --git a/dbatools.psd1 b/dbatools.psd1 index 31e849ecef..7fc43c7809 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -740,7 +740,10 @@ 'Get-DbaReplArticle', 'Get-DbaReplArticleColumn', 'Add-DbaReplArticle', - 'Remove-DbaReplArticle' + 'Remove-DbaReplArticle', + 'Remove-DbaReplPublication', + 'New-DbaReplSubscription', + 'Remove-DbaReplSubscription' ) # Cmdlets to export from this module diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 59c6826a14..5873626d49 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -22,20 +22,16 @@ function Add-DbaReplArticle { .PARAMETER PublicationName The name of the replication publication. - .PARAMETER Type - The flavour of replication. + .PARAMETER Schema + The schema name that contains the object to add as an article. + Default is dbo. - Currently supported 'Transactional' + .PARAMETER Name + The name of the object to add as an article. - Coming soon 'Snapshot', 'Merge' - - .PARAMETER LogReaderAgentCredential - Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs - - Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. - In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - - TODO: Implement & test this + .PARAMETER Filter + Horizontal filter for replication, implemented as a where clause, but don't include the word WHERE> + E.g. City = 'Seattle' .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -59,13 +55,18 @@ function Add-DbaReplArticle { https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure .LINK - https://dbatools.io/New-DbaReplPublication + https://dbatools.io/Add-DbaReplArticle .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Name TableToRepl + + Adds the TableToRepl table to the PubFromPosh publication from mssql1.Northwind - Creates a publication called PubFromPosh for the Northwind database on mssql1 + .EXAMPLE + PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName TestPub -Name publishers -Filter "city = 'seattle'" + + Adds the publishers table to the TestPub publication from mssql1.Pubs with a horizontal filter of only rows where city = 'seattle. #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( @@ -85,7 +86,7 @@ function Add-DbaReplArticle { [parameter(Mandatory)] [String]$Name, - [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; + [String]$Filter, [Switch]$EnableException ) @@ -105,14 +106,12 @@ function Add-DbaReplArticle { $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - if ($pub.Type -eq 'Transactional') { + if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle $article.Type = $ArticleOptions::LogBased } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle $article.Type = $ArticleOptions::TableBased - } else { - Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue } $article.ConnectionContext = $replServer.ConnectionContext @@ -122,8 +121,11 @@ function Add-DbaReplArticle { $article.SourceObjectOwner = $Schema $article.PublicationName = $PublicationName - if ($articleFilter) { - article.FilterClause = $Filter #TODO: This doesn't seem to be working + if ($Filter) { + if ($Filter -like 'WHERE*') { + Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue + } + $article.FilterClause = $Filter } if (-not ($article.IsExistingObject)) { @@ -133,7 +135,7 @@ function Add-DbaReplArticle { } } } catch { - Stop-Function -Message "Unable to add article $ArticleName to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Unable to add article $Name to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } #TODO: What should we return Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 351aa422e9..fa351a5abc 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -85,6 +85,7 @@ function Get-DbaReplArticle { } foreach ($db in $databases) { + Write-PSFMessage -Level Verbose -Message ('Working on {0}' -f $db) $RMOdb = Connect-ReplicationDB -Server $server -Database $db @@ -93,14 +94,24 @@ function Get-DbaReplArticle { # Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." #} - if ($PublicationType -eq 'Transactional') { - $publications = $RMOdb.TransPublications - } else { - $publications = $RMOdb.MergePublications - } + $publications = @() + $publications += $RMOdb.TransPublications + $publications += $RMOdb.MergePublications + + $publications + break + + #if ($PublicationType -in ('Snapshot','Transactional')) { + # $publications = $RMOdb.TransPublications + #} elseif ($PublicationType -eq 'Merge') { + # $publications = $RMOdb.MergePublications + #} else { + # $RMOdb + # $publications = @($RMOdb.TransPublications + $RMOdb.MergePublications) + #} if ($Publication) { - $publications = $publications | Where-Object Name -in $Publication + $publications = $publications | Where-Object PublicationName -in $Publication } if ($PublicationType -eq 'Transactional') { diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index e13b77159e..4e59808ef6 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -105,8 +105,8 @@ function Get-DbaReplPublication { $pubTypes = $repDB.TransPublications + $repDB.MergePublications - if ($PublicationType) { - $pubTypes = $pubTypes | Where-Object Type -in $PublicationType + if ($Type) { + $pubTypes = $pubTypes | Where-Object Type -in $Type } if ($Name) { @@ -114,6 +114,11 @@ function Get-DbaReplPublication { } foreach ($pub in $pubTypes) { + if ($pub.Type -eq 'Merge') { + $articles = $pub.MergeArticles + } else { + $articles = $pub.TransArticles + } [PSCustomObject]@{ ComputerName = $server.ComputerName @@ -123,8 +128,7 @@ function Get-DbaReplPublication { Database = $db.name Name = $pub.Name #TODO: breaking change from PublicationName to Name Type = $pub.Type #TODO: breaking change from PublicationType to Type - Articles = $pub.TransArticles #TODO what about merge articles? - + Articles = $articles } } } diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 new file mode 100644 index 0000000000..b43b9839e6 --- /dev/null +++ b/public/Get-DbaReplSubscription.ps1 @@ -0,0 +1,134 @@ +function Get-DbaReplSubscription { + <# + .SYNOPSIS + Displays all subscriptions for a publication. + + .DESCRIPTION + Displays all subscriptions for a publication + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER Database + The database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER Name + The name of the publication. + + .PARAMETER SqlCredential + Login to the target 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 Type + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + + .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. + + .NOTES + Tags: Replication + Author: Colin Douglas + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplPublication + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance sql2008, sqlserver2012 + + Return all publications for servers sql2008 and sqlserver2012. + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Database TestDB + + Return all publications on server sql2008 for only the TestDB database + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional + + Return all publications on server sql2008 for all databases that have Transactional publications + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey + + Returns the Mergey publications on server mssql1 + #> + [CmdletBinding()] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [object[]]$Database, + [PSCredential]$SqlCredential, + [String]$Name, + [Alias("PublicationType")] + [ValidateSet("Transactional", "Merge", "Snapshot")] + [object[]]$Type, + [switch]$EnableException + ) + begin { + Add-ReplicationLibrary + } + process { + if (Test-FunctionInterrupt) { return } + foreach ($instance in $SqlInstance) { + + # Connect to Publisher + try { + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } + if ($Database) { + $databases = $databases | Where-Object Name -In $Database + } + + foreach ($db in $databases) { + + if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { + Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + } + + $repDB = Connect-ReplicationDB -Server $server -Database $db + + $pubTypes = $repDB.TransPublications + $repDB.MergePublications + + if ($Type) { + $pubTypes = $pubTypes | Where-Object Type -in $Type + } + + if ($Name) { + $pubTypes = $pubTypes | Where-Object Name -in $Name + } + + foreach ($pub in $pubTypes) { + if ($pub.Type -eq 'Merge') { + $articles = $pub.MergeArticles + } else { + $articles = $pub.TransArticles + } + + [PSCustomObject]@{ + ComputerName = $server.ComputerName + InstanceName = $server.ServiceName + SqlInstance = $server.Name + Server = $server.name + Database = $db.name + Name = $pub.Name #TODO: breaking change from PublicationName to Name + Type = $pub.Type #TODO: breaking change from PublicationType to Type + Articles = $articles + } + } + } + } + } +} \ No newline at end of file diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 1aaa44786f..68ebf88e49 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -94,13 +94,10 @@ function New-DbaReplPublication { } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - Write-Message -Level Verbose -Message "Creating a new publication on $instance" + Write-Message -Level Verbose -Message "Creating publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Creating a new publication on $instance")) { - - # based off this - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 + if ($PSCmdlet.ShouldProcess($instance, "Creating publication on $instance")) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $replServer.ConnectionContext @@ -110,8 +107,10 @@ function New-DbaReplPublication { } if ($Type -in ('Transactional', 'Snapshot')) { + Write-Message -Level Verbose -Message "Enable trans publishing publication on $instance.$Database" $pubDatabase.EnabledTransPublishing = $true } elseif ($Type -eq 'Merge') { + Write-Message -Level Verbose -Message "Enable merge publishing publication on $instance.$Database" $pubDatabase.EnabledMergePublishing = $true $pubDatabase.CommitPropertyChanges } diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 new file mode 100644 index 0000000000..3d9d7bfcaa --- /dev/null +++ b/public/New-DbaReplSubscription.ps1 @@ -0,0 +1,275 @@ +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 SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 that will be replicated. + + .PARAMETER PublicationName + The name of the replication publication + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [String]$Database, + + [parameter(Mandatory)] + [DbaInstanceParameter]$PublisherSqlInstance, + + [PSCredential]$PublisherSqlCredential, + + [String]$PublicationDatabase, + + [parameter(Mandatory)] + [String]$PublicationName, + + [PSCredential] # this will be saved as the 'subscriber credential' in the subscription properties + $SubscriptionSqlCredential, + + [parameter(Mandatory)] + [ValidateSet("Push", "Pull")] #TODO: make this do something :) + [String]$Type, + + [Switch]$EnableException + ) + begin { + Write-Message -Level Verbose -Message "Connecting to publisher: $PublisherSqlInstance" + + # connect to publisher and get the publication + try { + $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + try { + $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + } catch { + Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue + } + } + + process { + + # for each subscription SqlInstance we need to create a subscription + foreach ($instance in $SqlInstance) { + + try { + if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { + Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it" + + if ($PSCmdlet.ShouldProcess($instance, "Creating subscription database")) { + + $newSubDb = @{ + SqlInstance = $instance + SqlCredential = $SqlCredential + Name = $Database + EnableException = $EnableException + } + $null = New-DbaDatabase @newSubDb + } + } + } catch { + Stop-Function -Message ("Couldn't create the subscription database {0}.{1}" -f $instance, $Database) -ErrorRecord $_ -Target $instance -Continue + } + + try { + Write-Message -Level Verbose -Message "Creating subscription on $instance" + if ($PSCmdlet.ShouldProcess($instance, "Creating subscription on $instance")) { + + if ($pub.Type -in ('Transactional', 'Snapshot')) { + + $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication + $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.DatabaseName = $PublicationDatabase + $transPub.Name = $PublicationName + + # if LoadProperties returns then the publication was found + if ( $transPub.LoadProperties() ) { + + if ($type = 'Push') { + + # 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 { + # Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull. + if ($transPub.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. + $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 = $replServer.ConnectionContext + $transSub.SubscriptionDBName = $Database + $transSub.SubscriberName = $instance + $transSub.DatabaseName = $PublicationDatabase + $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) -ErrorRecord $_ -Target $instance -Continue + } + + } elseif ($pub.Type -eq 'Merge') { + + $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication + $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.DatabaseName = $PublicationDatabase + $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 = $replServer.ConnectionContext + $mergeSub.SubscriptionDBName = $Database + $mergeSub.SubscriberName = $instance + $mergeSub.DatabaseName = $PublicationDatabase + $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) -ErrorRecord $_ -Target $instance -Continue + } + } + } catch { + Stop-Function -Message ("Unable to create subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + } + + #TODO: What to return + + } + } +} diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 new file mode 100644 index 0000000000..deb77664c6 --- /dev/null +++ b/public/Remove-DbaReplPublication.ps1 @@ -0,0 +1,152 @@ +function Remove-DbaReplPublication { + <# + .SYNOPSIS + Removes a publication from the database on the target SQL instances. + + .DESCRIPTION + Removes a publication from the database on the target SQL instances. + + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 that will be replicated. + + .PARAMETER Name + The name of the replication publication + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Remove-DbaReplPublication + + .EXAMPLE + PS C:\> Remove-DbaReplPublication -SqlInstance mssql1 -Database Northwind -Name PubFromPosh + + Removes a publication called PubFromPosh from the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [String]$Database, + + [parameter(Mandatory)] + [String]$Name, + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + try { + if ($PSCmdlet.ShouldProcess($instance, "Removing publication on $instance")) { + + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name + + if (-not $pub) { + Write-Warning "Didn't find $Name on $Instance.$Database" + } + + if ($pub.Type -in ('Transactional', 'Snapshot')) { + + $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication + $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.DatabaseName = $Database + $transPub.Name = $Name + + if ($transPub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" + $transPub.Remove() + } + + # If no other transactional publications exist for this database, the database can be disabled for transactional publishing + #TODO: transactional & snapshot.. or just trans? + if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Transactional, Snapshot)) { + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $pubDatabase.ConnectionContext = $replServer.ConnectionContext + $pubDatabase.Name = $Database + if (-not $pubDatabase.LoadProperties()) { + throw "Database $Database not found on $instance" + } + + if ($pubDatabase.EnabledTransPublishing) { + Write-Message -Level Verbose -Message "No transactional publications on $Instance.$Database so disabling transactional publishing" + $pubDatabase.EnabledTransPublishing = $false + } + } + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure + + } elseif ($pub.Type -eq 'Merge') { + $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication + $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.DatabaseName = $Database + $mergePub.Name = $Name + + if ($mergePub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" + $mergePub.Remove() + } else { + Write-Warning "Didn't find $Name on $Instance.$Database" + } + + # If no other merge publications exist for this database, the database can be disabled for merge publishing + if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Merge)) { + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $pubDatabase.ConnectionContext = $replServer.ConnectionContext + $pubDatabase.Name = $Database + + if (-not $pubDatabase.LoadProperties()) { + throw "Database $Database not found on $instance" + } + + if($pubDatabase.EnabledTransPublishing) { + Write-Message -Level Verbose -Message "No merge publications on $Instance.$Database so disabling merge publishing" + $pubDatabase.EnabledMergePublishing = $false + } + } + } + } + } catch { + Stop-Function -Message ("Unable to remove publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + } + } + } +} + + + diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 new file mode 100644 index 0000000000..87fd98d02a --- /dev/null +++ b/public/Remove-DbaReplSubscription.ps1 @@ -0,0 +1,156 @@ +function Remove-DbaReplSubscription { + <# + .SYNOPSIS + Removes a subscription for the target SQL instances. + + .DESCRIPTION + Removes a subscription for the target SQL instances. + + https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-push-subscription?view=sql-server-ver16 + https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 PublisherSqlInstance + The publisher SQL Server instance. + + .PARAMETER PublisherSqlCredential + Login to the publisher 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 PublicationDatabase + The database where the publication is located. + + .PARAMETER PublicationName + The name of the publication. + + .PARAMETER SubscriptionDatabase + The database where the subscription is located. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Remove-DbaReplSubscription + + .EXAMPLE + PS C:\> $sub = @{ + SqlInstance = 'mssql2' + SubscriptionDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationDatabase = 'pubs' + PublicationName = 'testPub' + } + PS C:\> Remove-DbaReplSubscription @sub + + Removes a subscription for the testPub publication on mssql2.pubs. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [parameter(Mandatory)] + [DbaInstanceParameter]$PublisherSqlInstance, + + [PSCredential]$PublisherSqlCredential, + + [String]$PublicationDatabase, + + [parameter(Mandatory)] + [String]$PublicationName, + + [String]$SubscriptionDatabase, + + [Switch]$EnableException + ) + begin { + + $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + + if (-not $pub) { + Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$Database" + } + + try { + $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + } + process { + foreach ($instance in $SqlInstance) { + + try { + if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $instance.$SubscriptionDatabase")) { + + if ($pub.Type -in ('Transactional', 'Snapshot')) { + + $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription + $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.DatabaseName = $PublicationDatabase + $transSub.PublicationName = $PublicationName + $transSub.SubscriptionDBName = $SubscriptionDatabase + $transSub.SubscriberName = $instance + + if ($transSub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing the subscription" + $transSub.Remove() + } + + } elseif ($pub.Type -eq 'Merge') { + $mergeSub = New-Object Microsoft.SqlServer.Replication.MergeSubscription + $mergeSub.ConnectionContext = $replServer.ConnectionContext + $mergeSub.DatabaseName = $PublicationDatabase + $mergeSub.PublicationName = $PublicationName + $mergeSub.SubscriptionDBName = $SubscriptionDatabase + $mergeSub.SubscriberName = $instance + + if ($mergeSub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing the merge subscription" + $mergeSub.Remove() + } else { + Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$SubscriptionDatabase" + } + } + } + } catch { + Stop-Function -Message ("Unable to remove subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + } + } + } +} + + + diff --git a/testing.ps1 b/testing.ps1 index 6c07458884..caedf045e6 100644 --- a/testing.ps1 +++ b/testing.ps1 @@ -38,6 +38,7 @@ $PSDefaultParameterValues = @{ "*:DestinationCredential" = $credential "*:DestinationSqlCredential" = $credential "*:SourceSqlCredential" = $credential + "*:PublisherSqlCredential" = $credential } @@ -76,7 +77,7 @@ Disable-DbaReplDistributor -SqlInstance mssql1 Enable-DbaReplPublishing -SqlInstance mssql1 Disable-DbaReplPublishing -SqlInstance mssql1 -# add a publication +# add a transactional publication $pub = @{ SqlInstance = 'mssql1' Database = 'pubs' @@ -86,6 +87,29 @@ $pub = @{ } New-DbaReplPublication @pub + + +# add a merge publication +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'mergey' + Type = 'Merge' + +} +New-DbaReplPublication @pub + +# add a snapshot publication +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'snappy' + Type = 'Snapshot' + +} +New-DbaReplPublication @pub + + # add an article $article = @{ @@ -93,6 +117,145 @@ $article = @{ Database = 'pubs' PublicationName = 'testpub' Name = 'publishers' - Filter = "where city = 'seattle'" ## not working? + Filter = "city = 'seattle'" ## not working? +} +Add-DbaReplArticle @article + + +# mergey +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'Mergey' + Name = 'publishers' + Filter = "city = 'seattle'" ## not working? +} +Add-DbaReplArticle @article + +# snappy +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'snappy' + Name = 'publishers' +} +Add-DbaReplArticle @article + + +# remove an article +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'publishers' } -Add-DbaReplArticle @article \ No newline at end of file +Remove-DbaReplArticle @article + +# remove an article +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'Mergey' + Name = 'publishers' +} +Remove-DbaReplArticle @article + + + +## remove pubs +$pub = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + Name = 'Snappy' +} +Remove-DbaReplPublication @pub +## remove pubs +$pub = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + Name = 'TestPub' +} +Remove-DbaReplPublication @pub +## remove pubs +$pub = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + Name = 'Mergey' +} +Remove-DbaReplPublication @pub + + +# add subscriptions. + +#transactional +$sub = @{ + SqlInstance = 'mssql2' + Database = 'pubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'testpub' + Type = 'Push' + SubscriptionSqlCredential = $credential + +} +New-DbaReplSubscription @sub + +#merge +$sub = @{ + SqlInstance = 'mssql2' + Database = 'Mergeypubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'Mergey' + Type = 'Push' + SubscriptionSqlCredential = $credential + +} +New-DbaReplSubscription @sub + +#snapshot +$sub = @{ + SqlInstance = 'mssql2' + Database = 'Snappypubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'Snappy' + Type = 'Push' + SubscriptionSqlCredential = $credential +} +New-DbaReplSubscription @sub + + +# remove subscriptions +$sub = @{ + SqlInstance = 'mssql2' + SubscriptionDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationDatabase = 'pubs' + PublicationName = 'testPub' +} +Remove-DbaReplSubscription @sub + +$sub = @{ + SqlInstance = 'mssql2' + SubscriptionDatabase = 'Mergeypubs' + PublisherSqlInstance = 'mssql1' + PublicationDatabase = 'pubs' + PublicationName = 'Mergey' +} +Remove-DbaReplSubscription @sub + +$sub = @{ + SqlInstance = 'mssql2' + PublisherSqlInstance = 'mssql1' + PublicationName = 'snappy' + PublicationDatabase = 'pubs' + SubscriptionDatabase = 'Snappypubs' +} +Remove-DbaReplSubscription @sub + +# TODO: Does the schema exist on the subscriber? +<# +// Ensure that we create the schema owner at the Subscriber. +article.SchemaOption |= CreationScriptOptions.Schema; +#> \ No newline at end of file diff --git a/tests/Get-DbaRepPublication.Tests.ps1 b/tests/Get-DbaRepPublication.Tests.ps1 index 57e1f5c9e4..3206515248 100644 --- a/tests/Get-DbaRepPublication.Tests.ps1 +++ b/tests/Get-DbaRepPublication.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', 'Database', 'SqlCredential', 'PublicationType', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'Type', '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 @@ -53,7 +53,7 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { $Results.Database | Should Be "TestDB" } - It "Honors the PublicationType parameter" { + It "Honors the Type parameter" { Mock Connect-ReplicationDB -MockWith { [object]@{ @@ -66,13 +66,13 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { } } - $Results = Get-DbaRepPublication -SqlInstance MockServerName -Database TestDB -PublicationType Snapshot - $Results.PublicationType | Should Be "Snapshot" + $Results = Get-DbaRepPublication -SqlInstance MockServerName -Database TestDB -Type Snapshot + $Results.Type | Should Be "Snapshot" } - It "Stops if validate set for PublicationType is not met" { + It "Stops if validate set for Type is not met" { - { Get-DbaRepPublication -SqlInstance MockServerName -PublicationType NotAPubType } | should Throw + { Get-DbaRepPublication -SqlInstance MockServerName -Type NotAPubType } | should Throw } } diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index fb4b3f4fee..e0dd246221 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -3,7 +3,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - $PSDefaultParameterValues["*:SqlInstance"] = "localhost" + $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" @@ -14,6 +14,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # load dbatools-lib #Import-Module dbatools-core-library Import-Module ./dbatools.psd1 -Force + + $null = New-DbaDatabase -Name ReplDb + $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' + } Context "Get-DbaReplDistributor works" { @@ -171,4 +175,115 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } + + Context "New-DbaReplPublication works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "New-DbaReplPublication creates a Transactional publication" { + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + } + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + } + + } + + Context "Add-DbaReplArticle works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } + + $article = + } + + It "Add-DbaReplArticle adds an article to a Transactional publication" { + $pubname = 'TestPub' + Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + } + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + } + + } + + Context "Add-DbaReplArticle works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + + } + + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + } + } From a574a767fe4676655fd63a8d7825e9478732cb6d Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:20:06 +0100 Subject: [PATCH 014/226] tests --- public/Remove-DbaReplSubscription.ps1 | 3 + tests/gh-actions-repl.ps1 | 413 +++++++++++++------------- 2 files changed, 212 insertions(+), 204 deletions(-) diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 87fd98d02a..b9cdc4fb71 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -115,8 +115,11 @@ function Remove-DbaReplSubscription { try { if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $instance.$SubscriptionDatabase")) { + if ($pub.Type -in ('Transactional', 'Snapshot')) { + #TODO: Only handles push subscriptions at the moment - need to add pull subscriptions + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription $transSub.ConnectionContext = $replServer.ConnectionContext $transSub.DatabaseName = $PublicationDatabase diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index e0dd246221..2a64d58216 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -3,7 +3,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" + $PSDefaultParameterValues["*:SqlInstance"] = "localhost" $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" @@ -20,270 +20,275 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Get-DbaReplDistributor works" { - BeforeAll { + Describe "Enable\Disable Functions" -Tag ReplSetup { - # if distribution is enabled, disable it & enable it with defaults - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + Context "Get-DbaReplDistributor works" { + BeforeAll { + + # if distribution is enabled, disable it & enable it with defaults + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + Enable-DbaReplDistributor } - Enable-DbaReplDistributor - } - It "gets a distributor" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "gets a distributor" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } - It "distribution database name is correct" { - (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + It "distribution database name is correct" { + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + } } - } - Context "Enable-DbaReplDistributor works" { - BeforeAll { - # if distribution is enabled - disable it - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + Context "Enable-DbaReplDistributor works" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } } - } - It "distribution starts disabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } - It "distribution is enabled" { - Enable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $true + It "distribution is enabled" { + Enable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } } - } - Context "Enable-DbaReplDistributor works with specified database name" { - BeforeAll { - # if distribution is enabled - disable it - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + Context "Enable-DbaReplDistributor works with specified database name" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } } - } - AfterAll { - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + AfterAll { + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } } - } - It "distribution starts disabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } - It "distribution is enabled with specific database" { - $distDb = ('distdb-{0}' -f (Get-Random)) - Enable-DbaReplDistributor -DistributionDatabase $distDb - (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + It "distribution is enabled with specific database" { + $distDb = ('distdb-{0}' -f (Get-Random)) + Enable-DbaReplDistributor -DistributionDatabase $distDb + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + } } - } - Context "Disable-DbaReplDistributor works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor + Context "Disable-DbaReplDistributor works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } } - } - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } } - } - Context "Enable-DbaReplPublishing works" { - BeforeAll { - # if Publishing is enabled - disable it - if ((Get-DbaReplServer).IsPublisher) { - Disable-DbaReplPublishing - write-output 'DISABLE PUB' + Context "Enable-DbaReplPublishing works" { + BeforeAll { + # if Publishing is enabled - disable it + if ((Get-DbaReplServer).IsPublisher) { + Disable-DbaReplPublishing + write-output 'DISABLE PUB' + } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + write-output 'ENABLE DIST' + } } - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - write-output 'ENABLE DIST' + + It "publishing starts disabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $false } - } - It "publishing starts disabled" { - (Get-DbaReplServer).IsPublisher | Should -Be $false + It "publishing is enabled" { + write-output 'work on enable' + Enable-DbaReplPublishing -EnableException -Outvariable test + $test + (Get-DbaReplServer).IsPublisher | Should -Be $true + } } - It "publishing is enabled" { - write-output 'work on enable' - Enable-DbaReplPublishing -EnableException -Outvariable test - $test - (Get-DbaReplServer).IsPublisher | Should -Be $true - } - } + Context "Disable-DbaReplPublishing works" { + BeforeAll { + + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) - Context "Disable-DbaReplPublishing works" { - BeforeAll { + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + write-output -message 'I should enable publishing' + Enable-DbaReplPublishing -EnableException + } - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - write-output -message 'I should enable publishing' - Enable-DbaReplPublishing -EnableException + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) } - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - write-output -message 'I should enable distribution' - Enable-DbaReplDistributor -EnableException + It "publishing starts enabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $true } - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + It "publishing is disabled" { + Disable-DbaReplPublishing -EnableException + (Get-DbaReplServer).IsPublisher | Should -Be $false + } } + } - It "publishing starts enabled" { - (Get-DbaReplServer).IsPublisher | Should -Be $true - } + Describe "RestofTests" -Tag "Rest" -Skip { - It "publishing is disabled" { - Disable-DbaReplPublishing -EnableException - (Get-DbaReplServer).IsPublisher | Should -Be $false - } - } + Context "Get-DbaReplPublisher works" -skip { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } - Context "Get-DbaReplPublisher works" -skip { - BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - } - It "gets a publisher" { - (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - } + Context "New-DbaReplPublication works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } - Context "New-DbaReplPublication works" -Tag test { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor + It "New-DbaReplPublication creates a Transactional publication" { + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } - } - It "New-DbaReplPublication creates a Transactional publication" { - $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } - It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' - } - It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' - } - - } - Context "Add-DbaReplArticle works" -Tag test { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + Context "Add-DbaReplArticle works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } + + #$article = } - # we need some publications too - $name = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + + It "Add-DbaReplArticle adds an article to a Transactional publication" { + $pubname = 'TestPub' + Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } - $name = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } - $name = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } - $article = } - It "Add-DbaReplArticle adds an article to a Transactional publication" { - $pubname = 'TestPub' - Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' - } - It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' - } - It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' - } - - } + Context "Add-DbaReplArticle works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } - Context "Add-DbaReplArticle works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - - } - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } } } - } From b24c29007f0e63b2fa63aca6935f1f7b5df8f2c0 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:38:11 +0100 Subject: [PATCH 015/226] verbose --- tests/gh-actions-repl.ps1 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 2a64d58216..517ec7f825 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -106,12 +106,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing - write-output 'DISABLE PUB' + write-verbose 'DISABLE PUB' } # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { Enable-DbaReplDistributor - write-output 'ENABLE DIST' + write-verbose 'ENABLE DIST' } } @@ -120,9 +120,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - write-output 'work on enable' - Enable-DbaReplPublishing -EnableException -Outvariable test - $test + write-verbose 'work on enable' + Enable-DbaReplPublishing -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true } } From 40bba9bfa59589899cc3967d38a981f392cbf1f0 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:42:49 +0100 Subject: [PATCH 016/226] test --- tests/gh-actions-repl.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 517ec7f825..03ec0b3317 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -106,12 +106,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing - write-verbose 'DISABLE PUB' } # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { Enable-DbaReplDistributor - write-verbose 'ENABLE DIST' } } @@ -121,7 +119,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "publishing is enabled" { write-verbose 'work on enable' - Enable-DbaReplPublishing -EnableException + Enable-DbaReplPublishing -SqlInstance localhost -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true } } From 078187689fde713da43932fca4538578ba0ad957 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:51:20 +0100 Subject: [PATCH 017/226] writewarning --- tests/gh-actions-repl.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 03ec0b3317..aef10b6dc4 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -118,9 +118,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - write-verbose 'work on enable' Enable-DbaReplPublishing -SqlInstance localhost -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true + 'test' | Write-Warning + Get-DbatoolsError | Out-String | Write-Warning } } From 3c1946702ad0827e2b7c135b0b1bf0090154796e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:58:10 +0100 Subject: [PATCH 018/226] no null --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index d7bb4b3f84..2e5a99d682 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -51,4 +51,4 @@ jobs: Import-Module ./dbatools.psd1 -Force Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning - $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru + Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru From 5351d1eba56a42c4b23fb8736c7a9562afc20f93 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 11:01:34 +0100 Subject: [PATCH 019/226] verbose --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 2e5a99d682..a544dea866 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -51,4 +51,4 @@ jobs: Import-Module ./dbatools.psd1 -Force Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning - Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru + $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru -Verbose From 660304a87aeb1505009dbd2cebfe2b9ce913cc90 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 13:42:50 +0100 Subject: [PATCH 020/226] use hostname --- .github/workflows/integration-tests-repl.yml | 4 ++++ tests/gh-actions-repl.ps1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index a544dea866..0ddd2ba4bc 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -33,6 +33,10 @@ jobs: # Expose second engine and endpoint on different port docker run -p 14333:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + - name: Add hostname to hosts file + run: | + echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts + - name: 👥 Clone appveyor repo working-directory: /tmp run: | diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index aef10b6dc4..ccb3c085dd 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -3,7 +3,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - $PSDefaultParameterValues["*:SqlInstance"] = "localhost" + $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" From 30a1bfdd9e382d44301fcdbbd09d3f39aa8e03f1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 13:46:45 +0100 Subject: [PATCH 021/226] right name --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 0ddd2ba4bc..303f7028c7 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -35,7 +35,7 @@ jobs: - name: Add hostname to hosts file run: | - echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts + echo "127.0.0.1 mssql1 mssql2" | sudo tee -a /etc/hosts - name: 👥 Clone appveyor repo working-directory: /tmp From e2ff595992dabd4109aaf9bc71ed4c64d774c18f Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 13:49:33 +0100 Subject: [PATCH 022/226] remove hard coded localhost --- tests/gh-actions-repl.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index ccb3c085dd..2de4b59bde 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -118,10 +118,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - Enable-DbaReplPublishing -SqlInstance localhost -EnableException + Enable-DbaReplPublishing -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true - 'test' | Write-Warning - Get-DbatoolsError | Out-String | Write-Warning } } From ed4e19fa6f3211a2db0d5416c5f98f901ee2e538 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 13 Apr 2023 14:39:34 +0100 Subject: [PATCH 023/226] fix issue causing test failure --- public/Get-DbaReplPublisher.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 1c3e2acd14..23919bcb97 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -55,7 +55,7 @@ function Get-DbaReplPublisher { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $server + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue } @@ -64,7 +64,6 @@ function Get-DbaReplPublisher { try { if ($PSCmdlet.ShouldProcess($server, "Getting publisher for $server")) { $publisher = $replServer.DistributionPublishers - $publisher } } catch { Stop-Function -Message "Unable to get publisher for" -ErrorRecord $_ -Target $server -Continue From fc4088e7072780b121251dd5a29de78f8a3cadfa Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:29:56 +0100 Subject: [PATCH 024/226] Added TODO why articles not appear in specific condition --- public/Get-DbaReplPublication.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 4e59808ef6..755c19259f 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -112,7 +112,7 @@ function Get-DbaReplPublication { if ($Name) { $pubTypes = $pubTypes | Where-Object Name -in $Name } - + #TODO: Check why if -Database is not passed, I can't see the articles foreach ($pub in $pubTypes) { if ($pub.Type -eq 'Merge') { $articles = $pub.MergeArticles From 6384490485cffbc48daba0e30ba7363e93737757 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:30:37 +0100 Subject: [PATCH 025/226] Fix property name & Change validation order --- public/Get-DbaReplArticle.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index fa351a5abc..1b0091ec15 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -98,8 +98,8 @@ function Get-DbaReplArticle { $publications += $RMOdb.TransPublications $publications += $RMOdb.MergePublications - $publications - break + #$publications + #break #if ($PublicationType -in ('Snapshot','Transactional')) { # $publications = $RMOdb.TransPublications @@ -111,13 +111,13 @@ function Get-DbaReplArticle { #} if ($Publication) { - $publications = $publications | Where-Object PublicationName -in $Publication + $publications = $publications | Where-Object Name -in $Publication } - if ($PublicationType -eq 'Transactional') { - $articles = $publications.TransArticles - } else { + if ($PublicationType -eq 'Merge') { $articles = $publications.MergeArticles + } else { + $articles = $publications.TransArticles } if ($Article) { From ea1500f238cdb84d8cc773acd31ee2fbd5cc31bf Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:33:32 +0100 Subject: [PATCH 026/226] Add PublicationName property --- public/Get-DbaReplArticle.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 1b0091ec15..34c6cfb467 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -128,8 +128,9 @@ function Get-DbaReplArticle { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $Publications.Name - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } } } From 7c61e5ca6f52f0e1e2c6d525381c655502da7611 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:46:58 +0100 Subject: [PATCH 027/226] Change parameters name --- public/Get-DbaReplArticle.ps1 | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 34c6cfb467..b33dbb3d7f 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -19,12 +19,10 @@ function Get-DbaReplArticle { .PARAMETER Database Specifies one or more database(s) to process. If unspecified, all databases will be processed. - .PARAMETER PublicationName - #TODO change to Name + .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. - .PARAMETER PublicationType - #TODO change to Type + .PARAMETER Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER Article @@ -60,7 +58,7 @@ function Get-DbaReplArticle { [object[]]$Database, [parameter(ValueFromPipeline)] [object[]]$Publication, - [String]$PublicationType, # Snapshot, Transactional, Merge + [String]$Type, # Snapshot, Transactional, Merge [string[]]$Article, [switch]$EnableException ) @@ -98,23 +96,11 @@ function Get-DbaReplArticle { $publications += $RMOdb.TransPublications $publications += $RMOdb.MergePublications - #$publications - #break - - #if ($PublicationType -in ('Snapshot','Transactional')) { - # $publications = $RMOdb.TransPublications - #} elseif ($PublicationType -eq 'Merge') { - # $publications = $RMOdb.MergePublications - #} else { - # $RMOdb - # $publications = @($RMOdb.TransPublications + $RMOdb.MergePublications) - #} - if ($Publication) { $publications = $publications | Where-Object Name -in $Publication } - if ($PublicationType -eq 'Merge') { + if ($Type -eq 'Merge') { $articles = $publications.MergeArticles } else { $articles = $publications.TransArticles @@ -128,7 +114,7 @@ function Get-DbaReplArticle { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $Publications.Name + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } From fbae7cb125089766690d7911aff100f0ee755c83 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Thu, 4 May 2023 08:43:24 +0100 Subject: [PATCH 028/226] So the local tests works --- tests/gh-actions-repl.ps1 | 45 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 2de4b59bde..c64fc2b3dd 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -7,6 +7,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" + + #TODO: To be removed? + $PSDefaultParameterValues["*:-SnapshotShare"] = "/shared" $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" $global:ProgressPreference = "SilentlyContinue" @@ -17,10 +20,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = New-DbaDatabase -Name ReplDb $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' - } - Describe "Enable\Disable Functions" -Tag ReplSetup { + Describe "Enable\Disable Functions" -Tag ReplSetup -Skip { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -156,7 +158,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "RestofTests" -Tag "Rest" -Skip { + Describe "RestofTests" -Tag "Rest" <#-Skip#> { Context "Get-DbaReplPublisher works" -skip { BeforeAll { @@ -177,7 +179,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "New-DbaReplPublication works" -Tag test { + Context "New-DbaReplPublication works" -Tag test -Skip { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -213,7 +215,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Add-DbaReplArticle works" -Tag test { + Context "Add-DbaReplArticle works" -Tag test -Skip { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -241,7 +243,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Add-DbaReplArticle adds an article to a Transactional publication" { - $pubname = 'TestPub' + $Name = 'TestPub' Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' @@ -261,10 +263,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } - } - Context "Add-DbaReplArticle works" { + Context "Get-DbaReplArticle works" -Tag ArtTestGet { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -275,16 +276,32 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } } - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "Get-DbaReplArticle get the article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" + Add-DbaReplArticle -Database ReplDb -PublicationName $PublicationName -Name $Name - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false + $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName + $TransArticle.Count | Should -Be 1 + $TransArticle.Name | Should -Be $Name + $TransArticle.PublicationName | Should -Be $PublicationName } } + } } From c57ed81d431d5a2ba3de4113bbc967659f6d0c2d Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:39:30 +0100 Subject: [PATCH 029/226] add tests --- tests/gh-actions-repl.ps1 | 85 +++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index c64fc2b3dd..56f7e90051 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -43,6 +43,25 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } + Context "Get-DbaReplPublisher works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + + } + Context "Enable-DbaReplDistributor works" { BeforeAll { # if distribution is enabled - disable it @@ -127,10 +146,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Disable-DbaReplPublishing works" { BeforeAll { - - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) - # if publishing is disabled - enable it if (-not (Get-DbaReplServer).IsPublisher) { write-output -message 'I should enable publishing' @@ -142,9 +157,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { write-output -message 'I should enable distribution' Enable-DbaReplDistributor -EnableException } - - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) } It "publishing starts enabled" { @@ -238,9 +250,35 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name } + } + } + } - #$article = + Describe "Article tests" -Tag "ReplArticle" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } + } + Context "Add-DbaReplArticle works" { It "Add-DbaReplArticle adds an article to a Transactional publication" { $Name = 'TestPub' @@ -250,31 +288,26 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + $pubname = 'TestSnap' + $article = 'ReplicateMe' + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + + #TODO: waiting on Get-DbaReplArticle } It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + $pubname = 'TestMerge' + $article = 'ReplicateMe' + + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + + #TODO: waiting on Get-DbaReplArticle } } Context "Get-DbaReplArticle works" -Tag ArtTestGet { BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } + # we need some articles too remove + $article = 'ReplicateMe' # we need some publications too $name = 'TestTrans' From 58d22137aa6bc422232e2e30423d57c8c3d8b8e4 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:40:35 +0100 Subject: [PATCH 030/226] add snapshot support --- public/Remove-DbaReplArticle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index b76f2e3cce..bbd5c885a2 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -104,7 +104,7 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - if ($pub.Type -eq 'Transactional') { + if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle From 54a5e846ae5672118c72bc96e9b278e8c050b35d Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:40:57 +0100 Subject: [PATCH 031/226] add todo --- public/Get-DbaReplPublication.ps1 | 3 ++- public/Remove-DbaReplPublication.ps1 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 755c19259f..9e158a0e34 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -98,6 +98,7 @@ function Get-DbaReplPublication { foreach ($db in $databases) { if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { + #TODO: is this right - it doesn't actually skip the database Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." } @@ -119,7 +120,7 @@ function Get-DbaReplPublication { } else { $articles = $pub.TransArticles } - + #TODO: can this return a replication object? [PSCustomObject]@{ ComputerName = $server.ComputerName InstanceName = $server.ServiceName diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index deb77664c6..90f2a7c337 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -76,7 +76,7 @@ function Remove-DbaReplPublication { try { if ($PSCmdlet.ShouldProcess($instance, "Removing publication on $instance")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name -Database $Database if (-not $pub) { Write-Warning "Didn't find $Name on $Instance.$Database" From f3ddd68a2f3e89764d3c74326ad34a47bfbcc4c9 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:41:29 +0100 Subject: [PATCH 032/226] bug fuix --- public/New-DbaReplSubscription.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 3d9d7bfcaa..9181f1eefa 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -105,6 +105,9 @@ function New-DbaReplSubscription { foreach ($instance in $SqlInstance) { try { + + $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it" @@ -160,12 +163,14 @@ function New-DbaReplSubscription { # create the subscription $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription - $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.ConnectionContext = $subReplServer.ConnectionContext $transSub.SubscriptionDBName = $Database $transSub.SubscriberName = $instance $transSub.DatabaseName = $PublicationDatabase $transSub.PublicationName = $PublicationName + $transSub + #TODO: <# From 0cc9aeeb174878146343ddef29e3c2fb7aa68848 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:53:54 +0100 Subject: [PATCH 033/226] function stub --- public/Get-DbaReplSubscription.ps1 | 50 +++++------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index b43b9839e6..e50b89e52e 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -82,53 +82,19 @@ function Get-DbaReplSubscription { # Connect to Publisher try { - $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $PublisherSqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } - if ($Database) { - $databases = $databases | Where-Object Name -In $Database - } + # Get all subscriptions + $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription + $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.EnumSubscriptions() + + + #TODO: finish this function - foreach ($db in $databases) { - - if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { - Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - } - - $repDB = Connect-ReplicationDB -Server $server -Database $db - - $pubTypes = $repDB.TransPublications + $repDB.MergePublications - - if ($Type) { - $pubTypes = $pubTypes | Where-Object Type -in $Type - } - - if ($Name) { - $pubTypes = $pubTypes | Where-Object Name -in $Name - } - - foreach ($pub in $pubTypes) { - if ($pub.Type -eq 'Merge') { - $articles = $pub.MergeArticles - } else { - $articles = $pub.TransArticles - } - - [PSCustomObject]@{ - ComputerName = $server.ComputerName - InstanceName = $server.ServiceName - SqlInstance = $server.Name - Server = $server.name - Database = $db.name - Name = $pub.Name #TODO: breaking change from PublicationName to Name - Type = $pub.Type #TODO: breaking change from PublicationType to Type - Articles = $articles - } - } - } } } } \ No newline at end of file From 6e1f2b638000cef4d1aafa05d0b269027107b308 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:54:08 +0100 Subject: [PATCH 034/226] testing notes --- testing.ps1 | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/testing.ps1 b/testing.ps1 index caedf045e6..1aac8cd70a 100644 --- a/testing.ps1 +++ b/testing.ps1 @@ -121,6 +121,30 @@ $article = @{ } Add-DbaReplArticle @article +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'publishers' +} +Add-DbaReplArticle @article -EnableException + + +$article = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + PublicationName = 'testtrans' + Name = 'ReplicateMe' +} +Add-DbaReplArticle @article -EnableException + +$article = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + PublicationName = 'testtrans' + Name = 'ReplicateMe' +} +Remove-DbaReplArticle @article # mergey $article = @{ @@ -128,7 +152,7 @@ $article = @{ Database = 'pubs' PublicationName = 'Mergey' Name = 'publishers' - Filter = "city = 'seattle'" ## not working? + #Filter = "city = 'seattle'" ## not working? } Add-DbaReplArticle @article @@ -185,6 +209,7 @@ $pub = @{ Remove-DbaReplPublication @pub + # add subscriptions. #transactional @@ -198,7 +223,7 @@ $sub = @{ SubscriptionSqlCredential = $credential } -New-DbaReplSubscription @sub +New-DbaReplSubscription @sub -enableexception #merge $sub = @{ From bf95f3896b0a17f1ae9a65d86a574d1b13b171ab Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:57:46 +0100 Subject: [PATCH 035/226] psm1\psd1 merging --- dbatools.psd1 | 27 ++++++--------------------- dbatools.psm1 | 23 ++++++----------------- 2 files changed, 12 insertions(+), 38 deletions(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index 7fc43c7809..26a2d3e37d 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -139,7 +139,7 @@ 'Export-DbaLogin', 'Export-DbaPfDataCollectorSetTemplate', 'Export-DbaRegServer', - 'Export-DbaReplServerSetting', + 'Export-DbaRepServerSetting', 'Export-DbaScript', 'Export-DbaServerRole', 'Export-DbaSpConfigure', @@ -350,10 +350,9 @@ 'Get-DbaRegServer', 'Get-DbaRegServerGroup', 'Get-DbaRegServerStore', - 'Get-DbaReplDistributor', - 'Get-DbaReplPublication', - 'Get-DbaReplPublisher', - 'Get-DbaReplServer', + 'Get-DbaRepDistributor', + 'Get-DbaRepPublication', + 'Get-DbaRepServer', 'Get-DbaResourceGovernor', 'Get-DbaRgClassifierFunction', 'Get-DbaRgResourcePool', @@ -694,7 +693,7 @@ 'Test-DbaOptimizeForAdHoc', 'Test-DbaPath', 'Test-DbaPowerPlan', - 'Test-DbaReplLatency', + 'Test-DbaRepLatency', 'Test-DbaSpn', 'Test-DbaTempDbConfig', 'Test-DbaWindowsLogin', @@ -729,21 +728,7 @@ 'New-DbaLinkedServerLogin', 'Remove-DbaLinkedServerLogin', 'Remove-DbaCredential', - 'Remove-DbaAgentProxy', - - # NEW REPLICATION STUFF - 'Disable-DbaReplDistributor', - 'Enable-DbaReplDistributor', - 'Disable-DbaReplPublishing', - 'Enable-DbaReplPublishing', - 'New-DbaReplPublication', - 'Get-DbaReplArticle', - 'Get-DbaReplArticleColumn', - 'Add-DbaReplArticle', - 'Remove-DbaReplArticle', - 'Remove-DbaReplPublication', - 'New-DbaReplSubscription', - 'Remove-DbaReplSubscription' + 'Remove-DbaAgentProxy' ) # Cmdlets to export from this module diff --git a/dbatools.psm1 b/dbatools.psm1 index 3e4390a21e..55fd649f59 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -295,19 +295,9 @@ $forever = @{ foreach ($_ in $forever.GetEnumerator()) { Set-Alias -Name $_.Key -Value $_.Value } - -# Replication Aliases -$replAliases = @{ - 'Get-DbaRepServer' = 'Get-DbaReplServer' - 'Export-DbaRepServerSetting' = 'Export-DbaReplServerSetting' - 'Get-DbaRepDistributor' = 'Get-DbaReplDistributor' - 'Test-DbaRepLatency' = 'Test-DbaReplLatency' -} -foreach ($_ in $replAliases.GetEnumerator()) { - Set-Alias -Name $_.Key -Value $_.Value -} #endregion Aliases +# apparently this is no longer required? :O if ($PSVersionTable.PSVersion.Major -lt 5) { # region Commands $script:xplat = @( @@ -854,10 +844,9 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Remove-DbaCredential', 'Remove-DbaAgentProxy' ) - #TODO: can repl commands be removed here? $script:noncoresmo = @( # SMO issues - 'Get-DbaReplDistributor', + 'Get-DbaRepDistributor', 'Copy-DbaPolicyManagement', 'Copy-DbaDataCollector', 'Get-DbaPbmCategory', @@ -866,10 +855,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Get-DbaPbmObjectSet', 'Get-DbaPbmPolicy', 'Get-DbaPbmStore', - 'Get-DbaReplPublication', - 'Test-DbaReplLatency', - 'Export-DbaReplServerSetting', - 'Get-DbaReplServer' + 'Get-DbaRepPublication', + 'Test-DbaRepLatency', + 'Export-DbaRepServerSetting', + 'Get-DbaRepServer' ) $script:windowsonly = @( # filesystem (\\ related), From b0164fe406063cbea80532d80358651cb9b9523e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:10:58 +0100 Subject: [PATCH 036/226] repl psd\psm changes --- dbatools.psd1 | 33 ++++++++++++++++++++++++++------- dbatools.psm1 | 22 +++++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index 26a2d3e37d..0d3cfb175e 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -139,7 +139,7 @@ 'Export-DbaLogin', 'Export-DbaPfDataCollectorSetTemplate', 'Export-DbaRegServer', - 'Export-DbaRepServerSetting', + 'Export-DbaReplServerSetting', 'Export-DbaScript', 'Export-DbaServerRole', 'Export-DbaSpConfigure', @@ -350,9 +350,10 @@ 'Get-DbaRegServer', 'Get-DbaRegServerGroup', 'Get-DbaRegServerStore', - 'Get-DbaRepDistributor', - 'Get-DbaRepPublication', - 'Get-DbaRepServer', + 'Get-DbaReplDistributor', + 'Get-DbaReplPublication', + 'Get-DbaReplPublisher', + 'Get-DbaReplServer', 'Get-DbaResourceGovernor', 'Get-DbaRgClassifierFunction', 'Get-DbaRgResourcePool', @@ -693,7 +694,7 @@ 'Test-DbaOptimizeForAdHoc', 'Test-DbaPath', 'Test-DbaPowerPlan', - 'Test-DbaRepLatency', + 'Test-DbaReplLatency', 'Test-DbaSpn', 'Test-DbaTempDbConfig', 'Test-DbaWindowsLogin', @@ -728,7 +729,21 @@ 'New-DbaLinkedServerLogin', 'Remove-DbaLinkedServerLogin', 'Remove-DbaCredential', - 'Remove-DbaAgentProxy' + 'Remove-DbaAgentProxy', + + # NEW REPLICATION STUFF + 'Disable-DbaReplDistributor', + 'Enable-DbaReplDistributor', + 'Disable-DbaReplPublishing', + 'Enable-DbaReplPublishing', + 'New-DbaReplPublication', + 'Get-DbaReplArticle', + 'Get-DbaReplArticleColumn', + 'Add-DbaReplArticle', + 'Remove-DbaReplArticle', + 'Remove-DbaReplPublication', + 'New-DbaReplSubscription', + 'Remove-DbaReplSubscription' ) # Cmdlets to export from this module @@ -757,7 +772,11 @@ 'Get-DbaRepServer', 'Export-DbaRepServerSetting', 'Get-DbaRepDistributor', - 'Test-DbaRepLatency' + 'Test-DbaRepLatency', + 'Get-DbaRepDistributor', + 'Get-DbaRepPublication', + 'Get-DbaRepServer' + ) diff --git a/dbatools.psm1 b/dbatools.psm1 index 55fd649f59..da9f7d41d4 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -295,6 +295,18 @@ $forever = @{ foreach ($_ in $forever.GetEnumerator()) { Set-Alias -Name $_.Key -Value $_.Value } + +# Replication Aliases +$replAliases = @{ + 'Get-DbaRepServer' = 'Get-DbaReplServer' + 'Export-DbaRepServerSetting' = 'Export-DbaReplServerSetting' + 'Get-DbaRepDistributor' = 'Get-DbaReplDistributor' + 'Test-DbaRepLatency' = 'Test-DbaReplLatency' + 'Get-DbaRepPublication' = 'Get-DbaReplPublication' +} +foreach ($_ in $replAliases.GetEnumerator()) { + Set-Alias -Name $_.Key -Value $_.Value +} #endregion Aliases # apparently this is no longer required? :O @@ -846,7 +858,7 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { ) $script:noncoresmo = @( # SMO issues - 'Get-DbaRepDistributor', + 'Get-DbaReplDistributor', 'Copy-DbaPolicyManagement', 'Copy-DbaDataCollector', 'Get-DbaPbmCategory', @@ -855,10 +867,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Get-DbaPbmObjectSet', 'Get-DbaPbmPolicy', 'Get-DbaPbmStore', - 'Get-DbaRepPublication', - 'Test-DbaRepLatency', - 'Export-DbaRepServerSetting', - 'Get-DbaRepServer' + 'Get-DbaReplPublication', + 'Test-DbaReplLatency', + 'Export-DbaReplServerSetting', + 'Get-DbaReplServer' ) $script:windowsonly = @( # filesystem (\\ related), From 0793003605de112a2902df01bfc6e2c81e7c4269 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:24:35 +0100 Subject: [PATCH 037/226] change module to cache for library --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 303f7028c7..45c162b89e 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -15,7 +15,7 @@ jobs: - name: Install and cache PowerShell modules uses: potatoqualitee/psmodulecache@v5.2 with: - modules-to-cache: dbatools.library:2023.1.29 + modules-to-cache: dbatools.library:2023.5.5 - name: Set encryption values run: | From 94938300180025c8593e1ffaa46f6fe491b596ec Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:39:42 +0100 Subject: [PATCH 038/226] testy tests --- tests/gh-actions-repl.ps1 | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 56f7e90051..34e0cd78ff 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -22,7 +22,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' } - Describe "Enable\Disable Functions" -Tag ReplSetup -Skip { + Describe "Enable\Disable Functions" -Tag ReplSetup { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -170,9 +170,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "RestofTests" -Tag "Rest" <#-Skip#> { + Describe "RestofTests" -Tag "Rest" { - Context "Get-DbaReplPublisher works" -skip { + Context "Get-DbaReplPublisher works" { BeforeAll { # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -191,7 +191,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "New-DbaReplPublication works" -Tag test -Skip { + Context "New-DbaReplPublication works" { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -227,7 +227,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Add-DbaReplArticle works" -Tag test -Skip { + Context "Add-DbaReplArticle works" { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -277,28 +277,25 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name } + $articleName = 'ReplicateMe' } Context "Add-DbaReplArticle works" { It "Add-DbaReplArticle adds an article to a Transactional publication" { - $Name = 'TestPub' - Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + $pubName = 'TestPub' + Add-DbaReplArticle -Database ReplDb -Name $articleName -PublicationName $pubName + + #TODO: waiting on Get-DbaReplArticle } It "New-DbaReplPublication creates a Snapshot publication" { $pubname = 'TestSnap' - $article = 'ReplicateMe' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw #TODO: waiting on Get-DbaReplArticle } It "New-DbaReplPublication creates a Merge publication" { $pubname = 'TestMerge' - $article = 'ReplicateMe' - - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw #TODO: waiting on Get-DbaReplArticle } From be4943aa16abcad032cdca6827b73237063424c3 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:43:20 +0100 Subject: [PATCH 039/226] psf --> just message --- public/Get-DbaReplArticle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index b33dbb3d7f..775c89b026 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -83,7 +83,7 @@ function Get-DbaReplArticle { } foreach ($db in $databases) { - Write-PSFMessage -Level Verbose -Message ('Working on {0}' -f $db) + Write-Message -Level Verbose -Message ('Working on {0}' -f $db) $RMOdb = Connect-ReplicationDB -Server $server -Database $db From 87e9e7e902d73fb0bed4fe2677a9547af081fa7c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 18 May 2023 16:18:26 +0100 Subject: [PATCH 040/226] remove SupportsShouldProcess on get --- public/Get-DbaReplPublisher.ps1 | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 23919bcb97..846cdf64e6 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -1,10 +1,10 @@ function Get-DbaReplPublisher { <# .SYNOPSIS - Gets publisher for the target SQL instances. + Gets publisher information for the target SQL instances. .DESCRIPTION - Gets publisher for the target SQL instances. + Gets publisher information for the target SQL instances. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -21,12 +21,6 @@ function Get-DbaReplPublisher { 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: Replication Author: Mikey Bronowski (@MikeyBronowski), bronowski.it @@ -43,8 +37,12 @@ function Get-DbaReplPublisher { Gets publisher for the mssql1 instance. + .EXAMPLE + PS C:\> Connect-DbaInstance -SqlInstance mssql1 | Get-DbaReplPublisher + + Pipes a SQL Server object to get publisher information for the mssql1 instance. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding()] param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, @@ -62,9 +60,7 @@ function Get-DbaReplPublisher { Write-Message -Level Verbose -Message "Getting publisher for $server" try { - if ($PSCmdlet.ShouldProcess($server, "Getting publisher for $server")) { - $publisher = $replServer.DistributionPublishers - } + $publisher = $replServer.DistributionPublishers } catch { Stop-Function -Message "Unable to get publisher for" -ErrorRecord $_ -Target $server -Continue } @@ -76,7 +72,6 @@ function Get-DbaReplPublisher { $publisher | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force } - Select-DefaultView -InputObject $publisher -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name } From 52038ec4115f64f737f369ac241938b861293fc5 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 26 May 2023 17:05:36 +0100 Subject: [PATCH 041/226] updates --- public/Add-DbaReplArticle.ps1 | 15 +++- public/Get-DbaReplArticle.ps1 | 140 ++++++++++++++++++++--------- public/Get-DbaReplDistributor.ps1 | 14 +-- public/Get-DbaReplPublication.ps1 | 106 ++++++++++++---------- public/New-DbaReplPublication.ps1 | 9 +- public/New-DbaReplSubscription.ps1 | 27 +++--- public/Remove-DbaReplArticle.ps1 | 8 ++ 7 files changed, 209 insertions(+), 110 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 5873626d49..dabda1cfa4 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -46,7 +46,7 @@ function Add-DbaReplArticle { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT @@ -88,9 +88,17 @@ function Add-DbaReplArticle { [String]$Filter, + #TODO: Build a New-DbaReplArticleOptions function + [Microsoft.SqlServer.Replication.ArticleOptions]$ArticleOptions, + [Switch]$EnableException ) process { + + if (Test-Bound -not ArticleOptions) { + $ArticleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions + } + foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential @@ -104,7 +112,7 @@ function Add-DbaReplArticle { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions + if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle @@ -133,6 +141,9 @@ function Add-DbaReplArticle { } else { Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } + + # need to refresh subscriptions so they know about new articles + $pub.RefreshSubscriptions() } } catch { Stop-Function -Message "Unable to add article $Name to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 775c89b026..4a38388f37 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -4,7 +4,9 @@ function Get-DbaReplArticle { Gets the information about publication articles. .DESCRIPTION - This function locates and enumerates articles' information for a given publication. + This function locates and enumerates articles' information. + + Can specify a database, publication or article name or publication type. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -23,7 +25,7 @@ function Get-DbaReplArticle { Specifies one or more publication(s) to process. If unspecified, all publications will be processed. .PARAMETER Type - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot. .PARAMETER Article Specifies one or more article(s) to process. If unspecified, all articles will be processed. @@ -45,6 +47,48 @@ function Get-DbaReplArticle { https://dbatools.io/Get-DbaReplArticle .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 + + Retrieve information of all articles from all publications on all databases for server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database pubs + + Retrieve information of all articles from all publications on 'pubs' database for server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database pubs -Publication PubName + + Retrieve information of all articles from 'PubName' on 'pubs' database for server mssql1. + + #TODO: results publicationname contains all the publication names if article is in more than one ? + ComputerName : mssql1 + InstanceName : MSSQLSERVER + SqlInstance : mssql1 + DatabaseName : ReplDb + PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} + Name : ReplicateMe + ArticleId : 2 + Description : + Type : LogBased + VerticalPartition : False + SourceObjectOwner : dbo + SourceObjectName : ReplicateMe + + ComputerName : mssql1 + InstanceName : MSSQLSERVER + SqlInstance : mssql1 + DatabaseName : ReplDb + PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} + Name : ReplicateMe + ArticleId : 3 + Description : + Type : LogBased + VerticalPartition : False + SourceObjectOwner : dbo + SourceObjectName : ReplicateMe + + PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. @@ -58,12 +102,12 @@ function Get-DbaReplArticle { [object[]]$Database, [parameter(ValueFromPipeline)] [object[]]$Publication, - [String]$Type, # Snapshot, Transactional, Merge + [ValidateSet("Transactional", "Merge", "Snapshot")] + [String]$Type, [string[]]$Article, [switch]$EnableException ) begin { - #TODO - Still needed? Add-ReplicationLibrary } process { @@ -73,51 +117,63 @@ function Get-DbaReplArticle { # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $databases = $server.Databases | Where-Object IsAccessible -eq $true - if ($Database) { - $databases = $databases | Where-Object Name -In $Database - } - - foreach ($db in $databases) { - Write-Message -Level Verbose -Message ('Working on {0}' -f $db) - - $RMOdb = Connect-ReplicationDB -Server $server -Database $db - - #TODO - Check if database has replication options - #if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { - # Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - #} - - $publications = @() - $publications += $RMOdb.TransPublications - $publications += $RMOdb.MergePublications - - if ($Publication) { - $publications = $publications | Where-Object Name -in $Publication - } - - if ($Type -eq 'Merge') { - $articles = $publications.MergeArticles - } else { - $articles = $publications.TransArticles - } - - if ($Article) { - $articles = $articles | Where-Object Name -In $Article + try { + $databases = $server.Databases | Where-Object IsAccessible -eq $true + if ($Database) { + $databases = $databases | Where-Object Name -In $Database } + } catch { + Stop-Function -Message "Error occurred while getting databases from $instance" -ErrorRecord $_ -Target $instance -Continue + } - foreach ($art in $articles) { - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name - - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + try { + foreach ($db in $databases) { + Write-Message -Level Verbose -Message ('Working on {0}' -f $db.Name) + + $RMOdb = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $RMOdb.ConnectionContext = $replServer.ConnectionContext + $RMOdb.Name = $db.Name + if (-not $RMOdb.LoadProperties()) { + Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + continue + } + + #$RMOdb = Connect-ReplicationDB -Server $server -Database $db + + $publications = @() + $publications += $RMOdb.TransPublications + $publications += $RMOdb.MergePublications + + if ($Publication) { + $publications = $publications | Where-Object Name -in $Publication + } + + if ($Type -eq 'Merge') { + $articles = $publications.MergeArticles + } else { + $articles = $publications.TransArticles + } + + if ($Article) { + $articles = $articles | Where-Object Name -In $Article + } + + foreach ($art in $articles) { + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + } } + } catch { + Stop-Function -Message "Error occurred while getting articles from $instance" -ErrorRecord $_ -Target $instance -Continue } } } diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index a93522df7c..58a76e0e69 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -6,6 +6,7 @@ function Get-DbaReplDistributor { .DESCRIPTION This function locates and enumerates distributor information for a given SQL Server instance. + TODO: I think we can remove this? All replication commands need SQL Server Management Studio installed and are therefore currently not supported. Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 @@ -40,6 +41,10 @@ function Get-DbaReplDistributor { Retrieve distributor information for servers sql2008 and sqlserver2012. + .EXAMPLE + PS C:\> Connect-DbaInstance -SqlInstance mssql1 | Get-DbaReplDistributor + + Pipe a SQL Server instance to Get-DbaReplDistributor to retrieve distributor information. #> [CmdletBinding()] param ( @@ -48,9 +53,6 @@ function Get-DbaReplDistributor { [PSCredential]$SqlCredential, [switch]$EnableException ) - begin { - Add-ReplicationLibrary - } process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { @@ -59,12 +61,12 @@ function Get-DbaReplDistributor { # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $sqlconn = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential - - $distributor = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlconn + $distributor = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } + Write-Message -Level Verbose -Message "Getting publisher for $server" + Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 9e158a0e34..0d2753e3ba 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -1,23 +1,18 @@ function Get-DbaReplPublication { <# .SYNOPSIS - Displays all publications for a server or database. + Displays all publications on a server. .DESCRIPTION - Quickly find all transactional, merge, and snapshot publications on a specific server or database. + Quickly find all transactional, merge, and snapshot publications on a server or filter by database, name or type. + TODO: is this still true? remove? All replication commands need SQL Server Management Studio installed and are therefore currently not supported. Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 .PARAMETER SqlInstance The target SQL Server instance or instances. - .PARAMETER Database - The database(s) to process. If unspecified, all databases will be processed. - - .PARAMETER Name - The name of the publication. - .PARAMETER SqlCredential Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). @@ -25,8 +20,14 @@ function Get-DbaReplPublication { For MFA support, please use Connect-DbaInstance. + .PARAMETER Database + The database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER Name + The name of the publication. + .PARAMETER Type - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -57,19 +58,24 @@ function Get-DbaReplPublication { .EXAMPLE PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional - Return all publications on server sql2008 for all databases that have Transactional publications + Return all transactional publications on server sql2008. .EXAMPLE PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey Returns the Mergey publications on server mssql1 + + .EXAMPLE + PS C:\> Connect-DbaInstance -SqlInstance mssql1 | Get-DbaReplPublication + + Returns all publications on server mssql1 using the pipeline. #> [CmdletBinding()] param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [object[]]$Database, [PSCredential]$SqlCredential, + [object[]]$Database, [String]$Name, [Alias("PublicationType")] [ValidateSet("Transactional", "Merge", "Snapshot")] @@ -82,7 +88,7 @@ function Get-DbaReplPublication { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - + write-message 'jo' # Connect to Publisher try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 @@ -90,48 +96,58 @@ function Get-DbaReplPublication { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } - if ($Database) { - $databases = $databases | Where-Object Name -In $Database + try { + $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } + if ($Database) { + $databases = $databases | Where-Object Name -In $Database + } + } catch { + Stop-Function -Message "Unable to get databases for" -ErrorRecord $_ -Target $server -Continue } - foreach ($db in $databases) { - - if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { - #TODO: is this right - it doesn't actually skip the database - Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - } + try { + foreach ($db in $databases) { + + #test if the database published + if ((($db.ReplicationOptions -band [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::Published) -ne [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::Published) -and + (($db.ReplicationOptions -band [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::MergePublished) -ne [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::MergePublished)) { + # The database is not published + Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + continue + } - $repDB = Connect-ReplicationDB -Server $server -Database $db + $repDB = Connect-ReplicationDB -Server $server -Database $db - $pubTypes = $repDB.TransPublications + $repDB.MergePublications + $pubTypes = $repDB.TransPublications + $repDB.MergePublications - if ($Type) { - $pubTypes = $pubTypes | Where-Object Type -in $Type - } + if ($Type) { + $pubTypes = $pubTypes | Where-Object Type -in $Type + } - if ($Name) { - $pubTypes = $pubTypes | Where-Object Name -in $Name - } - #TODO: Check why if -Database is not passed, I can't see the articles - foreach ($pub in $pubTypes) { - if ($pub.Type -eq 'Merge') { - $articles = $pub.MergeArticles - } else { - $articles = $pub.TransArticles + if ($Name) { + $pubTypes = $pubTypes | Where-Object Name -in $Name } - #TODO: can this return a replication object? - [PSCustomObject]@{ - ComputerName = $server.ComputerName - InstanceName = $server.ServiceName - SqlInstance = $server.Name - Server = $server.name - Database = $db.name - Name = $pub.Name #TODO: breaking change from PublicationName to Name - Type = $pub.Type #TODO: breaking change from PublicationType to Type - Articles = $articles + + #TODO: Check why if -Database is not passed, I can't see the articles (JP - this works for me... 🤔) + foreach ($pub in $pubTypes) { + if ($pub.Type -eq 'Merge') { + $articles = $pub.MergeArticles + } else { + $articles = $pub.TransArticles + } + + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Articles -Value $articles + + Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles + #TODO: breaking change from PublicationName to Name + #TODO: breaking change from PublicationType to Type } } + } catch { + Stop-Function -Message "Unable to get publications from " -ErrorRecord $_ -Target $server -Continue } } } diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 68ebf88e49..2226e9e1bd 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -62,9 +62,9 @@ function New-DbaReplPublication { https://dbatools.io/New-DbaReplPublication .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Type Transactional - Creates a publication called PubFromPosh for the Northwind database on mssql1 + Creates a transactional publication called PubFromPosh for the Northwind database on mssql1 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] @@ -99,6 +99,7 @@ function New-DbaReplPublication { try { if ($PSCmdlet.ShouldProcess($instance, "Creating publication on $instance")) { + #TODO: could replace this with call to Connect-ReplicationDB $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $replServer.ConnectionContext $pubDatabase.Name = $Database @@ -109,12 +110,12 @@ function New-DbaReplPublication { if ($Type -in ('Transactional', 'Snapshot')) { Write-Message -Level Verbose -Message "Enable trans publishing publication on $instance.$Database" $pubDatabase.EnabledTransPublishing = $true + $pubDatabase.CommitPropertyChanges() } elseif ($Type -eq 'Merge') { Write-Message -Level Verbose -Message "Enable merge publishing publication on $instance.$Database" $pubDatabase.EnabledMergePublishing = $true - $pubDatabase.CommitPropertyChanges + $pubDatabase.CommitPropertyChanges() } - #TODO: snapshot repl? if (-not $pubDatabase.LogReaderAgentExists) { #TODO: if this needed for merge? diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 9181f1eefa..b2caaf4c54 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -25,7 +25,6 @@ function New-DbaReplSubscription { .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. @@ -77,7 +76,7 @@ function New-DbaReplSubscription { $SubscriptionSqlCredential, [parameter(Mandatory)] - [ValidateSet("Push", "Pull")] #TODO: make this do something :) + [ValidateSet("Push", "Pull")] [String]$Type, [Switch]$EnableException @@ -87,13 +86,15 @@ function New-DbaReplSubscription { # connect to publisher and get the publication try { - $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + $pubReplServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } try { $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + + } catch { Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue } @@ -109,7 +110,7 @@ function New-DbaReplSubscription { $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { - Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it" + Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it - but you should check the settings!" if ($PSCmdlet.ShouldProcess($instance, "Creating subscription database")) { @@ -133,17 +134,21 @@ function New-DbaReplSubscription { if ($pub.Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication - $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.ConnectionContext = $pubReplServer.ConnectionContext $transPub.DatabaseName = $PublicationDatabase $transPub.Name = $PublicationName # if LoadProperties returns then the publication was found if ( $transPub.LoadProperties() ) { - if ($type = 'Push') { + 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 'ALlowPush' -eq 'None' ) { + 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' @@ -152,7 +157,7 @@ function New-DbaReplSubscription { } } else { # Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull. - if ($transPub.Attributes -band 'ALlowPull' -eq 'None' ) { + if ($transPub.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. $transPub.Attributes = $transPub.Attributes -bor 'AllowPull' @@ -163,7 +168,7 @@ function New-DbaReplSubscription { # create the subscription $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription - $transSub.ConnectionContext = $subReplServer.ConnectionContext + $transSub.ConnectionContext = $pubReplServer.ConnectionContext $transSub.SubscriptionDBName = $Database $transSub.SubscriberName = $instance $transSub.DatabaseName = $PublicationDatabase @@ -201,7 +206,7 @@ function New-DbaReplSubscription { } elseif ($pub.Type -eq 'Merge') { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication - $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.ConnectionContext = $pubReplServer.ConnectionContext $mergePub.DatabaseName = $PublicationDatabase $mergePub.Name = $PublicationName @@ -235,7 +240,7 @@ function New-DbaReplSubscription { $mergeSub = New-Object Microsoft.SqlServer.Replication.MergePullSubscription } - $mergeSub.ConnectionContext = $replServer.ConnectionContext + $mergeSub.ConnectionContext = $pubReplServer.ConnectionContext $mergeSub.SubscriptionDBName = $Database $mergeSub.SubscriberName = $instance $mergeSub.DatabaseName = $PublicationDatabase diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index bbd5c885a2..7743569026 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -15,6 +15,8 @@ If an article is dropped after one or more subscriptions is created, the subscri Dropping an article from a publication involves dropping the article and creating a new snapshot for the publication. Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. +TODO: WARNING: [16:39:55][Remove-DbaReplArticle] Unable to remove article from testPub on mssql1 | Could not drop article. A subscription exists on it. +Need to drop from sub? https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 @@ -118,6 +120,12 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a $article.PublicationName = $PublicationName $article.DatabaseName = $Database + #TODO: Fix this - hard coded subscriber name + # if it has a subscription, we need to drop it first = can't work it out with RMO + # how do we get subscriber name too? + $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, 'mssql2' + Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query + if (($article.IsExistingObject)) { $article.Remove() } else { From 89094f93eddb5cb16d96ab9985cf8e8aefbd11b6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 26 May 2023 17:05:44 +0100 Subject: [PATCH 042/226] new tests --- tests/gh-actions-repl.ps1 | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 34e0cd78ff..2fd197c68a 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -41,6 +41,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "distribution database name is correct" { (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' } + + It "can pipe a sql server object to it" { + Connect-DbaInstance | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty + } } Context "Get-DbaReplPublisher works" { @@ -60,6 +64,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } + It "gets a publisher using piping" { + (Connect-DbaInstance | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + } Context "Enable-DbaReplDistributor works" { @@ -191,6 +199,47 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } + Context "Get-DbaReplPublication works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + + # create a publication + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName ('{0}-Trans' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName ('{0}-Merge' -f $Name) + $null = New-DbaDatabase -Name Test + New-DbaReplPublication -Database Test -Type Snapshot -PublicationName ('{0}-Snapshot' -f $Name) + } + + It "gets all publications" { + Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + + It "gets publications for a specific database" { + Get-DbaReplPublication -Database ReplDb | Should -Not -BeNullOrEmpty + (Get-DbaRepPublication -Database ReplDb).Database | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + + It "gets publications for a specific type" { + Get-DbaReplPublication -Type Transactional | Should -Not -BeNullOrEmpty + (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } + } + + It "works with piping" { + Connect-DbaInstance | Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + } + + + Context "New-DbaReplPublication works" { BeforeAll { # if replication is disabled - enable it From 8300876efca26b3d8e13ca5d4f6c8082cd5dfdc1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 26 May 2023 17:05:50 +0100 Subject: [PATCH 043/226] stuff --- ReplicationCommands.md | 2 +- ReplicationDemo.ps1 | 99 ++++++++++++++++++++++++++++++++++++++++++ testing.ps1 | 23 ++-------- 3 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 ReplicationDemo.ps1 diff --git a/ReplicationCommands.md b/ReplicationCommands.md index fdd790c96b..933a9f5ada 100644 --- a/ReplicationCommands.md +++ b/ReplicationCommands.md @@ -56,7 +56,7 @@ Meaning of the checkmarks: - [ ] Get-DbaReplSnapshotAgentStatus - [ ] Get-DbaReplLogReaderAgentStatus - [ ] Test-DbaReplSnapFolder - similar to Test-DbaPath but from replication service account perspective or something similar to check If the share (UNC or Local) is accessible from both, publisher and subscriber side - +- [ ] Reinitialise-? - what do we need here ## How to run pester tests locally ```PowerShell diff --git a/ReplicationDemo.ps1 b/ReplicationDemo.ps1 new file mode 100644 index 0000000000..4205c4445f --- /dev/null +++ b/ReplicationDemo.ps1 @@ -0,0 +1,99 @@ +# dbatools 💜 dbatools + +############################## +# create docker environment +############################## +# create a shared network +docker network create localnet + +# Expose engines and setup shared path for migrations +docker run -p 2500:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance +docker run -p 2600:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + +# create the repl folder +docker exec mssql1 mkdir /var/opt/mssql/ReplData + +# also need these folders for setting up replication +docker exec mssql1 mkdir /shared/data /shared/repldata + +############################## + +# import out version of the module +cd C:\GitHub\DMM-GitHub\dbatools +Import-Module .\dbatools.psd1 + +# lets save the password for connecting to containers because I'm lazy +$securePassword = ('dbatools.IO' | ConvertTo-SecureString -AsPlainText -Force) +$credential = New-Object System.Management.Automation.PSCredential('sqladmin', $securePassword) + +$PSDefaultParameterValues = @{ + "*:SqlCredential" = $credential + "*:DestinationCredential" = $credential + "*:DestinationSqlCredential" = $credential + "*:SourceSqlCredential" = $credential + "*:PublisherSqlCredential" = $credential +} + +# what do we have so far +Get-DbaReplServer -SqlInstance mssql1 +Get-DbaReplDistributor -SqlInstance mssql1 +Get-DbaReplPublisher -SqlInstance mssql1 + +# enable distribution +Enable-DbaReplDistributor -SqlInstance mssql1 + +# enable publishing +Enable-DbaReplPublishing -SqlInstance mssql1 + +# create a transactional publication using splat format +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Type = 'Transactional' +} +New-DbaReplPublication @pub + +# add an article to the publication +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'authors' +} +Add-DbaReplArticle @article + +# create a pubs database on mssql2 to replicate to +New-DbaDatabase -SqlInstance mssql2 -Name pubs + +# if you don't the New-DbaReplSubscription command will create the database for you + +# add a subscription to the publication +$sub = @{ + SqlInstance = 'mssql2' + Database = 'pubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'testpub' + Type = 'Push' + SubscriptionSqlCredential = $credential + +} +New-DbaReplSubscription @sub + +# creates the snapshot job with a daily schedule at 8am - is that expected? good default? +# should adding a subscription kick off snapshot? should that be an param -StartSnapshotNow -- yes + # create that without a schedule by default maybe a param for a schedule + # + +# stats on the subscription - in the distribution database + # could we make a command to get stats + + + + + + ## when adding an article - we need the options + # - action if name is in use 'drop existing object and create new' + # copy nonclusterd indexes + # nuno diff --git a/testing.ps1 b/testing.ps1 index 1aac8cd70a..842d9de1e1 100644 --- a/testing.ps1 +++ b/testing.ps1 @@ -73,6 +73,8 @@ Get-DbaReplPublication -SqlInstance mssql1 Enable-DbaReplDistributor -SqlInstance mssql1 Disable-DbaReplDistributor -SqlInstance mssql1 +Get-DbaReplDistributor -SqlInstance + # enable publishing Enable-DbaReplPublishing -SqlInstance mssql1 Disable-DbaReplPublishing -SqlInstance mssql1 @@ -85,7 +87,7 @@ $pub = @{ Type = 'Transactional' } -New-DbaReplPublication @pub +New-DbaReplPublication @pub -verbose @@ -117,19 +119,10 @@ $article = @{ Database = 'pubs' PublicationName = 'testpub' Name = 'publishers' - Filter = "city = 'seattle'" ## not working? + Filter = "city = 'seattle'" } Add-DbaReplArticle @article -$article = @{ - SqlInstance = 'mssql1' - Database = 'pubs' - PublicationName = 'testpub' - Name = 'publishers' -} -Add-DbaReplArticle @article -EnableException - - $article = @{ SqlInstance = 'mssql1' Database = 'ReplDb' @@ -138,14 +131,6 @@ $article = @{ } Add-DbaReplArticle @article -EnableException -$article = @{ - SqlInstance = 'mssql1' - Database = 'ReplDb' - PublicationName = 'testtrans' - Name = 'ReplicateMe' -} -Remove-DbaReplArticle @article - # mergey $article = @{ SqlInstance = 'mssql1' From 6cf34559a707dfb9a0f928322963c87312b5064c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 30 May 2023 17:29:38 +0100 Subject: [PATCH 044/226] new command New-DbaReplCreationScriptOptions --- dbatools.psd1 | 3 +- public/Add-DbaReplArticle.ps1 | 30 ++++++-- public/New-DbaReplCreationScriptOptions.ps1 | 81 +++++++++++++++++++++ tests/gh-actions-repl.ps1 | 27 +++++++ 4 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 public/New-DbaReplCreationScriptOptions.ps1 diff --git a/dbatools.psd1 b/dbatools.psd1 index 0d3cfb175e..333a177391 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -743,7 +743,8 @@ 'Remove-DbaReplArticle', 'Remove-DbaReplPublication', 'New-DbaReplSubscription', - 'Remove-DbaReplSubscription' + 'Remove-DbaReplSubscription', + 'New-DbaReplCreationScriptOptions' ) # Cmdlets to export from this module diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index dabda1cfa4..afe156ebe4 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -33,6 +33,10 @@ function Add-DbaReplArticle { Horizontal filter for replication, implemented as a where clause, but don't include the word WHERE> E.g. City = 'Seattle' + .PARAMETER CreationScriptOptions + Options for the creation script. + Use New-DbaReplCreationScriptOptions to create this object. + .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. @@ -67,6 +71,20 @@ function Add-DbaReplArticle { PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName TestPub -Name publishers -Filter "city = 'seattle'" Adds the publishers table to the TestPub publication from mssql1.Pubs with a horizontal filter of only rows where city = 'seattle. + + .EXAMPLE + PS C:\> $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics + PS C:\> $article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Name = 'stores' + CreationScriptOptions = $cso + } + Add-DbaReplArticle @article -EnableException + + Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set + includes default options. #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( @@ -89,16 +107,12 @@ function Add-DbaReplArticle { [String]$Filter, #TODO: Build a New-DbaReplArticleOptions function - [Microsoft.SqlServer.Replication.ArticleOptions]$ArticleOptions, + [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, [Switch]$EnableException ) process { - if (Test-Bound -not ArticleOptions) { - $ArticleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - } - foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential @@ -112,7 +126,7 @@ function Add-DbaReplArticle { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - + $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle @@ -129,6 +143,10 @@ function Add-DbaReplArticle { $article.SourceObjectOwner = $Schema $article.PublicationName = $PublicationName + if ($CreationScriptOptions) { + $article.SchemaOption = $CreationScriptOptions + } + if ($Filter) { if ($Filter -like 'WHERE*') { Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/New-DbaReplCreationScriptOptions.ps1 b/public/New-DbaReplCreationScriptOptions.ps1 new file mode 100644 index 0000000000..23caf8b2a7 --- /dev/null +++ b/public/New-DbaReplCreationScriptOptions.ps1 @@ -0,0 +1,81 @@ +function New-DbaReplCreationScriptOptions { + <# + .SYNOPSIS + Creates a new Microsoft.SqlServer.Replication.CreationScriptOptions enumeration object. + + .DESCRIPTION + Creates a new Microsoft.SqlServer.Replication.CreationScriptOptions enumeration object that allows you to specify article options. + + See https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.replication.creationscriptoptions for more information + + .PARAMETER Options + The options to set on published articles. + See https://docs.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.replication.creationscriptoptions for a list of available options + + .PARAMETER NoDefaults + If specified, no default options will be set on the object + + Defaults are copied from when you add an article in SQL Server Management Studio and include: + PrimaryObject, CustomProcedures, Identity, KeepTimestamp, + ClusteredIndexes, DriPrimaryKey, Collation, DriUniqueKeys, + MarkReplicatedCheckConstraintsAsNotForReplication, + MarkReplicatedForeignKeyConstraintsAsNotForReplication, and Schema + + .NOTES + Tags: Replication, Script + 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-DbaReplCreationScriptOptions + + .EXAMPLE + PS C:\> $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics + PS C:\> $article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Name = 'stores' + CreationScriptOptions = $cso + } + Add-DbaReplArticle @article -EnableException + + Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set + includes default options. + + + .EXAMPLE + PS C:\> $cso = New-DbaReplCreationScriptOptions -Options ClusteredIndexes, Identity -NoDefaults + PS C:\> $article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Name = 'stores' + CreationScriptOptions = $cso + } + Add-DbaReplArticle @article -EnableException + + Adds the stores table to the testPub publication from mssql1.pubs with the ClusteredIndexes and Identity options set, excludes default options. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] + param ( + [String[]]$Options, + + [switch]$NoDefaults + ) + + $cso = New-Object Microsoft.SqlServer.Replication.CreationScriptOptions + + if (-not $NoDefaults) { + 'PrimaryObject', 'CustomProcedures', 'Identity', 'KeepTimestamp', 'ClusteredIndexes', 'DriPrimaryKey', 'Collation', 'DriUniqueKeys', 'MarkReplicatedCheckConstraintsAsNotForReplication', 'MarkReplicatedForeignKeyConstraintsAsNotForReplication', 'Schema' | ForEach-Object { $cso += $_ } + } + + foreach ($opt in $options) { + $cso += $opt + } + + $cso +} \ No newline at end of file diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 2fd197c68a..a0dc37a42e 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -328,6 +328,33 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } $articleName = 'ReplicateMe' } + + Context "New-DbaReplCreationScriptOptions works" { + It "New-DbaReplCreationScriptOptions creates a Microsoft.SqlServer.Replication.CreationScriptOptions" { + $options = New-DbaReplCreationScriptOptions + $options | Should -BeOfType Microsoft.SqlServer.Replication.CreationScriptOptions + } + It "Microsoft.SqlServer.Replication.CreationScriptOptions should include the 11 defaults by default" { + ((New-DbaReplCreationScriptOptions).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 11 + } + It "Microsoft.SqlServer.Replication.CreationScriptOptions should include ClusteredIndexes" { + ((New-DbaReplCreationScriptOptions).ToString().Split(',').Trim() | Should -Contain 'ClusteredIndexes') + } + It "Microsoft.SqlServer.Replication.CreationScriptOptions with option of NonClusteredIndexes should add NonClusteredIndexes" { + ((New-DbaReplCreationScriptOptions -Option NonClusteredIndexes).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 12 + ((New-DbaReplCreationScriptOptions -Option NonClusteredIndexes).ToString().Split(',').Trim() | Should -Contain 'NonClusteredIndexes') + } + + It "NoDefaults should mean Microsoft.SqlServer.Replication.CreationScriptOptions only contains DisableScripting" { + ((New-DbaReplCreationScriptOptions -NoDefaults).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 1 + ((New-DbaReplCreationScriptOptions -NoDefaults).ToString().Split(',').Trim() | Should -Contain 'DisableScripting') + } + It "NoDefaults plus option of NonClusteredIndexes should mean Microsoft.SqlServer.Replication.CreationScriptOptions only contains NonClusteredIndexes" { + ((New-DbaReplCreationScriptOptions -NoDefaults -Option NonClusteredIndexes).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 1 + ((New-DbaReplCreationScriptOptions -NoDefaults -Option NonClusteredIndexes).ToString().Split(',').Trim() | Should -Contain 'NonClusteredIndexes') + } + } + Context "Add-DbaReplArticle works" { It "Add-DbaReplArticle adds an article to a Transactional publication" { From 746178612157bdf4418b568c3e0bcde8450b97cd Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 30 May 2023 17:29:43 +0100 Subject: [PATCH 045/226] remove comment --- public/Get-DbaReplServer.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index ca50bf70f6..e9ac8f5897 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -60,7 +60,6 @@ function Get-DbaReplServer { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { try { - # use System.Data instead of Microsoft.Data $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential $sqlCon = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlCon From df229cf33da6a46e457fe661f0375e1c4501f138 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 31 May 2023 15:10:24 +0100 Subject: [PATCH 046/226] fixes for remove article --- public/Remove-DbaReplArticle.ps1 | 35 +++++++++++++++----------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 7743569026..b59e9bf4b7 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -9,16 +9,7 @@ function Remove-DbaReplArticle { Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this ClearUpSubObject -For snapshot or transactional publications, articles can be dropped with no special considerations prior to subscriptions being created. -If an article is dropped after one or more subscriptions is created, the subscriptions must be dropped, recreated, and synchronized. - -Dropping an article from a publication involves dropping the article and creating a new snapshot for the publication. -Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. - -TODO: WARNING: [16:39:55][Remove-DbaReplArticle] Unable to remove article from testPub on mssql1 | Could not drop article. A subscription exists on it. -Need to drop from sub? - -https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 + Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -42,6 +33,9 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a .PARAMETER Name The name of the article to remove. + .PARAMETER DropObjectOnSubscriber + If this switch is enabled, the object will be dropped from the subscriber database. + .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. @@ -74,7 +68,6 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, @@ -90,6 +83,8 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a [parameter(Mandatory)] [String]$Name, + [Switch]$DropObjectOnSubscriber, + [Switch]$EnableException ) process { @@ -120,24 +115,26 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a $article.PublicationName = $PublicationName $article.DatabaseName = $Database - #TODO: Fix this - hard coded subscriber name - # if it has a subscription, we need to drop it first = can't work it out with RMO - # how do we get subscriber name too? - $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, 'mssql2' - Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query + #TODO: change to RMO? if it has a subscription, we need to drop it first = can't work it out with RMO + if ($pub.Subscriptions) { + Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $Name, $pub.Subscriptions.SubscriberName) + $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, $pub.Subscriptions.SubscriberName + Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query + } if (($article.IsExistingObject)) { $article.Remove() } else { Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } + + if ($DropObjectOnSubscriber) { + #TODO: Drop object on subscriber + } } } catch { Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } - - #TODO: What should we return anything? - } } } From c3ca1170245ca21756dedb6fa579e60d2d220af1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:15:54 +0100 Subject: [PATCH 047/226] RefreshSubscriptions not a thing for merge --- public/Add-DbaReplArticle.ps1 | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index afe156ebe4..d0343cb437 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -97,7 +97,7 @@ function Add-DbaReplArticle { [String]$Database, [parameter(Mandatory)] - [String]$PublicationName, + [String]$Publication, [String]$Schema = 'dbo', @@ -119,12 +119,12 @@ function Add-DbaReplArticle { } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - Write-Message -Level Verbose -Message "Adding article $Name to publication $PublicationName on $instance" + Write-Message -Level Verbose -Message "Adding article $Name to publication $Publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { + if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $Publication")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions @@ -141,7 +141,7 @@ function Add-DbaReplArticle { $article.DatabaseName = $Database $article.SourceObjectName = $Name $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName + $article.PublicationName = $Publication if ($CreationScriptOptions) { $article.SchemaOption = $CreationScriptOptions @@ -157,17 +157,20 @@ function Add-DbaReplArticle { if (-not ($article.IsExistingObject)) { $article.Create() } else { - Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Article already exists in $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue } # need to refresh subscriptions so they know about new articles - $pub.RefreshSubscriptions() + # only on trans\snap publications + # (Method invocation failed because [Microsoft.SqlServer.Replication.MergePublication] does not contain a method named 'RefreshSubscriptions'.) + if ($pub.Type -in ('Transactional', 'Snapshot')) { + $pub.RefreshSubscriptions() + } } } catch { - Stop-Function -Message "Unable to add article $Name to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Unable to add article $Name to $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue } - #TODO: What should we return - Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name + Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $Publication -Name $Name } } } From 715da5b817e13a6a20ac65a05adbb769e396365a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:38:28 +0100 Subject: [PATCH 048/226] add url --- public/Disable-DbaReplDistributor.ps1 | 2 +- public/Disable-DbaReplPublishing.ps1 | 2 +- public/Enable-DbaReplDistributor.ps1 | 2 +- public/Enable-DbaReplPublishing.ps1 | 2 +- public/New-DbaReplPublication.ps1 | 2 +- public/New-DbaReplSubscription.ps1 | 2 +- public/Remove-DbaReplPublication.ps1 | 2 +- public/Remove-DbaReplSubscription.ps1 | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index c2d325f673..0f9e61ff37 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -38,7 +38,7 @@ function Disable-DbaReplDistributor { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 39d500924c..7a2b95376b 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -38,7 +38,7 @@ function Disable-DbaReplPublishing { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 1cba0e42a4..020b734ec1 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -34,7 +34,7 @@ function Enable-DbaReplDistributor { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 409da62131..444f93eae0 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -36,7 +36,7 @@ function Enable-DbaReplPublishing { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 2226e9e1bd..7f0464f672 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -52,7 +52,7 @@ function New-DbaReplPublication { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index b2caaf4c54..c363514a49 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -38,7 +38,7 @@ function New-DbaReplSubscription { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 90f2a7c337..f6183dca39 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -37,7 +37,7 @@ function Remove-DbaReplPublication { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index b9cdc4fb71..3c1d0dbac3 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -51,7 +51,7 @@ function Remove-DbaReplSubscription { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT From eff3db348f2fdf2011215d105e6bbfef9ecfb142 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:38:55 +0100 Subject: [PATCH 049/226] remove write-message and fix bug with publication output --- public/Get-DbaReplPublication.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 0d2753e3ba..fc1967f2e6 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -88,7 +88,6 @@ function Get-DbaReplPublication { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - write-message 'jo' # Connect to Publisher try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 @@ -132,16 +131,20 @@ function Get-DbaReplPublication { foreach ($pub in $pubTypes) { if ($pub.Type -eq 'Merge') { $articles = $pub.MergeArticles + $subscriptions = $pub.MergeSubscriptions } else { $articles = $pub.TransArticles + $subscriptions = $pub.TransSubscriptions } + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Articles -Value $articles + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Subscriptions -Value $subscriptions - Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles + Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles, Subscriptions #TODO: breaking change from PublicationName to Name #TODO: breaking change from PublicationType to Type } From 5c2682890cc9f6054682a07e1b6b47b0f09493d7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:39:06 +0100 Subject: [PATCH 050/226] enable piping and tidy up --- public/Get-DbaReplArticle.ps1 | 70 +++------------------ public/Remove-DbaReplArticle.ps1 | 101 +++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 73 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 4a38388f37..4462f09851 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -24,11 +24,8 @@ function Get-DbaReplArticle { .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. - .PARAMETER Type - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot. - - .PARAMETER Article - Specifies one or more article(s) to process. If unspecified, all articles will be processed. + .PARAMETER Name + Specify the name of one or more article(s) to process. If unspecified, all articles will be processed. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -61,35 +58,8 @@ function Get-DbaReplArticle { Retrieve information of all articles from 'PubName' on 'pubs' database for server mssql1. - #TODO: results publicationname contains all the publication names if article is in more than one ? - ComputerName : mssql1 - InstanceName : MSSQLSERVER - SqlInstance : mssql1 - DatabaseName : ReplDb - PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} - Name : ReplicateMe - ArticleId : 2 - Description : - Type : LogBased - VerticalPartition : False - SourceObjectOwner : dbo - SourceObjectName : ReplicateMe - - ComputerName : mssql1 - InstanceName : MSSQLSERVER - SqlInstance : mssql1 - DatabaseName : ReplDb - PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} - Name : ReplicateMe - ArticleId : 3 - Description : - Type : LogBased - VerticalPartition : False - SourceObjectOwner : dbo - SourceObjectName : ReplicateMe - - - PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -Name sales Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. @@ -100,11 +70,10 @@ function Get-DbaReplArticle { [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [object[]]$Database, - [parameter(ValueFromPipeline)] [object[]]$Publication, [ValidateSet("Transactional", "Merge", "Snapshot")] [String]$Type, - [string[]]$Article, + [string[]]$Name, [switch]$EnableException ) begin { @@ -117,7 +86,6 @@ function Get-DbaReplArticle { # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -135,41 +103,23 @@ function Get-DbaReplArticle { foreach ($db in $databases) { Write-Message -Level Verbose -Message ('Working on {0}' -f $db.Name) - $RMOdb = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase - $RMOdb.ConnectionContext = $replServer.ConnectionContext - $RMOdb.Name = $db.Name - if (-not $RMOdb.LoadProperties()) { - Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - continue - } - - #$RMOdb = Connect-ReplicationDB -Server $server -Database $db - - $publications = @() - $publications += $RMOdb.TransPublications - $publications += $RMOdb.MergePublications + $publications = Get-DbaReplPublication -SqlInstance $server -Database $db.Name if ($Publication) { $publications = $publications | Where-Object Name -in $Publication } - if ($Type -eq 'Merge') { - $articles = $publications.MergeArticles - } else { - $articles = $publications.TransArticles - } - - if ($Article) { - $articles = $articles | Where-Object Name -In $Article + $articles = $publications.Articles + if ($Name) { + $articles = $articles | Where-Object Name -In $Name } foreach ($art in $articles) { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } } } catch { diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index b59e9bf4b7..9e28049a0a 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -7,7 +7,7 @@ function Remove-DbaReplArticle { Removes an article from a publication for the database on the target SQL instances. Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. - Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this ClearUpSubObject + Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this DropObjectOnSubscriber Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. @@ -24,7 +24,7 @@ function Remove-DbaReplArticle { .PARAMETER Database The database on the publisher that contains the article to be removed from replication. - .PARAMETER PublicationName + .PARAMETER Publication The name of the replication publication. .PARAMETER Schema @@ -36,6 +36,9 @@ function Remove-DbaReplArticle { .PARAMETER DropObjectOnSubscriber If this switch is enabled, the object will be dropped from the subscriber database. + .PARAMETER InputObject + Enables piping from Get-DbaReplArticle + .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. @@ -49,45 +52,115 @@ function Remove-DbaReplArticle { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT - https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-an-article?view=sql-server-ver16 + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-an-article .LINK https://dbatools.io/Remove-DbaReplArticle .EXAMPLE - PS C:\> Remove-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName PubFromPosh -Name 'publishers' + PS C:\> Remove-DbaReplArticle -SqlInstance mssql1 -Database Pubs -Publication PubFromPosh -Name 'publishers' Removes the publishers article from a publication called PubFromPosh on mssql1 + .EXAMPLE + + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database Pubs -Publication TestPub | Remove-DbaReplArticle + + Removes all articles from a publication called TestPub on mssql1 #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] param ( + # [parameter(Mandatory, ParameterSetName = "Default")] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - [parameter(Mandatory)] + #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Database, - [parameter(Mandatory)] - [String]$PublicationName, + #[parameter(Mandatory, ParameterSetName = "Default")] + [String]$Publication, [String]$Schema = 'dbo', - [parameter(Mandatory)] + #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Name, [Switch]$DropObjectOnSubscriber, + [Parameter(ValueFromPipeline)] # , Mandatory, ParameterSetName = "input")] + [Microsoft.SqlServer.Replication.Article[]]$InputObject, + [Switch]$EnableException ) + + begin { + $articles = @( ) + } + process { + if (-not $PSBoundParameters.SqlInstance -and -not $PSBoundParameters.InputObject) { + Stop-Function -Message "You must specify either SqlInstance or InputObject" + return + } + if ($SqlInstance) { + $params = $PSBoundParameters + $null = $params.Remove('InputObject') + $null = $params.Remove('WhatIf') + $null = $params.Remove('Confirm') + $articles = Get-DbaReplArticle @params + } else { + $articles += $InputObject + } + } + + end { + # We have to delete in the end block to prevent "Collection was modified; enumeration operation may not execute." if directly piped from Get-DbaReplArticle. + foreach ($art in $articles) { + if ($PSCmdlet.ShouldProcess($art.Name, "Removing the article $($art.SourceObjectOwner).$($art.SourceObjectName) from the $($art.PublicationName) publication on $($art.SqlServerName)")) { + $output = [pscustomobject]@{ + ComputerName = $art.ComputerName + InstanceName = $art.InstanceName + SqlInstance = $art.SqlInstance + Database = $art.DatabaseName + ObjectName = $art.SourceObjectName + ObjectSchema = $art.SourceObjectOwner + Status = $null + IsRemoved = $false + } + try { + + $pub = Get-DbaReplPublication -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -Name $art.PublicationName + + if ($pub.Subscriptions) { + Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $art.Name, $pub.Subscriptions.SubscriberName) + $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $art.PublicationName, $art.Name, $pub.Subscriptions.SubscriberName + Invoke-DbaQuery -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -query $query + } + if (($art.IsExistingObject)) { + $art.Remove() + } else { + Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + $output.Status = "Removed" + $output.IsRemoved = $true + } catch { + Stop-Function -Message "Failed to remove the article from publication" -ErrorRecord $_ + $output.Status = (Get-ErrorMessage -Record $_) + $output.IsRemoved = $false + } + $output + } + } + } + + <# foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential @@ -129,14 +202,16 @@ function Remove-DbaReplArticle { } if ($DropObjectOnSubscriber) { - #TODO: Drop object on subscriber + } } } catch { Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } } - } + }#> + + } From c3fa99abbe6e984ba2382f825d82bdcf6c341163 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:39:11 +0100 Subject: [PATCH 051/226] more tests --- tests/gh-actions-repl.ps1 | 193 ++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 51 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index a0dc37a42e..767e3c0d1f 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -42,7 +42,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' } - It "can pipe a sql server object to it" { + It "can pipe a sql server object to it" -skip { Connect-DbaInstance | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty } } @@ -64,7 +64,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - It "gets a publisher using piping" { + It "gets a publisher using piping" -skip { (Connect-DbaInstance | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } @@ -178,8 +178,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "RestofTests" -Tag "Rest" { - + Describe "Publication commands" { Context "Get-DbaReplPublisher works" { BeforeAll { # if distribution is disabled - enable it @@ -225,7 +224,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "gets publications for a specific database" { Get-DbaReplPublication -Database ReplDb | Should -Not -BeNullOrEmpty - (Get-DbaRepPublication -Database ReplDb).Database | ForEach-Object { $_ | Should -Be 'ReplDb' } + (Get-DbaRepPublication -Database ReplDb).DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } } It "gets publications for a specific type" { @@ -233,13 +232,11 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } } - It "works with piping" { + It "works with piping" -skip { Connect-DbaInstance | Get-DbaReplPublication | Should -Not -BeNullOrEmpty } } - - Context "New-DbaReplPublication works" { BeforeAll { # if replication is disabled - enable it @@ -256,54 +253,28 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $name = 'TestPub' New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { $name = 'Snappy' New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } It "New-DbaReplPublication creates a Merge publication" { $name = 'Mergey' New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } } - - Context "Add-DbaReplArticle works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - # we need some publications too - $name = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - } - $name = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name - } - $name = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name - } - } - } } - Describe "Article tests" -Tag "ReplArticle" { + Describe "Article commands" { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -356,24 +327,34 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Context "Add-DbaReplArticle works" { + BeforeAll { + $articleName = 'ReplicateMe' + } It "Add-DbaReplArticle adds an article to a Transactional publication" { $pubName = 'TestPub' - Add-DbaReplArticle -Database ReplDb -Name $articleName -PublicationName $pubName - - #TODO: waiting on Get-DbaReplArticle + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $articleName } - It "New-DbaReplPublication creates a Snapshot publication" { - $pubname = 'TestSnap' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw - #TODO: waiting on Get-DbaReplArticle + It "Add-DbaReplArticle adds an article to a Snapshot publication" { + $pubname = 'TestSnap' + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $articleName } - It "New-DbaReplPublication creates a Merge publication" { + It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw - - #TODO: waiting on Get-DbaReplArticle + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $articleName } } @@ -397,17 +378,127 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - It "Get-DbaReplArticle get the article from a Transactional publication" { + It "Get-DbaReplArticle gets the article from a Transactional publication" { $PublicationName = 'TestTrans' $Name = "ReplicateMe" - Add-DbaReplArticle -Database ReplDb -PublicationName $PublicationName -Name $Name + Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName $TransArticle.Count | Should -Be 1 $TransArticle.Name | Should -Be $Name $TransArticle.PublicationName | Should -Be $PublicationName } + + It "Piping from Connect-DbaInstance works" -skip { + Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + + + + It "Get-DbaReplArticle gets the article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" + Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + + $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName + $TransArticle.Count | Should -Be 1 + $TransArticle.Name | Should -Be $Name + $TransArticle.PublicationName | Should -Be $PublicationName + } + + It "Piping from Connect-DbaInstance works" -skip { + Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + } + } + + Context "Remove-DbaReplArticle works" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + } + + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubname = 'TestTrans' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } + + It "Remove-DbaReplArticle removes an article from a Snapshot publication" { + $pubname = 'TestSnap ' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } + + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubname = 'TestMerge' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } + } + + Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } } + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" + + $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + $article | Should -BeNullOrEmpty + } } } From 8eb4d6d9966b86013dac89515e5aad4218960423 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:44:45 +0100 Subject: [PATCH 052/226] test fix --- tests/gh-actions-repl.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 767e3c0d1f..9930ea05a7 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -464,7 +464,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $article | Should -BeNullOrEmpty } - It "Remove-DbaReplArticle removes an article from a Transactional publication" { + It "Remove-DbaReplArticle removes an article from a Merge publication" { $pubname = 'TestMerge' $Name = "ReplicateMe" $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name From 97a395bd3e92d306e410a44ce3774ef453929869 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:53:03 +0100 Subject: [PATCH 053/226] add logging --- tests/gh-actions-repl.ps1 | 171 +++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 93 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 9930ea05a7..438bd88c81 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -22,7 +22,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' } - Describe "Enable\Disable Functions" -Tag ReplSetup { + Describe "Publishing\Distribution Functions" -Tag ReplSetup { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -179,24 +179,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Describe "Publication commands" { - Context "Get-DbaReplPublisher works" { - BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - } - It "gets a publisher" { - (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" - } - - } Context "Get-DbaReplPublication works" { BeforeAll { @@ -410,95 +393,97 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty } } - } - Context "Remove-DbaReplArticle works" -Tag ArtTestGet { - BeforeAll { - # we need some articles too remove - $article = 'ReplicateMe' + Context "Remove-DbaReplArticle works" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } - $pubname = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot -EnableException)) { + write-hose 'creating snapshot publication' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname -EnableException + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException)) { + # write-host 'adding article to snapshot publication' + Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException + } - $pubname = 'TestMerge' - if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } - } + } - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $pubname = 'TestTrans' - $Name = "ReplicateMe" - $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $rm.IsRemoved | Should -Be $true - $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty - } + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubname = 'TestTrans' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } - It "Remove-DbaReplArticle removes an article from a Snapshot publication" { - $pubname = 'TestSnap ' - $Name = "ReplicateMe" - $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $rm.IsRemoved | Should -Be $true - $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty - } + It "Remove-DbaReplArticle removes an article from a Snapshot publication" { + $pubname = 'TestSnap ' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } - It "Remove-DbaReplArticle removes an article from a Merge publication" { - $pubname = 'TestMerge' - $Name = "ReplicateMe" - $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $rm.IsRemoved | Should -Be $true - $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty + It "Remove-DbaReplArticle removes an article from a Merge publication" { + $pubname = 'TestMerge' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } } - } - Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { - BeforeAll { - # we need some articles too remove - $article = 'ReplicateMe' + Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } } - } - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $PublicationName = 'TestTrans' - $Name = "ReplicateMe" + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" - $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false - $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } - $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name - $article | Should -BeNullOrEmpty + $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + $article | Should -BeNullOrEmpty + } } } } From 69aedd00247e77e6871ce05092c84a2857280f68 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 12:04:07 +0100 Subject: [PATCH 054/226] fixed now? --- tests/gh-actions-repl.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 438bd88c81..0ab9a7bbdf 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -325,7 +325,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Add-DbaReplArticle adds an article to a Snapshot publication" { $pubname = 'TestSnap' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName @@ -333,7 +333,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName @@ -341,7 +341,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Get-DbaReplArticle works" -Tag ArtTestGet { + Context "Get-DbaReplArticle works" { BeforeAll { # we need some articles too remove $article = 'ReplicateMe' @@ -394,7 +394,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Remove-DbaReplArticle works" -Tag ArtTestGet { + Context "Remove-DbaReplArticle works" { BeforeAll { # we need some articles too remove $article = 'ReplicateMe' @@ -459,7 +459,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { + Context "Remove-DbaReplArticle works with piping" { BeforeAll { # we need some articles too remove $article = 'ReplicateMe' @@ -485,5 +485,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $article | Should -BeNullOrEmpty } } + + Context "Get-DbaReplArticleColumn works" { + # TODO: + } } } From 572a0389f5eab9ef2c0be79f07b7ef6f32ec2f40 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 12:16:18 +0100 Subject: [PATCH 055/226] tests --- tests/gh-actions-repl.ps1 | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 0ab9a7bbdf..e42646de12 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -409,17 +409,15 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } $pubname = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot -EnableException)) { - write-hose 'creating snapshot publication' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname -EnableException + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException)) { - # write-host 'adding article to snapshot publication' - Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article } $pubname = 'TestMerge' - if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { @@ -439,7 +437,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Remove-DbaReplArticle removes an article from a Snapshot publication" { - $pubname = 'TestSnap ' + $pubname = 'TestSnap' $Name = "ReplicateMe" $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name $rm.IsRemoved | Should -Be $true From dc1af8645bc6c65fe522681a2c6dfa79aa2e6665 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:27:35 +0100 Subject: [PATCH 056/226] add more Add-DbaReplArticle tests --- tests/gh-actions-repl.ps1 | 125 +++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index e42646de12..15137eab31 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -19,7 +19,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Import-Module ./dbatools.psd1 -Force $null = New-DbaDatabase -Name ReplDb - $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' + $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' + } Describe "Publishing\Distribution Functions" -Tag ReplSetup { @@ -280,7 +281,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name } - $articleName = 'ReplicateMe' + $article = 'ReplicateMe' + $article2 = 'ReplicateMeToo' } Context "New-DbaReplCreationScriptOptions works" { @@ -309,89 +311,130 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Add-DbaReplArticle works" { + Context "Add-DbaReplArticle works" -tag test{ BeforeAll { - $articleName = 'ReplicateMe' + # remove all articles + $null = Get-DbaReplArticle -Database ReplDb | Remove-DbaReplArticle -Confirm:$false } It "Add-DbaReplArticle adds an article to a Transactional publication" { $pubName = 'TestPub' - { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $article + } + + It "Add-DbaReplArticle adds an article to a Snapshot publication and specifies create script options" { + $pubname = 'TestPub' + $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics + { Add-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubname -CreationScriptOptions $cso -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $articleName + $art.Name | Should -Be $article2 } It "Add-DbaReplArticle adds an article to a Snapshot publication" { $pubname = 'TestSnap' - { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $articleName + $art.Name | Should -Be $article } + + It "Add-DbaReplArticle adds an article to a Snapshot publication with a filter" { + $pubName = 'TestSnap' + { Add-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName -Filter "col1 = 'test'" -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $article2 + $art.FilterClause | Should -Be "col1 = 'test'" + } + It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $articleName + $art.Name | Should -Be $article } } Context "Get-DbaReplArticle works" { BeforeAll { - # we need some articles too remove + # we need some articles too get $article = 'ReplicateMe' + $article2 = 'ReplicateMeToo' # we need some publications too - $name = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $name -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubName } - $name = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article } - $name = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article2 } - } - It "Get-DbaReplArticle gets the article from a Transactional publication" { - $PublicationName = 'TestTrans' - $Name = "ReplicateMe" - Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + } - $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName - $TransArticle.Count | Should -Be 1 - $TransArticle.Name | Should -Be $Name - $TransArticle.PublicationName | Should -Be $PublicationName + It "Get-DbaReplArticle gets all the articles from a server" { + $getArt = Get-DbaReplArticle + $getArt | Should -Not -BeNullOrEmpty + $t | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } } - It "Piping from Connect-DbaInstance works" -skip { - Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + It "Get-DbaReplArticle gets all the articles from a particular database on a server" { + $getArt = Get-DbaReplArticle -Database ReplDb + $getArt | Should -Not -BeNullOrEmpty + $getArt | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } + $getArt | ForEach-Object { $_.DatabaseName | Should -Be 'ReplDb' } } + It "Get-DbaReplArticle gets all the articles from a specific publication" { + $pubName = 'TestSnap' + $arts = $article, $article2 + $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName + $getArt.Count | Should -Be 2 + $getArt.Name | Should -Be $arts + $getArt | Foreach-Object {$_.PublicationName | Should -Be $pubName } + } - It "Get-DbaReplArticle gets the article from a Transactional publication" { - $PublicationName = 'TestTrans' + It "Get-DbaReplArticle gets a certain article from a specific publication" { + $pubName = 'TestTrans' $Name = "ReplicateMe" - Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name - $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName - $TransArticle.Count | Should -Be 1 - $TransArticle.Name | Should -Be $Name - $TransArticle.PublicationName | Should -Be $PublicationName + $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $Name + $getArt.Count | Should -Be 1 + $getArt.Name | Should -Be $Name + $getArt.PublicationName | Should -Be $pubName } It "Piping from Connect-DbaInstance works" -skip { Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty } + } Context "Remove-DbaReplArticle works" { From 150cf81125369b9db8ed7ca7118696b34f3a2a5a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:28:02 +0100 Subject: [PATCH 057/226] add examples, tidy up --- public/Add-DbaReplArticle.ps1 | 12 +++++++++--- public/Get-DbaReplArticle.ps1 | 4 +--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index d0343cb437..d642b8d6e0 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -68,7 +68,14 @@ function Add-DbaReplArticle { .EXAMPLE - PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName TestPub -Name publishers -Filter "city = 'seattle'" + PS C:\> $article = @{ + SqlInstance = "mssql1" + Database = "pubs" + PublicationName = "testPub" + Name = "publishers" + Filter = "city = 'seattle'" + } + PS C:\> Add-DbaReplArticle @article -EnableException Adds the publishers table to the TestPub publication from mssql1.Pubs with a horizontal filter of only rows where city = 'seattle. @@ -81,7 +88,7 @@ function Add-DbaReplArticle { Name = 'stores' CreationScriptOptions = $cso } - Add-DbaReplArticle @article -EnableException + PS C:\> Add-DbaReplArticle @article -EnableException Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set includes default options. @@ -106,7 +113,6 @@ function Add-DbaReplArticle { [String]$Filter, - #TODO: Build a New-DbaReplArticleOptions function [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, [Switch]$EnableException diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 4462f09851..767b804da5 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -6,7 +6,7 @@ function Get-DbaReplArticle { .DESCRIPTION This function locates and enumerates articles' information. - Can specify a database, publication or article name or publication type. + Can specify a database, publication or article name. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -71,8 +71,6 @@ function Get-DbaReplArticle { [PSCredential]$SqlCredential, [object[]]$Database, [object[]]$Publication, - [ValidateSet("Transactional", "Merge", "Snapshot")] - [String]$Type, [string[]]$Name, [switch]$EnableException ) From f840f89e473dbe44c7541a2f4b56ff8432e278b6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:28:10 +0100 Subject: [PATCH 058/226] remove a bug with piping --- public/Remove-DbaReplArticle.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 9e28049a0a..0f85065673 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -109,21 +109,22 @@ function Remove-DbaReplArticle { Stop-Function -Message "You must specify either SqlInstance or InputObject" return } - if ($SqlInstance) { + + if ($InputObject) { + $articles += $InputObject + } else { $params = $PSBoundParameters $null = $params.Remove('InputObject') $null = $params.Remove('WhatIf') $null = $params.Remove('Confirm') $articles = Get-DbaReplArticle @params - } else { - $articles += $InputObject } } end { # We have to delete in the end block to prevent "Collection was modified; enumeration operation may not execute." if directly piped from Get-DbaReplArticle. foreach ($art in $articles) { - if ($PSCmdlet.ShouldProcess($art.Name, "Removing the article $($art.SourceObjectOwner).$($art.SourceObjectName) from the $($art.PublicationName) publication on $($art.SqlServerName)")) { + if ($PSCmdlet.ShouldProcess($art.Name, "Removing the article $($art.SourceObjectOwner).$($art.SourceObjectName) from the $($art.PublicationName) publication on $($art.SqlInstance)")) { $output = [pscustomobject]@{ ComputerName = $art.ComputerName InstanceName = $art.InstanceName From 4a7a43e2d21c88378a3e0d635b5f2b740b091edc Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:29:02 +0100 Subject: [PATCH 059/226] spelling word added --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7744d49149..c44f3d5962 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,6 +57,7 @@ "Kokkinos", "Kravtsov", "Mikey", + "mssql", "nchar", "niphlod", "ntext", From aab5a3cc69e2dd1a96bfd0996b4fbfc1ff799408 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:32:49 +0100 Subject: [PATCH 060/226] typos --- tests/gh-actions-repl.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 15137eab31..513d14d372 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -401,7 +401,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Get-DbaReplArticle gets all the articles from a server" { $getArt = Get-DbaReplArticle $getArt | Should -Not -BeNullOrEmpty - $t | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } + $getArt | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } } It "Get-DbaReplArticle gets all the articles from a particular database on a server" { From d46362b0973269c427bf88f8c401581564029b5b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:43:37 +0100 Subject: [PATCH 061/226] more examples, cleaned up help --- public/New-DbaReplPublication.ps1 | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 7f0464f672..572e21e7d4 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -19,17 +19,14 @@ function New-DbaReplPublication { For MFA support, please use Connect-DbaInstance. .PARAMETER Database - The database that will be replicated. + The database that contains the articles to be replicated. .PARAMETER PublicationName - The name of the replication publication + The name of the replication publication. .PARAMETER Type The flavour of replication. - - Currently supported 'Transactional' - - Coming soon 'Snapshot', 'Merge' + Options are Transactional, Snapshot, Merge .PARAMETER LogReaderAgentCredential Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs @@ -37,7 +34,7 @@ function New-DbaReplPublication { Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - TODO: Implement & test this + TODO: test this .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -55,7 +52,7 @@ function New-DbaReplPublication { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -66,6 +63,15 @@ function New-DbaReplPublication { Creates a transactional publication called PubFromPosh for the Northwind database on mssql1 + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName snapPub -Type Snapshot + + Creates a snapshot publication called snapPub for the pubs database on mssql1 + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName mergePub -Type Merge + + Creates a merge publication called mergePub for the pubs database on mssql1 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( @@ -74,6 +80,7 @@ function New-DbaReplPublication { [PSCredential]$SqlCredential, + [parameter(Mandatory)] [String]$Database, [parameter(Mandatory)] From d3947312608b9b3dac6d7de182674417738b3941 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:50:47 +0100 Subject: [PATCH 062/226] tidy help and examples --- public/Disable-DbaReplPublishing.ps1 | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 7a2b95376b..5b7676e4da 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -1,10 +1,10 @@ function Disable-DbaReplPublishing { <# .SYNOPSIS - Disables publication for the target SQL instances. + Disables publishing for the target SQL instances. .DESCRIPTION - Disables publication for the target SQL instances. + Disables publishing for the target SQL instances. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -17,13 +17,13 @@ function Disable-DbaReplPublishing { For MFA support, please use Connect-DbaInstance. .PARAMETER Force - Boolean value that specifies whether or not replication objects are removed from the server, - even if a remote Distributor cannot be reached. + A Boolean value that specifies whether the Publisher is uninstalled from the Distributor without verifying that + Publisher has also uninstalled the Distributor, if the Publisher is on a separate server. - If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or - not dependent publishing and distribution objects are uninstalled. + If true, all the replication objects associated with the Publisher are dropped even if the Publisher is on a remote server + that cannot be reached. - If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + If false, replication first verifies that the remote Publisher has uninstalled the Distributor. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -41,7 +41,7 @@ function Disable-DbaReplPublishing { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -57,8 +57,9 @@ function Disable-DbaReplPublishing { PS C:\> Disable-DbaReplPublishing -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force Disables replication distribution for the mssql1 and mssql2 instances using a sql login. - Specifies force so the publishing and Distributor configuration at the current server is uninstalled - regardless of whether or not dependent publishing and distribution objects are uninstalled. + + Specifies force so all the replication objects associated with the Publisher are dropped even + if the Publisher is on a remote server that cannot be reached. #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] @@ -81,7 +82,6 @@ function Disable-DbaReplPublishing { if ($replServer.IsPublisher) { try { if ($PSCmdlet.ShouldProcess($instance, "Disabling publishing on $instance")) { - #Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess # uninstall distribution $replServer.DistributionPublishers.Remove($Force) } @@ -95,12 +95,6 @@ function Disable-DbaReplPublishing { } else { Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category InvalidData } - - #$replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force - #$replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force - #$replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force - #Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name - } } } From abf06fe5fc19add8200b2d0d9b49f8984e1f07b6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 11:50:32 +0100 Subject: [PATCH 063/226] tidy help --- public/Disable-DbaReplDistributor.ps1 | 14 +++++++------- public/Disable-DbaReplPublishing.ps1 | 5 ++++- public/Enable-DbaReplDistributor.ps1 | 5 +++-- public/Enable-DbaReplPublishing.ps1 | 10 +++++----- public/Get-DbaReplDistributor.ps1 | 1 - public/Get-DbaReplServer.ps1 | 3 --- public/Remove-DbaReplPublication.ps1 | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 0f9e61ff37..34848f0af9 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -20,10 +20,11 @@ function Disable-DbaReplDistributor { Boolean value that specifies whether or not replication objects are removed from the server, even if a remote Distributor cannot be reached. - If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or - not dependent publishing and distribution objects are uninstalled. + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of + whether or not dependent publishing and distribution objects are uninstalled. - If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + If false, the publisher and distribution databases must already be uninstalled, and no local databases + are enabled for publishing. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -41,7 +42,7 @@ function Disable-DbaReplDistributor { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -66,8 +67,7 @@ function Disable-DbaReplDistributor { [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - - [switch]$force, + [switch]$Force, [switch]$EnableException ) process { @@ -85,7 +85,7 @@ function Disable-DbaReplDistributor { # remove any connections to the distribution database Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess # uninstall distribution - $replServer.UninstallDistributor($force) + $replServer.UninstallDistributor($Force) } } catch { Stop-Function -Message "Unable to disable replication distribution" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 5b7676e4da..a3b2104871 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -66,8 +66,11 @@ function Disable-DbaReplPublishing { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, - [switch]$force, + + [switch]$Force, + [switch]$EnableException ) process { diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 020b734ec1..93c025c8b2 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -37,7 +37,7 @@ function Enable-DbaReplDistributor { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -76,7 +76,8 @@ function Enable-DbaReplDistributor { $distributionDb = New-Object Microsoft.SqlServer.Replication.DistributionDatabase $distributionDb.ConnectionContext = $replServer.ConnectionContext $distributionDb.Name = $DistributionDatabase - # lots more properties to add as params + + #TODO: lots more properties to add as params $replServer.InstallDistributor($null, $distributionDb) } } catch { diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 444f93eae0..39ec195e48 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -21,7 +21,7 @@ function Enable-DbaReplPublishing { .PARAMETER PublisherSqlLogin If this is used the PublisherSecurity will be set to use this. - If not specified WindowsAuthentication can will used - this is the default, and recommended method. + If not specified WindowsAuthentication will be used - this is the default, and recommended method. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -39,7 +39,7 @@ function Enable-DbaReplPublishing { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -56,7 +56,7 @@ function Enable-DbaReplPublishing { [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - $SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? + [string]$SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? can we get the default? [PSCredential]$PublisherSqlLogin, [switch]$EnableException ) @@ -93,7 +93,7 @@ function Enable-DbaReplPublishing { } else { Write-Message -Level Verbose -Message "Configuring with WindowsAuth for PublisherSecurity" - $distPublisher.PublisherSecurity.WindowsAuthentication = $true # TODO: test with windows auth + $distPublisher.PublisherSecurity.WindowsAuthentication = $true } Write-Message -Level Debug -Message $distPublisher @@ -108,7 +108,7 @@ function Enable-DbaReplPublishing { } $replServer.Refresh() - $replServer # TODO: Standard output + $replServer } } diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index 58a76e0e69..040f1af13a 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -67,7 +67,6 @@ function Get-DbaReplDistributor { } Write-Message -Level Verbose -Message "Getting publisher for $server" - Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index e9ac8f5897..c82da3b2d1 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -6,9 +6,6 @@ function Get-DbaReplServer { .DESCRIPTION Gets a replication server object - All replication commands need SQL Server Management Studio installed and are therefore currently not supported. - Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 - .PARAMETER SqlInstance The target SQL Server instance or instances diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index f6183dca39..1353d173eb 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -109,7 +109,7 @@ function Remove-DbaReplPublication { $pubDatabase.EnabledTransPublishing = $false } } - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure } elseif ($pub.Type -eq 'Merge') { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication From 4ac31a024cd01941d71ce4aa723f26579e1d1022 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 11:50:48 +0100 Subject: [PATCH 064/226] add check for publishing and log reader job not for merge --- public/New-DbaReplPublication.ps1 | 43 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 572e21e7d4..4edf87db81 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -98,6 +98,11 @@ function New-DbaReplPublication { foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + + if (-not $replServer.IsPublisher) { + Stop-Function -Message "Instance $instance is not a publisher, run Enable-DbaReplPublishing to set this up" -Target $instance -Continue + } + } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -106,7 +111,8 @@ function New-DbaReplPublication { try { if ($PSCmdlet.ShouldProcess($instance, "Creating publication on $instance")) { - #TODO: could replace this with call to Connect-ReplicationDB + + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $replServer.ConnectionContext $pubDatabase.Name = $Database @@ -118,30 +124,29 @@ function New-DbaReplPublication { Write-Message -Level Verbose -Message "Enable trans publishing publication on $instance.$Database" $pubDatabase.EnabledTransPublishing = $true $pubDatabase.CommitPropertyChanges() + # log reader agent is only needed for transactional and snapshot replication. + if (-not $pubDatabase.LogReaderAgentExists) { + Write-Message -Level Verbose -Message "Create log reader agent job for $Database on $instance" + if ($LogReaderAgentCredential) { + #TODO: Test this + $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName + $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password + } + + #(Optional) Set the SqlStandardLogin and SqlStandardPassword or + # SecureSqlStandardPassword fields of LogReaderAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. + + $pubDatabase.CreateLogReaderAgent() + } else { + Write-Message -Level Verbose -Message "Log reader agent job already exists for $Database on $instance" + } + } elseif ($Type -eq 'Merge') { Write-Message -Level Verbose -Message "Enable merge publishing publication on $instance.$Database" $pubDatabase.EnabledMergePublishing = $true $pubDatabase.CommitPropertyChanges() } - if (-not $pubDatabase.LogReaderAgentExists) { - #TODO: if this needed for merge? - - Write-Message -Level Verbose -Message "Create Log Read Agent job for $Database on $instance" - if ($LogReaderAgentCredential) { - #TODO: Test this - $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName - $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password - } - - #(Optional) Set the SqlStandardLogin and SqlStandardPassword or - # SecureSqlStandardPassword fields of LogReaderAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. - - $pubDatabase.CreateLogReaderAgent() - } else { - Write-Message -Level Verbose -Message "Log Read Agent job already exists for $Database on $instance" - } - if ($Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication From 49466d4420c63dde330efd6d075ecb6b25687219 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 11:50:55 +0100 Subject: [PATCH 065/226] added tests --- tests/gh-actions-repl.ps1 | 59 +++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 513d14d372..b06011b3fc 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -23,7 +23,29 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Describe "Publishing\Distribution Functions" -Tag ReplSetup { + Describe "General commands" { + + Context "Get-DbaReplServer works" -tag test { + + It "Doesn't throw errors" { + { Get-DbaReplServer -EnableException } | Should -Not -Throw + } + + It "Returns a ReplicationObject" { + (Get-DbaReplServer).GetType().BaseType | Should -Be "Microsoft.SqlServer.Replication.ReplicationObject" + } + + It "Gets a replication server" { + (Get-DbaReplServer).SqlInstance | Should -Be 'mssql1' + (Get-DbaReplServer).DistributorInstalled | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).DistributorAvailable | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).IsDistributor | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).IsPublisher | Should -Not -BeNullOrEmpty + } + } + } + + Describe "Publishing\Distribution commands" { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -35,6 +57,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Enable-DbaReplDistributor } + It "gets a distributor without error" { + { Get-DbaReplDistributor -EnableException } | Should -Not -Throw + } + It "gets a distributor" { (Get-DbaReplDistributor).IsDistributor | Should -Be $true } @@ -148,7 +174,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - Enable-DbaReplPublishing -EnableException + { Enable-DbaReplPublishing -EnableException } | Should -Not -Throw (Get-DbaReplServer).IsPublisher | Should -Be $true } } @@ -173,7 +199,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is disabled" { - Disable-DbaReplPublishing -EnableException + { Disable-DbaReplPublishing -EnableException } | Should -Not -Throw (Get-DbaReplServer).IsPublisher | Should -Be $false } } @@ -181,7 +207,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Describe "Publication commands" { - Context "Get-DbaReplPublication works" { BeforeAll { # if distribution is disabled - enable it @@ -235,26 +260,29 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "New-DbaReplPublication creates a Transactional publication" { $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + { New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + { New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } It "New-DbaReplPublication creates a Merge publication" { $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + { New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } + } + Context "Remove-DbaReplPublication works" { + # TODO: } } @@ -311,7 +339,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Add-DbaReplArticle works" -tag test{ + Context "Add-DbaReplArticle works" { BeforeAll { # remove all articles $null = Get-DbaReplArticle -Database ReplDb | Remove-DbaReplArticle -Confirm:$false @@ -531,4 +559,19 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # TODO: } } + + Describe "Subscription commands" { + BeforeAll { + + } + + Context "New-DbaReplSubscription works" { + # TODO: + } + + Context "Remove-DbaReplSubscription works" { + # TODO: + } + + } } From e3bed4d6df9d7d119914850c3da0a9d6360b5bbe Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 12:50:46 +0100 Subject: [PATCH 066/226] remove hard coded default for snapshot --- public/Enable-DbaReplPublishing.ps1 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 39ec195e48..b184208d0f 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -17,7 +17,9 @@ function Enable-DbaReplPublishing { For MFA support, please use Connect-DbaInstance. .PARAMETER SnapshotShare - The share used to access snapshot files. + The share used to access snapshot files. + + The default is the ReplData folder within the InstallDataDirectory for the instance. .PARAMETER PublisherSqlLogin If this is used the PublisherSecurity will be set to use this. @@ -56,7 +58,7 @@ function Enable-DbaReplPublishing { [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - [string]$SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? can we get the default? + [string]$SnapshotShare, [PSCredential]$PublisherSqlLogin, [switch]$EnableException ) @@ -79,10 +81,11 @@ function Enable-DbaReplPublishing { $distPublisher.Name = $instance #- name of the Publisher. $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name #- the name of the database created in step 5. - #TODO: test snapshot path and warn\error? - #if (Test-DbaPath -SqlInstance mssql1 -Path $SnapshotShare) { - # Stop-Function -Message ("Snapshot path '{0}' does not exist - will attempt to create it" -f $SnapshotShare) -ErrorRecord $_ -Target $instance -Continue - #} + if (-not $PSBoundParameters.SnapshotShare) { + $SnapshotShare = Join-Path (Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential).InstallDataDirectory 'ReplData' + Write-Message -Level Verbose -Message ('No snapshot share specified, using default of {0}' -f $SnapshotShare) + } + $distPublisher.WorkingDirectory = $SnapshotShare if ($PublisherSqlLogin) { From 5123bc7ef33ffcb47b51e535aa8208e737ee0931 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 16:45:43 +0100 Subject: [PATCH 067/226] add get-replsubscription --- dbatools.psd1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index 333a177391..07c5df66fb 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -744,7 +744,8 @@ 'Remove-DbaReplPublication', 'New-DbaReplSubscription', 'Remove-DbaReplSubscription', - 'New-DbaReplCreationScriptOptions' + 'New-DbaReplCreationScriptOptions', + 'Get-DbaReplSubscription' ) # Cmdlets to export from this module From 2d7bd48506a55fad2008937d5b8bc611a48a43b7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 16:46:04 +0100 Subject: [PATCH 068/226] spacing and year --- public/Add-DbaReplArticle.ps1 | 10 +-- public/Disable-DbaReplPublishing.ps1 | 3 - public/Get-DbaReplArticle.ps1 | 2 +- public/Get-DbaReplArticleColumn.ps1 | 91 +++++++++++++-------- public/Get-DbaReplSubscription.ps1 | 34 ++------ public/New-DbaReplCreationScriptOptions.ps1 | 1 - public/New-DbaReplPublication.ps1 | 6 -- public/New-DbaReplSubscription.ps1 | 18 +--- public/Remove-DbaReplArticle.ps1 | 14 +--- public/Remove-DbaReplPublication.ps1 | 6 +- public/Remove-DbaReplSubscription.ps1 | 11 +-- 11 files changed, 73 insertions(+), 123 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index d642b8d6e0..a130c04c4f 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -53,7 +53,7 @@ function Add-DbaReplArticle { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure @@ -97,24 +97,16 @@ function Add-DbaReplArticle { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [parameter(Mandatory)] [String]$Database, - [parameter(Mandatory)] [String]$Publication, - [String]$Schema = 'dbo', - [parameter(Mandatory)] [String]$Name, - [String]$Filter, - [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, - [Switch]$EnableException ) process { diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index a3b2104871..eaba0e2b30 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -66,11 +66,8 @@ function Disable-DbaReplPublishing { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [switch]$Force, - [switch]$EnableException ) process { diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 767b804da5..b6774e0086 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -37,7 +37,7 @@ function Get-DbaReplArticle { Author: Cláudio Silva (@claudioessilva), claudioessilva.eu Website: https://dbatools.io - Copyright: (c) 2018 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 index 46ec46bd52..592bdf1378 100644 --- a/public/Get-DbaReplArticleColumn.ps1 +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -1,10 +1,10 @@ function Get-DbaReplArticleColumn { <# .SYNOPSIS - Gets the information about publication article columns. + Gets the information about replicated article columns. .DESCRIPTION - This function enumerates columns information for a given articles. + This function enumerates column information for given articles. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -19,12 +19,9 @@ function Get-DbaReplArticleColumn { .PARAMETER Database Specifies one or more database(s) to process. If unspecified, all databases will be processed. - .PARAMETER PublicationName + .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. - .PARAMETER PublicationType - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot - .PARAMETER Article Specifies one or more article(s) to process. If unspecified, all articles will be processed. @@ -41,17 +38,37 @@ function Get-DbaReplArticleColumn { Author: Cláudio Silva (@claudioessilva), claudioessilva.eu Website: https://dbatools.io - Copyright: (c) 2018 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK https://dbatools.io/Get-DbaReplArticleColumn .EXAMPLE - PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 + + Retrieve information of all replicated columns in any publications on server sqlserver2019. + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs + + Retrieve information of all replicated columns in any publications from the pubs database on server sqlserver2019. + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Publication test + + Retrieve information of all replicated columns in the test publication on server sqlserver2019. + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs -Publication PubName -Article sales Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Column state + + Retrieve information for the state column in any publication from any database on server sqlserver2019. + #> [CmdletBinding()] param ( @@ -61,43 +78,45 @@ function Get-DbaReplArticleColumn { [object[]]$Database, [parameter(ValueFromPipeline)] [object[]]$Publication, - [String]$PublicationType, # Snapshot, Transactional, Merge [string[]]$Article, [string[]]$Column, [switch]$EnableException ) - begin { - #TODO - Still needed? - Add-ReplicationLibrary - } process { if (Test-FunctionInterrupt) { return } - $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -PublicationType $PublicationType -Article $Article + $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -Name $Article foreach ($art in $articles) { - $columns = $art.ListReplicatedColumns() - - if ($Column) { - $columns = $columns | Where-Object { $_ -In $Column } - } - - foreach ($col in $columns) { - - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $art.ComputerName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $art.InstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $art.SqlInstance - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleName -Value $art.Name - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleId -Value $art.ArticleId - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Description -Value $art.Description - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Type -Value $art.Type - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name VerticalPartition -Value $art.VerticalPartition - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectOwner -Value $art.SourceObjectOwner - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectName -Value $art.SourceObjectName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ColumnName -Value $col - - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, ArticleName, ArticleId, Description, ColumnName #, DestinationObjectOwner, DestinationObjectName + try { + + $columns = $art.ListReplicatedColumns() + + if ($Column) { + $columns = $columns | Where-Object { $_ -In $Column } + } + + foreach ($col in $columns) { + + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $art.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $art.InstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $art.SqlInstance + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name DatabaseName -Value $art.DatabaseName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $art.PublicationName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleName -Value $art.Name + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleId -Value $art.ArticleId + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Description -Value $art.Description + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Type -Value $art.Type + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name VerticalPartition -Value $art.VerticalPartition + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectOwner -Value $art.SourceObjectOwner + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectName -Value $art.SourceObjectName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ColumnName -Value $col + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, ArticleName, ArticleId, ColumnName #, DestinationObjectOwner, DestinationObjectName + } + } catch { + Stop-Function -Message "Error occurred while getting article columns from $instance" -ErrorRecord $_ -Target $instance -Continue } } } -} \ No newline at end of file +} diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index e50b89e52e..81858f8674 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -32,34 +32,18 @@ function Get-DbaReplSubscription { .NOTES Tags: Replication - Author: Colin Douglas + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2018 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaReplPublication + https://dbatools.io/Get-DbaReplSubscription .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008, sqlserver2012 + PS C:\> #TODO: add example - Return all publications for servers sql2008 and sqlserver2012. - - .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Database TestDB - - Return all publications on server sql2008 for only the TestDB database - - .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional - - Return all publications on server sql2008 for all databases that have Transactional publications - - .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey - - Returns the Mergey publications on server mssql1 #> [CmdletBinding()] param ( @@ -69,20 +53,17 @@ function Get-DbaReplSubscription { [PSCredential]$SqlCredential, [String]$Name, [Alias("PublicationType")] - [ValidateSet("Transactional", "Merge", "Snapshot")] + [ValidateSet("Push","Pull")] [object[]]$Type, [switch]$EnableException ) - begin { - Add-ReplicationLibrary - } process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { # Connect to Publisher try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $PublisherSqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -94,6 +75,9 @@ function Get-DbaReplSubscription { #TODO: finish this function + # can we get subscriptions by passing in subscription server mssql2 ... or do we need to start at the publisher + # get-publications --> subscriptions info is in there + } } diff --git a/public/New-DbaReplCreationScriptOptions.ps1 b/public/New-DbaReplCreationScriptOptions.ps1 index 23caf8b2a7..14956b98b4 100644 --- a/public/New-DbaReplCreationScriptOptions.ps1 +++ b/public/New-DbaReplCreationScriptOptions.ps1 @@ -63,7 +63,6 @@ function New-DbaReplCreationScriptOptions { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] param ( [String[]]$Options, - [switch]$NoDefaults ) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 4edf87db81..9ba9f8185b 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -77,21 +77,15 @@ function New-DbaReplPublication { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [parameter(Mandatory)] [String]$Database, - [parameter(Mandatory)] [String]$PublicationName, - [parameter(Mandatory)] [ValidateSet("Snapshot", "Transactional", "Merge")] [String]$Type, - [PSCredential]$LogReaderAgentCredential, - [Switch]$EnableException ) process { diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index c363514a49..7a2e7df162 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -41,14 +41,14 @@ function New-DbaReplSubscription { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/New-DbaReplPublication + https://dbatools.io/New-DbaReplSubscription .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> New-DbaReplSubscription -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh Creates a publication called PubFromPosh for the Northwind database on mssql1 @@ -57,28 +57,19 @@ function New-DbaReplSubscription { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [String]$Database, - [parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, - [PSCredential]$PublisherSqlCredential, - [String]$PublicationDatabase, - [parameter(Mandatory)] [String]$PublicationName, - [PSCredential] # this will be saved as the 'subscriber credential' in the subscription properties $SubscriptionSqlCredential, - [parameter(Mandatory)] [ValidateSet("Push", "Pull")] [String]$Type, - [Switch]$EnableException ) begin { @@ -93,8 +84,6 @@ function New-DbaReplSubscription { try { $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName - - } catch { Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue } @@ -106,7 +95,6 @@ function New-DbaReplSubscription { foreach ($instance in $SqlInstance) { try { - $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 0f85065673..da614d2a38 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -76,27 +76,15 @@ function Remove-DbaReplArticle { #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] param ( - # [parameter(Mandatory, ParameterSetName = "Default")] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - - #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Database, - - #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Publication, - [String]$Schema = 'dbo', - - #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Name, - [Switch]$DropObjectOnSubscriber, - - [Parameter(ValueFromPipeline)] # , Mandatory, ParameterSetName = "input")] + [Parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Article[]]$InputObject, - [Switch]$EnableException ) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 1353d173eb..0a53e617ee 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -40,7 +40,7 @@ function Remove-DbaReplPublication { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -56,14 +56,10 @@ function Remove-DbaReplPublication { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [String]$Database, - [parameter(Mandatory)] [String]$Name, - [Switch]$EnableException ) process { diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 3c1d0dbac3..88b8a7296a 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -1,7 +1,7 @@ function Remove-DbaReplSubscription { <# .SYNOPSIS - Removes a subscription for the target SQL instances. + Removes a subscription \for the target SQL instances. .DESCRIPTION Removes a subscription for the target SQL instances. @@ -54,7 +54,7 @@ function Remove-DbaReplSubscription { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -77,21 +77,14 @@ function Remove-DbaReplSubscription { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, - [PSCredential]$PublisherSqlCredential, - [String]$PublicationDatabase, - [parameter(Mandatory)] [String]$PublicationName, - [String]$SubscriptionDatabase, - [Switch]$EnableException ) begin { From 534b784594a0134fd444c677d6740becb82b8819 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 16:46:11 +0100 Subject: [PATCH 069/226] tests --- tests/gh-actions-repl.ps1 | 131 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 6 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index b06011b3fc..39f04542c2 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -5,6 +5,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred + $PSDefaultParameterValues["*:SubscriptionSqlCredential1"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" @@ -25,7 +26,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Describe "General commands" { - Context "Get-DbaReplServer works" -tag test { + Context "Get-DbaReplServer works" { It "Doesn't throw errors" { { Get-DbaReplServer -EnableException } | Should -Not -Throw @@ -554,23 +555,141 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $article | Should -BeNullOrEmpty } } + } + Describe "Article Column commands" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $article = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + } Context "Get-DbaReplArticleColumn works" { - # TODO: + It "Gets all column information for a server" { + $cols = Get-DbaReplArticleColumn + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + } + + It "Gets all column information for specific database on a server" { + $cols = Get-DbaReplArticleColumn -Database ReplDb + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + + It "Gets all column information for specific publication on a server" { + $pubname = 'TestTrans' + $cols = Get-DbaReplArticleColumn -Publication $pubname + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.PublicationName | ForEach-Object { $_ | Should -Be $pubname } + } + + It "Gets all column information for specific article on a server" { + $pubname = 'TestTrans' + $cols = Get-DbaReplArticleColumn -Publication $pubname -Article $article + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.ArticleName | ForEach-Object { $_ | Should -Be $article } + } + + It "Gets all column information for specific column on a server" { + $pubname = 'TestTrans' + $cols = Get-DbaReplArticleColumn -Publication $pubname -Column 'col1' + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.ColumnName | ForEach-Object { $_ | Should -Be 'col1' } + } } } Describe "Subscription commands" { BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $article = 'ReplicateMe' + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } } - Context "New-DbaReplSubscription works" { - # TODO: + Context "New-DbaReplSubscription works" -tag test -skip { + It "Adds a subscription" { + { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' -EnableException } | Should -Not -Throw + + #TODO: waiting on get-dbareplsubscription to be implemented + } } - Context "Remove-DbaReplSubscription works" { - # TODO: + Context "Remove-DbaReplSubscription works" -tag test -skip{ + BeforeEach { + #TODO: check it doesn't exist with get-dbareplsubscription + New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' + } + It "Removes a subscription" { + { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + + #TODO: waiting on get-dbareplsubscription to be implemented + } } } From 2290aa11f809df1c9d7e02ecbb3afbb73b6cec19 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 5 Jun 2023 11:07:01 +0100 Subject: [PATCH 070/226] add note about ReplicationDatabases property --- public/Get-DbaReplServer.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index c82da3b2d1..2632ab287d 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -4,7 +4,10 @@ function Get-DbaReplServer { Gets a replication server object .DESCRIPTION - Gets a replication server object + Gets a replication server object. + + Note: The ReplicationDatabases property gets the databases enabled for replication in the connected instance of Microsoft SQL Server/. + Not necessarily the databases that are actually replicated. .PARAMETER SqlInstance The target SQL Server instance or instances @@ -71,6 +74,4 @@ function Get-DbaReplServer { } } } -} - -# TODO: Replication databases are shown even if they have no pubs \ No newline at end of file +} \ No newline at end of file From c77d0e65cfe696c7f34b948a844159a4f0463e42 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 5 Jun 2023 13:38:23 +0100 Subject: [PATCH 071/226] change to allow piping --- public/Remove-DbaReplPublication.ps1 | 106 +++++++++++++++------------ 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 0a53e617ee..2d1050b148 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -54,50 +54,63 @@ function Remove-DbaReplPublication { #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [String]$Database, - [parameter(Mandatory)] [String]$Name, + [parameter(ValueFromPipeline)] + [Microsoft.SqlServer.Replication.Publication[]]$InputObject, [Switch]$EnableException ) + begin { + $publications = @( ) + } process { - foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } - try { - if ($PSCmdlet.ShouldProcess($instance, "Removing publication on $instance")) { - - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name -Database $Database + if (-not $PSBoundParameters.SqlInstance -and -not $PSBoundParameters.InputObject) { + Stop-Function -Message "You must specify either SqlInstance or InputObject" + return + } - if (-not $pub) { - Write-Warning "Didn't find $Name on $Instance.$Database" - } + if ($InputObject) { + $publications += $InputObject + } else { + $params = $PSBoundParameters + $null = $params.Remove('InputObject') + $null = $params.Remove('WhatIf') + $null = $params.Remove('Confirm') + $publications = Get-DbaReplPublication @params + } + } + end { + # We have to delete in the end block to prevent "Collection was modified; enumeration operation may not execute." if directly piped from Get-DbaReplArticle. + foreach ($pub in $publications) { + if ($PSCmdlet.ShouldProcess($pub.Name, "Removing the publication $($pub.Name) on $($pub.SqlInstance)")) { + $output = [PSCustomObject]@{ + ComputerName = $pub.ComputerName + InstanceName = $pub.InstanceName + SqlInstance = $pub.SqlInstance + Database = $pub.DatabaseName + Name = $pub.Name + Type = $pub.Type + Status = $null + IsRemoved = $false + } + try { if ($pub.Type -in ('Transactional', 'Snapshot')) { - $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication - $transPub.ConnectionContext = $replServer.ConnectionContext - $transPub.DatabaseName = $Database - $transPub.Name = $Name - - if ($transPub.IsExistingObject) { - Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" - $transPub.Remove() + if ($pub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + $pub.Remove() } # If no other transactional publications exist for this database, the database can be disabled for transactional publishing - #TODO: transactional & snapshot.. or just trans? - if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Transactional, Snapshot)) { + if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Transactional, Snapshot)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase - $pubDatabase.ConnectionContext = $replServer.ConnectionContext - $pubDatabase.Name = $Database + $pubDatabase.ConnectionContext = $pub.ConnectionContext + $pubDatabase.Name = $pub.DatabaseName if (-not $pubDatabase.LoadProperties()) { - throw "Database $Database not found on $instance" + throw "Database $Database not found on $($pub.SqlInstance)" } if ($pubDatabase.EnabledTransPublishing) { @@ -105,44 +118,41 @@ function Remove-DbaReplPublication { $pubDatabase.EnabledTransPublishing = $false } } - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure } elseif ($pub.Type -eq 'Merge') { - $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication - $mergePub.ConnectionContext = $replServer.ConnectionContext - $mergePub.DatabaseName = $Database - $mergePub.Name = $Name - - if ($mergePub.IsExistingObject) { - Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" - $mergePub.Remove() + + if ($pub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + $pub.Remove() } else { - Write-Warning "Didn't find $Name on $Instance.$Database" + Write-Warning "Didn't find $($pub.Name) on $($pub.SqlInstance).$($pub.DatabaseName)" } # If no other merge publications exist for this database, the database can be disabled for merge publishing - if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Merge)) { + if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Merge)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase - $pubDatabase.ConnectionContext = $replServer.ConnectionContext - $pubDatabase.Name = $Database + $pubDatabase.ConnectionContext = $pub.ConnectionContext + $pubDatabase.Name = $pub.DatabaseName if (-not $pubDatabase.LoadProperties()) { throw "Database $Database not found on $instance" } - if($pubDatabase.EnabledTransPublishing) { + if ($pubDatabase.EnabledTransPublishing) { Write-Message -Level Verbose -Message "No merge publications on $Instance.$Database so disabling merge publishing" $pubDatabase.EnabledMergePublishing = $false } } } + $output.Status = "Removed" + $output.IsRemoved = $true + } catch { + Stop-Function -Message "Failed to remove the article from publication" -ErrorRecord $_ + $output.Status = (Get-ErrorMessage -Record $_) + $output.IsRemoved = $false } - } catch { - Stop-Function -Message ("Unable to remove publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + $output } } } -} - - - +} \ No newline at end of file From ba418b6f800c8237f6426a5588f7d91240e8013f Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 5 Jun 2023 13:39:08 +0100 Subject: [PATCH 072/226] change publicationname --> name --- public/Get-DbaReplDistributor.ps1 | 4 -- public/Get-DbaReplPublication.ps1 | 8 +--- public/New-DbaReplPublication.ps1 | 29 ++++++-------- public/New-DbaReplSubscription.ps1 | 10 ++--- public/Remove-DbaReplArticle.ps1 | 61 ++---------------------------- 5 files changed, 18 insertions(+), 94 deletions(-) diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index 040f1af13a..646a9d1b74 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -6,10 +6,6 @@ function Get-DbaReplDistributor { .DESCRIPTION This function locates and enumerates distributor information for a given SQL Server instance. - TODO: I think we can remove this? - All replication commands need SQL Server Management Studio installed and are therefore currently not supported. - Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 - .PARAMETER SqlInstance The target SQL Server instance or instances. diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index fc1967f2e6..4e4e080488 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -6,10 +6,6 @@ function Get-DbaReplPublication { .DESCRIPTION Quickly find all transactional, merge, and snapshot publications on a server or filter by database, name or type. - TODO: is this still true? remove? - All replication commands need SQL Server Management Studio installed and are therefore currently not supported. - Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 - .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -127,7 +123,6 @@ function Get-DbaReplPublication { $pubTypes = $pubTypes | Where-Object Name -in $Name } - #TODO: Check why if -Database is not passed, I can't see the articles (JP - this works for me... 🤔) foreach ($pub in $pubTypes) { if ($pub.Type -eq 'Merge') { $articles = $pub.MergeArticles @@ -145,8 +140,7 @@ function Get-DbaReplPublication { Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Subscriptions -Value $subscriptions Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles, Subscriptions - #TODO: breaking change from PublicationName to Name - #TODO: breaking change from PublicationType to Type + } } } catch { diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 9ba9f8185b..a32551d593 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -21,7 +21,7 @@ function New-DbaReplPublication { .PARAMETER Database The database that contains the articles to be replicated. - .PARAMETER PublicationName + .PARAMETER Name The name of the replication publication. .PARAMETER Type @@ -34,7 +34,7 @@ function New-DbaReplPublication { Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - TODO: test this + TODO: test LogReaderAgentCredential parameters .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -59,17 +59,17 @@ function New-DbaReplPublication { https://dbatools.io/New-DbaReplPublication .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Type Transactional + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -Name PubFromPosh -Type Transactional Creates a transactional publication called PubFromPosh for the Northwind database on mssql1 .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName snapPub -Type Snapshot + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -Name snapPub -Type Snapshot Creates a snapshot publication called snapPub for the pubs database on mssql1 .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName mergePub -Type Merge + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -Name mergePub -Type Merge Creates a merge publication called mergePub for the pubs database on mssql1 #> @@ -81,7 +81,7 @@ function New-DbaReplPublication { [parameter(Mandatory)] [String]$Database, [parameter(Mandatory)] - [String]$PublicationName, + [String]$Name, [parameter(Mandatory)] [ValidateSet("Snapshot", "Transactional", "Merge")] [String]$Type, @@ -122,7 +122,6 @@ function New-DbaReplPublication { if (-not $pubDatabase.LogReaderAgentExists) { Write-Message -Level Verbose -Message "Create log reader agent job for $Database on $instance" if ($LogReaderAgentCredential) { - #TODO: Test this $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password } @@ -146,7 +145,7 @@ function New-DbaReplPublication { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication $transPub.ConnectionContext = $replServer.ConnectionContext $transPub.DatabaseName = $Database - $transPub.Name = $PublicationName + $transPub.Name = $Name $transPub.Type = $Type $transPub.Create() @@ -154,7 +153,7 @@ function New-DbaReplPublication { $transPub.CreateSnapshotAgent() <# - TODO: add these in? + TODO: add SnapshotGenerationAgentProcessSecurity creds in? The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. @@ -170,14 +169,14 @@ function New-DbaReplPublication { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication $mergePub.ConnectionContext = $replServer.ConnectionContext $mergePub.DatabaseName = $Database - $mergePub.Name = $PublicationName + $mergePub.Name = $Name $mergePub.Create() # create the Snapshot Agent job $mergePub.CreateSnapshotAgent() <# - TODO: add these in? + TODO: add SnapshotGenerationAgentProcessSecurity creds in? The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. @@ -190,18 +189,12 @@ function New-DbaReplPublication { to set the PublicationAttributes values for the Attributes property. #> - } - - - } } catch { Stop-Function -Message ("Unable to create publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } - - #TODO: What to return - + Get-DbaRepPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Name $Name } } } diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 7a2e7df162..aa6156e308 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -162,8 +162,6 @@ function New-DbaReplSubscription { $transSub.DatabaseName = $PublicationDatabase $transSub.PublicationName = $PublicationName - $transSub - #TODO: <# @@ -202,7 +200,7 @@ function New-DbaReplSubscription { 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 ($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' @@ -212,7 +210,7 @@ function New-DbaReplSubscription { } 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 ($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' @@ -265,9 +263,7 @@ function New-DbaReplSubscription { } catch { Stop-Function -Message ("Unable to create subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } - - #TODO: What to return - + #TODO: call Get-DbaReplSubscription when it's done } } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index da614d2a38..108104e475 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -7,7 +7,8 @@ function Remove-DbaReplArticle { Removes an article from a publication for the database on the target SQL instances. Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. - Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this DropObjectOnSubscriber + Use DROP <Object> to remove these objects if necessary. + #TODO: add a param for this DropObjectOnSubscriber Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. @@ -82,7 +83,7 @@ function Remove-DbaReplArticle { [String]$Publication, [String]$Schema = 'dbo', [String]$Name, - [Switch]$DropObjectOnSubscriber, + #[Switch]$DropObjectOnSubscriber, [Parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Article[]]$InputObject, [Switch]$EnableException @@ -148,60 +149,4 @@ function Remove-DbaReplArticle { } } } - - <# - foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } - Write-Message -Level Verbose -Message "Removing article $Name from publication $PublicationName on $instance" - - try { - if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { - - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - - if ($pub.Type -in ('Transactional', 'Snapshot')) { - $article = New-Object Microsoft.SqlServer.Replication.TransArticle - } elseif ($pub.Type -eq 'Merge') { - $article = New-Object Microsoft.SqlServer.Replication.MergeArticle - } else { - Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue - } - - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName - $article.DatabaseName = $Database - - #TODO: change to RMO? if it has a subscription, we need to drop it first = can't work it out with RMO - if ($pub.Subscriptions) { - Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $Name, $pub.Subscriptions.SubscriberName) - $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, $pub.Subscriptions.SubscriberName - Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query - } - - if (($article.IsExistingObject)) { - $article.Remove() - } else { - Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } - - if ($DropObjectOnSubscriber) { - - } - } - } catch { - Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } - } - }#> - - } - - - From 199f6daa20f34c06076711808e3a3dd5c9135f99 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 6 Jun 2023 20:05:44 +0100 Subject: [PATCH 073/226] sort out piping --- public/Remove-DbaReplPublication.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 2d1050b148..42f56722c0 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -24,6 +24,11 @@ function Remove-DbaReplPublication { .PARAMETER Name The name of the replication publication + .PARAMETER InputObject + + .PARAMETER Force + If this switch is enabled, this command will look for the REPL-LogReader SQL Agent Job for this database and if it's running, stop the job. + .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. @@ -60,6 +65,7 @@ function Remove-DbaReplPublication { [String]$Name, [parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Publication[]]$InputObject, + [Switch]$Force, [Switch]$EnableException ) begin { @@ -77,6 +83,7 @@ function Remove-DbaReplPublication { $params = $PSBoundParameters $null = $params.Remove('InputObject') $null = $params.Remove('WhatIf') + $null = $params.Remove('Force') $null = $params.Remove('Confirm') $publications = Get-DbaReplPublication @params } @@ -101,6 +108,9 @@ function Remove-DbaReplPublication { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + if ($Force) { + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob + } $pub.Remove() } @@ -123,6 +133,9 @@ function Remove-DbaReplPublication { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + if ($Force) { + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob + } $pub.Remove() } else { Write-Warning "Didn't find $($pub.Name) on $($pub.SqlInstance).$($pub.DatabaseName)" From d187ed87a3a0e6dfc6c3c5f3a26d6e96dd425ed8 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 6 Jun 2023 20:07:04 +0100 Subject: [PATCH 074/226] fix piping issue --- public/Get-DbaReplPublisher.ps1 | 2 +- public/Get-DbaReplServer.ps1 | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 846cdf64e6..2824f1beeb 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -53,7 +53,7 @@ function Get-DbaReplPublisher { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $server } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue } diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index 2632ab287d..b79d0ddf27 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -61,9 +61,8 @@ function Get-DbaReplServer { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $sqlCon = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlCon - + $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer + $replServer.ConnectionContext = $Server.ConnectionContext.SqlConnectionObject $replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force $replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force $replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force From ea5db60da47842c257668bbdff3c4c27d18b874c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 6 Jun 2023 20:07:19 +0100 Subject: [PATCH 075/226] tests --- tests/gh-actions-repl.ps1 | 228 +++++++++++++++++++++++++------------- 1 file changed, 154 insertions(+), 74 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 39f04542c2..0c6da59f32 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -8,20 +8,13 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SubscriptionSqlCredential1"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" - - #TODO: To be removed? - $PSDefaultParameterValues["*:-SnapshotShare"] = "/shared" $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" $global:ProgressPreference = "SilentlyContinue" - #$null = Get-XPlatVariable | Where-Object { $PSItem -notmatch "Copy-", "Migration" } | Sort-Object - # load dbatools-lib - #Import-Module dbatools-core-library Import-Module ./dbatools.psd1 -Force $null = New-DbaDatabase -Name ReplDb $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' - } Describe "General commands" { @@ -70,9 +63,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' } - It "can pipe a sql server object to it" -skip { - Connect-DbaInstance | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty - } + } Context "Get-DbaReplPublisher works" { @@ -92,9 +83,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - It "gets a publisher using piping" -skip { - (Connect-DbaInstance | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" - } } @@ -222,10 +210,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # create a publication $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName ('{0}-Trans' -f $Name) - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName ('{0}-Merge' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Transactional -Name ('{0}-Trans' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Merge -Name ('{0}-Merge' -f $Name) $null = New-DbaDatabase -Name Test - New-DbaReplPublication -Database Test -Type Snapshot -PublicationName ('{0}-Snapshot' -f $Name) + New-DbaReplPublication -Database Test -Type Snapshot -Name ('{0}-Snapshot' -f $Name) } It "gets all publications" { @@ -242,9 +230,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } } - It "works with piping" -skip { - Connect-DbaInstance | Get-DbaReplPublication | Should -Not -BeNullOrEmpty - } } Context "New-DbaReplPublication works" { @@ -261,21 +246,21 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "New-DbaReplPublication creates a Transactional publication" { $name = 'TestPub' - { New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name -EnableException } | Should -Not -Throw + { New-DbaReplPublication -Database ReplDb -Type Transactional -Name $Name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { $name = 'Snappy' - { New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name -EnableException } | Should -Not -Throw + { New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } It "New-DbaReplPublication creates a Merge publication" { $name = 'Mergey' - { New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name -EnableException } | Should -Not -Throw + { New-DbaReplPublication -Database ReplDb -Type Merge -Name $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' @@ -283,7 +268,48 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Context "Remove-DbaReplPublication works" { - # TODO: + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $article = 'ReplicateMe' + + # we need some publications too + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName + } + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName + } + } + + It "Remove-DbaReplPublication removes a publication that has articles" { + $name = 'TestTrans' + { Remove-DbaReplPublication -Name $name -EnableException -Force } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty + } + + It "Remove-DbaReplPublication removes a publication that has no articles" { + $name = 'TestSnap' + { Remove-DbaReplPublication -Name $name -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty + } + } } @@ -300,15 +326,15 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications too $name = 'TestTrans' if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $Name } $name = 'TestSnap' if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $Name } $name = 'TestMerge' if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $Name } $article = 'ReplicateMe' $article2 = 'ReplicateMeToo' @@ -403,7 +429,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications too $pubName = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article @@ -411,7 +437,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubName = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -420,7 +446,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubName = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -447,7 +473,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName $getArt.Count | Should -Be 2 $getArt.Name | Should -Be $arts - $getArt | Foreach-Object {$_.PublicationName | Should -Be $pubName } + $getArt | Foreach-Object { $_.PublicationName | Should -Be $pubName } } It "Get-DbaReplArticle gets a certain article from a specific publication" { @@ -459,11 +485,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $getArt.Name | Should -Be $Name $getArt.PublicationName | Should -Be $pubName } - - It "Piping from Connect-DbaInstance works" -skip { - Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty - } - } Context "Remove-DbaReplArticle works" { @@ -474,7 +495,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -482,7 +503,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -490,7 +511,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -529,33 +550,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Remove-DbaReplArticle works with piping" { - BeforeAll { - # we need some articles too remove - $article = 'ReplicateMe' - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } - } - - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $PublicationName = 'TestTrans' - $Name = "ReplicateMe" - - $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false - $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } - $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name - $article | Should -BeNullOrEmpty - } - } } + Describe "Article Column commands" { BeforeAll { # if replication is disabled - enable it @@ -571,7 +568,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -579,7 +576,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -587,7 +584,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -649,7 +646,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -657,7 +654,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -665,32 +662,115 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article } } - Context "New-DbaReplSubscription works" -tag test -skip { + Context "New-DbaReplSubscription works" -skip { It "Adds a subscription" { - { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' -EnableException } | Should -Not -Throw + { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -Type 'Push' -EnableException } | Should -Not -Throw #TODO: waiting on get-dbareplsubscription to be implemented } } - Context "Remove-DbaReplSubscription works" -tag test -skip{ + Context "Remove-DbaReplSubscription works" -skip{ BeforeEach { #TODO: check it doesn't exist with get-dbareplsubscription - New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' + New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -Type 'Push' } It "Removes a subscription" { - { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -EnableException } | Should -Not -Throw #TODO: waiting on get-dbareplsubscription to be implemented } } } + + Describe "Piping" -tag test { + BeforeAll { + # we need some articles too get + $article = 'ReplicateMe' + $article2 = 'ReplicateMeToo' + + # we need some publications too + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article2 + } + + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + # piping doesn't work well if there are PSDefaultParameterValues set + $PSDefaultParameterValues = $null + + } + + Context "Get-DbaReplPublisher works with piping" { + It "gets a publisher using piping" { + (Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + } + + Context "Get-DbaReplPublication works with piping" { + It "works with piping" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + } + + Context "Get-DbaReplDistributor works with piping" { + It "can pipe a sql server object to it" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty + } + } + + Context "Get-DbaReplArticle works with piping" { + It "Piping from Connect-DbaInstance to works" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + } + + Context "Remove-DbaReplArticle works with piping" { + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubName = 'TestTrans' + $Name = "ReplicateMe" + + $rm = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + #$article = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name + #$article | Should -BeNullOrEmpty + } + } + + Context "Remove-DbaReplPublication works with piping" { + It "Remove-DbaReplPublication removes a publication using piping" { + $name = 'TestMerge' + { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name | Remove-DbaReplPublication -EnableException } | Should -Not -Throw + #(Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name) | Should -BeNullOrEmpty + } + } + } } From 162a7c04733c7c2402213b8103f3b1a098e55402 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 11:51:23 +0000 Subject: [PATCH 076/226] repl testing --- ReplicationCommands.md | 75 ++++++++++++++++++++++++++++++++ testing.ps1 | 98 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 ReplicationCommands.md create mode 100644 testing.ps1 diff --git a/ReplicationCommands.md b/ReplicationCommands.md new file mode 100644 index 0000000000..adf1bc1ee2 --- /dev/null +++ b/ReplicationCommands.md @@ -0,0 +1,75 @@ +# Replication Work + +## Commands to Create + +List to keep track of commands we need and who's working on them, most of the names are being pulled from thin air so if you don't agree with new vs add they can all be discussed\changed. + +Meaning of the checkmarks: +- [X] Done +- [ ] not done +- [-] in progress by... + + +### General + +- [X] Get-DbaReplServer +- [X] Export-DbaReplServerSetting + +### Distribution + +- [X] Get-DbaReplDistributor +- [X] Disable-DbaReplDistributor +- [X] Enable-DbaReplDistributor +- [ ] Set-DbaReplDistributor (updating properties?) + +### Publishing + +- [-] Get-DbaReplPublisher - Mikey +- [ ] Set-DbaReplPublisher (updating properties?) +- [X] Get-DbaReplPublication -- #TODO: Exists but needs some love +- [X] Disable-DbaReplPublishing +- [X] Enable-DbaReplPublishing +- [-] New-DbaReplPublication - Jess +- [ ] Remove-DbaReplPublication + +### Articles +- [-] Add-DbaReplArticle - Jess +- [ ] Remove-DbaReplArticle +- [-] Get-DbaReplArticle - Cláudio +- [ ] Set-DbaReplArticle + +### Columns +- [-] Get-DbaReplArticleColumn +- [ ] Add-DbaReplArticleColumn +- [ ] Remove-DbaReplArticleColumn + +### Subscriptions +- [ ] Get-DbaDbSubscription +- [ ] New-DbaDbSubscription +- [ ] Set-DbaReplDistributor (update properties) + +### Monitoring\Troubleshooting + +- [X] Test-DbaReplLatency +- [ ] Run-DbaReplSnapshotAgent ? +- [ ] Get-DbaReplSnapshotAgentStatus +- [ ] Get-DbaReplLogReaderAgentStatus +- [ ] Test-DbaReplSnapFolder - similiar to Test-DbaPath but from replication service account perspective or something similiar to check If the share (UNC or Local) is accesable from both, publisher and subscriber side + +## How to run pester tests locally + +```PowerShell + # run this against fresh containers to setup replication as it would be in gh action + #.\bin\Replication\Invoke-ReplicationSetup.ps1 + # commented out + + #run the tests -Show All will caus + invoke-pester .\tests\gh-actions-repl.ps1 + +``` + +## Testing + +Some additional scenarios for us to test commands against. + +- how the commands work when we have a "third site" involved , i mean if we have the distribution db not on the Publication-Server and not on the Subscriber-Server (thats not so common, but it is a thing imo) - I saw some unusual behaviour with replcation commands when the setup is with a seperate Distribution-DB-Server. diff --git a/testing.ps1 b/testing.ps1 new file mode 100644 index 0000000000..6c07458884 --- /dev/null +++ b/testing.ps1 @@ -0,0 +1,98 @@ +############################## +# create docker environment +############################## +# create a shared network +docker network create localnet + +# Expose engines and setup shared path for migrations +docker run -p 2500:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance +docker run -p 2600:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + +# create the repl folder +docker exec mssql1 mkdir /var/opt/mssql/ReplData + +# also need these folders for setting up replication +docker exec mssql1 mkdir /shared/data /shared/repldata + +############################## +# import our working module +############################## +Import-Module .\dbatools.psd1 -Force +Get-module dbatools* + +############################## +# create alias +############################## +New-DbaClientAlias -ServerName 'localhost,2500' -Alias mssql1 +New-DbaClientAlias -ServerName 'localhost,2600' -Alias mssql2 + + +############################## +# save the password for ease +############################## +$securePassword = ('dbatools.IO' | ConvertTo-SecureString -AsPlainText -Force) +$credential = New-Object System.Management.Automation.PSCredential('sqladmin', $securePassword) + +$PSDefaultParameterValues = @{ + "*:SqlCredential" = $credential + "*:DestinationCredential" = $credential + "*:DestinationSqlCredential" = $credential + "*:SourceSqlCredential" = $credential +} + + +############################## +# change silly defaults +############################## +Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig #-Scope SystemMandatory +Set-DbatoolsConfig -FullName sql.connection.EncryptConnection -Value optional -PassThru | Register-DbatoolsConfig #-Scope SystemMandatory + +############################## +# test things :) +############################## + + +## already existing commands +<# +Get-DbaReplServer +Get-DbaReplDistributor +Get-DbaReplPublication +Test-DbaReplLatency + +Export-DbaReplServerSetting +#> + +$sqlInstance = Connect-DbaInstance -SqlInstance mssql1 + +Get-DbaReplServer -SqlInstance mssql1 +Get-DbaReplDistributor -SqlInstance mssql1 +Get-DbaReplPublication -SqlInstance mssql1 + +# enable\disable distribution +Enable-DbaReplDistributor -SqlInstance mssql1 +Disable-DbaReplDistributor -SqlInstance mssql1 + +# enable publishing +Enable-DbaReplPublishing -SqlInstance mssql1 +Disable-DbaReplPublishing -SqlInstance mssql1 + +# add a publication +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Type = 'Transactional' + +} +New-DbaReplPublication @pub + +# add an article + +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'publishers' + Filter = "where city = 'seattle'" ## not working? +} +Add-DbaReplArticle @article \ No newline at end of file From f3827f85b839aa64ef5efdd4f5abb6219367eaa6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 11:51:39 +0000 Subject: [PATCH 077/226] tests --- .github/workflows/integration-tests-repl.yml | 110 ++++++++++++ bin/Replication/Invoke-ReplicationSetup.ps1 | 13 ++ bin/Replication/setup-test-replication.sql | 40 +++++ ...s.ps1 => Get-DbaReplDistributor.Tests.ps1} | 2 +- tests/Get-DbaReplPublication.Tests.ps1 | 80 +++++++++ tests/Get-DbaReplServer.Tests.ps1 | 19 ++ tests/Test-DbaReplLatency.Tests.ps1 | 14 ++ tests/gh-actions-repl.ps1 | 170 ++++++++++++++++++ 8 files changed, 447 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/integration-tests-repl.yml create mode 100644 bin/Replication/Invoke-ReplicationSetup.ps1 create mode 100644 bin/Replication/setup-test-replication.sql rename tests/{Get-DbaRepDistributor.Tests.ps1 => Get-DbaReplDistributor.Tests.ps1} (93%) create mode 100644 tests/Get-DbaReplPublication.Tests.ps1 create mode 100644 tests/Get-DbaReplServer.Tests.ps1 create mode 100644 tests/Test-DbaReplLatency.Tests.ps1 create mode 100644 tests/gh-actions-repl.ps1 diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml new file mode 100644 index 0000000000..a64a6c1da9 --- /dev/null +++ b/.github/workflows/integration-tests-repl.yml @@ -0,0 +1,110 @@ +name: Run Cross Platform Tests - repl +on: [push] +defaults: + run: + shell: pwsh +jobs: + linux-tests: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + steps: + - uses: actions/checkout@v3 + + - name: Install and cache PowerShell modules + uses: potatoqualitee/psmodulecache@v5.1 + with: + modules-to-cache: dbatools-core-library:2022.10.27 + modules-to-cache-prerelease: dbatools-library:2022.10.28-preview + + - name: Install and cache dbatools-library + run: | + Import-Module ./dbatools.psd1 -Force + Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register + Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -Register + Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + + - name: Setup docker images + run: | + # create a shared network + docker network create localnet + # Expose engine and endpoint then setup a shared path for migrations + docker run -p 1433:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance + # Expose second engine and endpoint on different port + docker run -p 14333:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + + - name: 👥 Clone appveyor repo + working-directory: /tmp + run: | + gh repo clone sqlcollaborative/appveyor-lab + + - name: Setup Replication + run: | + Import-Module ./dbatools.psd1 -Force + # need some folders for our repl stuff + docker exec mssql1 mkdir /shared/data /shared/repldata /var/opt/mssql/ReplData + # setup distribution, 1xPublication with 1xSubscription + # $null = .\bin\Replication\Invoke-ReplicationSetup.ps1 + + - name: Run tests + run: | + Import-Module ./dbatools.psd1 -Force + Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning + Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru + + + +# windows-tests: +# runs-on: windows-latest +# env: +# GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} +# +# steps: +# - name: Checkout dbatools repo +# uses: actions/checkout@v3 +# +# - name: Install and cache PowerShell modules +# uses: potatoqualitee/psmodulecache@v5.1 +# with: +# shell: powershell, pwsh +# modules-to-cache: dbatools-core-library:2022.10.27 +# modules-to-cache-prerelease: dbatools-library:2022.10.28-preview +# +# - name: Install SQL Server localdb +# uses: potatoqualitee/mssqlsuite@v1.3 +# with: +# install: localdb +# +# - name: Connect to localdb instance powershell +# shell: powershell +# run: | +# Import-Module ./dbatools -Force +# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" +# +# - name: Connect to localdb instance pwsh +# shell: pwsh +# run: | +# Import-Module ./dbatools -Force +# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory +# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" +# +# - name: Run pwsh tests +# env: +# TENANTID: ${{secrets.TENANTID}} +# CLIENTID: ${{secrets.CLIENTID}} +# CLIENTSECRET: ${{secrets.CLIENTSECRET}} +# shell: pwsh +# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru +# +# - name: Run PowerShell tests +# env: +# TENANTID: ${{secrets.TENANTID}} +# CLIENTID: ${{secrets.CLIENTID}} +# CLIENTSECRET: ${{secrets.CLIENTSECRET}} +# shell: powershell +# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru \ No newline at end of file diff --git a/bin/Replication/Invoke-ReplicationSetup.ps1 b/bin/Replication/Invoke-ReplicationSetup.ps1 new file mode 100644 index 0000000000..0636a538b9 --- /dev/null +++ b/bin/Replication/Invoke-ReplicationSetup.ps1 @@ -0,0 +1,13 @@ +$password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force +$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password + +$PSDefaultParameterValues["*:SqlInstance"] = "localhost" +$PSDefaultParameterValues["*:SqlCredential"] = $cred +$PSDefaultParameterValues["*:Confirm"] = $false +$PSDefaultParameterValues["*:SharedPath"] = "/shared" +##$PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" +#$global:ProgressPreference = "SilentlyContinue" + + + +Invoke-DbaQuery -File .\bin\Replication\setup-test-replication.sql \ No newline at end of file diff --git a/bin/Replication/setup-test-replication.sql b/bin/Replication/setup-test-replication.sql new file mode 100644 index 0000000000..9ac6fcb442 --- /dev/null +++ b/bin/Replication/setup-test-replication.sql @@ -0,0 +1,40 @@ +-- Set up distribution + use master + exec sp_adddistributor @distributor = N'mssql1', @password = N'dbatools.IO' + GO + exec sp_adddistributiondb @database = N'distribution', @data_folder = N'/shared/data/', @log_folder = N'/shared/data/', @log_file_size = 2, @min_distretention = 0, @max_distretention = 72, @history_retention = 48, @deletebatchsize_xact = 5000, @deletebatchsize_cmd = 2000, @security_mode = 1 + GO + + use [distribution] + if (not exists (select * from sysobjects where name = 'UIProperties' and type = 'U ')) + create table UIProperties(id int) + if (exists (select * from ::fn_listextendedproperty('SnapshotFolder', 'user', 'dbo', 'table', 'UIProperties', null, null))) + EXEC sp_updateextendedproperty N'SnapshotFolder', N'/shared/ReplData', 'user', dbo, 'table', 'UIProperties' + else + EXEC sp_addextendedproperty N'SnapshotFolder', N'/shared/ReplData', 'user', dbo, 'table', 'UIProperties' + GO + + exec sp_adddistpublisher @publisher = N'mssql1', @distribution_db = N'distribution', @security_mode = 0, @login = N'sqladmin', @password = N'', @working_directory = N'/shared/ReplData', @trusted = N'false', @thirdparty_flag = 0, @publisher_type = N'MSSQLSERVER' + GO + +-- set up publication + use [pubs] + exec sp_replicationdboption @dbname = N'pubs', @optname = N'publish', @value = N'true' + GO + -- Adding the transactional publication + use [pubs] + exec sp_addpublication @publication = N'DMMRepl', @description = N'Transactional publication of database ''pubs'' from Publisher ''mssql1''.', @sync_method = N'concurrent', @retention = 0, @allow_push = N'true', @allow_pull = N'true', @allow_anonymous = N'true', @enabled_for_internet = N'false', @snapshot_in_defaultfolder = N'true', @compress_snapshot = N'false', @ftp_port = 21, @allow_subscription_copy = N'false', @add_to_active_directory = N'false', @repl_freq = N'continuous', @status = N'active', @independent_agent = N'true', @immediate_sync = N'true', @allow_sync_tran = N'false', @allow_queued_tran = N'false', @allow_dts = N'false', @replicate_ddl = 1, @allow_initialize_from_backup = N'false', @enabled_for_p2p = N'false', @enabled_for_het_sub = N'false' + exec sp_addpublication_snapshot @publication = N'DMMRepl', @frequency_type = 1, @frequency_interval = 1, @frequency_relative_interval = 1, @frequency_recurrence_factor = 0, @frequency_subday = 8, @frequency_subday_interval = 1, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 0, @active_end_date = 0, @job_login = null, @job_password = null, @publisher_security_mode = 1 + exec sp_addarticle @publication = N'DMMRepl', @article = N'authors', @source_owner = N'dbo', @source_object = N'authors', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'authors', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dboauthors', @del_cmd = N'CALL sp_MSdel_dboauthors', @upd_cmd = N'SCALL sp_MSupd_dboauthors' + exec sp_addarticle @publication = N'DMMRepl', @article = N'employee', @source_owner = N'dbo', @source_object = N'employee', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'employee', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dboemployee', @del_cmd = N'CALL sp_MSdel_dboemployee', @upd_cmd = N'SCALL sp_MSupd_dboemployee' + exec sp_addarticle @publication = N'DMMRepl', @article = N'jobs', @source_owner = N'dbo', @source_object = N'jobs', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'jobs', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbojobs', @del_cmd = N'CALL sp_MSdel_dbojobs', @upd_cmd = N'SCALL sp_MSupd_dbojobs' + exec sp_addarticle @publication = N'DMMRepl', @article = N'pub_info', @source_owner = N'dbo', @source_object = N'pub_info', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'pub_info', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbopub_info', @del_cmd = N'CALL sp_MSdel_dbopub_info', @upd_cmd = N'SCALL sp_MSupd_dbopub_info' + exec sp_addarticle @publication = N'DMMRepl', @article = N'publishers', @source_owner = N'dbo', @source_object = N'publishers', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'publishers', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbopublishers', @del_cmd = N'CALL sp_MSdel_dbopublishers', @upd_cmd = N'SCALL sp_MSupd_dbopublishers' + GO + +-- add a subscription + use [pubs] + exec sp_addsubscription @publication = N'DMMRepl', @subscriber = N'mssql2', @destination_db = N'pubs', @subscription_type = N'Push', @sync_type = N'automatic', @article = N'all', @update_mode = N'read only', @subscriber_type = 0 + exec sp_addpushsubscription_agent @publication = N'DMMRepl', @subscriber = N'mssql2', @subscriber_db = N'pubs', @job_login = null, @job_password = null, @subscriber_security_mode = 0, @subscriber_login = N'sqladmin', @subscriber_password = 'dbatools.IO', @frequency_type = 64, @frequency_interval = 0, @frequency_relative_interval = 0, @frequency_recurrence_factor = 0, @frequency_subday = 0, @frequency_subday_interval = 0, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 20221101, @active_end_date = 99991231, @enabled_for_syncmgr = N'False', @dts_package_location = N'Distributor' + GO + diff --git a/tests/Get-DbaRepDistributor.Tests.ps1 b/tests/Get-DbaReplDistributor.Tests.ps1 similarity index 93% rename from tests/Get-DbaRepDistributor.Tests.ps1 rename to tests/Get-DbaReplDistributor.Tests.ps1 index 2d4231cb8a..dded7c7e9d 100644 --- a/tests/Get-DbaRepDistributor.Tests.ps1 +++ b/tests/Get-DbaReplDistributor.Tests.ps1 @@ -15,7 +15,7 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { Describe "$CommandName Integration Tests" -Tags "IntegrationTests" { Context "ensuring accuracy of results" { - $results = Get-DbaRepDistributor -SqlInstance $script:instance1 + $results = Get-DbaReplDistributor -SqlInstance $script:instance1 It "accurately reports that the distributor is not installed" { $results.DistributorInstalled | Should Be $false } diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 new file mode 100644 index 0000000000..3e1a3096e5 --- /dev/null +++ b/tests/Get-DbaReplPublication.Tests.ps1 @@ -0,0 +1,80 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +Describe "$commandname Unit Tests" -Tag 'UnitTests' { + Context "Validate parameters" { + [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'PublicationType', '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 + } + } + + InModuleScope dbatools { + Context "Code Validation" { + + Mock Connect-ReplicationDB -MockWith { + [object]@{ + Name = 'TestDB' + TransPublications = @{ + Name = 'TestDB_pub' + Type = 'Transactional' + } + MergePublications = @{} + } + } + + Mock Connect-DbaInstance -MockWith { + [object]@{ + Name = "MockServerName" + ComputerName = 'MockComputerName' + Databases = @{ + Name = 'TestDB' + #state + #status + ID = 5 + ReplicationOptions = 'Published' + } + ConnectionContext = @{ + SqlConnectionObject = 'FakeConnectionContext' + } + } + } + + It "Honors the SQLInstance parameter" { + $Results = Get-DbaReplPublication -SqlInstance MockServerName + $Results.Server | Should Be "MockServerName" + } + + It "Honors the Database parameter" { + $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB + $Results.Database | Should Be "TestDB" + } + + It "Honors the PublicationType parameter" { + + Mock Connect-ReplicationDB -MockWith { + [object]@{ + Name = 'TestDB' + TransPublications = @{ + Name = 'TestDB_pub' + Type = 'Snapshot' + } + MergePublications = @{} + } + } + + $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB -PublicationType Snapshot + $Results.PublicationType | Should Be "Snapshot" + } + + It "Stops if validate set for PublicationType is not met" { + + { Get-DbaReplPublication -SqlInstance MockServerName -PublicationType NotAPubType } | should Throw + + } + } + } +} \ No newline at end of file diff --git a/tests/Get-DbaReplServer.Tests.ps1 b/tests/Get-DbaReplServer.Tests.ps1 new file mode 100644 index 0000000000..43b16dc2ce --- /dev/null +++ b/tests/Get-DbaReplServer.Tests.ps1 @@ -0,0 +1,19 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +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', '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 + } + } +} +<# + Integration test should appear below and are custom to the command you are writing. + Read https://github.com/dataplat/dbatools/blob/development/contributing.md#tests + for more guidence. +#> \ No newline at end of file diff --git a/tests/Test-DbaReplLatency.Tests.ps1 b/tests/Test-DbaReplLatency.Tests.ps1 new file mode 100644 index 0000000000..de02df1513 --- /dev/null +++ b/tests/Test-DbaReplLatency.Tests.ps1 @@ -0,0 +1,14 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +Describe "$commandname Unit Tests" -Tag 'UnitTests' { + Context "Validate parameters" { + [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'PublicationName', 'TimeToLive', 'RetainToken', 'DisplayTokenHistory', '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 + } + } +} \ No newline at end of file diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 new file mode 100644 index 0000000000..12b63b6ea3 --- /dev/null +++ b/tests/gh-actions-repl.ps1 @@ -0,0 +1,170 @@ +Describe "Integration Tests" -Tag "IntegrationTests" { + BeforeAll { + $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force + $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password + + $PSDefaultParameterValues["*:SqlInstance"] = "localhost" + $PSDefaultParameterValues["*:SqlCredential"] = $cred + $PSDefaultParameterValues["*:Confirm"] = $false + $PSDefaultParameterValues["*:SharedPath"] = "/shared" + $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" + $global:ProgressPreference = "SilentlyContinue" + + #$null = Get-XPlatVariable | Where-Object { $PSItem -notmatch "Copy-", "Migration" } | Sort-Object + # load dbatools-lib + #Import-Module dbatools-core-library + Import-Module ./dbatools.psd1 -Force + } + + Context "Get-DbaReplDistributor works" { + BeforeAll { + + # if distribution is enabled, disable it & enable it with defaults + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + Enable-DbaReplDistributor + } + + It "gets a distributor" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution database name is correct" { + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + } + } + + Context "Enable-DbaReplDistributor works" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + + It "distribution is enabled" { + Enable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + } + + Context "Enable-DbaReplDistributor works with specified database name" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + AfterAll { + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + + It "distribution is enabled with specific database" { + $distDb = ('distdb-{0}' -f (Get-Random)) + Enable-DbaReplDistributor -DistributionDatabase $distDb + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + } + } + + Context "Disable-DbaReplDistributor works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + } + + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + } + + Context "Enable-DbaReplPublishing works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if Publishing is enabled - disable it + if ((Get-DbaReplServer).IsPublisher) { + Disable-DbaReplPublishing + } + } + + It "publishing starts disabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $false + } + + It "publishing is enabled" { + Enable-DbaReplPublishing -EnableException + (Get-DbaReplServer).IsPublisher | Should -Be $true + } + } + + Context "Disable-DbaReplPublishing works" { + BeforeAll { + + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + write-output -message 'I should enable publishing' + Enable-DbaReplPublishing -EnableException + } + + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + } + + It "publishing starts enabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $true + } + + It "publishing is disabled" { + Disable-DbaReplPublishing -EnableException + (Get-DbaReplServer).IsPublisher | Should -Be $false + } + } + + Context "Get-DbaReplPublisher works" -skip { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + + } +} From 2db7fa420299b48c91f77a537ab32751ec3aa0d7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 11:51:47 +0000 Subject: [PATCH 078/226] functions --- public/Add-DbaReplArticle.ps1 | 152 ++++++++++++++ public/Disable-DbaReplDistributor.ps1 | 102 ++++++++++ public/Disable-DbaReplPublishing.ps1 | 106 ++++++++++ public/Enable-DbaReplDistributor.ps1 | 94 +++++++++ public/Enable-DbaReplPublishing.ps1 | 118 +++++++++++ public/Export-DbaInstance.ps1 | 2 +- ...ng.ps1 => Export-DbaReplServerSetting.ps1} | 12 +- public/Get-DbaReplArticle.ps1 | 124 ++++++++++++ public/Get-DbaReplArticleColumn.ps1 | 103 ++++++++++ ...ributor.ps1 => Get-DbaReplDistributor.ps1} | 6 +- ...ication.ps1 => Get-DbaReplPublication.ps1} | 36 ++-- public/Get-DbaReplPublisher.ps1 | 85 ++++++++ ...DbaRepServer.ps1 => Get-DbaReplServer.ps1} | 23 ++- public/New-DbaReplPublication.ps1 | 185 ++++++++++++++++++ public/Remove-DbaReplArticle.ps1 | 152 ++++++++++++++ ...RepLatency.ps1 => Test-DbaReplLatency.ps1} | 12 +- 16 files changed, 1272 insertions(+), 40 deletions(-) create mode 100644 public/Add-DbaReplArticle.ps1 create mode 100644 public/Disable-DbaReplDistributor.ps1 create mode 100644 public/Disable-DbaReplPublishing.ps1 create mode 100644 public/Enable-DbaReplDistributor.ps1 create mode 100644 public/Enable-DbaReplPublishing.ps1 rename public/{Export-DbaRepServerSetting.ps1 => Export-DbaReplServerSetting.ps1} (91%) create mode 100644 public/Get-DbaReplArticle.ps1 create mode 100644 public/Get-DbaReplArticleColumn.ps1 rename public/{Get-DbaRepDistributor.ps1 => Get-DbaReplDistributor.ps1} (95%) rename public/{Get-DbaRepPublication.ps1 => Get-DbaReplPublication.ps1} (70%) create mode 100644 public/Get-DbaReplPublisher.ps1 rename public/{Get-DbaRepServer.ps1 => Get-DbaReplServer.ps1} (64%) create mode 100644 public/New-DbaReplPublication.ps1 create mode 100644 public/Remove-DbaReplArticle.ps1 rename public/{Test-DbaRepLatency.ps1 => Test-DbaReplLatency.ps1} (95%) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 new file mode 100644 index 0000000000..51ceb60f51 --- /dev/null +++ b/public/Add-DbaReplArticle.ps1 @@ -0,0 +1,152 @@ +function Add-DbaReplArticle { + <# + .SYNOPSIS + Adds an article to a publication for the database on the target SQL instances. + + .DESCRIPTION + Adds an article to a publication for the database on the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 contains the article to be replicated. + + .PARAMETER PublicationName + The name of the replication publication. + + .PARAMETER Type + The flavour of replication. + + Currently supported 'Transactional' + + Coming soon 'Snapshot', 'Merge' + + .PARAMETER LogReaderAgentCredential + Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs + + Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + TODO: Implement & test this + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [parameter(Mandatory)] + [String]$Database, + + [parameter(Mandatory)] + [String]$PublicationName, + + [String]$Schema = 'dbo', + + [parameter(Mandatory)] + [String]$Name, + + [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Adding article $Name to publication $PublicationName on $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { + + # based off this + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + + #TODO: add name field to Get-DbaReplPublication so don't have to where + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName + $pub + if ($pub.PublicationType -eq 'Transactional') { + + $article = New-Object Microsoft.SqlServer.Replication.TransArticle + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.DatabaseName = $Database + $article.SourceObjectName = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + + # think this is the default + #$article.Type = ArticleOptions.LogBased + + if ($articleFilter) { + article.FilterClause = $Filter #TODO: This doesn't seem to be working + } + + if (-not ($article.IsExistingObject)) { + $article.Create() + } else { + Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + } + # TODO: what if it's not transactional + + # TODO: Does the schema exist on the subscriber? + <# + // Ensure that we create the schema owner at the Subscriber. + article.SchemaOption |= CreationScriptOptions.Schema; + #> + + } + } catch { + Stop-Function -Message "Unable to add article $ArticleName to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + + #TODO: What should we return + Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name + + } + } +} + + + diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 new file mode 100644 index 0000000000..c2d325f673 --- /dev/null +++ b/public/Disable-DbaReplDistributor.ps1 @@ -0,0 +1,102 @@ +function Disable-DbaReplDistributor { + <# + .SYNOPSIS + Disables replication distribution for the target SQL instances. + + .DESCRIPTION + Disables replication distribution for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 Force + Boolean value that specifies whether or not replication objects are removed from the server, + even if a remote Distributor cannot be reached. + + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or + not dependent publishing and distribution objects are uninstalled. + + If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Disable-DbaReplDistributor + + .EXAMPLE + PS C:\> Disable-DbaReplDistributor -SqlInstance mssql1 + + Disables replication distribution for the mssql1 instance. + + .EXAMPLE + PS C:\> $cred = Get-Credential sqladmin + PS C:\> Disable-DbaReplDistributor -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force + + Disables replication distribution for the mssql1 and mssql2 instances using a sql login. + Specifies force so the publishing and Distributor configuration at the current server is uninstalled + regardless of whether or not dependent publishing and distribution objects are uninstalled. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + + [switch]$force, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Disabling replication distribution for $instance" + + if ($replServer.IsDistributor) { + try { + if ($PSCmdlet.ShouldProcess($instance, "Disabling distribution on $instance")) { + # remove any connections to the distribution database + Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess + # uninstall distribution + $replServer.UninstallDistributor($force) + } + } catch { + Stop-Function -Message "Unable to disable replication distribution" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } else { + Stop-Function -Message "$instance isn't currently enabled for distributing." -ErrorRecord $_ -Target $instance -Continue + } + } + } +} diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 new file mode 100644 index 0000000000..39d500924c --- /dev/null +++ b/public/Disable-DbaReplPublishing.ps1 @@ -0,0 +1,106 @@ +function Disable-DbaReplPublishing { + <# + .SYNOPSIS + Disables publication for the target SQL instances. + + .DESCRIPTION + Disables publication for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 Force + Boolean value that specifies whether or not replication objects are removed from the server, + even if a remote Distributor cannot be reached. + + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or + not dependent publishing and distribution objects are uninstalled. + + If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Disable-DbaReplPublishing + + .EXAMPLE + PS C:\> Disable-DbaReplPublishing -SqlInstance mssql1 + + Disables replication distribution for the mssql1 instance. + + .EXAMPLE + PS C:\> $cred = Get-Credential sqladmin + PS C:\> Disable-DbaReplPublishing -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force + + Disables replication distribution for the mssql1 and mssql2 instances using a sql login. + Specifies force so the publishing and Distributor configuration at the current server is uninstalled + regardless of whether or not dependent publishing and distribution objects are uninstalled. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [switch]$force, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Disabling publishing for $instance" + + if ($replServer.IsPublisher) { + try { + if ($PSCmdlet.ShouldProcess($instance, "Disabling publishing on $instance")) { + #Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess + # uninstall distribution + $replServer.DistributionPublishers.Remove($Force) + } + } catch { + Stop-Function -Message "Unable to disable replication publishing" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } else { + Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category InvalidData + } + + #$replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force + #$replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force + #$replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force + #Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name + + } + } +} diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 new file mode 100644 index 0000000000..1cba0e42a4 --- /dev/null +++ b/public/Enable-DbaReplDistributor.ps1 @@ -0,0 +1,94 @@ +function Enable-DbaReplDistributor { + <# + .SYNOPSIS + Enables replication distribution for the target SQL instances. + + .DESCRIPTION + Enables replication distribution for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 DistributionDatabase + Name of the distribution database that will be created. + + Default is 'distribution'. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Enable-DbaReplDistributor + + .EXAMPLE + PS C:\> Enable-DbaReplDistributor -SqlInstance mssql1 + + Enables distribution for the mssql1 instance. + + .EXAMPLE + PS C:\> Enable-DbaReplDistributor -SqlInstance mssql1 -DistributionDatabase repDatabase + + Enables distribution for the mssql1 instance and names the distribution database repDatabase. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [string]$DistributionDatabase = 'distribution', + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Enabling replication distribution for $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Enabling distributor for $instance")) { + $distributionDb = New-Object Microsoft.SqlServer.Replication.DistributionDatabase + $distributionDb.ConnectionContext = $replServer.ConnectionContext + $distributionDb.Name = $DistributionDatabase + # lots more properties to add as params + $replServer.InstallDistributor($null, $distributionDb) + } + } catch { + Stop-Function -Message "Unable to enable replication distributor" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } + } +} + + + diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 new file mode 100644 index 0000000000..409da62131 --- /dev/null +++ b/public/Enable-DbaReplPublishing.ps1 @@ -0,0 +1,118 @@ +function Enable-DbaReplPublishing { + <# + .SYNOPSIS + Enables replication publishing for the target SQL instances. + + .DESCRIPTION + Enables replication publishing for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 SnapshotShare + The share used to access snapshot files. + + .PARAMETER PublisherSqlLogin + If this is used the PublisherSecurity will be set to use this. + If not specified WindowsAuthentication can will used - this is the default, and recommended method. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Enable-DbaReplPublishing + + .EXAMPLE + PS C:\> Enable-DbaReplPublishing -SqlInstance SqlBox1\Instance2 -StartupProcedure '[dbo].[StartUpProc1]' + + Attempts to set the procedure '[dbo].[StartUpProc1]' in the master database of SqlBox1\Instance2 for automatic execution when the instance is started. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + $SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? + [PSCredential]$PublisherSqlLogin, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Enabling replication publishing for $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Enabling publishing on $instance")) { + + if ($replServer.IsDistributor) { + + $distPublisher = New-Object Microsoft.SqlServer.Replication.DistributionPublisher + $distPublisher.ConnectionContext = $replServer.ConnectionContext + $distPublisher.Name = $instance #- name of the Publisher. + $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name #- the name of the database created in step 5. + + #TODO: test snapshot path and warn\error? + #if (Test-DbaPath -SqlInstance mssql1 -Path $SnapshotShare) { + # Stop-Function -Message ("Snapshot path '{0}' does not exist - will attempt to create it" -f $SnapshotShare) -ErrorRecord $_ -Target $instance -Continue + #} + $distPublisher.WorkingDirectory = $SnapshotShare + + if ($PublisherSqlLogin) { + Write-Message -Level Verbose -Message "Configuring with a SQLLogin for PublisherSecurity" + $distPublisher.PublisherSecurity.WindowsAuthentication = $false + $distPublisher.PublisherSecurity.SqlStandardLogin = $PublisherSqlLogin.UserName + $distPublisher.PublisherSecurity.SecureSqlStandardPassword = $PublisherSqlLogin.Password + + } else { + Write-Message -Level Verbose -Message "Configuring with WindowsAuth for PublisherSecurity" + $distPublisher.PublisherSecurity.WindowsAuthentication = $true # TODO: test with windows auth + } + + Write-Message -Level Debug -Message $distPublisher + # lots more properties to add as params + $distPublisher.Create() + } else { + Stop-Function -Message "$instance isn't currently enabled for distributing. Please enable that first." -ErrorRecord $_ -Target $instance -Continue + } + } + } catch { + Stop-Function -Message "Unable to enable replication publishing" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer # TODO: Standard output + + } + } +} + + + diff --git a/public/Export-DbaInstance.ps1 b/public/Export-DbaInstance.ps1 index 625e272ffc..b5229e3431 100644 --- a/public/Export-DbaInstance.ps1 +++ b/public/Export-DbaInstance.ps1 @@ -385,7 +385,7 @@ function Export-DbaInstance { Write-ProgressHelper -StepNumber ($stepCounter++) -Message "Exporting replication settings" try { - $null = Export-DbaRepServerSetting -SqlInstance $instance -SqlCredential $SqlCredential -FilePath "$exportPath\replication.sql" -EnableException + $null = Export-DbaReplServerSetting -SqlInstance $instance -SqlCredential $SqlCredential -FilePath "$exportPath\replication.sql" -EnableException Get-ChildItem -ErrorAction Ignore -Path "$exportPath\replication.sql" } catch { Write-Message -Level Verbose -Message "Replication failed, skipping" diff --git a/public/Export-DbaRepServerSetting.ps1 b/public/Export-DbaReplServerSetting.ps1 similarity index 91% rename from public/Export-DbaRepServerSetting.ps1 rename to public/Export-DbaReplServerSetting.ps1 index 7ab3ecc52d..8ab1b71a23 100644 --- a/public/Export-DbaRepServerSetting.ps1 +++ b/public/Export-DbaReplServerSetting.ps1 @@ -1,4 +1,4 @@ -function Export-DbaRepServerSetting { +function Export-DbaReplServerSetting { <# .SYNOPSIS Exports replication server settings to file. @@ -51,7 +51,7 @@ function Export-DbaRepServerSetting { Not real sure how to use this yet .PARAMETER InputObject - Allows piping from Get-DbaRepServer + Allows piping from Get-DbaReplServer .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -67,15 +67,15 @@ function Export-DbaRepServerSetting { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Export-DbaRepServerSetting + https://dbatools.io/Export-DbaReplServerSetting .EXAMPLE - PS C:\> Export-DbaRepServerSetting -SqlInstance sql2017 -Path C:\temp\replication.sql + PS C:\> Export-DbaReplServerSetting -SqlInstance sql2017 -Path C:\temp\replication.sql Exports the replication settings on sql2017 to the file C:\temp\replication.sql .EXAMPLE - PS C:\> Get-DbaRepServer -SqlInstance sql2017 | Export-DbaRepServerSettings -Path C:\temp\replication.sql + PS C:\> Get-DbaReplServer -SqlInstance sql2017 | Export-DbaReplServerSetting -Path C:\temp\replication.sql Exports the replication settings on sql2017 to the file C:\temp\replication.sql @@ -104,7 +104,7 @@ function Export-DbaRepServerSetting { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - $InputObject += Get-DbaRepServer -SqlInstance $instance -SqlCredential $SqlCredential + $InputObject += Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } foreach ($repserver in $InputObject) { diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 new file mode 100644 index 0000000000..2fddf5e3f1 --- /dev/null +++ b/public/Get-DbaReplArticle.ps1 @@ -0,0 +1,124 @@ +function Get-DbaReplArticle { + <# + .SYNOPSIS + Gets the information about publication articles. + + .DESCRIPTION + This function locates and enumerates articles' information for a given publication. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 + Specifies one or more database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER PublicationName + Specifies one or more publication(s) to process. If unspecified, all publications will be processed. + + .PARAMETER PublicationType + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + + .PARAMETER Article + Specifies one or more article(s) to process. If unspecified, all articles will be processed. + + .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. + + .NOTES + Tags: Replication + Author: Cláudio Silva (@claudioessilva), claudioessilva.eu + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplArticle + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + + Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + + #> + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [object[]]$Database, + [parameter(ValueFromPipeline)] + [object[]]$Publication, + [String]$PublicationType, # Snapshot, Transactional, Merge + [string[]]$Article, + [switch]$EnableException + ) + begin { + #TODO - Still needed? + Add-ReplicationLibrary + } + process { + if (Test-FunctionInterrupt) { return } + + foreach ($instance in $SqlInstance) { + # Connect to the distributor of the instance + try { + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + $databases = $server.Databases | Where-Object IsAccessible -eq $true + if ($Database) { + $databases = $databases | Where-Object Name -In $Database + } + + foreach ($db in $databases) { + + $RMOdb = Connect-ReplicationDB -Server $server -Database $db + + #TODO - Check if database has replication options + #if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { + # Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + #} + + if ($PublicationType -eq 'Transactional') { + $publications = $RMOdb.TransPublications + } else { + $publications = $RMOdb.MergePublications + } + + if ($Publication) { + $publications = $publications | Where-Object Name -in $Publication + } + + if ($PublicationType -eq 'Transactional') { + $articles = $publications.TransArticles + } else { + $articles = $publications.MergeArticles + } + + if ($Article) { + $articles = $articles | Where-Object Name -In $Article + } + + foreach ($art in $articles) { + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + } + } + } + } +} \ No newline at end of file diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 new file mode 100644 index 0000000000..46ec46bd52 --- /dev/null +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -0,0 +1,103 @@ +function Get-DbaReplArticleColumn { + <# + .SYNOPSIS + Gets the information about publication article columns. + + .DESCRIPTION + This function enumerates columns information for a given articles. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 + Specifies one or more database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER PublicationName + Specifies one or more publication(s) to process. If unspecified, all publications will be processed. + + .PARAMETER PublicationType + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + + .PARAMETER Article + Specifies one or more article(s) to process. If unspecified, all articles will be processed. + + .PARAMETER Column + Specifies one or more column(s) to process. If unspecified, all columns will be processed. + + .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. + + .NOTES + Tags: Replication + Author: Cláudio Silva (@claudioessilva), claudioessilva.eu + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplArticleColumn + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + + Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + + #> + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [object[]]$Database, + [parameter(ValueFromPipeline)] + [object[]]$Publication, + [String]$PublicationType, # Snapshot, Transactional, Merge + [string[]]$Article, + [string[]]$Column, + [switch]$EnableException + ) + begin { + #TODO - Still needed? + Add-ReplicationLibrary + } + process { + if (Test-FunctionInterrupt) { return } + + $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -PublicationType $PublicationType -Article $Article + + foreach ($art in $articles) { + $columns = $art.ListReplicatedColumns() + + if ($Column) { + $columns = $columns | Where-Object { $_ -In $Column } + } + + foreach ($col in $columns) { + + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $art.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $art.InstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $art.SqlInstance + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleName -Value $art.Name + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleId -Value $art.ArticleId + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Description -Value $art.Description + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Type -Value $art.Type + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name VerticalPartition -Value $art.VerticalPartition + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectOwner -Value $art.SourceObjectOwner + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectName -Value $art.SourceObjectName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ColumnName -Value $col + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, ArticleName, ArticleId, Description, ColumnName #, DestinationObjectOwner, DestinationObjectName + } + } + } +} \ No newline at end of file diff --git a/public/Get-DbaRepDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 similarity index 95% rename from public/Get-DbaRepDistributor.ps1 rename to public/Get-DbaReplDistributor.ps1 index c5657c688e..a93522df7c 100644 --- a/public/Get-DbaRepDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -1,4 +1,4 @@ -function Get-DbaRepDistributor { +function Get-DbaReplDistributor { <# .SYNOPSIS Gets the information about a replication distributor for a given SQL Server instance. @@ -33,10 +33,10 @@ function Get-DbaRepDistributor { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaRepDistributor + https://dbatools.io/Get-DbaReplDistributor .EXAMPLE - PS C:\> Get-DbaRepDistributor -SqlInstance sql2008, sqlserver2012 + PS C:\> Get-DbaReplDistributor -SqlInstance sql2008, sqlserver2012 Retrieve distributor information for servers sql2008 and sqlserver2012. diff --git a/public/Get-DbaRepPublication.ps1 b/public/Get-DbaReplPublication.ps1 similarity index 70% rename from public/Get-DbaRepPublication.ps1 rename to public/Get-DbaReplPublication.ps1 index 8a04b05640..783c15c7bb 100644 --- a/public/Get-DbaRepPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -1,4 +1,4 @@ -function Get-DbaRepPublication { +function Get-DbaReplPublication { <# .SYNOPSIS Displays all publications for a server or database. @@ -26,7 +26,9 @@ function Get-DbaRepPublication { Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER EnableException - byng this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. + 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. .NOTES Tags: Replication @@ -37,20 +39,20 @@ function Get-DbaRepPublication { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaRepPublication + https://dbatools.io/Get-DbaReplPublication .EXAMPLE - PS C:\> Get-DbaRepPublication -SqlInstance sql2008, sqlserver2012 + PS C:\> Get-DbaReplPublication -SqlInstance sql2008, sqlserver2012 Return all publications for servers sql2008 and sqlserver2012. .EXAMPLE - PS C:\> Get-DbaRepPublication -SqlInstance sql2008 -Database TestDB + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Database TestDB Return all publications on server sql2008 for only the TestDB database .EXAMPLE - PS C:\> Get-DbaRepPublication -SqlInstance sql2008 -PublicationType Transactional + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -PublicationType Transactional Return all publications on server sql2008 for all databases that have Transactional publications @@ -62,8 +64,9 @@ function Get-DbaRepPublication { [object[]]$Database, [PSCredential]$SqlCredential, [ValidateSet("Transactional", "Merge", "Snapshot")] - [object[]]$PublicationType, + [object[]]$PublicationType, #TODO: change to just Type [switch]$EnableException + #TODO: add a name parameter ) begin { Add-ReplicationLibrary @@ -79,16 +82,13 @@ function Get-DbaRepPublication { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $dbList = $server.Databases - + $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } if ($Database) { - $dbList = $dbList | Where-Object name -in $Database + $databases = $databases | Where-Object Name -In $Database } - $dbList = $dbList | Where-Object { ($_.ID -gt 4) -and ($_.status -ne "Offline") } - - foreach ($db in $dbList) { + foreach ($db in $databases) { if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." @@ -106,12 +106,14 @@ function Get-DbaRepPublication { [PSCustomObject]@{ ComputerName = $server.ComputerName - InstanceName = $server.InstanceName - SqlInstance = $server.SqlInstance + InstanceName = $server.ServiceName + SqlInstance = $server.Name Server = $server.name Database = $db.name - PublicationName = $pub.Name - PublicationType = $pub.Type + PublicationName = $pub.Name #TODO: change to just name + PublicationType = $pub.Type #TODO: change to just Type + Articles = $pub.TransArticles #TODO what about merge articles? + } } } diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 new file mode 100644 index 0000000000..1c3e2acd14 --- /dev/null +++ b/public/Get-DbaReplPublisher.ps1 @@ -0,0 +1,85 @@ +function Get-DbaReplPublisher { + <# + .SYNOPSIS + Gets publisher for the target SQL instances. + + .DESCRIPTION + Gets publisher for the target SQL instances. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 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: Replication + Author: Mikey Bronowski (@MikeyBronowski), bronowski.it + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplPublisher + + .EXAMPLE + PS C:\> Get-DbaReplPublisher -SqlInstance mssql1 + + Gets publisher for the mssql1 instance. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $server + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue + } + Write-Message -Level Verbose -Message "Getting publisher for $server" + + try { + if ($PSCmdlet.ShouldProcess($server, "Getting publisher for $server")) { + $publisher = $replServer.DistributionPublishers + $publisher + } + } catch { + Stop-Function -Message "Unable to get publisher for" -ErrorRecord $_ -Target $server -Continue + } + + # fails if there isn't any + if ($publisher) { + $publisher | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force + $publisher | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force + $publisher | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force + } + + + Select-DefaultView -InputObject $publisher -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name + + } + } +} diff --git a/public/Get-DbaRepServer.ps1 b/public/Get-DbaReplServer.ps1 similarity index 64% rename from public/Get-DbaRepServer.ps1 rename to public/Get-DbaReplServer.ps1 index 9a9d692110..ca50bf70f6 100644 --- a/public/Get-DbaRepServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -1,4 +1,4 @@ -function Get-DbaRepServer { +function Get-DbaReplServer { <# .SYNOPSIS Gets a replication server object @@ -33,15 +33,15 @@ function Get-DbaRepServer { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaRepServer + https://dbatools.io/Get-DbaReplServer .EXAMPLE - PS C:\> Get-DbaRepServer -SqlInstance sql2016 + PS C:\> Get-DbaReplServer -SqlInstance sql2016 Gets the replication server object for sql2016 using Windows authentication .EXAMPLE - PS C:\> Get-DbaRepServer -SqlInstance sql2016 -SqlCredential repadmin + PS C:\> Get-DbaReplServer -SqlInstance sql2016 -SqlCredential repadmin Gets the replication server object for sql2016 using SQL authentication @@ -61,11 +61,20 @@ function Get-DbaRepServer { foreach ($instance in $SqlInstance) { try { # use System.Data instead of Microsoft.Data - $sqlconn = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential - New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlconn + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + $sqlCon = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlCon + + $replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force + $replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force + $replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force + + Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, DistributorInstalled, DistributorAvailable, IsDistributor, IsPublisher, HasRemotePublisher, DistributionServer, DistributionDatabase, WorkingDirectory, AgentCheckupInterval, DistributionDatabases, DistributionPublishers, ReplicationDatabases, RegisteredSubscribers } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } } } -} \ No newline at end of file +} + +# TODO: Replication databases are shown even if they have no pubs \ No newline at end of file diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 new file mode 100644 index 0000000000..232955d5c2 --- /dev/null +++ b/public/New-DbaReplPublication.ps1 @@ -0,0 +1,185 @@ +function New-DbaReplPublication { + <# + .SYNOPSIS + Creates a publication for the database on the target SQL instances. + + .DESCRIPTION + Creates a publication for the database on the target SQL instances. + + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 that will be replicated. + + .PARAMETER PublicationName + The name of the replication publication + + .PARAMETER Type + The flavour of replication. + + Currently supported 'Transactional' + + Coming soon 'Snapshot', 'Merge' + + .PARAMETER LogReaderAgentCredential + Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs + + Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + TODO: Implement & test this + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [String]$Database, + + [parameter(Mandatory)] + [String]$PublicationName, + + [parameter(Mandatory)] + [ValidateSet("Snapshot", "Transactional", "Merge")] + [String]$Type, + + [PSCredential]$LogReaderAgentCredential, + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Creating a new publication on $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Enabling distribution on $instance")) { + + # based off this + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 + + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $pubDatabase.ConnectionContext = $replServer.ConnectionContext + $pubDatabase.Name = $Database + if (-not $pubDatabase.LoadProperties()) { + throw "Database $Database not found on $instance" + } + + if ($Type -eq 'Transactional') { + $pubDatabase.EnabledTransPublishing = $true + } elseif ($Type -eq 'Merge') { + $pubDatabase.EnabledMergePublishing = $true + $pubDatabase.CommitPropertyChanges + } + #TODO: snapshot repl? + + if (-not $pubDatabase.LogReaderAgentExists) { + #TODO: if this needed for merge? + + Write-Message -Level Verbose -Message "Create Log Read Agent job for $Database on $instance" + if ($LogReaderAgentCredential) { + #TODO: Test this + $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName + $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password + } + + #(Optional) Set the SqlStandardLogin and SqlStandardPassword or + # SecureSqlStandardPassword fields of LogReaderAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. + + $pubDatabase.CreateLogReaderAgent() + } else { + Write-Message -Level Verbose -Message "Log Read Agent job already exists for $Database on $instance" + } + + if ($Type -eq 'Transactional') { + + $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication + $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.DatabaseName = $Database + $transPub.Name = $PublicationName + $transPub.Type = $Type + $transPub.Create() + + # create the Snapshot Agent job + #TODO: also for snapshot pub? + $transPub.CreateSnapshotAgent() + + #$transPub.CreateSnapshotAgent + + <# + TODO: add these in? + + The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. + This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. + + Note + Setting SnapshotGenerationAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + (Optional) The SqlStandardLogin and SqlStandardPassword or + SecureSqlStandardPassword fields of SnapshotGenerationAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. + #> + } + + #TODO: merge? + + + + } + } catch { + Stop-Function -Message "Unable to enable replication distribution" -ErrorRecord $_ -Target $instance -Continue + } + + $replServer.Refresh() + $replServer + + } + } +} + + + diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 new file mode 100644 index 0000000000..b838bdb784 --- /dev/null +++ b/public/Remove-DbaReplArticle.ps1 @@ -0,0 +1,152 @@ +function Remove-DbaReplArticle { + <# + .SYNOPSIS + Removes an article from a publication for the database on the target SQL instances. + + .DESCRIPTION + Removes an article from a publication for the database on the target SQL instances. + + Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. + Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this ClearUpSubObject + +For snapshot or transactional publications, articles can be dropped with no special considerations prior to subscriptions being created. +If an article is dropped after one or more subscriptions is created, the subscriptions must be dropped, recreated, and synchronized. + +Dropping an article from a publication involves dropping the article and creating a new snapshot for the publication. +Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. + + +https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 + + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 contains the article to be removed from replication. + + .PARAMETER PublicationName + The name of the replication publication. + + .PARAMETER Type + The flavour of replication. + + Currently supported 'Transactional' + + Coming soon 'Snapshot', 'Merge' + + .PARAMETER LogReaderAgentCredential + Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs + + Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. + + TODO: Implement & test this + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [parameter(Mandatory)] + [String]$Database, + + [parameter(Mandatory)] + [String]$PublicationName, + + [String]$Schema = 'dbo', + + [parameter(Mandatory)] + [String]$Name, + + [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + Write-Message -Level Verbose -Message "Removing article $Name from publication $PublicationName on $instance" + + try { + if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { + + # based off this + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + + #TODO: add name field to Get-DbaReplPublication so don't have to where + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName + + if ($pub.PublicationType -eq 'Transactional') { + + $article = New-Object Microsoft.SqlServer.Replication.TransArticle + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + $article.DatabaseName = $Database + + # think this is the default + #$article.Type = ArticleOptions.LogBased + + if (($article.IsExistingObject)) { + $article.Remove() + } else { + Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + } + # TODO: what if it's not transactional + } + } catch { + Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + + #TODO: What should we return anything? + + } + } +} + + + diff --git a/public/Test-DbaRepLatency.ps1 b/public/Test-DbaReplLatency.ps1 similarity index 95% rename from public/Test-DbaRepLatency.ps1 rename to public/Test-DbaReplLatency.ps1 index 6224e0041a..a1e4cbdc0c 100644 --- a/public/Test-DbaRepLatency.ps1 +++ b/public/Test-DbaReplLatency.ps1 @@ -1,4 +1,4 @@ -function Test-DbaRepLatency { +function Test-DbaReplLatency { <# .SYNOPSIS Displays replication latency for all transactional publications for a server or database. @@ -50,20 +50,20 @@ function Test-DbaRepLatency { License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Test-DbaRepLatency + https://dbatools.io/Test-DbaReplLatency .EXAMPLE - PS C:\> Test-DbaRepLatency -SqlInstance sql2008, sqlserver2012 + PS C:\> Test-DbaReplLatency -SqlInstance sql2008, sqlserver2012 Return replication latency for all transactional publications for servers sql2008 and sqlserver2012. .EXAMPLE - PS C:\> Test-DbaRepLatency -SqlInstance sql2008 -Database TestDB + PS C:\> Test-DbaReplLatency -SqlInstance sql2008 -Database TestDB Return replication latency for all transactional publications on server sql2008 for only the TestDB database .EXAMPLE - PS C:\> Test-DbaRepLatency -SqlInstance sql2008 -Database TestDB -PublicationName TestDB_Pub + PS C:\> Test-DbaReplLatency -SqlInstance sql2008 -Database TestDB -PublicationName TestDB_Pub Return replication latency for the TestDB_Pub publication for the TestDB database located on the server sql2008. @@ -94,7 +94,7 @@ function Test-DbaRepLatency { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $publicationNames = Get-DbaRepPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -PublicationType "Transactional" + $publicationNames = Get-DbaReplPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -PublicationType "Transactional" if ($PublicationName) { $publicationNames = $publicationNames | Where-Object PublicationName -in $PublicationName From dd55165810dfeed34e1916f13507b873e295ad76 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:01:26 +0000 Subject: [PATCH 079/226] psd1\psm1 merging --- dbatools.psd1 | 33 ++++++++++++++++++++++++++------- dbatools.psm1 | 23 +++++++++++++++++------ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index dabc275dd7..bd89b1a78d 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -139,7 +139,7 @@ 'Export-DbaLogin', 'Export-DbaPfDataCollectorSetTemplate', 'Export-DbaRegServer', - 'Export-DbaRepServerSetting', + 'Export-DbaReplServerSetting', 'Export-DbaScript', 'Export-DbaServerRole', 'Export-DbaSpConfigure', @@ -350,9 +350,10 @@ 'Get-DbaRegServer', 'Get-DbaRegServerGroup', 'Get-DbaRegServerStore', - 'Get-DbaRepDistributor', - 'Get-DbaRepPublication', - 'Get-DbaRepServer', + 'Get-DbaReplDistributor', + 'Get-DbaReplPublication', + 'Get-DbaReplPublisher', + 'Get-DbaReplServer', 'Get-DbaResourceGovernor', 'Get-DbaRgClassifierFunction', 'Get-DbaRgResourcePool', @@ -693,7 +694,7 @@ 'Test-DbaOptimizeForAdHoc', 'Test-DbaPath', 'Test-DbaPowerPlan', - 'Test-DbaRepLatency', + 'Test-DbaReplLatency', 'Test-DbaSpn', 'Test-DbaTempDbConfig', 'Test-DbaWindowsLogin', @@ -728,7 +729,18 @@ 'New-DbaLinkedServerLogin', 'Remove-DbaLinkedServerLogin', 'Remove-DbaCredential', - 'Remove-DbaAgentProxy' + 'Remove-DbaAgentProxy', + + # NEW REPLICATION STUFF + 'Disable-DbaReplDistributor', + 'Enable-DbaReplDistributor', + 'Disable-DbaReplPublishing', + 'Enable-DbaReplPublishing', + 'New-DbaReplPublication', + 'Get-DbaReplArticle', + 'Get-DbaReplArticleColumn', + 'Add-DbaReplArticle', + 'Remove-DbaReplArticle' ) # Cmdlets to export from this module @@ -751,9 +763,16 @@ 'Write-DbaDataTable', 'Get-DbaDbModule', 'Get-DbaBuildReference', - 'Copy-DbaSysDbUserObject' + 'Copy-DbaSysDbUserObject', + + # replication aliases - these existed before the repl overhaul in 2.0+ + 'Get-DbaRepServer', + 'Export-DbaRepServerSetting', + 'Get-DbaRepDistributor', + 'Test-DbaRepLatency' ) + # List of all modules packaged with this module ModuleList = @() diff --git a/dbatools.psm1 b/dbatools.psm1 index 55fd649f59..3e4390a21e 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -295,9 +295,19 @@ $forever = @{ foreach ($_ in $forever.GetEnumerator()) { Set-Alias -Name $_.Key -Value $_.Value } + +# Replication Aliases +$replAliases = @{ + 'Get-DbaRepServer' = 'Get-DbaReplServer' + 'Export-DbaRepServerSetting' = 'Export-DbaReplServerSetting' + 'Get-DbaRepDistributor' = 'Get-DbaReplDistributor' + 'Test-DbaRepLatency' = 'Test-DbaReplLatency' +} +foreach ($_ in $replAliases.GetEnumerator()) { + Set-Alias -Name $_.Key -Value $_.Value +} #endregion Aliases -# apparently this is no longer required? :O if ($PSVersionTable.PSVersion.Major -lt 5) { # region Commands $script:xplat = @( @@ -844,9 +854,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Remove-DbaCredential', 'Remove-DbaAgentProxy' ) + #TODO: can repl commands be removed here? $script:noncoresmo = @( # SMO issues - 'Get-DbaRepDistributor', + 'Get-DbaReplDistributor', 'Copy-DbaPolicyManagement', 'Copy-DbaDataCollector', 'Get-DbaPbmCategory', @@ -855,10 +866,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Get-DbaPbmObjectSet', 'Get-DbaPbmPolicy', 'Get-DbaPbmStore', - 'Get-DbaRepPublication', - 'Test-DbaRepLatency', - 'Export-DbaRepServerSetting', - 'Get-DbaRepServer' + 'Get-DbaReplPublication', + 'Test-DbaReplLatency', + 'Export-DbaReplServerSetting', + 'Get-DbaReplServer' ) $script:windowsonly = @( # filesystem (\\ related), From 1d1820950dfce4055783b74a135022795a221b35 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:32:58 +0000 Subject: [PATCH 080/226] update wf --- .github/workflows/integration-tests-repl.yml | 64 ++------------------ 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index a64a6c1da9..a199934b3e 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -13,12 +13,11 @@ jobs: - uses: actions/checkout@v3 - name: Install and cache PowerShell modules - uses: potatoqualitee/psmodulecache@v5.1 + uses: potatoqualitee/psmodulecache@v5.2 with: - modules-to-cache: dbatools-core-library:2022.10.27 - modules-to-cache-prerelease: dbatools-library:2022.10.28-preview + modules-to-cache: dbatools.library:2023.1.29 - - name: Install and cache dbatools-library + - name: Set encryption values run: | Import-Module ./dbatools.psd1 -Force Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register @@ -37,7 +36,7 @@ jobs: - name: 👥 Clone appveyor repo working-directory: /tmp run: | - gh repo clone sqlcollaborative/appveyor-lab + gh repo clone dataplat/appveyor-lab - name: Setup Replication run: | @@ -53,58 +52,3 @@ jobs: Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru - - - -# windows-tests: -# runs-on: windows-latest -# env: -# GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} -# -# steps: -# - name: Checkout dbatools repo -# uses: actions/checkout@v3 -# -# - name: Install and cache PowerShell modules -# uses: potatoqualitee/psmodulecache@v5.1 -# with: -# shell: powershell, pwsh -# modules-to-cache: dbatools-core-library:2022.10.27 -# modules-to-cache-prerelease: dbatools-library:2022.10.28-preview -# -# - name: Install SQL Server localdb -# uses: potatoqualitee/mssqlsuite@v1.3 -# with: -# install: localdb -# -# - name: Connect to localdb instance powershell -# shell: powershell -# run: | -# Import-Module ./dbatools -Force -# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" -# -# - name: Connect to localdb instance pwsh -# shell: pwsh -# run: | -# Import-Module ./dbatools -Force -# Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -PassThru | Register-DbatoolsConfig -Scope SystemMandatory -# Connect-DbaInstance -SqlInstance "(localdb)\MSSQLLocalDB" -# -# - name: Run pwsh tests -# env: -# TENANTID: ${{secrets.TENANTID}} -# CLIENTID: ${{secrets.CLIENTID}} -# CLIENTSECRET: ${{secrets.CLIENTSECRET}} -# shell: pwsh -# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru -# -# - name: Run PowerShell tests -# env: -# TENANTID: ${{secrets.TENANTID}} -# CLIENTID: ${{secrets.CLIENTID}} -# CLIENTSECRET: ${{secrets.CLIENTSECRET}} -# shell: powershell -# run: $null = Invoke-Pester ./tests/gh-winactions.ps1 -Output Detailed -PassThru \ No newline at end of file From 6bccfa0a1b522d151a0fdafb9140e5c96bdf477c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:44:31 +0000 Subject: [PATCH 081/226] Swap order of pub dist --- tests/gh-actions-repl.ps1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 12b63b6ea3..f2234d63bd 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -97,14 +97,14 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Enable-DbaReplPublishing works" { BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } } It "publishing starts disabled" { @@ -123,18 +123,18 @@ Describe "Integration Tests" -Tag "IntegrationTests" { write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - write-output -message 'I should enable distribution' - Enable-DbaReplDistributor -EnableException - } - # if publishing is disabled - enable it if (-not (Get-DbaReplServer).IsPublisher) { write-output -message 'I should enable publishing' Enable-DbaReplPublishing -EnableException } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) } From 39c92c77843f8045aca33cf3c549e9c736d048da Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 14:45:48 +0000 Subject: [PATCH 082/226] rename --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index a199934b3e..d7bb4b3f84 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -1,4 +1,4 @@ -name: Run Cross Platform Tests - repl +name: Run Replication Tests on: [push] defaults: run: From 23b9d4108c894c8fe70c3fb70b6d2a0ac5c6a7b6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 16 Feb 2023 15:05:13 +0000 Subject: [PATCH 083/226] debug --- tests/gh-actions-repl.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index f2234d63bd..fb4b3f4fee 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -100,10 +100,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing + write-output 'DISABLE PUB' } # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { Enable-DbaReplDistributor + write-output 'ENABLE DIST' } } @@ -112,7 +114,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - Enable-DbaReplPublishing -EnableException + write-output 'work on enable' + Enable-DbaReplPublishing -EnableException -Outvariable test + $test (Get-DbaReplServer).IsPublisher | Should -Be $true } } From 867e9e24ec50edb6852b7e1cfbc158c1bbc17c27 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 17 Feb 2023 13:47:49 +0000 Subject: [PATCH 084/226] add name to get-dbareplpublication --- public/Get-DbaReplPublication.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 783c15c7bb..b9501b12dd 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -15,6 +15,9 @@ function Get-DbaReplPublication { .PARAMETER Database The database(s) to process. If unspecified, all databases will be processed. + .PARAMETER Name + The name of the publication. + .PARAMETER SqlCredential Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). @@ -56,6 +59,10 @@ function Get-DbaReplPublication { Return all publications on server sql2008 for all databases that have Transactional publications + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey + + Returns the Mergey publications on server mssql1 #> [CmdletBinding()] param ( @@ -63,10 +70,10 @@ function Get-DbaReplPublication { [DbaInstanceParameter[]]$SqlInstance, [object[]]$Database, [PSCredential]$SqlCredential, + [String]$Name, [ValidateSet("Transactional", "Merge", "Snapshot")] [object[]]$PublicationType, #TODO: change to just Type [switch]$EnableException - #TODO: add a name parameter ) begin { Add-ReplicationLibrary @@ -96,12 +103,17 @@ function Get-DbaReplPublication { $repDB = Connect-ReplicationDB -Server $server -Database $db + $pubTypes = $repDB.TransPublications + $repDB.MergePublications if ($PublicationType) { $pubTypes = $pubTypes | Where-Object Type -in $PublicationType } + if ($Name) { + $pubTypes = $pubTypes | Where-Object Name -in $Name + } + foreach ($pub in $pubTypes) { [PSCustomObject]@{ From a8bd41a5c6ee56669734a46c3d608fb9d5b4d6e1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 17 Feb 2023 13:48:49 +0000 Subject: [PATCH 085/226] add support for merge and snapshot --- public/Add-DbaReplArticle.ps1 | 61 +++++++++++++--------------- public/New-DbaReplPublication.ps1 | 41 +++++++++++++------ public/Remove-DbaReplArticle.ps1 | 66 ++++++++++++------------------- 3 files changed, 83 insertions(+), 85 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 51ceb60f51..e114d65946 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -56,6 +56,8 @@ function Add-DbaReplArticle { Copyright: (c) 2022 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + .LINK https://dbatools.io/New-DbaReplPublication @@ -99,51 +101,42 @@ function Add-DbaReplArticle { try { if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { - # based off this - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName - #TODO: add name field to Get-DbaReplPublication so don't have to where - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName - $pub - if ($pub.PublicationType -eq 'Transactional') { + $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - $article = New-Object Microsoft.SqlServer.Replication.TransArticle - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.DatabaseName = $Database - $article.SourceObjectName = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName - - # think this is the default - #$article.Type = ArticleOptions.LogBased - - if ($articleFilter) { - article.FilterClause = $Filter #TODO: This doesn't seem to be working - } - - if (-not ($article.IsExistingObject)) { - $article.Create() - } else { - Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } + if ($pub.PublicationType -eq 'Transactional') { + $article = New-Object Microsoft.SqlServer.Replication.TransArticle + $article.Type = $ArticleOptions::LogBased + } elseif ($pub.PublicationType -eq 'Merge') { + $article = New-Object Microsoft.SqlServer.Replication.MergeArticle + $article.Type = $ArticleOptions::TableBased + } else { + Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue } - # TODO: what if it's not transactional - # TODO: Does the schema exist on the subscriber? - <# - // Ensure that we create the schema owner at the Subscriber. - article.SchemaOption |= CreationScriptOptions.Schema; - #> + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.DatabaseName = $Database + $article.SourceObjectName = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + + if ($articleFilter) { + article.FilterClause = $Filter #TODO: This doesn't seem to be working + } + if (-not ($article.IsExistingObject)) { + $article.Create() + } else { + Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } } } catch { Stop-Function -Message "Unable to add article $ArticleName to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } - #TODO: What should we return Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name - } } } diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 232955d5c2..1aaa44786f 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -97,7 +97,7 @@ function New-DbaReplPublication { Write-Message -Level Verbose -Message "Creating a new publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Enabling distribution on $instance")) { + if ($PSCmdlet.ShouldProcess($instance, "Creating a new publication on $instance")) { # based off this # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 @@ -109,7 +109,7 @@ function New-DbaReplPublication { throw "Database $Database not found on $instance" } - if ($Type -eq 'Transactional') { + if ($Type -in ('Transactional', 'Snapshot')) { $pubDatabase.EnabledTransPublishing = $true } elseif ($Type -eq 'Merge') { $pubDatabase.EnabledMergePublishing = $true @@ -135,7 +135,7 @@ function New-DbaReplPublication { Write-Message -Level Verbose -Message "Log Read Agent job already exists for $Database on $instance" } - if ($Type -eq 'Transactional') { + if ($Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication $transPub.ConnectionContext = $replServer.ConnectionContext @@ -145,11 +145,8 @@ function New-DbaReplPublication { $transPub.Create() # create the Snapshot Agent job - #TODO: also for snapshot pub? $transPub.CreateSnapshotAgent() - #$transPub.CreateSnapshotAgent - <# TODO: add these in? @@ -163,19 +160,41 @@ function New-DbaReplPublication { (Optional) The SqlStandardLogin and SqlStandardPassword or SecureSqlStandardPassword fields of SnapshotGenerationAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. #> - } + } elseif ($Type -eq 'Merge') { + $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication + $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.DatabaseName = $Database + $mergePub.Name = $PublicationName + $mergePub.Create() + + # create the Snapshot Agent job + $mergePub.CreateSnapshotAgent() + + <# + TODO: add these in? + + The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. + This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. + + Note + Setting SnapshotGenerationAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. + For more information, see Replication Agent Security Model. - #TODO: merge? + (Optional) Use the inclusive logical OR operator (| in Visual C# and Or in Visual Basic) and the exclusive logical OR operator (^ in Visual C# and Xor in Visual Basic) + to set the PublicationAttributes values for the Attributes property. + + #> + + } } } catch { - Stop-Function -Message "Unable to enable replication distribution" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message ("Unable to create publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } - $replServer.Refresh() - $replServer + #TODO: What to return } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index b838bdb784..cc796b6aa3 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -18,7 +18,6 @@ Dropping an article invalidates the current snapshot; therefore a new snapshot m https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 - .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -35,20 +34,11 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a .PARAMETER PublicationName The name of the replication publication. - .PARAMETER Type - The flavour of replication. - - Currently supported 'Transactional' - - Coming soon 'Snapshot', 'Merge' + .PARAMETER Schema + Source schema of the replicated object to remove from the publication. - .PARAMETER LogReaderAgentCredential - Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs - - Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. - In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - - TODO: Implement & test this + .PARAMETER Name + The name of the article to remove. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -69,13 +59,15 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a Copyright: (c) 2022 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-an-article?view=sql-server-ver16 + .LINK - https://dbatools.io/New-DbaReplPublication + https://dbatools.io/Remove-DbaReplArticle .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> Remove-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName PubFromPosh -Name 'publishers' - Creates a publication called PubFromPosh for the Northwind database on mssql1 + Removes the publishers article from a publication called PubFromPosh on mssql1 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] @@ -96,8 +88,6 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a [parameter(Mandatory)] [String]$Name, - [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; - [Switch]$EnableException ) process { @@ -112,31 +102,27 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a try { if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { - # based off this - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure - - #TODO: add name field to Get-DbaReplPublication so don't have to where - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential | Where-Object PublicationName -eq $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName if ($pub.PublicationType -eq 'Transactional') { - $article = New-Object Microsoft.SqlServer.Replication.TransArticle - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName - $article.DatabaseName = $Database - - # think this is the default - #$article.Type = ArticleOptions.LogBased - - if (($article.IsExistingObject)) { - $article.Remove() - } else { - Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } + } elseif ($pub.PublicationType -eq 'Merge') { + $article = New-Object Microsoft.SqlServer.Replication.MergeArticle + } else { + Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue + } + + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $PublicationName + $article.DatabaseName = $Database + + if (($article.IsExistingObject)) { + $article.Remove() + } else { + Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } - # TODO: what if it's not transactional } } catch { Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue From d821c849aebee215368dc618c605e1c40973ea6a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 23 Feb 2023 16:15:54 +0000 Subject: [PATCH 086/226] change publicationtype --> type --- public/Add-DbaReplArticle.ps1 | 6 +++--- public/Get-DbaReplPublication.ps1 | 21 ++++++++++----------- public/Remove-DbaReplArticle.ps1 | 6 +++--- public/Test-DbaReplLatency.ps1 | 6 +++--- tests/Get-DbaReplPublication.Tests.ps1 | 12 ++++++------ 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index e114d65946..59c6826a14 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -101,14 +101,14 @@ function Add-DbaReplArticle { try { if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - if ($pub.PublicationType -eq 'Transactional') { + if ($pub.Type -eq 'Transactional') { $article = New-Object Microsoft.SqlServer.Replication.TransArticle $article.Type = $ArticleOptions::LogBased - } elseif ($pub.PublicationType -eq 'Merge') { + } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle $article.Type = $ArticleOptions::TableBased } else { diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index b9501b12dd..5a8662b06e 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -71,8 +71,9 @@ function Get-DbaReplPublication { [object[]]$Database, [PSCredential]$SqlCredential, [String]$Name, + [Alias("PublicationType")] [ValidateSet("Transactional", "Merge", "Snapshot")] - [object[]]$PublicationType, #TODO: change to just Type + [object[]]$Type, [switch]$EnableException ) begin { @@ -94,7 +95,6 @@ function Get-DbaReplPublication { $databases = $databases | Where-Object Name -In $Database } - foreach ($db in $databases) { if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { @@ -103,7 +103,6 @@ function Get-DbaReplPublication { $repDB = Connect-ReplicationDB -Server $server -Database $db - $pubTypes = $repDB.TransPublications + $repDB.MergePublications if ($PublicationType) { @@ -117,14 +116,14 @@ function Get-DbaReplPublication { foreach ($pub in $pubTypes) { [PSCustomObject]@{ - ComputerName = $server.ComputerName - InstanceName = $server.ServiceName - SqlInstance = $server.Name - Server = $server.name - Database = $db.name - PublicationName = $pub.Name #TODO: change to just name - PublicationType = $pub.Type #TODO: change to just Type - Articles = $pub.TransArticles #TODO what about merge articles? + ComputerName = $server.ComputerName + InstanceName = $server.ServiceName + SqlInstance = $server.Name + Server = $server.name + Database = $db.name + Name = $pub.Name #TODO: breaking change from PublicationName to Name + Type = $pub.Type #TODO: breaking change from PublicationType to Type + Articles = $pub.TransArticles #TODO what about merge articles? } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index cc796b6aa3..b76f2e3cce 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -102,11 +102,11 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a try { if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name -eq $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - if ($pub.PublicationType -eq 'Transactional') { + if ($pub.Type -eq 'Transactional') { $article = New-Object Microsoft.SqlServer.Replication.TransArticle - } elseif ($pub.PublicationType -eq 'Merge') { + } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle } else { Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/Test-DbaReplLatency.ps1 b/public/Test-DbaReplLatency.ps1 index a1e4cbdc0c..aff54d33a1 100644 --- a/public/Test-DbaReplLatency.ps1 +++ b/public/Test-DbaReplLatency.ps1 @@ -94,7 +94,7 @@ function Test-DbaReplLatency { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $publicationNames = Get-DbaReplPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -PublicationType "Transactional" + $publicationNames = Get-DbaReplPublication -SqlInstance $server -Database $Database -SqlCredential $SqlCredentials -Type "Transactional" if ($PublicationName) { $publicationNames = $publicationNames | Where-Object PublicationName -in $PublicationName @@ -205,7 +205,7 @@ function Test-DbaReplLatency { PublicationServer = $publication.Server PublicationDB = $publication.Database PublicationName = $publication.PublicationName - PublicationType = $publication.PublicationType + PublicationType = $publication.Type DistributionServer = $distributionServer DistributionDB = $distributionDatabase SubscriberServer = $info.subscriber @@ -213,7 +213,7 @@ function Test-DbaReplLatency { PublisherToDistributorLatency = $info.distributor_latency DistributorToSubscriberLatency = $info.subscriber_latency TotalLatency = $totalLatency - } | Select-DefaultView -ExcludeProperty PublicationType + } | Select-DefaultView -ExcludeProperty Type if (!$RetainToken) { diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 index 3e1a3096e5..7b303a7a4b 100644 --- a/tests/Get-DbaReplPublication.Tests.ps1 +++ b/tests/Get-DbaReplPublication.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', 'Database', 'SqlCredential', 'PublicationType', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'Type', '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 @@ -53,7 +53,7 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { $Results.Database | Should Be "TestDB" } - It "Honors the PublicationType parameter" { + It "Honors the Type parameter" { Mock Connect-ReplicationDB -MockWith { [object]@{ @@ -66,13 +66,13 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { } } - $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB -PublicationType Snapshot - $Results.PublicationType | Should Be "Snapshot" + $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB -Type Snapshot + $Results.Type | Should Be "Snapshot" } - It "Stops if validate set for PublicationType is not met" { + It "Stops if validate set for Type is not met" { - { Get-DbaReplPublication -SqlInstance MockServerName -PublicationType NotAPubType } | should Throw + { Get-DbaReplPublication -SqlInstance MockServerName -Type NotAPubType } | should Throw } } From a989f1a38b3ffb706ad3addc2864437b93de32fe Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 23 Feb 2023 16:16:47 +0000 Subject: [PATCH 087/226] change pubtype --> type --- public/Get-DbaReplArticle.ps1 | 2 ++ public/Get-DbaReplPublication.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 2fddf5e3f1..351aa422e9 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -20,9 +20,11 @@ function Get-DbaReplArticle { Specifies one or more database(s) to process. If unspecified, all databases will be processed. .PARAMETER PublicationName + #TODO change to Name Specifies one or more publication(s) to process. If unspecified, all publications will be processed. .PARAMETER PublicationType + #TODO change to Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER Article diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 5a8662b06e..e13b77159e 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -25,7 +25,7 @@ function Get-DbaReplPublication { For MFA support, please use Connect-DbaInstance. - .PARAMETER PublicationType + .PARAMETER Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER EnableException @@ -55,7 +55,7 @@ function Get-DbaReplPublication { Return all publications on server sql2008 for only the TestDB database .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -PublicationType Transactional + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional Return all publications on server sql2008 for all databases that have Transactional publications From 7c185c827acfc92fc7e13bdc362cf20f036823ef Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 31 Mar 2023 17:16:17 +0100 Subject: [PATCH 088/226] working --- ReplicationCommands.md | 17 +- dbatools.psd1 | 5 +- public/Add-DbaReplArticle.ps1 | 46 ++--- public/Get-DbaReplArticle.ps1 | 23 ++- public/Get-DbaReplPublication.ps1 | 12 +- public/Get-DbaReplSubscription.ps1 | 134 +++++++++++++ public/New-DbaReplPublication.ps1 | 9 +- public/New-DbaReplSubscription.ps1 | 275 ++++++++++++++++++++++++++ public/Remove-DbaReplPublication.ps1 | 152 ++++++++++++++ public/Remove-DbaReplSubscription.ps1 | 156 +++++++++++++++ testing.ps1 | 169 +++++++++++++++- tests/Get-DbaRepPublication.Tests.ps1 | 12 +- tests/gh-actions-repl.ps1 | 117 ++++++++++- 13 files changed, 1073 insertions(+), 54 deletions(-) create mode 100644 public/Get-DbaReplSubscription.ps1 create mode 100644 public/New-DbaReplSubscription.ps1 create mode 100644 public/Remove-DbaReplPublication.ps1 create mode 100644 public/Remove-DbaReplSubscription.ps1 diff --git a/ReplicationCommands.md b/ReplicationCommands.md index adf1bc1ee2..fdd790c96b 100644 --- a/ReplicationCommands.md +++ b/ReplicationCommands.md @@ -29,12 +29,12 @@ Meaning of the checkmarks: - [X] Get-DbaReplPublication -- #TODO: Exists but needs some love - [X] Disable-DbaReplPublishing - [X] Enable-DbaReplPublishing -- [-] New-DbaReplPublication - Jess -- [ ] Remove-DbaReplPublication +- [X] New-DbaReplPublication - Jess +- [X] Remove-DbaReplPublication ### Articles -- [-] Add-DbaReplArticle - Jess -- [ ] Remove-DbaReplArticle +- [X] Add-DbaReplArticle - Jess +- [X] Remove-DbaReplArticle - Jess - [-] Get-DbaReplArticle - Cláudio - [ ] Set-DbaReplArticle @@ -45,8 +45,9 @@ Meaning of the checkmarks: ### Subscriptions - [ ] Get-DbaDbSubscription -- [ ] New-DbaDbSubscription - [ ] Set-DbaReplDistributor (update properties) +- [X] New-DbaDbSubscription +- [X] Remove-DbaReplSubscription ### Monitoring\Troubleshooting @@ -54,7 +55,7 @@ Meaning of the checkmarks: - [ ] Run-DbaReplSnapshotAgent ? - [ ] Get-DbaReplSnapshotAgentStatus - [ ] Get-DbaReplLogReaderAgentStatus -- [ ] Test-DbaReplSnapFolder - similiar to Test-DbaPath but from replication service account perspective or something similiar to check If the share (UNC or Local) is accesable from both, publisher and subscriber side +- [ ] Test-DbaReplSnapFolder - similar to Test-DbaPath but from replication service account perspective or something similar to check If the share (UNC or Local) is accessible from both, publisher and subscriber side ## How to run pester tests locally @@ -73,3 +74,7 @@ Meaning of the checkmarks: Some additional scenarios for us to test commands against. - how the commands work when we have a "third site" involved , i mean if we have the distribution db not on the Publication-Server and not on the Subscriber-Server (thats not so common, but it is a thing imo) - I saw some unusual behaviour with replcation commands when the setup is with a seperate Distribution-DB-Server. + +## Questions + +- Should parameter be `PublicationType` or `Type` and `PublicationName` or `Name` diff --git a/dbatools.psd1 b/dbatools.psd1 index bd89b1a78d..c7aa185b60 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -740,7 +740,10 @@ 'Get-DbaReplArticle', 'Get-DbaReplArticleColumn', 'Add-DbaReplArticle', - 'Remove-DbaReplArticle' + 'Remove-DbaReplArticle', + 'Remove-DbaReplPublication', + 'New-DbaReplSubscription', + 'Remove-DbaReplSubscription' ) # Cmdlets to export from this module diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 59c6826a14..5873626d49 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -22,20 +22,16 @@ function Add-DbaReplArticle { .PARAMETER PublicationName The name of the replication publication. - .PARAMETER Type - The flavour of replication. + .PARAMETER Schema + The schema name that contains the object to add as an article. + Default is dbo. - Currently supported 'Transactional' + .PARAMETER Name + The name of the object to add as an article. - Coming soon 'Snapshot', 'Merge' - - .PARAMETER LogReaderAgentCredential - Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs - - Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. - In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - - TODO: Implement & test this + .PARAMETER Filter + Horizontal filter for replication, implemented as a where clause, but don't include the word WHERE> + E.g. City = 'Seattle' .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -59,13 +55,18 @@ function Add-DbaReplArticle { https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure .LINK - https://dbatools.io/New-DbaReplPublication + https://dbatools.io/Add-DbaReplArticle .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Name TableToRepl + + Adds the TableToRepl table to the PubFromPosh publication from mssql1.Northwind - Creates a publication called PubFromPosh for the Northwind database on mssql1 + .EXAMPLE + PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName TestPub -Name publishers -Filter "city = 'seattle'" + + Adds the publishers table to the TestPub publication from mssql1.Pubs with a horizontal filter of only rows where city = 'seattle. #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( @@ -85,7 +86,7 @@ function Add-DbaReplArticle { [parameter(Mandatory)] [String]$Name, - [String]$Filter, # some sql to horizontal filter "DiscontinuedDate IS NULL"; + [String]$Filter, [Switch]$EnableException ) @@ -105,14 +106,12 @@ function Add-DbaReplArticle { $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - if ($pub.Type -eq 'Transactional') { + if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle $article.Type = $ArticleOptions::LogBased } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle $article.Type = $ArticleOptions::TableBased - } else { - Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue } $article.ConnectionContext = $replServer.ConnectionContext @@ -122,8 +121,11 @@ function Add-DbaReplArticle { $article.SourceObjectOwner = $Schema $article.PublicationName = $PublicationName - if ($articleFilter) { - article.FilterClause = $Filter #TODO: This doesn't seem to be working + if ($Filter) { + if ($Filter -like 'WHERE*') { + Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue + } + $article.FilterClause = $Filter } if (-not ($article.IsExistingObject)) { @@ -133,7 +135,7 @@ function Add-DbaReplArticle { } } } catch { - Stop-Function -Message "Unable to add article $ArticleName to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Unable to add article $Name to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } #TODO: What should we return Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 351aa422e9..fa351a5abc 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -85,6 +85,7 @@ function Get-DbaReplArticle { } foreach ($db in $databases) { + Write-PSFMessage -Level Verbose -Message ('Working on {0}' -f $db) $RMOdb = Connect-ReplicationDB -Server $server -Database $db @@ -93,14 +94,24 @@ function Get-DbaReplArticle { # Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." #} - if ($PublicationType -eq 'Transactional') { - $publications = $RMOdb.TransPublications - } else { - $publications = $RMOdb.MergePublications - } + $publications = @() + $publications += $RMOdb.TransPublications + $publications += $RMOdb.MergePublications + + $publications + break + + #if ($PublicationType -in ('Snapshot','Transactional')) { + # $publications = $RMOdb.TransPublications + #} elseif ($PublicationType -eq 'Merge') { + # $publications = $RMOdb.MergePublications + #} else { + # $RMOdb + # $publications = @($RMOdb.TransPublications + $RMOdb.MergePublications) + #} if ($Publication) { - $publications = $publications | Where-Object Name -in $Publication + $publications = $publications | Where-Object PublicationName -in $Publication } if ($PublicationType -eq 'Transactional') { diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index e13b77159e..4e59808ef6 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -105,8 +105,8 @@ function Get-DbaReplPublication { $pubTypes = $repDB.TransPublications + $repDB.MergePublications - if ($PublicationType) { - $pubTypes = $pubTypes | Where-Object Type -in $PublicationType + if ($Type) { + $pubTypes = $pubTypes | Where-Object Type -in $Type } if ($Name) { @@ -114,6 +114,11 @@ function Get-DbaReplPublication { } foreach ($pub in $pubTypes) { + if ($pub.Type -eq 'Merge') { + $articles = $pub.MergeArticles + } else { + $articles = $pub.TransArticles + } [PSCustomObject]@{ ComputerName = $server.ComputerName @@ -123,8 +128,7 @@ function Get-DbaReplPublication { Database = $db.name Name = $pub.Name #TODO: breaking change from PublicationName to Name Type = $pub.Type #TODO: breaking change from PublicationType to Type - Articles = $pub.TransArticles #TODO what about merge articles? - + Articles = $articles } } } diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 new file mode 100644 index 0000000000..b43b9839e6 --- /dev/null +++ b/public/Get-DbaReplSubscription.ps1 @@ -0,0 +1,134 @@ +function Get-DbaReplSubscription { + <# + .SYNOPSIS + Displays all subscriptions for a publication. + + .DESCRIPTION + Displays all subscriptions for a publication + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER Database + The database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER Name + The name of the publication. + + .PARAMETER SqlCredential + Login to the target 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 Type + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + + .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. + + .NOTES + Tags: Replication + Author: Colin Douglas + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Get-DbaReplPublication + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance sql2008, sqlserver2012 + + Return all publications for servers sql2008 and sqlserver2012. + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Database TestDB + + Return all publications on server sql2008 for only the TestDB database + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional + + Return all publications on server sql2008 for all databases that have Transactional publications + + .EXAMPLE + PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey + + Returns the Mergey publications on server mssql1 + #> + [CmdletBinding()] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + [object[]]$Database, + [PSCredential]$SqlCredential, + [String]$Name, + [Alias("PublicationType")] + [ValidateSet("Transactional", "Merge", "Snapshot")] + [object[]]$Type, + [switch]$EnableException + ) + begin { + Add-ReplicationLibrary + } + process { + if (Test-FunctionInterrupt) { return } + foreach ($instance in $SqlInstance) { + + # Connect to Publisher + try { + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } + if ($Database) { + $databases = $databases | Where-Object Name -In $Database + } + + foreach ($db in $databases) { + + if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { + Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + } + + $repDB = Connect-ReplicationDB -Server $server -Database $db + + $pubTypes = $repDB.TransPublications + $repDB.MergePublications + + if ($Type) { + $pubTypes = $pubTypes | Where-Object Type -in $Type + } + + if ($Name) { + $pubTypes = $pubTypes | Where-Object Name -in $Name + } + + foreach ($pub in $pubTypes) { + if ($pub.Type -eq 'Merge') { + $articles = $pub.MergeArticles + } else { + $articles = $pub.TransArticles + } + + [PSCustomObject]@{ + ComputerName = $server.ComputerName + InstanceName = $server.ServiceName + SqlInstance = $server.Name + Server = $server.name + Database = $db.name + Name = $pub.Name #TODO: breaking change from PublicationName to Name + Type = $pub.Type #TODO: breaking change from PublicationType to Type + Articles = $articles + } + } + } + } + } +} \ No newline at end of file diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 1aaa44786f..68ebf88e49 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -94,13 +94,10 @@ function New-DbaReplPublication { } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - Write-Message -Level Verbose -Message "Creating a new publication on $instance" + Write-Message -Level Verbose -Message "Creating publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Creating a new publication on $instance")) { - - # based off this - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/create-a-publication?view=sql-server-ver16 + if ($PSCmdlet.ShouldProcess($instance, "Creating publication on $instance")) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $replServer.ConnectionContext @@ -110,8 +107,10 @@ function New-DbaReplPublication { } if ($Type -in ('Transactional', 'Snapshot')) { + Write-Message -Level Verbose -Message "Enable trans publishing publication on $instance.$Database" $pubDatabase.EnabledTransPublishing = $true } elseif ($Type -eq 'Merge') { + Write-Message -Level Verbose -Message "Enable merge publishing publication on $instance.$Database" $pubDatabase.EnabledMergePublishing = $true $pubDatabase.CommitPropertyChanges } diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 new file mode 100644 index 0000000000..3d9d7bfcaa --- /dev/null +++ b/public/New-DbaReplSubscription.ps1 @@ -0,0 +1,275 @@ +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 SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 that will be replicated. + + .PARAMETER PublicationName + The name of the replication publication + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/New-DbaReplPublication + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + + Creates a publication called PubFromPosh for the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [String]$Database, + + [parameter(Mandatory)] + [DbaInstanceParameter]$PublisherSqlInstance, + + [PSCredential]$PublisherSqlCredential, + + [String]$PublicationDatabase, + + [parameter(Mandatory)] + [String]$PublicationName, + + [PSCredential] # this will be saved as the 'subscriber credential' in the subscription properties + $SubscriptionSqlCredential, + + [parameter(Mandatory)] + [ValidateSet("Push", "Pull")] #TODO: make this do something :) + [String]$Type, + + [Switch]$EnableException + ) + begin { + Write-Message -Level Verbose -Message "Connecting to publisher: $PublisherSqlInstance" + + # connect to publisher and get the publication + try { + $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + try { + $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + } catch { + Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue + } + } + + process { + + # for each subscription SqlInstance we need to create a subscription + foreach ($instance in $SqlInstance) { + + try { + if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { + Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it" + + if ($PSCmdlet.ShouldProcess($instance, "Creating subscription database")) { + + $newSubDb = @{ + SqlInstance = $instance + SqlCredential = $SqlCredential + Name = $Database + EnableException = $EnableException + } + $null = New-DbaDatabase @newSubDb + } + } + } catch { + Stop-Function -Message ("Couldn't create the subscription database {0}.{1}" -f $instance, $Database) -ErrorRecord $_ -Target $instance -Continue + } + + try { + Write-Message -Level Verbose -Message "Creating subscription on $instance" + if ($PSCmdlet.ShouldProcess($instance, "Creating subscription on $instance")) { + + if ($pub.Type -in ('Transactional', 'Snapshot')) { + + $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication + $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.DatabaseName = $PublicationDatabase + $transPub.Name = $PublicationName + + # if LoadProperties returns then the publication was found + if ( $transPub.LoadProperties() ) { + + if ($type = 'Push') { + + # 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 { + # Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull. + if ($transPub.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. + $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 = $replServer.ConnectionContext + $transSub.SubscriptionDBName = $Database + $transSub.SubscriberName = $instance + $transSub.DatabaseName = $PublicationDatabase + $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) -ErrorRecord $_ -Target $instance -Continue + } + + } elseif ($pub.Type -eq 'Merge') { + + $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication + $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.DatabaseName = $PublicationDatabase + $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 = $replServer.ConnectionContext + $mergeSub.SubscriptionDBName = $Database + $mergeSub.SubscriberName = $instance + $mergeSub.DatabaseName = $PublicationDatabase + $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) -ErrorRecord $_ -Target $instance -Continue + } + } + } catch { + Stop-Function -Message ("Unable to create subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + } + + #TODO: What to return + + } + } +} diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 new file mode 100644 index 0000000000..deb77664c6 --- /dev/null +++ b/public/Remove-DbaReplPublication.ps1 @@ -0,0 +1,152 @@ +function Remove-DbaReplPublication { + <# + .SYNOPSIS + Removes a publication from the database on the target SQL instances. + + .DESCRIPTION + Removes a publication from the database on the target SQL instances. + + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 that will be replicated. + + .PARAMETER Name + The name of the replication publication + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Remove-DbaReplPublication + + .EXAMPLE + PS C:\> Remove-DbaReplPublication -SqlInstance mssql1 -Database Northwind -Name PubFromPosh + + Removes a publication called PubFromPosh from the Northwind database on mssql1 + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [String]$Database, + + [parameter(Mandatory)] + [String]$Name, + + [Switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + try { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + try { + if ($PSCmdlet.ShouldProcess($instance, "Removing publication on $instance")) { + + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name + + if (-not $pub) { + Write-Warning "Didn't find $Name on $Instance.$Database" + } + + if ($pub.Type -in ('Transactional', 'Snapshot')) { + + $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication + $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.DatabaseName = $Database + $transPub.Name = $Name + + if ($transPub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" + $transPub.Remove() + } + + # If no other transactional publications exist for this database, the database can be disabled for transactional publishing + #TODO: transactional & snapshot.. or just trans? + if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Transactional, Snapshot)) { + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $pubDatabase.ConnectionContext = $replServer.ConnectionContext + $pubDatabase.Name = $Database + if (-not $pubDatabase.LoadProperties()) { + throw "Database $Database not found on $instance" + } + + if ($pubDatabase.EnabledTransPublishing) { + Write-Message -Level Verbose -Message "No transactional publications on $Instance.$Database so disabling transactional publishing" + $pubDatabase.EnabledTransPublishing = $false + } + } + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure + + } elseif ($pub.Type -eq 'Merge') { + $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication + $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.DatabaseName = $Database + $mergePub.Name = $Name + + if ($mergePub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" + $mergePub.Remove() + } else { + Write-Warning "Didn't find $Name on $Instance.$Database" + } + + # If no other merge publications exist for this database, the database can be disabled for merge publishing + if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Merge)) { + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $pubDatabase.ConnectionContext = $replServer.ConnectionContext + $pubDatabase.Name = $Database + + if (-not $pubDatabase.LoadProperties()) { + throw "Database $Database not found on $instance" + } + + if($pubDatabase.EnabledTransPublishing) { + Write-Message -Level Verbose -Message "No merge publications on $Instance.$Database so disabling merge publishing" + $pubDatabase.EnabledMergePublishing = $false + } + } + } + } + } catch { + Stop-Function -Message ("Unable to remove publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + } + } + } +} + + + diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 new file mode 100644 index 0000000000..87fd98d02a --- /dev/null +++ b/public/Remove-DbaReplSubscription.ps1 @@ -0,0 +1,156 @@ +function Remove-DbaReplSubscription { + <# + .SYNOPSIS + Removes a subscription for the target SQL instances. + + .DESCRIPTION + Removes a subscription for the target SQL instances. + + https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-push-subscription?view=sql-server-ver16 + https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target 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 PublisherSqlInstance + The publisher SQL Server instance. + + .PARAMETER PublisherSqlCredential + Login to the publisher 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 PublicationDatabase + The database where the publication is located. + + .PARAMETER PublicationName + The name of the publication. + + .PARAMETER SubscriptionDatabase + The database where the subscription is located. + + .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: Replication + Author: Jess Pomfret (@jpomfret) + + Website: https://dbatools.io + Copyright: (c) 2022 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Remove-DbaReplSubscription + + .EXAMPLE + PS C:\> $sub = @{ + SqlInstance = 'mssql2' + SubscriptionDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationDatabase = 'pubs' + PublicationName = 'testPub' + } + PS C:\> Remove-DbaReplSubscription @sub + + Removes a subscription for the testPub publication on mssql2.pubs. + + #> + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [DbaInstanceParameter[]]$SqlInstance, + + [PSCredential]$SqlCredential, + + [parameter(Mandatory)] + [DbaInstanceParameter]$PublisherSqlInstance, + + [PSCredential]$PublisherSqlCredential, + + [String]$PublicationDatabase, + + [parameter(Mandatory)] + [String]$PublicationName, + + [String]$SubscriptionDatabase, + + [Switch]$EnableException + ) + begin { + + $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + + if (-not $pub) { + Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$Database" + } + + try { + $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + } catch { + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + } + + } + process { + foreach ($instance in $SqlInstance) { + + try { + if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $instance.$SubscriptionDatabase")) { + + if ($pub.Type -in ('Transactional', 'Snapshot')) { + + $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription + $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.DatabaseName = $PublicationDatabase + $transSub.PublicationName = $PublicationName + $transSub.SubscriptionDBName = $SubscriptionDatabase + $transSub.SubscriberName = $instance + + if ($transSub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing the subscription" + $transSub.Remove() + } + + } elseif ($pub.Type -eq 'Merge') { + $mergeSub = New-Object Microsoft.SqlServer.Replication.MergeSubscription + $mergeSub.ConnectionContext = $replServer.ConnectionContext + $mergeSub.DatabaseName = $PublicationDatabase + $mergeSub.PublicationName = $PublicationName + $mergeSub.SubscriptionDBName = $SubscriptionDatabase + $mergeSub.SubscriberName = $instance + + if ($mergeSub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing the merge subscription" + $mergeSub.Remove() + } else { + Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$SubscriptionDatabase" + } + } + } + } catch { + Stop-Function -Message ("Unable to remove subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + } + } + } +} + + + diff --git a/testing.ps1 b/testing.ps1 index 6c07458884..caedf045e6 100644 --- a/testing.ps1 +++ b/testing.ps1 @@ -38,6 +38,7 @@ $PSDefaultParameterValues = @{ "*:DestinationCredential" = $credential "*:DestinationSqlCredential" = $credential "*:SourceSqlCredential" = $credential + "*:PublisherSqlCredential" = $credential } @@ -76,7 +77,7 @@ Disable-DbaReplDistributor -SqlInstance mssql1 Enable-DbaReplPublishing -SqlInstance mssql1 Disable-DbaReplPublishing -SqlInstance mssql1 -# add a publication +# add a transactional publication $pub = @{ SqlInstance = 'mssql1' Database = 'pubs' @@ -86,6 +87,29 @@ $pub = @{ } New-DbaReplPublication @pub + + +# add a merge publication +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'mergey' + Type = 'Merge' + +} +New-DbaReplPublication @pub + +# add a snapshot publication +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'snappy' + Type = 'Snapshot' + +} +New-DbaReplPublication @pub + + # add an article $article = @{ @@ -93,6 +117,145 @@ $article = @{ Database = 'pubs' PublicationName = 'testpub' Name = 'publishers' - Filter = "where city = 'seattle'" ## not working? + Filter = "city = 'seattle'" ## not working? +} +Add-DbaReplArticle @article + + +# mergey +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'Mergey' + Name = 'publishers' + Filter = "city = 'seattle'" ## not working? +} +Add-DbaReplArticle @article + +# snappy +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'snappy' + Name = 'publishers' +} +Add-DbaReplArticle @article + + +# remove an article +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'publishers' } -Add-DbaReplArticle @article \ No newline at end of file +Remove-DbaReplArticle @article + +# remove an article +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'Mergey' + Name = 'publishers' +} +Remove-DbaReplArticle @article + + + +## remove pubs +$pub = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + Name = 'Snappy' +} +Remove-DbaReplPublication @pub +## remove pubs +$pub = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + Name = 'TestPub' +} +Remove-DbaReplPublication @pub +## remove pubs +$pub = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + Name = 'Mergey' +} +Remove-DbaReplPublication @pub + + +# add subscriptions. + +#transactional +$sub = @{ + SqlInstance = 'mssql2' + Database = 'pubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'testpub' + Type = 'Push' + SubscriptionSqlCredential = $credential + +} +New-DbaReplSubscription @sub + +#merge +$sub = @{ + SqlInstance = 'mssql2' + Database = 'Mergeypubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'Mergey' + Type = 'Push' + SubscriptionSqlCredential = $credential + +} +New-DbaReplSubscription @sub + +#snapshot +$sub = @{ + SqlInstance = 'mssql2' + Database = 'Snappypubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'Snappy' + Type = 'Push' + SubscriptionSqlCredential = $credential +} +New-DbaReplSubscription @sub + + +# remove subscriptions +$sub = @{ + SqlInstance = 'mssql2' + SubscriptionDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationDatabase = 'pubs' + PublicationName = 'testPub' +} +Remove-DbaReplSubscription @sub + +$sub = @{ + SqlInstance = 'mssql2' + SubscriptionDatabase = 'Mergeypubs' + PublisherSqlInstance = 'mssql1' + PublicationDatabase = 'pubs' + PublicationName = 'Mergey' +} +Remove-DbaReplSubscription @sub + +$sub = @{ + SqlInstance = 'mssql2' + PublisherSqlInstance = 'mssql1' + PublicationName = 'snappy' + PublicationDatabase = 'pubs' + SubscriptionDatabase = 'Snappypubs' +} +Remove-DbaReplSubscription @sub + +# TODO: Does the schema exist on the subscriber? +<# +// Ensure that we create the schema owner at the Subscriber. +article.SchemaOption |= CreationScriptOptions.Schema; +#> \ No newline at end of file diff --git a/tests/Get-DbaRepPublication.Tests.ps1 b/tests/Get-DbaRepPublication.Tests.ps1 index 57e1f5c9e4..3206515248 100644 --- a/tests/Get-DbaRepPublication.Tests.ps1 +++ b/tests/Get-DbaRepPublication.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', 'Database', 'SqlCredential', 'PublicationType', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'Type', '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 @@ -53,7 +53,7 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { $Results.Database | Should Be "TestDB" } - It "Honors the PublicationType parameter" { + It "Honors the Type parameter" { Mock Connect-ReplicationDB -MockWith { [object]@{ @@ -66,13 +66,13 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { } } - $Results = Get-DbaRepPublication -SqlInstance MockServerName -Database TestDB -PublicationType Snapshot - $Results.PublicationType | Should Be "Snapshot" + $Results = Get-DbaRepPublication -SqlInstance MockServerName -Database TestDB -Type Snapshot + $Results.Type | Should Be "Snapshot" } - It "Stops if validate set for PublicationType is not met" { + It "Stops if validate set for Type is not met" { - { Get-DbaRepPublication -SqlInstance MockServerName -PublicationType NotAPubType } | should Throw + { Get-DbaRepPublication -SqlInstance MockServerName -Type NotAPubType } | should Throw } } diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index fb4b3f4fee..e0dd246221 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -3,7 +3,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - $PSDefaultParameterValues["*:SqlInstance"] = "localhost" + $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" @@ -14,6 +14,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # load dbatools-lib #Import-Module dbatools-core-library Import-Module ./dbatools.psd1 -Force + + $null = New-DbaDatabase -Name ReplDb + $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' + } Context "Get-DbaReplDistributor works" { @@ -171,4 +175,115 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } + + Context "New-DbaReplPublication works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "New-DbaReplPublication creates a Transactional publication" { + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + } + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + } + + } + + Context "Add-DbaReplArticle works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } + + $article = + } + + It "Add-DbaReplArticle adds an article to a Transactional publication" { + $pubname = 'TestPub' + Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + } + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + } + + } + + Context "Add-DbaReplArticle works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + + } + + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + } + } From 4c97b4dfe7ffb095245a9cdbd0a66a4f8a069f6d Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:20:06 +0100 Subject: [PATCH 089/226] tests --- public/Remove-DbaReplSubscription.ps1 | 3 + tests/gh-actions-repl.ps1 | 413 +++++++++++++------------- 2 files changed, 212 insertions(+), 204 deletions(-) diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 87fd98d02a..b9cdc4fb71 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -115,8 +115,11 @@ function Remove-DbaReplSubscription { try { if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $instance.$SubscriptionDatabase")) { + if ($pub.Type -in ('Transactional', 'Snapshot')) { + #TODO: Only handles push subscriptions at the moment - need to add pull subscriptions + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription $transSub.ConnectionContext = $replServer.ConnectionContext $transSub.DatabaseName = $PublicationDatabase diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index e0dd246221..2a64d58216 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -3,7 +3,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" + $PSDefaultParameterValues["*:SqlInstance"] = "localhost" $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" @@ -20,270 +20,275 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Get-DbaReplDistributor works" { - BeforeAll { + Describe "Enable\Disable Functions" -Tag ReplSetup { - # if distribution is enabled, disable it & enable it with defaults - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + Context "Get-DbaReplDistributor works" { + BeforeAll { + + # if distribution is enabled, disable it & enable it with defaults + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + Enable-DbaReplDistributor } - Enable-DbaReplDistributor - } - It "gets a distributor" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "gets a distributor" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } - It "distribution database name is correct" { - (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + It "distribution database name is correct" { + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + } } - } - Context "Enable-DbaReplDistributor works" { - BeforeAll { - # if distribution is enabled - disable it - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + Context "Enable-DbaReplDistributor works" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } } - } - It "distribution starts disabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } - It "distribution is enabled" { - Enable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $true + It "distribution is enabled" { + Enable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } } - } - Context "Enable-DbaReplDistributor works with specified database name" { - BeforeAll { - # if distribution is enabled - disable it - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + Context "Enable-DbaReplDistributor works with specified database name" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } } - } - AfterAll { - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor + AfterAll { + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } } - } - It "distribution starts disabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } - It "distribution is enabled with specific database" { - $distDb = ('distdb-{0}' -f (Get-Random)) - Enable-DbaReplDistributor -DistributionDatabase $distDb - (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + It "distribution is enabled with specific database" { + $distDb = ('distdb-{0}' -f (Get-Random)) + Enable-DbaReplDistributor -DistributionDatabase $distDb + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + } } - } - Context "Disable-DbaReplDistributor works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor + Context "Disable-DbaReplDistributor works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } } - } - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } } - } - Context "Enable-DbaReplPublishing works" { - BeforeAll { - # if Publishing is enabled - disable it - if ((Get-DbaReplServer).IsPublisher) { - Disable-DbaReplPublishing - write-output 'DISABLE PUB' + Context "Enable-DbaReplPublishing works" { + BeforeAll { + # if Publishing is enabled - disable it + if ((Get-DbaReplServer).IsPublisher) { + Disable-DbaReplPublishing + write-output 'DISABLE PUB' + } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + write-output 'ENABLE DIST' + } } - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - write-output 'ENABLE DIST' + + It "publishing starts disabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $false } - } - It "publishing starts disabled" { - (Get-DbaReplServer).IsPublisher | Should -Be $false + It "publishing is enabled" { + write-output 'work on enable' + Enable-DbaReplPublishing -EnableException -Outvariable test + $test + (Get-DbaReplServer).IsPublisher | Should -Be $true + } } - It "publishing is enabled" { - write-output 'work on enable' - Enable-DbaReplPublishing -EnableException -Outvariable test - $test - (Get-DbaReplServer).IsPublisher | Should -Be $true - } - } + Context "Disable-DbaReplPublishing works" { + BeforeAll { + + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) - Context "Disable-DbaReplPublishing works" { - BeforeAll { + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + write-output -message 'I should enable publishing' + Enable-DbaReplPublishing -EnableException + } - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - write-output -message 'I should enable publishing' - Enable-DbaReplPublishing -EnableException + write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) + write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) } - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - write-output -message 'I should enable distribution' - Enable-DbaReplDistributor -EnableException + It "publishing starts enabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $true } - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) + It "publishing is disabled" { + Disable-DbaReplPublishing -EnableException + (Get-DbaReplServer).IsPublisher | Should -Be $false + } } + } - It "publishing starts enabled" { - (Get-DbaReplServer).IsPublisher | Should -Be $true - } + Describe "RestofTests" -Tag "Rest" -Skip { - It "publishing is disabled" { - Disable-DbaReplPublishing -EnableException - (Get-DbaReplServer).IsPublisher | Should -Be $false - } - } + Context "Get-DbaReplPublisher works" -skip { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } - Context "Get-DbaReplPublisher works" -skip { - BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - } - It "gets a publisher" { - (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - } + Context "New-DbaReplPublication works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } - Context "New-DbaReplPublication works" -Tag test { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor + It "New-DbaReplPublication creates a Transactional publication" { + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } - } - It "New-DbaReplPublication creates a Transactional publication" { - $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } - It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' - } - It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' - } - - } - Context "Add-DbaReplArticle works" -Tag test { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + Context "Add-DbaReplArticle works" -Tag test { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } + + #$article = } - # we need some publications too - $name = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + + It "Add-DbaReplArticle adds an article to a Transactional publication" { + $pubname = 'TestPub' + Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } - $name = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } - $name = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } - $article = } - It "Add-DbaReplArticle adds an article to a Transactional publication" { - $pubname = 'TestPub' - Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' - } - It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' - } - It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' - } - - } + Context "Add-DbaReplArticle works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } - Context "Add-DbaReplArticle works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - - } - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } } } - } From 541400753891d2a6d2c5a93098a89acb8b58cec8 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:38:11 +0100 Subject: [PATCH 090/226] verbose --- tests/gh-actions-repl.ps1 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 2a64d58216..517ec7f825 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -106,12 +106,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing - write-output 'DISABLE PUB' + write-verbose 'DISABLE PUB' } # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { Enable-DbaReplDistributor - write-output 'ENABLE DIST' + write-verbose 'ENABLE DIST' } } @@ -120,9 +120,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - write-output 'work on enable' - Enable-DbaReplPublishing -EnableException -Outvariable test - $test + write-verbose 'work on enable' + Enable-DbaReplPublishing -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true } } From 1d6abd276a23d22e05f62a047da57113b9b044ab Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:42:49 +0100 Subject: [PATCH 091/226] test --- tests/gh-actions-repl.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 517ec7f825..03ec0b3317 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -106,12 +106,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # if Publishing is enabled - disable it if ((Get-DbaReplServer).IsPublisher) { Disable-DbaReplPublishing - write-verbose 'DISABLE PUB' } # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { Enable-DbaReplDistributor - write-verbose 'ENABLE DIST' } } @@ -121,7 +119,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "publishing is enabled" { write-verbose 'work on enable' - Enable-DbaReplPublishing -EnableException + Enable-DbaReplPublishing -SqlInstance localhost -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true } } From 67ddcd6e32a64e00fe6ffda616e470c86121716c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:51:20 +0100 Subject: [PATCH 092/226] writewarning --- tests/gh-actions-repl.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 03ec0b3317..aef10b6dc4 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -118,9 +118,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - write-verbose 'work on enable' Enable-DbaReplPublishing -SqlInstance localhost -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true + 'test' | Write-Warning + Get-DbatoolsError | Out-String | Write-Warning } } From 8302e902a08c59d6855fb1d10d2440c3d72edc21 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 10:58:10 +0100 Subject: [PATCH 093/226] no null --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index d7bb4b3f84..2e5a99d682 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -51,4 +51,4 @@ jobs: Import-Module ./dbatools.psd1 -Force Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning - $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru + Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru From d5a01b0ffc60216a7ebf7adbb7706db6e8fd43cf Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 11:01:34 +0100 Subject: [PATCH 094/226] verbose --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 2e5a99d682..a544dea866 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -51,4 +51,4 @@ jobs: Import-Module ./dbatools.psd1 -Force Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning - Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru + $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru -Verbose From 56cc42616c67a3a8e11d65ce1bd3db75b119e031 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 13:42:50 +0100 Subject: [PATCH 095/226] use hostname --- .github/workflows/integration-tests-repl.yml | 4 ++++ tests/gh-actions-repl.ps1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index a544dea866..0ddd2ba4bc 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -33,6 +33,10 @@ jobs: # Expose second engine and endpoint on different port docker run -p 14333:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + - name: Add hostname to hosts file + run: | + echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts + - name: 👥 Clone appveyor repo working-directory: /tmp run: | diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index aef10b6dc4..ccb3c085dd 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -3,7 +3,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - $PSDefaultParameterValues["*:SqlInstance"] = "localhost" + $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" From 595f55aaa917634b7082e41adf02604e86ed973b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 13:46:45 +0100 Subject: [PATCH 096/226] right name --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 0ddd2ba4bc..303f7028c7 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -35,7 +35,7 @@ jobs: - name: Add hostname to hosts file run: | - echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts + echo "127.0.0.1 mssql1 mssql2" | sudo tee -a /etc/hosts - name: 👥 Clone appveyor repo working-directory: /tmp From 836fe4d65f81be14f37f676df4c4571a34e2d3c5 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Apr 2023 13:49:33 +0100 Subject: [PATCH 097/226] remove hard coded localhost --- tests/gh-actions-repl.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index ccb3c085dd..2de4b59bde 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -118,10 +118,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - Enable-DbaReplPublishing -SqlInstance localhost -EnableException + Enable-DbaReplPublishing -EnableException (Get-DbaReplServer).IsPublisher | Should -Be $true - 'test' | Write-Warning - Get-DbatoolsError | Out-String | Write-Warning } } From 641b99cdda1f49583a9b67c0980b310ac86d2e9c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 13 Apr 2023 14:39:34 +0100 Subject: [PATCH 098/226] fix issue causing test failure --- public/Get-DbaReplPublisher.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 1c3e2acd14..23919bcb97 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -55,7 +55,7 @@ function Get-DbaReplPublisher { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $server + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue } @@ -64,7 +64,6 @@ function Get-DbaReplPublisher { try { if ($PSCmdlet.ShouldProcess($server, "Getting publisher for $server")) { $publisher = $replServer.DistributionPublishers - $publisher } } catch { Stop-Function -Message "Unable to get publisher for" -ErrorRecord $_ -Target $server -Continue From 0315ea9605f743bd7526747d18ce22d39e2f8f29 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:29:56 +0100 Subject: [PATCH 099/226] Added TODO why articles not appear in specific condition --- public/Get-DbaReplPublication.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 4e59808ef6..755c19259f 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -112,7 +112,7 @@ function Get-DbaReplPublication { if ($Name) { $pubTypes = $pubTypes | Where-Object Name -in $Name } - + #TODO: Check why if -Database is not passed, I can't see the articles foreach ($pub in $pubTypes) { if ($pub.Type -eq 'Merge') { $articles = $pub.MergeArticles From 0f352c99a6eabe0c29a440522c37f5b7e7ac1893 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:30:37 +0100 Subject: [PATCH 100/226] Fix property name & Change validation order --- public/Get-DbaReplArticle.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index fa351a5abc..1b0091ec15 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -98,8 +98,8 @@ function Get-DbaReplArticle { $publications += $RMOdb.TransPublications $publications += $RMOdb.MergePublications - $publications - break + #$publications + #break #if ($PublicationType -in ('Snapshot','Transactional')) { # $publications = $RMOdb.TransPublications @@ -111,13 +111,13 @@ function Get-DbaReplArticle { #} if ($Publication) { - $publications = $publications | Where-Object PublicationName -in $Publication + $publications = $publications | Where-Object Name -in $Publication } - if ($PublicationType -eq 'Transactional') { - $articles = $publications.TransArticles - } else { + if ($PublicationType -eq 'Merge') { $articles = $publications.MergeArticles + } else { + $articles = $publications.TransArticles } if ($Article) { From 1a07c2c7851bb177b0763499491e2cd170075b6b Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:33:32 +0100 Subject: [PATCH 101/226] Add PublicationName property --- public/Get-DbaReplArticle.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 1b0091ec15..34c6cfb467 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -128,8 +128,9 @@ function Get-DbaReplArticle { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $Publications.Name - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } } } From 6096a6d176827e6f5a315cb1d4ab5820f1c5dfec Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Mon, 24 Apr 2023 15:46:58 +0100 Subject: [PATCH 102/226] Change parameters name --- public/Get-DbaReplArticle.ps1 | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 34c6cfb467..b33dbb3d7f 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -19,12 +19,10 @@ function Get-DbaReplArticle { .PARAMETER Database Specifies one or more database(s) to process. If unspecified, all databases will be processed. - .PARAMETER PublicationName - #TODO change to Name + .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. - .PARAMETER PublicationType - #TODO change to Type + .PARAMETER Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot .PARAMETER Article @@ -60,7 +58,7 @@ function Get-DbaReplArticle { [object[]]$Database, [parameter(ValueFromPipeline)] [object[]]$Publication, - [String]$PublicationType, # Snapshot, Transactional, Merge + [String]$Type, # Snapshot, Transactional, Merge [string[]]$Article, [switch]$EnableException ) @@ -98,23 +96,11 @@ function Get-DbaReplArticle { $publications += $RMOdb.TransPublications $publications += $RMOdb.MergePublications - #$publications - #break - - #if ($PublicationType -in ('Snapshot','Transactional')) { - # $publications = $RMOdb.TransPublications - #} elseif ($PublicationType -eq 'Merge') { - # $publications = $RMOdb.MergePublications - #} else { - # $RMOdb - # $publications = @($RMOdb.TransPublications + $RMOdb.MergePublications) - #} - if ($Publication) { $publications = $publications | Where-Object Name -in $Publication } - if ($PublicationType -eq 'Merge') { + if ($Type -eq 'Merge') { $articles = $publications.MergeArticles } else { $articles = $publications.TransArticles @@ -128,7 +114,7 @@ function Get-DbaReplArticle { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $Publications.Name + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } From 714c9231c87edbcc7bfb3f75afd9a6a7666e4c0a Mon Sep 17 00:00:00 2001 From: ClaudioESSilva <claudiosil100@gmail.com> Date: Thu, 4 May 2023 08:43:24 +0100 Subject: [PATCH 103/226] So the local tests works --- tests/gh-actions-repl.ps1 | 45 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 2de4b59bde..c64fc2b3dd 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -7,6 +7,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" + + #TODO: To be removed? + $PSDefaultParameterValues["*:-SnapshotShare"] = "/shared" $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" $global:ProgressPreference = "SilentlyContinue" @@ -17,10 +20,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = New-DbaDatabase -Name ReplDb $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' - } - Describe "Enable\Disable Functions" -Tag ReplSetup { + Describe "Enable\Disable Functions" -Tag ReplSetup -Skip { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -156,7 +158,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "RestofTests" -Tag "Rest" -Skip { + Describe "RestofTests" -Tag "Rest" <#-Skip#> { Context "Get-DbaReplPublisher works" -skip { BeforeAll { @@ -177,7 +179,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "New-DbaReplPublication works" -Tag test { + Context "New-DbaReplPublication works" -Tag test -Skip { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -213,7 +215,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Add-DbaReplArticle works" -Tag test { + Context "Add-DbaReplArticle works" -Tag test -Skip { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -241,7 +243,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Add-DbaReplArticle adds an article to a Transactional publication" { - $pubname = 'TestPub' + $Name = 'TestPub' Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' @@ -261,10 +263,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } - } - Context "Add-DbaReplArticle works" { + Context "Get-DbaReplArticle works" -Tag ArtTestGet { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -275,16 +276,32 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } } - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } + It "Get-DbaReplArticle get the article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" + Add-DbaReplArticle -Database ReplDb -PublicationName $PublicationName -Name $Name - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false + $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName + $TransArticle.Count | Should -Be 1 + $TransArticle.Name | Should -Be $Name + $TransArticle.PublicationName | Should -Be $PublicationName } } + } } From ab159ee0123a1e5a55628acab9e2bf9087845541 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:39:30 +0100 Subject: [PATCH 104/226] add tests --- tests/gh-actions-repl.ps1 | 85 +++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index c64fc2b3dd..56f7e90051 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -43,6 +43,25 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } + Context "Get-DbaReplPublisher works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + + } + Context "Enable-DbaReplDistributor works" { BeforeAll { # if distribution is enabled - disable it @@ -127,10 +146,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Disable-DbaReplPublishing works" { BeforeAll { - - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) - # if publishing is disabled - enable it if (-not (Get-DbaReplServer).IsPublisher) { write-output -message 'I should enable publishing' @@ -142,9 +157,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { write-output -message 'I should enable distribution' Enable-DbaReplDistributor -EnableException } - - write-output -Message ('I am a distributor {0}' -f (Get-DbaReplServer).IsDistributor) - write-output -Message ('I am a publisher {0}' -f (Get-DbaReplServer).IsPublisher) } It "publishing starts enabled" { @@ -238,9 +250,35 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name } + } + } + } - #$article = + Describe "Article tests" -Tag "ReplArticle" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } + # we need some publications too + $name = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + $name = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + } + $name = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + } + } + Context "Add-DbaReplArticle works" { It "Add-DbaReplArticle adds an article to a Transactional publication" { $Name = 'TestPub' @@ -250,31 +288,26 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + $pubname = 'TestSnap' + $article = 'ReplicateMe' + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + + #TODO: waiting on Get-DbaReplArticle } It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + $pubname = 'TestMerge' + $article = 'ReplicateMe' + + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + + #TODO: waiting on Get-DbaReplArticle } } Context "Get-DbaReplArticle works" -Tag ArtTestGet { BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } + # we need some articles too remove + $article = 'ReplicateMe' # we need some publications too $name = 'TestTrans' From e92629bc216fa105033d3ce677bbbe50323543eb Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:40:35 +0100 Subject: [PATCH 105/226] add snapshot support --- public/Remove-DbaReplArticle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index b76f2e3cce..bbd5c885a2 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -104,7 +104,7 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - if ($pub.Type -eq 'Transactional') { + if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle } elseif ($pub.Type -eq 'Merge') { $article = New-Object Microsoft.SqlServer.Replication.MergeArticle From 36e2b121304e773529c8f381064d2ae80bf0da1b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:40:57 +0100 Subject: [PATCH 106/226] add todo --- public/Get-DbaReplPublication.ps1 | 3 ++- public/Remove-DbaReplPublication.ps1 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 755c19259f..9e158a0e34 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -98,6 +98,7 @@ function Get-DbaReplPublication { foreach ($db in $databases) { if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { + #TODO: is this right - it doesn't actually skip the database Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." } @@ -119,7 +120,7 @@ function Get-DbaReplPublication { } else { $articles = $pub.TransArticles } - + #TODO: can this return a replication object? [PSCustomObject]@{ ComputerName = $server.ComputerName InstanceName = $server.ServiceName diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index deb77664c6..90f2a7c337 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -76,7 +76,7 @@ function Remove-DbaReplPublication { try { if ($PSCmdlet.ShouldProcess($instance, "Removing publication on $instance")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name -Database $Database if (-not $pub) { Write-Warning "Didn't find $Name on $Instance.$Database" From f3256f8e2a5de1cd5396a89081a72f664572ab5a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:41:29 +0100 Subject: [PATCH 107/226] bug fuix --- public/New-DbaReplSubscription.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 3d9d7bfcaa..9181f1eefa 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -105,6 +105,9 @@ function New-DbaReplSubscription { foreach ($instance in $SqlInstance) { try { + + $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it" @@ -160,12 +163,14 @@ function New-DbaReplSubscription { # create the subscription $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription - $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.ConnectionContext = $subReplServer.ConnectionContext $transSub.SubscriptionDBName = $Database $transSub.SubscriberName = $instance $transSub.DatabaseName = $PublicationDatabase $transSub.PublicationName = $PublicationName + $transSub + #TODO: <# From 3c39b9968c38670f2ff7ccfd4464357c529d67bf Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:53:54 +0100 Subject: [PATCH 108/226] function stub --- public/Get-DbaReplSubscription.ps1 | 50 +++++------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index b43b9839e6..e50b89e52e 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -82,53 +82,19 @@ function Get-DbaReplSubscription { # Connect to Publisher try { - $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $PublisherSqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } - if ($Database) { - $databases = $databases | Where-Object Name -In $Database - } + # Get all subscriptions + $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription + $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.EnumSubscriptions() + + + #TODO: finish this function - foreach ($db in $databases) { - - if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { - Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - } - - $repDB = Connect-ReplicationDB -Server $server -Database $db - - $pubTypes = $repDB.TransPublications + $repDB.MergePublications - - if ($Type) { - $pubTypes = $pubTypes | Where-Object Type -in $Type - } - - if ($Name) { - $pubTypes = $pubTypes | Where-Object Name -in $Name - } - - foreach ($pub in $pubTypes) { - if ($pub.Type -eq 'Merge') { - $articles = $pub.MergeArticles - } else { - $articles = $pub.TransArticles - } - - [PSCustomObject]@{ - ComputerName = $server.ComputerName - InstanceName = $server.ServiceName - SqlInstance = $server.Name - Server = $server.name - Database = $db.name - Name = $pub.Name #TODO: breaking change from PublicationName to Name - Type = $pub.Type #TODO: breaking change from PublicationType to Type - Articles = $articles - } - } - } } } } \ No newline at end of file From b3c83c75ad04268deeff53ee28675c9f15ec4f0e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:54:08 +0100 Subject: [PATCH 109/226] testing notes --- testing.ps1 | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/testing.ps1 b/testing.ps1 index caedf045e6..1aac8cd70a 100644 --- a/testing.ps1 +++ b/testing.ps1 @@ -121,6 +121,30 @@ $article = @{ } Add-DbaReplArticle @article +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'publishers' +} +Add-DbaReplArticle @article -EnableException + + +$article = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + PublicationName = 'testtrans' + Name = 'ReplicateMe' +} +Add-DbaReplArticle @article -EnableException + +$article = @{ + SqlInstance = 'mssql1' + Database = 'ReplDb' + PublicationName = 'testtrans' + Name = 'ReplicateMe' +} +Remove-DbaReplArticle @article # mergey $article = @{ @@ -128,7 +152,7 @@ $article = @{ Database = 'pubs' PublicationName = 'Mergey' Name = 'publishers' - Filter = "city = 'seattle'" ## not working? + #Filter = "city = 'seattle'" ## not working? } Add-DbaReplArticle @article @@ -185,6 +209,7 @@ $pub = @{ Remove-DbaReplPublication @pub + # add subscriptions. #transactional @@ -198,7 +223,7 @@ $sub = @{ SubscriptionSqlCredential = $credential } -New-DbaReplSubscription @sub +New-DbaReplSubscription @sub -enableexception #merge $sub = @{ From f41482eb2049eec1fc9bcde89cfc77a80d7d7a0b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 08:57:46 +0100 Subject: [PATCH 110/226] psm1\psd1 merging --- dbatools.psd1 | 27 ++++++--------------------- dbatools.psm1 | 23 ++++++----------------- 2 files changed, 12 insertions(+), 38 deletions(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index c7aa185b60..5ad131e201 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -139,7 +139,7 @@ 'Export-DbaLogin', 'Export-DbaPfDataCollectorSetTemplate', 'Export-DbaRegServer', - 'Export-DbaReplServerSetting', + 'Export-DbaRepServerSetting', 'Export-DbaScript', 'Export-DbaServerRole', 'Export-DbaSpConfigure', @@ -350,10 +350,9 @@ 'Get-DbaRegServer', 'Get-DbaRegServerGroup', 'Get-DbaRegServerStore', - 'Get-DbaReplDistributor', - 'Get-DbaReplPublication', - 'Get-DbaReplPublisher', - 'Get-DbaReplServer', + 'Get-DbaRepDistributor', + 'Get-DbaRepPublication', + 'Get-DbaRepServer', 'Get-DbaResourceGovernor', 'Get-DbaRgClassifierFunction', 'Get-DbaRgResourcePool', @@ -694,7 +693,7 @@ 'Test-DbaOptimizeForAdHoc', 'Test-DbaPath', 'Test-DbaPowerPlan', - 'Test-DbaReplLatency', + 'Test-DbaRepLatency', 'Test-DbaSpn', 'Test-DbaTempDbConfig', 'Test-DbaWindowsLogin', @@ -729,21 +728,7 @@ 'New-DbaLinkedServerLogin', 'Remove-DbaLinkedServerLogin', 'Remove-DbaCredential', - 'Remove-DbaAgentProxy', - - # NEW REPLICATION STUFF - 'Disable-DbaReplDistributor', - 'Enable-DbaReplDistributor', - 'Disable-DbaReplPublishing', - 'Enable-DbaReplPublishing', - 'New-DbaReplPublication', - 'Get-DbaReplArticle', - 'Get-DbaReplArticleColumn', - 'Add-DbaReplArticle', - 'Remove-DbaReplArticle', - 'Remove-DbaReplPublication', - 'New-DbaReplSubscription', - 'Remove-DbaReplSubscription' + 'Remove-DbaAgentProxy' ) # Cmdlets to export from this module diff --git a/dbatools.psm1 b/dbatools.psm1 index 3e4390a21e..55fd649f59 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -295,19 +295,9 @@ $forever = @{ foreach ($_ in $forever.GetEnumerator()) { Set-Alias -Name $_.Key -Value $_.Value } - -# Replication Aliases -$replAliases = @{ - 'Get-DbaRepServer' = 'Get-DbaReplServer' - 'Export-DbaRepServerSetting' = 'Export-DbaReplServerSetting' - 'Get-DbaRepDistributor' = 'Get-DbaReplDistributor' - 'Test-DbaRepLatency' = 'Test-DbaReplLatency' -} -foreach ($_ in $replAliases.GetEnumerator()) { - Set-Alias -Name $_.Key -Value $_.Value -} #endregion Aliases +# apparently this is no longer required? :O if ($PSVersionTable.PSVersion.Major -lt 5) { # region Commands $script:xplat = @( @@ -854,10 +844,9 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Remove-DbaCredential', 'Remove-DbaAgentProxy' ) - #TODO: can repl commands be removed here? $script:noncoresmo = @( # SMO issues - 'Get-DbaReplDistributor', + 'Get-DbaRepDistributor', 'Copy-DbaPolicyManagement', 'Copy-DbaDataCollector', 'Get-DbaPbmCategory', @@ -866,10 +855,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Get-DbaPbmObjectSet', 'Get-DbaPbmPolicy', 'Get-DbaPbmStore', - 'Get-DbaReplPublication', - 'Test-DbaReplLatency', - 'Export-DbaReplServerSetting', - 'Get-DbaReplServer' + 'Get-DbaRepPublication', + 'Test-DbaRepLatency', + 'Export-DbaRepServerSetting', + 'Get-DbaRepServer' ) $script:windowsonly = @( # filesystem (\\ related), From 0971580eba0d400ad12857568972a1b6d5edfa19 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:10:58 +0100 Subject: [PATCH 111/226] repl psd\psm changes --- dbatools.psd1 | 33 ++++++++++++++++++++++++++------- dbatools.psm1 | 22 +++++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index 5ad131e201..b342cc3fce 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -139,7 +139,7 @@ 'Export-DbaLogin', 'Export-DbaPfDataCollectorSetTemplate', 'Export-DbaRegServer', - 'Export-DbaRepServerSetting', + 'Export-DbaReplServerSetting', 'Export-DbaScript', 'Export-DbaServerRole', 'Export-DbaSpConfigure', @@ -350,9 +350,10 @@ 'Get-DbaRegServer', 'Get-DbaRegServerGroup', 'Get-DbaRegServerStore', - 'Get-DbaRepDistributor', - 'Get-DbaRepPublication', - 'Get-DbaRepServer', + 'Get-DbaReplDistributor', + 'Get-DbaReplPublication', + 'Get-DbaReplPublisher', + 'Get-DbaReplServer', 'Get-DbaResourceGovernor', 'Get-DbaRgClassifierFunction', 'Get-DbaRgResourcePool', @@ -693,7 +694,7 @@ 'Test-DbaOptimizeForAdHoc', 'Test-DbaPath', 'Test-DbaPowerPlan', - 'Test-DbaRepLatency', + 'Test-DbaReplLatency', 'Test-DbaSpn', 'Test-DbaTempDbConfig', 'Test-DbaWindowsLogin', @@ -728,7 +729,21 @@ 'New-DbaLinkedServerLogin', 'Remove-DbaLinkedServerLogin', 'Remove-DbaCredential', - 'Remove-DbaAgentProxy' + 'Remove-DbaAgentProxy', + + # NEW REPLICATION STUFF + 'Disable-DbaReplDistributor', + 'Enable-DbaReplDistributor', + 'Disable-DbaReplPublishing', + 'Enable-DbaReplPublishing', + 'New-DbaReplPublication', + 'Get-DbaReplArticle', + 'Get-DbaReplArticleColumn', + 'Add-DbaReplArticle', + 'Remove-DbaReplArticle', + 'Remove-DbaReplPublication', + 'New-DbaReplSubscription', + 'Remove-DbaReplSubscription' ) # Cmdlets to export from this module @@ -757,7 +772,11 @@ 'Get-DbaRepServer', 'Export-DbaRepServerSetting', 'Get-DbaRepDistributor', - 'Test-DbaRepLatency' + 'Test-DbaRepLatency', + 'Get-DbaRepDistributor', + 'Get-DbaRepPublication', + 'Get-DbaRepServer' + ) diff --git a/dbatools.psm1 b/dbatools.psm1 index 55fd649f59..da9f7d41d4 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -295,6 +295,18 @@ $forever = @{ foreach ($_ in $forever.GetEnumerator()) { Set-Alias -Name $_.Key -Value $_.Value } + +# Replication Aliases +$replAliases = @{ + 'Get-DbaRepServer' = 'Get-DbaReplServer' + 'Export-DbaRepServerSetting' = 'Export-DbaReplServerSetting' + 'Get-DbaRepDistributor' = 'Get-DbaReplDistributor' + 'Test-DbaRepLatency' = 'Test-DbaReplLatency' + 'Get-DbaRepPublication' = 'Get-DbaReplPublication' +} +foreach ($_ in $replAliases.GetEnumerator()) { + Set-Alias -Name $_.Key -Value $_.Value +} #endregion Aliases # apparently this is no longer required? :O @@ -846,7 +858,7 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { ) $script:noncoresmo = @( # SMO issues - 'Get-DbaRepDistributor', + 'Get-DbaReplDistributor', 'Copy-DbaPolicyManagement', 'Copy-DbaDataCollector', 'Get-DbaPbmCategory', @@ -855,10 +867,10 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'Get-DbaPbmObjectSet', 'Get-DbaPbmPolicy', 'Get-DbaPbmStore', - 'Get-DbaRepPublication', - 'Test-DbaRepLatency', - 'Export-DbaRepServerSetting', - 'Get-DbaRepServer' + 'Get-DbaReplPublication', + 'Test-DbaReplLatency', + 'Export-DbaReplServerSetting', + 'Get-DbaReplServer' ) $script:windowsonly = @( # filesystem (\\ related), From d033262f4e02919aec9e962339912392f12299a7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:24:35 +0100 Subject: [PATCH 112/226] change module to cache for library --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 303f7028c7..45c162b89e 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -15,7 +15,7 @@ jobs: - name: Install and cache PowerShell modules uses: potatoqualitee/psmodulecache@v5.2 with: - modules-to-cache: dbatools.library:2023.1.29 + modules-to-cache: dbatools.library:2023.5.5 - name: Set encryption values run: | From e728f9882a7a5a00cea328210681744a331fdb7d Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:39:42 +0100 Subject: [PATCH 113/226] testy tests --- tests/gh-actions-repl.ps1 | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 56f7e90051..34e0cd78ff 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -22,7 +22,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' } - Describe "Enable\Disable Functions" -Tag ReplSetup -Skip { + Describe "Enable\Disable Functions" -Tag ReplSetup { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -170,9 +170,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "RestofTests" -Tag "Rest" <#-Skip#> { + Describe "RestofTests" -Tag "Rest" { - Context "Get-DbaReplPublisher works" -skip { + Context "Get-DbaReplPublisher works" { BeforeAll { # if distribution is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -191,7 +191,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "New-DbaReplPublication works" -Tag test -Skip { + Context "New-DbaReplPublication works" { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -227,7 +227,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Add-DbaReplArticle works" -Tag test -Skip { + Context "Add-DbaReplArticle works" { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -277,28 +277,25 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name } + $articleName = 'ReplicateMe' } Context "Add-DbaReplArticle works" { It "Add-DbaReplArticle adds an article to a Transactional publication" { - $Name = 'TestPub' - Add-DbaReplArticle -Database ReplDb -Type Transactional -PublicationName $Name - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + $pubName = 'TestPub' + Add-DbaReplArticle -Database ReplDb -Name $articleName -PublicationName $pubName + + #TODO: waiting on Get-DbaReplArticle } It "New-DbaReplPublication creates a Snapshot publication" { $pubname = 'TestSnap' - $article = 'ReplicateMe' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw #TODO: waiting on Get-DbaReplArticle } It "New-DbaReplPublication creates a Merge publication" { $pubname = 'TestMerge' - $article = 'ReplicateMe' - - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $article -PublicationName $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw #TODO: waiting on Get-DbaReplArticle } From 4905cd0f25cf61e1305ced4490fb257f1857311d Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 16 May 2023 09:43:20 +0100 Subject: [PATCH 114/226] psf --> just message --- public/Get-DbaReplArticle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index b33dbb3d7f..775c89b026 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -83,7 +83,7 @@ function Get-DbaReplArticle { } foreach ($db in $databases) { - Write-PSFMessage -Level Verbose -Message ('Working on {0}' -f $db) + Write-Message -Level Verbose -Message ('Working on {0}' -f $db) $RMOdb = Connect-ReplicationDB -Server $server -Database $db From b74083d0e1310d101ad8069900efdb21f6618343 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 18 May 2023 16:18:26 +0100 Subject: [PATCH 115/226] remove SupportsShouldProcess on get --- public/Get-DbaReplPublisher.ps1 | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 23919bcb97..846cdf64e6 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -1,10 +1,10 @@ function Get-DbaReplPublisher { <# .SYNOPSIS - Gets publisher for the target SQL instances. + Gets publisher information for the target SQL instances. .DESCRIPTION - Gets publisher for the target SQL instances. + Gets publisher information for the target SQL instances. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -21,12 +21,6 @@ function Get-DbaReplPublisher { 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: Replication Author: Mikey Bronowski (@MikeyBronowski), bronowski.it @@ -43,8 +37,12 @@ function Get-DbaReplPublisher { Gets publisher for the mssql1 instance. + .EXAMPLE + PS C:\> Connect-DbaInstance -SqlInstance mssql1 | Get-DbaReplPublisher + + Pipes a SQL Server object to get publisher information for the mssql1 instance. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding()] param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, @@ -62,9 +60,7 @@ function Get-DbaReplPublisher { Write-Message -Level Verbose -Message "Getting publisher for $server" try { - if ($PSCmdlet.ShouldProcess($server, "Getting publisher for $server")) { - $publisher = $replServer.DistributionPublishers - } + $publisher = $replServer.DistributionPublishers } catch { Stop-Function -Message "Unable to get publisher for" -ErrorRecord $_ -Target $server -Continue } @@ -76,7 +72,6 @@ function Get-DbaReplPublisher { $publisher | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force } - Select-DefaultView -InputObject $publisher -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name } From 2f6540118ca7c01887fc5e65d701a557f4b7923b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 26 May 2023 17:05:36 +0100 Subject: [PATCH 116/226] updates --- public/Add-DbaReplArticle.ps1 | 15 +++- public/Get-DbaReplArticle.ps1 | 140 ++++++++++++++++++++--------- public/Get-DbaReplDistributor.ps1 | 14 +-- public/Get-DbaReplPublication.ps1 | 106 ++++++++++++---------- public/New-DbaReplPublication.ps1 | 9 +- public/New-DbaReplSubscription.ps1 | 27 +++--- public/Remove-DbaReplArticle.ps1 | 8 ++ 7 files changed, 209 insertions(+), 110 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 5873626d49..dabda1cfa4 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -46,7 +46,7 @@ function Add-DbaReplArticle { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT @@ -88,9 +88,17 @@ function Add-DbaReplArticle { [String]$Filter, + #TODO: Build a New-DbaReplArticleOptions function + [Microsoft.SqlServer.Replication.ArticleOptions]$ArticleOptions, + [Switch]$EnableException ) process { + + if (Test-Bound -not ArticleOptions) { + $ArticleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions + } + foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential @@ -104,7 +112,7 @@ function Add-DbaReplArticle { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions + if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle @@ -133,6 +141,9 @@ function Add-DbaReplArticle { } else { Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } + + # need to refresh subscriptions so they know about new articles + $pub.RefreshSubscriptions() } } catch { Stop-Function -Message "Unable to add article $Name to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 775c89b026..4a38388f37 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -4,7 +4,9 @@ function Get-DbaReplArticle { Gets the information about publication articles. .DESCRIPTION - This function locates and enumerates articles' information for a given publication. + This function locates and enumerates articles' information. + + Can specify a database, publication or article name or publication type. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -23,7 +25,7 @@ function Get-DbaReplArticle { Specifies one or more publication(s) to process. If unspecified, all publications will be processed. .PARAMETER Type - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot. .PARAMETER Article Specifies one or more article(s) to process. If unspecified, all articles will be processed. @@ -45,6 +47,48 @@ function Get-DbaReplArticle { https://dbatools.io/Get-DbaReplArticle .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 + + Retrieve information of all articles from all publications on all databases for server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database pubs + + Retrieve information of all articles from all publications on 'pubs' database for server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database pubs -Publication PubName + + Retrieve information of all articles from 'PubName' on 'pubs' database for server mssql1. + + #TODO: results publicationname contains all the publication names if article is in more than one ? + ComputerName : mssql1 + InstanceName : MSSQLSERVER + SqlInstance : mssql1 + DatabaseName : ReplDb + PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} + Name : ReplicateMe + ArticleId : 2 + Description : + Type : LogBased + VerticalPartition : False + SourceObjectOwner : dbo + SourceObjectName : ReplicateMe + + ComputerName : mssql1 + InstanceName : MSSQLSERVER + SqlInstance : mssql1 + DatabaseName : ReplDb + PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} + Name : ReplicateMe + ArticleId : 3 + Description : + Type : LogBased + VerticalPartition : False + SourceObjectOwner : dbo + SourceObjectName : ReplicateMe + + PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. @@ -58,12 +102,12 @@ function Get-DbaReplArticle { [object[]]$Database, [parameter(ValueFromPipeline)] [object[]]$Publication, - [String]$Type, # Snapshot, Transactional, Merge + [ValidateSet("Transactional", "Merge", "Snapshot")] + [String]$Type, [string[]]$Article, [switch]$EnableException ) begin { - #TODO - Still needed? Add-ReplicationLibrary } process { @@ -73,51 +117,63 @@ function Get-DbaReplArticle { # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $databases = $server.Databases | Where-Object IsAccessible -eq $true - if ($Database) { - $databases = $databases | Where-Object Name -In $Database - } - - foreach ($db in $databases) { - Write-Message -Level Verbose -Message ('Working on {0}' -f $db) - - $RMOdb = Connect-ReplicationDB -Server $server -Database $db - - #TODO - Check if database has replication options - #if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { - # Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - #} - - $publications = @() - $publications += $RMOdb.TransPublications - $publications += $RMOdb.MergePublications - - if ($Publication) { - $publications = $publications | Where-Object Name -in $Publication - } - - if ($Type -eq 'Merge') { - $articles = $publications.MergeArticles - } else { - $articles = $publications.TransArticles - } - - if ($Article) { - $articles = $articles | Where-Object Name -In $Article + try { + $databases = $server.Databases | Where-Object IsAccessible -eq $true + if ($Database) { + $databases = $databases | Where-Object Name -In $Database } + } catch { + Stop-Function -Message "Error occurred while getting databases from $instance" -ErrorRecord $_ -Target $instance -Continue + } - foreach ($art in $articles) { - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name - - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + try { + foreach ($db in $databases) { + Write-Message -Level Verbose -Message ('Working on {0}' -f $db.Name) + + $RMOdb = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase + $RMOdb.ConnectionContext = $replServer.ConnectionContext + $RMOdb.Name = $db.Name + if (-not $RMOdb.LoadProperties()) { + Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + continue + } + + #$RMOdb = Connect-ReplicationDB -Server $server -Database $db + + $publications = @() + $publications += $RMOdb.TransPublications + $publications += $RMOdb.MergePublications + + if ($Publication) { + $publications = $publications | Where-Object Name -in $Publication + } + + if ($Type -eq 'Merge') { + $articles = $publications.MergeArticles + } else { + $articles = $publications.TransArticles + } + + if ($Article) { + $articles = $articles | Where-Object Name -In $Article + } + + foreach ($art in $articles) { + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + } } + } catch { + Stop-Function -Message "Error occurred while getting articles from $instance" -ErrorRecord $_ -Target $instance -Continue } } } diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index a93522df7c..58a76e0e69 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -6,6 +6,7 @@ function Get-DbaReplDistributor { .DESCRIPTION This function locates and enumerates distributor information for a given SQL Server instance. + TODO: I think we can remove this? All replication commands need SQL Server Management Studio installed and are therefore currently not supported. Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 @@ -40,6 +41,10 @@ function Get-DbaReplDistributor { Retrieve distributor information for servers sql2008 and sqlserver2012. + .EXAMPLE + PS C:\> Connect-DbaInstance -SqlInstance mssql1 | Get-DbaReplDistributor + + Pipe a SQL Server instance to Get-DbaReplDistributor to retrieve distributor information. #> [CmdletBinding()] param ( @@ -48,9 +53,6 @@ function Get-DbaReplDistributor { [PSCredential]$SqlCredential, [switch]$EnableException ) - begin { - Add-ReplicationLibrary - } process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { @@ -59,12 +61,12 @@ function Get-DbaReplDistributor { # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $sqlconn = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential - - $distributor = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlconn + $distributor = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } + Write-Message -Level Verbose -Message "Getting publisher for $server" + Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 9e158a0e34..0d2753e3ba 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -1,23 +1,18 @@ function Get-DbaReplPublication { <# .SYNOPSIS - Displays all publications for a server or database. + Displays all publications on a server. .DESCRIPTION - Quickly find all transactional, merge, and snapshot publications on a specific server or database. + Quickly find all transactional, merge, and snapshot publications on a server or filter by database, name or type. + TODO: is this still true? remove? All replication commands need SQL Server Management Studio installed and are therefore currently not supported. Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 .PARAMETER SqlInstance The target SQL Server instance or instances. - .PARAMETER Database - The database(s) to process. If unspecified, all databases will be processed. - - .PARAMETER Name - The name of the publication. - .PARAMETER SqlCredential Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). @@ -25,8 +20,14 @@ function Get-DbaReplPublication { For MFA support, please use Connect-DbaInstance. + .PARAMETER Database + The database(s) to process. If unspecified, all databases will be processed. + + .PARAMETER Name + The name of the publication. + .PARAMETER Type - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot + Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -57,19 +58,24 @@ function Get-DbaReplPublication { .EXAMPLE PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional - Return all publications on server sql2008 for all databases that have Transactional publications + Return all transactional publications on server sql2008. .EXAMPLE PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey Returns the Mergey publications on server mssql1 + + .EXAMPLE + PS C:\> Connect-DbaInstance -SqlInstance mssql1 | Get-DbaReplPublication + + Returns all publications on server mssql1 using the pipeline. #> [CmdletBinding()] param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [object[]]$Database, [PSCredential]$SqlCredential, + [object[]]$Database, [String]$Name, [Alias("PublicationType")] [ValidateSet("Transactional", "Merge", "Snapshot")] @@ -82,7 +88,7 @@ function Get-DbaReplPublication { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - + write-message 'jo' # Connect to Publisher try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 @@ -90,48 +96,58 @@ function Get-DbaReplPublication { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } - if ($Database) { - $databases = $databases | Where-Object Name -In $Database + try { + $databases = $server.Databases | Where-Object { $_.IsAccessible -eq $true -and (-not $_.IsSystemObject) } + if ($Database) { + $databases = $databases | Where-Object Name -In $Database + } + } catch { + Stop-Function -Message "Unable to get databases for" -ErrorRecord $_ -Target $server -Continue } - foreach ($db in $databases) { - - if (($db.ReplicationOptions -ne "Published") -and ($db.ReplicationOptions -ne "MergePublished")) { - #TODO: is this right - it doesn't actually skip the database - Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - } + try { + foreach ($db in $databases) { + + #test if the database published + if ((($db.ReplicationOptions -band [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::Published) -ne [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::Published) -and + (($db.ReplicationOptions -band [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::MergePublished) -ne [Microsoft.SqlServer.Management.Smo.ReplicationOptions]::MergePublished)) { + # The database is not published + Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." + continue + } - $repDB = Connect-ReplicationDB -Server $server -Database $db + $repDB = Connect-ReplicationDB -Server $server -Database $db - $pubTypes = $repDB.TransPublications + $repDB.MergePublications + $pubTypes = $repDB.TransPublications + $repDB.MergePublications - if ($Type) { - $pubTypes = $pubTypes | Where-Object Type -in $Type - } + if ($Type) { + $pubTypes = $pubTypes | Where-Object Type -in $Type + } - if ($Name) { - $pubTypes = $pubTypes | Where-Object Name -in $Name - } - #TODO: Check why if -Database is not passed, I can't see the articles - foreach ($pub in $pubTypes) { - if ($pub.Type -eq 'Merge') { - $articles = $pub.MergeArticles - } else { - $articles = $pub.TransArticles + if ($Name) { + $pubTypes = $pubTypes | Where-Object Name -in $Name } - #TODO: can this return a replication object? - [PSCustomObject]@{ - ComputerName = $server.ComputerName - InstanceName = $server.ServiceName - SqlInstance = $server.Name - Server = $server.name - Database = $db.name - Name = $pub.Name #TODO: breaking change from PublicationName to Name - Type = $pub.Type #TODO: breaking change from PublicationType to Type - Articles = $articles + + #TODO: Check why if -Database is not passed, I can't see the articles (JP - this works for me... 🤔) + foreach ($pub in $pubTypes) { + if ($pub.Type -eq 'Merge') { + $articles = $pub.MergeArticles + } else { + $articles = $pub.TransArticles + } + + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Articles -Value $articles + + Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles + #TODO: breaking change from PublicationName to Name + #TODO: breaking change from PublicationType to Type } } + } catch { + Stop-Function -Message "Unable to get publications from " -ErrorRecord $_ -Target $server -Continue } } } diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 68ebf88e49..2226e9e1bd 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -62,9 +62,9 @@ function New-DbaReplPublication { https://dbatools.io/New-DbaReplPublication .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Type Transactional - Creates a publication called PubFromPosh for the Northwind database on mssql1 + Creates a transactional publication called PubFromPosh for the Northwind database on mssql1 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] @@ -99,6 +99,7 @@ function New-DbaReplPublication { try { if ($PSCmdlet.ShouldProcess($instance, "Creating publication on $instance")) { + #TODO: could replace this with call to Connect-ReplicationDB $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $replServer.ConnectionContext $pubDatabase.Name = $Database @@ -109,12 +110,12 @@ function New-DbaReplPublication { if ($Type -in ('Transactional', 'Snapshot')) { Write-Message -Level Verbose -Message "Enable trans publishing publication on $instance.$Database" $pubDatabase.EnabledTransPublishing = $true + $pubDatabase.CommitPropertyChanges() } elseif ($Type -eq 'Merge') { Write-Message -Level Verbose -Message "Enable merge publishing publication on $instance.$Database" $pubDatabase.EnabledMergePublishing = $true - $pubDatabase.CommitPropertyChanges + $pubDatabase.CommitPropertyChanges() } - #TODO: snapshot repl? if (-not $pubDatabase.LogReaderAgentExists) { #TODO: if this needed for merge? diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 9181f1eefa..b2caaf4c54 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -25,7 +25,6 @@ function New-DbaReplSubscription { .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. @@ -77,7 +76,7 @@ function New-DbaReplSubscription { $SubscriptionSqlCredential, [parameter(Mandatory)] - [ValidateSet("Push", "Pull")] #TODO: make this do something :) + [ValidateSet("Push", "Pull")] [String]$Type, [Switch]$EnableException @@ -87,13 +86,15 @@ function New-DbaReplSubscription { # connect to publisher and get the publication try { - $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + $pubReplServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } try { $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + + } catch { Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue } @@ -109,7 +110,7 @@ function New-DbaReplSubscription { $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { - Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it" + Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it - but you should check the settings!" if ($PSCmdlet.ShouldProcess($instance, "Creating subscription database")) { @@ -133,17 +134,21 @@ function New-DbaReplSubscription { if ($pub.Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication - $transPub.ConnectionContext = $replServer.ConnectionContext + $transPub.ConnectionContext = $pubReplServer.ConnectionContext $transPub.DatabaseName = $PublicationDatabase $transPub.Name = $PublicationName # if LoadProperties returns then the publication was found if ( $transPub.LoadProperties() ) { - if ($type = 'Push') { + 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 'ALlowPush' -eq 'None' ) { + 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' @@ -152,7 +157,7 @@ function New-DbaReplSubscription { } } else { # Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull. - if ($transPub.Attributes -band 'ALlowPull' -eq 'None' ) { + if ($transPub.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. $transPub.Attributes = $transPub.Attributes -bor 'AllowPull' @@ -163,7 +168,7 @@ function New-DbaReplSubscription { # create the subscription $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription - $transSub.ConnectionContext = $subReplServer.ConnectionContext + $transSub.ConnectionContext = $pubReplServer.ConnectionContext $transSub.SubscriptionDBName = $Database $transSub.SubscriberName = $instance $transSub.DatabaseName = $PublicationDatabase @@ -201,7 +206,7 @@ function New-DbaReplSubscription { } elseif ($pub.Type -eq 'Merge') { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication - $mergePub.ConnectionContext = $replServer.ConnectionContext + $mergePub.ConnectionContext = $pubReplServer.ConnectionContext $mergePub.DatabaseName = $PublicationDatabase $mergePub.Name = $PublicationName @@ -235,7 +240,7 @@ function New-DbaReplSubscription { $mergeSub = New-Object Microsoft.SqlServer.Replication.MergePullSubscription } - $mergeSub.ConnectionContext = $replServer.ConnectionContext + $mergeSub.ConnectionContext = $pubReplServer.ConnectionContext $mergeSub.SubscriptionDBName = $Database $mergeSub.SubscriberName = $instance $mergeSub.DatabaseName = $PublicationDatabase diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index bbd5c885a2..7743569026 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -15,6 +15,8 @@ If an article is dropped after one or more subscriptions is created, the subscri Dropping an article from a publication involves dropping the article and creating a new snapshot for the publication. Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. +TODO: WARNING: [16:39:55][Remove-DbaReplArticle] Unable to remove article from testPub on mssql1 | Could not drop article. A subscription exists on it. +Need to drop from sub? https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 @@ -118,6 +120,12 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a $article.PublicationName = $PublicationName $article.DatabaseName = $Database + #TODO: Fix this - hard coded subscriber name + # if it has a subscription, we need to drop it first = can't work it out with RMO + # how do we get subscriber name too? + $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, 'mssql2' + Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query + if (($article.IsExistingObject)) { $article.Remove() } else { From 4052ea720aca48e9ead65cff43715c3b52ff086f Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 26 May 2023 17:05:44 +0100 Subject: [PATCH 117/226] new tests --- tests/gh-actions-repl.ps1 | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 34e0cd78ff..2fd197c68a 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -41,6 +41,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "distribution database name is correct" { (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' } + + It "can pipe a sql server object to it" { + Connect-DbaInstance | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty + } } Context "Get-DbaReplPublisher works" { @@ -60,6 +64,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } + It "gets a publisher using piping" { + (Connect-DbaInstance | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + } Context "Enable-DbaReplDistributor works" { @@ -191,6 +199,47 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } + Context "Get-DbaReplPublication works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + + # create a publication + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName ('{0}-Trans' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName ('{0}-Merge' -f $Name) + $null = New-DbaDatabase -Name Test + New-DbaReplPublication -Database Test -Type Snapshot -PublicationName ('{0}-Snapshot' -f $Name) + } + + It "gets all publications" { + Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + + It "gets publications for a specific database" { + Get-DbaReplPublication -Database ReplDb | Should -Not -BeNullOrEmpty + (Get-DbaRepPublication -Database ReplDb).Database | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + + It "gets publications for a specific type" { + Get-DbaReplPublication -Type Transactional | Should -Not -BeNullOrEmpty + (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } + } + + It "works with piping" { + Connect-DbaInstance | Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + } + + + Context "New-DbaReplPublication works" { BeforeAll { # if replication is disabled - enable it From 657fad03e1309b6db506da6b7b002c6401ec99f2 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 26 May 2023 17:05:50 +0100 Subject: [PATCH 118/226] stuff --- ReplicationCommands.md | 2 +- ReplicationDemo.ps1 | 99 ++++++++++++++++++++++++++++++++++++++++++ testing.ps1 | 23 ++-------- 3 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 ReplicationDemo.ps1 diff --git a/ReplicationCommands.md b/ReplicationCommands.md index fdd790c96b..933a9f5ada 100644 --- a/ReplicationCommands.md +++ b/ReplicationCommands.md @@ -56,7 +56,7 @@ Meaning of the checkmarks: - [ ] Get-DbaReplSnapshotAgentStatus - [ ] Get-DbaReplLogReaderAgentStatus - [ ] Test-DbaReplSnapFolder - similar to Test-DbaPath but from replication service account perspective or something similar to check If the share (UNC or Local) is accessible from both, publisher and subscriber side - +- [ ] Reinitialise-? - what do we need here ## How to run pester tests locally ```PowerShell diff --git a/ReplicationDemo.ps1 b/ReplicationDemo.ps1 new file mode 100644 index 0000000000..4205c4445f --- /dev/null +++ b/ReplicationDemo.ps1 @@ -0,0 +1,99 @@ +# dbatools 💜 dbatools + +############################## +# create docker environment +############################## +# create a shared network +docker network create localnet + +# Expose engines and setup shared path for migrations +docker run -p 2500:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance +docker run -p 2600:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + +# create the repl folder +docker exec mssql1 mkdir /var/opt/mssql/ReplData + +# also need these folders for setting up replication +docker exec mssql1 mkdir /shared/data /shared/repldata + +############################## + +# import out version of the module +cd C:\GitHub\DMM-GitHub\dbatools +Import-Module .\dbatools.psd1 + +# lets save the password for connecting to containers because I'm lazy +$securePassword = ('dbatools.IO' | ConvertTo-SecureString -AsPlainText -Force) +$credential = New-Object System.Management.Automation.PSCredential('sqladmin', $securePassword) + +$PSDefaultParameterValues = @{ + "*:SqlCredential" = $credential + "*:DestinationCredential" = $credential + "*:DestinationSqlCredential" = $credential + "*:SourceSqlCredential" = $credential + "*:PublisherSqlCredential" = $credential +} + +# what do we have so far +Get-DbaReplServer -SqlInstance mssql1 +Get-DbaReplDistributor -SqlInstance mssql1 +Get-DbaReplPublisher -SqlInstance mssql1 + +# enable distribution +Enable-DbaReplDistributor -SqlInstance mssql1 + +# enable publishing +Enable-DbaReplPublishing -SqlInstance mssql1 + +# create a transactional publication using splat format +$pub = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Type = 'Transactional' +} +New-DbaReplPublication @pub + +# add an article to the publication +$article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testpub' + Name = 'authors' +} +Add-DbaReplArticle @article + +# create a pubs database on mssql2 to replicate to +New-DbaDatabase -SqlInstance mssql2 -Name pubs + +# if you don't the New-DbaReplSubscription command will create the database for you + +# add a subscription to the publication +$sub = @{ + SqlInstance = 'mssql2' + Database = 'pubs' + PublicationDatabase = 'pubs' + PublisherSqlInstance = 'mssql1' + PublicationName = 'testpub' + Type = 'Push' + SubscriptionSqlCredential = $credential + +} +New-DbaReplSubscription @sub + +# creates the snapshot job with a daily schedule at 8am - is that expected? good default? +# should adding a subscription kick off snapshot? should that be an param -StartSnapshotNow -- yes + # create that without a schedule by default maybe a param for a schedule + # + +# stats on the subscription - in the distribution database + # could we make a command to get stats + + + + + + ## when adding an article - we need the options + # - action if name is in use 'drop existing object and create new' + # copy nonclusterd indexes + # nuno diff --git a/testing.ps1 b/testing.ps1 index 1aac8cd70a..842d9de1e1 100644 --- a/testing.ps1 +++ b/testing.ps1 @@ -73,6 +73,8 @@ Get-DbaReplPublication -SqlInstance mssql1 Enable-DbaReplDistributor -SqlInstance mssql1 Disable-DbaReplDistributor -SqlInstance mssql1 +Get-DbaReplDistributor -SqlInstance + # enable publishing Enable-DbaReplPublishing -SqlInstance mssql1 Disable-DbaReplPublishing -SqlInstance mssql1 @@ -85,7 +87,7 @@ $pub = @{ Type = 'Transactional' } -New-DbaReplPublication @pub +New-DbaReplPublication @pub -verbose @@ -117,19 +119,10 @@ $article = @{ Database = 'pubs' PublicationName = 'testpub' Name = 'publishers' - Filter = "city = 'seattle'" ## not working? + Filter = "city = 'seattle'" } Add-DbaReplArticle @article -$article = @{ - SqlInstance = 'mssql1' - Database = 'pubs' - PublicationName = 'testpub' - Name = 'publishers' -} -Add-DbaReplArticle @article -EnableException - - $article = @{ SqlInstance = 'mssql1' Database = 'ReplDb' @@ -138,14 +131,6 @@ $article = @{ } Add-DbaReplArticle @article -EnableException -$article = @{ - SqlInstance = 'mssql1' - Database = 'ReplDb' - PublicationName = 'testtrans' - Name = 'ReplicateMe' -} -Remove-DbaReplArticle @article - # mergey $article = @{ SqlInstance = 'mssql1' From ac484f879c97c21ba7f92edcc789560adce60a68 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 30 May 2023 17:29:38 +0100 Subject: [PATCH 119/226] new command New-DbaReplCreationScriptOptions --- dbatools.psd1 | 3 +- public/Add-DbaReplArticle.ps1 | 30 ++++++-- public/New-DbaReplCreationScriptOptions.ps1 | 81 +++++++++++++++++++++ tests/gh-actions-repl.ps1 | 27 +++++++ 4 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 public/New-DbaReplCreationScriptOptions.ps1 diff --git a/dbatools.psd1 b/dbatools.psd1 index b342cc3fce..c8d63ede33 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -743,7 +743,8 @@ 'Remove-DbaReplArticle', 'Remove-DbaReplPublication', 'New-DbaReplSubscription', - 'Remove-DbaReplSubscription' + 'Remove-DbaReplSubscription', + 'New-DbaReplCreationScriptOptions' ) # Cmdlets to export from this module diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index dabda1cfa4..afe156ebe4 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -33,6 +33,10 @@ function Add-DbaReplArticle { Horizontal filter for replication, implemented as a where clause, but don't include the word WHERE> E.g. City = 'Seattle' + .PARAMETER CreationScriptOptions + Options for the creation script. + Use New-DbaReplCreationScriptOptions to create this object. + .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. @@ -67,6 +71,20 @@ function Add-DbaReplArticle { PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName TestPub -Name publishers -Filter "city = 'seattle'" Adds the publishers table to the TestPub publication from mssql1.Pubs with a horizontal filter of only rows where city = 'seattle. + + .EXAMPLE + PS C:\> $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics + PS C:\> $article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Name = 'stores' + CreationScriptOptions = $cso + } + Add-DbaReplArticle @article -EnableException + + Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set + includes default options. #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( @@ -89,16 +107,12 @@ function Add-DbaReplArticle { [String]$Filter, #TODO: Build a New-DbaReplArticleOptions function - [Microsoft.SqlServer.Replication.ArticleOptions]$ArticleOptions, + [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, [Switch]$EnableException ) process { - if (Test-Bound -not ArticleOptions) { - $ArticleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions - } - foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential @@ -112,7 +126,7 @@ function Add-DbaReplArticle { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - + $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions if ($pub.Type -in ('Transactional', 'Snapshot')) { $article = New-Object Microsoft.SqlServer.Replication.TransArticle @@ -129,6 +143,10 @@ function Add-DbaReplArticle { $article.SourceObjectOwner = $Schema $article.PublicationName = $PublicationName + if ($CreationScriptOptions) { + $article.SchemaOption = $CreationScriptOptions + } + if ($Filter) { if ($Filter -like 'WHERE*') { Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/New-DbaReplCreationScriptOptions.ps1 b/public/New-DbaReplCreationScriptOptions.ps1 new file mode 100644 index 0000000000..23caf8b2a7 --- /dev/null +++ b/public/New-DbaReplCreationScriptOptions.ps1 @@ -0,0 +1,81 @@ +function New-DbaReplCreationScriptOptions { + <# + .SYNOPSIS + Creates a new Microsoft.SqlServer.Replication.CreationScriptOptions enumeration object. + + .DESCRIPTION + Creates a new Microsoft.SqlServer.Replication.CreationScriptOptions enumeration object that allows you to specify article options. + + See https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.replication.creationscriptoptions for more information + + .PARAMETER Options + The options to set on published articles. + See https://docs.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.replication.creationscriptoptions for a list of available options + + .PARAMETER NoDefaults + If specified, no default options will be set on the object + + Defaults are copied from when you add an article in SQL Server Management Studio and include: + PrimaryObject, CustomProcedures, Identity, KeepTimestamp, + ClusteredIndexes, DriPrimaryKey, Collation, DriUniqueKeys, + MarkReplicatedCheckConstraintsAsNotForReplication, + MarkReplicatedForeignKeyConstraintsAsNotForReplication, and Schema + + .NOTES + Tags: Replication, Script + 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-DbaReplCreationScriptOptions + + .EXAMPLE + PS C:\> $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics + PS C:\> $article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Name = 'stores' + CreationScriptOptions = $cso + } + Add-DbaReplArticle @article -EnableException + + Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set + includes default options. + + + .EXAMPLE + PS C:\> $cso = New-DbaReplCreationScriptOptions -Options ClusteredIndexes, Identity -NoDefaults + PS C:\> $article = @{ + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + Name = 'stores' + CreationScriptOptions = $cso + } + Add-DbaReplArticle @article -EnableException + + Adds the stores table to the testPub publication from mssql1.pubs with the ClusteredIndexes and Identity options set, excludes default options. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] + param ( + [String[]]$Options, + + [switch]$NoDefaults + ) + + $cso = New-Object Microsoft.SqlServer.Replication.CreationScriptOptions + + if (-not $NoDefaults) { + 'PrimaryObject', 'CustomProcedures', 'Identity', 'KeepTimestamp', 'ClusteredIndexes', 'DriPrimaryKey', 'Collation', 'DriUniqueKeys', 'MarkReplicatedCheckConstraintsAsNotForReplication', 'MarkReplicatedForeignKeyConstraintsAsNotForReplication', 'Schema' | ForEach-Object { $cso += $_ } + } + + foreach ($opt in $options) { + $cso += $opt + } + + $cso +} \ No newline at end of file diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 2fd197c68a..a0dc37a42e 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -328,6 +328,33 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } $articleName = 'ReplicateMe' } + + Context "New-DbaReplCreationScriptOptions works" { + It "New-DbaReplCreationScriptOptions creates a Microsoft.SqlServer.Replication.CreationScriptOptions" { + $options = New-DbaReplCreationScriptOptions + $options | Should -BeOfType Microsoft.SqlServer.Replication.CreationScriptOptions + } + It "Microsoft.SqlServer.Replication.CreationScriptOptions should include the 11 defaults by default" { + ((New-DbaReplCreationScriptOptions).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 11 + } + It "Microsoft.SqlServer.Replication.CreationScriptOptions should include ClusteredIndexes" { + ((New-DbaReplCreationScriptOptions).ToString().Split(',').Trim() | Should -Contain 'ClusteredIndexes') + } + It "Microsoft.SqlServer.Replication.CreationScriptOptions with option of NonClusteredIndexes should add NonClusteredIndexes" { + ((New-DbaReplCreationScriptOptions -Option NonClusteredIndexes).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 12 + ((New-DbaReplCreationScriptOptions -Option NonClusteredIndexes).ToString().Split(',').Trim() | Should -Contain 'NonClusteredIndexes') + } + + It "NoDefaults should mean Microsoft.SqlServer.Replication.CreationScriptOptions only contains DisableScripting" { + ((New-DbaReplCreationScriptOptions -NoDefaults).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 1 + ((New-DbaReplCreationScriptOptions -NoDefaults).ToString().Split(',').Trim() | Should -Contain 'DisableScripting') + } + It "NoDefaults plus option of NonClusteredIndexes should mean Microsoft.SqlServer.Replication.CreationScriptOptions only contains NonClusteredIndexes" { + ((New-DbaReplCreationScriptOptions -NoDefaults -Option NonClusteredIndexes).ToString().Split(',').Trim() | Measure-Object).Count | Should -Be 1 + ((New-DbaReplCreationScriptOptions -NoDefaults -Option NonClusteredIndexes).ToString().Split(',').Trim() | Should -Contain 'NonClusteredIndexes') + } + } + Context "Add-DbaReplArticle works" { It "Add-DbaReplArticle adds an article to a Transactional publication" { From 3467134a05ea95f528e7744e1fb529f0274a2713 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 30 May 2023 17:29:43 +0100 Subject: [PATCH 120/226] remove comment --- public/Get-DbaReplServer.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index ca50bf70f6..e9ac8f5897 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -60,7 +60,6 @@ function Get-DbaReplServer { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { try { - # use System.Data instead of Microsoft.Data $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential $sqlCon = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlCon From bab88ef85d9873c1cd103d8b077bfadf2ffe1427 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 31 May 2023 15:10:24 +0100 Subject: [PATCH 121/226] fixes for remove article --- public/Remove-DbaReplArticle.ps1 | 35 +++++++++++++++----------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 7743569026..b59e9bf4b7 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -9,16 +9,7 @@ function Remove-DbaReplArticle { Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this ClearUpSubObject -For snapshot or transactional publications, articles can be dropped with no special considerations prior to subscriptions being created. -If an article is dropped after one or more subscriptions is created, the subscriptions must be dropped, recreated, and synchronized. - -Dropping an article from a publication involves dropping the article and creating a new snapshot for the publication. -Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. - -TODO: WARNING: [16:39:55][Remove-DbaReplArticle] Unable to remove article from testPub on mssql1 | Could not drop article. A subscription exists on it. -Need to drop from sub? - -https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/add-articles-to-and-drop-articles-from-existing-publications?view=sql-server-ver16 + Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -42,6 +33,9 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a .PARAMETER Name The name of the article to remove. + .PARAMETER DropObjectOnSubscriber + If this switch is enabled, the object will be dropped from the subscriber database. + .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. @@ -74,7 +68,6 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, @@ -90,6 +83,8 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a [parameter(Mandatory)] [String]$Name, + [Switch]$DropObjectOnSubscriber, + [Switch]$EnableException ) process { @@ -120,24 +115,26 @@ https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/a $article.PublicationName = $PublicationName $article.DatabaseName = $Database - #TODO: Fix this - hard coded subscriber name - # if it has a subscription, we need to drop it first = can't work it out with RMO - # how do we get subscriber name too? - $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, 'mssql2' - Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query + #TODO: change to RMO? if it has a subscription, we need to drop it first = can't work it out with RMO + if ($pub.Subscriptions) { + Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $Name, $pub.Subscriptions.SubscriberName) + $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, $pub.Subscriptions.SubscriberName + Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query + } if (($article.IsExistingObject)) { $article.Remove() } else { Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } + + if ($DropObjectOnSubscriber) { + #TODO: Drop object on subscriber + } } } catch { Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } - - #TODO: What should we return anything? - } } } From 276f0e9ace4dfbdac8127d374b2c7dfba7144080 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:15:54 +0100 Subject: [PATCH 122/226] RefreshSubscriptions not a thing for merge --- public/Add-DbaReplArticle.ps1 | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index afe156ebe4..d0343cb437 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -97,7 +97,7 @@ function Add-DbaReplArticle { [String]$Database, [parameter(Mandatory)] - [String]$PublicationName, + [String]$Publication, [String]$Schema = 'dbo', @@ -119,12 +119,12 @@ function Add-DbaReplArticle { } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - Write-Message -Level Verbose -Message "Adding article $Name to publication $PublicationName on $instance" + Write-Message -Level Verbose -Message "Adding article $Name to publication $Publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $PublicationName")) { + if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $Publication")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions @@ -141,7 +141,7 @@ function Add-DbaReplArticle { $article.DatabaseName = $Database $article.SourceObjectName = $Name $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName + $article.PublicationName = $Publication if ($CreationScriptOptions) { $article.SchemaOption = $CreationScriptOptions @@ -157,17 +157,20 @@ function Add-DbaReplArticle { if (-not ($article.IsExistingObject)) { $article.Create() } else { - Stop-Function -Message "Article already exists in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Article already exists in $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue } # need to refresh subscriptions so they know about new articles - $pub.RefreshSubscriptions() + # only on trans\snap publications + # (Method invocation failed because [Microsoft.SqlServer.Replication.MergePublication] does not contain a method named 'RefreshSubscriptions'.) + if ($pub.Type -in ('Transactional', 'Snapshot')) { + $pub.RefreshSubscriptions() + } } } catch { - Stop-Function -Message "Unable to add article $Name to $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Unable to add article $Name to $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue } - #TODO: What should we return - Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $PublicationName -Article $Name + Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $Publication -Name $Name } } } From 72bd797b8f255623d31c15c9e1db8ba013415554 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:38:28 +0100 Subject: [PATCH 123/226] add url --- public/Disable-DbaReplDistributor.ps1 | 2 +- public/Disable-DbaReplPublishing.ps1 | 2 +- public/Enable-DbaReplDistributor.ps1 | 2 +- public/Enable-DbaReplPublishing.ps1 | 2 +- public/New-DbaReplPublication.ps1 | 2 +- public/New-DbaReplSubscription.ps1 | 2 +- public/Remove-DbaReplPublication.ps1 | 2 +- public/Remove-DbaReplSubscription.ps1 | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index c2d325f673..0f9e61ff37 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -38,7 +38,7 @@ function Disable-DbaReplDistributor { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 39d500924c..7a2b95376b 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -38,7 +38,7 @@ function Disable-DbaReplPublishing { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 1cba0e42a4..020b734ec1 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -34,7 +34,7 @@ function Enable-DbaReplDistributor { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 409da62131..444f93eae0 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -36,7 +36,7 @@ function Enable-DbaReplPublishing { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 2226e9e1bd..7f0464f672 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -52,7 +52,7 @@ function New-DbaReplPublication { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index b2caaf4c54..c363514a49 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -38,7 +38,7 @@ function New-DbaReplSubscription { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 90f2a7c337..f6183dca39 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -37,7 +37,7 @@ function Remove-DbaReplPublication { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index b9cdc4fb71..3c1d0dbac3 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -51,7 +51,7 @@ function Remove-DbaReplSubscription { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io Copyright: (c) 2022 by dbatools, licensed under MIT From 79809d32569b99092dc8e73ceabd5625e4a06799 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:38:55 +0100 Subject: [PATCH 124/226] remove write-message and fix bug with publication output --- public/Get-DbaReplPublication.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 0d2753e3ba..fc1967f2e6 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -88,7 +88,6 @@ function Get-DbaReplPublication { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - write-message 'jo' # Connect to Publisher try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 9 @@ -132,16 +131,20 @@ function Get-DbaReplPublication { foreach ($pub in $pubTypes) { if ($pub.Type -eq 'Merge') { $articles = $pub.MergeArticles + $subscriptions = $pub.MergeSubscriptions } else { $articles = $pub.TransArticles + $subscriptions = $pub.TransSubscriptions } + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Articles -Value $articles + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Subscriptions -Value $subscriptions - Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles + Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles, Subscriptions #TODO: breaking change from PublicationName to Name #TODO: breaking change from PublicationType to Type } From 86cd0f667c907b4c19d77a61e5f5e9cda6a1e876 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:39:06 +0100 Subject: [PATCH 125/226] enable piping and tidy up --- public/Get-DbaReplArticle.ps1 | 70 +++------------------ public/Remove-DbaReplArticle.ps1 | 101 +++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 73 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 4a38388f37..4462f09851 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -24,11 +24,8 @@ function Get-DbaReplArticle { .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. - .PARAMETER Type - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot. - - .PARAMETER Article - Specifies one or more article(s) to process. If unspecified, all articles will be processed. + .PARAMETER Name + Specify the name of one or more article(s) to process. If unspecified, all articles will be processed. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -61,35 +58,8 @@ function Get-DbaReplArticle { Retrieve information of all articles from 'PubName' on 'pubs' database for server mssql1. - #TODO: results publicationname contains all the publication names if article is in more than one ? - ComputerName : mssql1 - InstanceName : MSSQLSERVER - SqlInstance : mssql1 - DatabaseName : ReplDb - PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} - Name : ReplicateMe - ArticleId : 2 - Description : - Type : LogBased - VerticalPartition : False - SourceObjectOwner : dbo - SourceObjectName : ReplicateMe - - ComputerName : mssql1 - InstanceName : MSSQLSERVER - SqlInstance : mssql1 - DatabaseName : ReplDb - PublicationName : {Snappy, TestPub, TestPub-Trans, TestSnap…} - Name : ReplicateMe - ArticleId : 3 - Description : - Type : LogBased - VerticalPartition : False - SourceObjectOwner : dbo - SourceObjectName : ReplicateMe - - - PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -Name sales Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. @@ -100,11 +70,10 @@ function Get-DbaReplArticle { [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [object[]]$Database, - [parameter(ValueFromPipeline)] [object[]]$Publication, [ValidateSet("Transactional", "Merge", "Snapshot")] [String]$Type, - [string[]]$Article, + [string[]]$Name, [switch]$EnableException ) begin { @@ -117,7 +86,6 @@ function Get-DbaReplArticle { # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -135,41 +103,23 @@ function Get-DbaReplArticle { foreach ($db in $databases) { Write-Message -Level Verbose -Message ('Working on {0}' -f $db.Name) - $RMOdb = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase - $RMOdb.ConnectionContext = $replServer.ConnectionContext - $RMOdb.Name = $db.Name - if (-not $RMOdb.LoadProperties()) { - Write-Message -Level Verbose -Message "Skipping $($db.name). Database is not published." - continue - } - - #$RMOdb = Connect-ReplicationDB -Server $server -Database $db - - $publications = @() - $publications += $RMOdb.TransPublications - $publications += $RMOdb.MergePublications + $publications = Get-DbaReplPublication -SqlInstance $server -Database $db.Name if ($Publication) { $publications = $publications | Where-Object Name -in $Publication } - if ($Type -eq 'Merge') { - $articles = $publications.MergeArticles - } else { - $articles = $publications.TransArticles - } - - if ($Article) { - $articles = $articles | Where-Object Name -In $Article + $articles = $publications.Articles + if ($Name) { + $articles = $articles | Where-Object Name -In $Name } foreach ($art in $articles) { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $publications.Name - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, ArticleId, Description, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } } } catch { diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index b59e9bf4b7..9e28049a0a 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -7,7 +7,7 @@ function Remove-DbaReplArticle { Removes an article from a publication for the database on the target SQL instances. Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. - Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this ClearUpSubObject + Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this DropObjectOnSubscriber Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. @@ -24,7 +24,7 @@ function Remove-DbaReplArticle { .PARAMETER Database The database on the publisher that contains the article to be removed from replication. - .PARAMETER PublicationName + .PARAMETER Publication The name of the replication publication. .PARAMETER Schema @@ -36,6 +36,9 @@ function Remove-DbaReplArticle { .PARAMETER DropObjectOnSubscriber If this switch is enabled, the object will be dropped from the subscriber database. + .PARAMETER InputObject + Enables piping from Get-DbaReplArticle + .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. @@ -49,45 +52,115 @@ function Remove-DbaReplArticle { .NOTES Tags: Replication - Author: Jess Pomfret (@jpomfret) + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT - https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-an-article?view=sql-server-ver16 + https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-an-article .LINK https://dbatools.io/Remove-DbaReplArticle .EXAMPLE - PS C:\> Remove-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName PubFromPosh -Name 'publishers' + PS C:\> Remove-DbaReplArticle -SqlInstance mssql1 -Database Pubs -Publication PubFromPosh -Name 'publishers' Removes the publishers article from a publication called PubFromPosh on mssql1 + .EXAMPLE + + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database Pubs -Publication TestPub | Remove-DbaReplArticle + + Removes all articles from a publication called TestPub on mssql1 #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] param ( + # [parameter(Mandatory, ParameterSetName = "Default")] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - [parameter(Mandatory)] + #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Database, - [parameter(Mandatory)] - [String]$PublicationName, + #[parameter(Mandatory, ParameterSetName = "Default")] + [String]$Publication, [String]$Schema = 'dbo', - [parameter(Mandatory)] + #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Name, [Switch]$DropObjectOnSubscriber, + [Parameter(ValueFromPipeline)] # , Mandatory, ParameterSetName = "input")] + [Microsoft.SqlServer.Replication.Article[]]$InputObject, + [Switch]$EnableException ) + + begin { + $articles = @( ) + } + process { + if (-not $PSBoundParameters.SqlInstance -and -not $PSBoundParameters.InputObject) { + Stop-Function -Message "You must specify either SqlInstance or InputObject" + return + } + if ($SqlInstance) { + $params = $PSBoundParameters + $null = $params.Remove('InputObject') + $null = $params.Remove('WhatIf') + $null = $params.Remove('Confirm') + $articles = Get-DbaReplArticle @params + } else { + $articles += $InputObject + } + } + + end { + # We have to delete in the end block to prevent "Collection was modified; enumeration operation may not execute." if directly piped from Get-DbaReplArticle. + foreach ($art in $articles) { + if ($PSCmdlet.ShouldProcess($art.Name, "Removing the article $($art.SourceObjectOwner).$($art.SourceObjectName) from the $($art.PublicationName) publication on $($art.SqlServerName)")) { + $output = [pscustomobject]@{ + ComputerName = $art.ComputerName + InstanceName = $art.InstanceName + SqlInstance = $art.SqlInstance + Database = $art.DatabaseName + ObjectName = $art.SourceObjectName + ObjectSchema = $art.SourceObjectOwner + Status = $null + IsRemoved = $false + } + try { + + $pub = Get-DbaReplPublication -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -Name $art.PublicationName + + if ($pub.Subscriptions) { + Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $art.Name, $pub.Subscriptions.SubscriberName) + $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $art.PublicationName, $art.Name, $pub.Subscriptions.SubscriberName + Invoke-DbaQuery -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -query $query + } + if (($art.IsExistingObject)) { + $art.Remove() + } else { + Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue + } + $output.Status = "Removed" + $output.IsRemoved = $true + } catch { + Stop-Function -Message "Failed to remove the article from publication" -ErrorRecord $_ + $output.Status = (Get-ErrorMessage -Record $_) + $output.IsRemoved = $false + } + $output + } + } + } + + <# foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential @@ -129,14 +202,16 @@ function Remove-DbaReplArticle { } if ($DropObjectOnSubscriber) { - #TODO: Drop object on subscriber + } } } catch { Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue } } - } + }#> + + } From e8ce7ecde73d16efeb504b7f873a138819c5e5f3 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:39:11 +0100 Subject: [PATCH 126/226] more tests --- tests/gh-actions-repl.ps1 | 193 ++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 51 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index a0dc37a42e..767e3c0d1f 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -42,7 +42,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' } - It "can pipe a sql server object to it" { + It "can pipe a sql server object to it" -skip { Connect-DbaInstance | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty } } @@ -64,7 +64,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - It "gets a publisher using piping" { + It "gets a publisher using piping" -skip { (Connect-DbaInstance | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } @@ -178,8 +178,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "RestofTests" -Tag "Rest" { - + Describe "Publication commands" { Context "Get-DbaReplPublisher works" { BeforeAll { # if distribution is disabled - enable it @@ -225,7 +224,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "gets publications for a specific database" { Get-DbaReplPublication -Database ReplDb | Should -Not -BeNullOrEmpty - (Get-DbaRepPublication -Database ReplDb).Database | ForEach-Object { $_ | Should -Be 'ReplDb' } + (Get-DbaRepPublication -Database ReplDb).DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } } It "gets publications for a specific type" { @@ -233,13 +232,11 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } } - It "works with piping" { + It "works with piping" -skip { Connect-DbaInstance | Get-DbaReplPublication | Should -Not -BeNullOrEmpty } } - - Context "New-DbaReplPublication works" { BeforeAll { # if replication is disabled - enable it @@ -256,54 +253,28 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $name = 'TestPub' New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { $name = 'Snappy' New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } It "New-DbaReplPublication creates a Merge publication" { $name = 'Mergey' New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).Database | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } } - - Context "Add-DbaReplArticle works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - # we need some publications too - $name = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - } - $name = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name - } - $name = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name - } - } - } } - Describe "Article tests" -Tag "ReplArticle" { + Describe "Article commands" { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -356,24 +327,34 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Context "Add-DbaReplArticle works" { + BeforeAll { + $articleName = 'ReplicateMe' + } It "Add-DbaReplArticle adds an article to a Transactional publication" { $pubName = 'TestPub' - Add-DbaReplArticle -Database ReplDb -Name $articleName -PublicationName $pubName - - #TODO: waiting on Get-DbaReplArticle + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $articleName } - It "New-DbaReplPublication creates a Snapshot publication" { - $pubname = 'TestSnap' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw - #TODO: waiting on Get-DbaReplArticle + It "Add-DbaReplArticle adds an article to a Snapshot publication" { + $pubname = 'TestSnap' + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $articleName } - It "New-DbaReplPublication creates a Merge publication" { + It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -PublicationName $pubname -EnableException } | Should -not -throw - - #TODO: waiting on Get-DbaReplArticle + { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $articleName } } @@ -397,17 +378,127 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - It "Get-DbaReplArticle get the article from a Transactional publication" { + It "Get-DbaReplArticle gets the article from a Transactional publication" { $PublicationName = 'TestTrans' $Name = "ReplicateMe" - Add-DbaReplArticle -Database ReplDb -PublicationName $PublicationName -Name $Name + Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName $TransArticle.Count | Should -Be 1 $TransArticle.Name | Should -Be $Name $TransArticle.PublicationName | Should -Be $PublicationName } + + It "Piping from Connect-DbaInstance works" -skip { + Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + + + + It "Get-DbaReplArticle gets the article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" + Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + + $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName + $TransArticle.Count | Should -Be 1 + $TransArticle.Name | Should -Be $Name + $TransArticle.PublicationName | Should -Be $PublicationName + } + + It "Piping from Connect-DbaInstance works" -skip { + Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + } + } + + Context "Remove-DbaReplArticle works" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + } + + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubname = 'TestTrans' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } + + It "Remove-DbaReplArticle removes an article from a Snapshot publication" { + $pubname = 'TestSnap ' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } + + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubname = 'TestMerge' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } + } + + Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } } + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" + + $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + $article | Should -BeNullOrEmpty + } } } From 0d6af7dc544c97f7bcac6ebf0bcba9bbe498eb5c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:44:45 +0100 Subject: [PATCH 127/226] test fix --- tests/gh-actions-repl.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 767e3c0d1f..9930ea05a7 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -464,7 +464,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $article | Should -BeNullOrEmpty } - It "Remove-DbaReplArticle removes an article from a Transactional publication" { + It "Remove-DbaReplArticle removes an article from a Merge publication" { $pubname = 'TestMerge' $Name = "ReplicateMe" $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name From 72beb49abbc9612b7973b2431f768b25bb299121 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 11:53:03 +0100 Subject: [PATCH 128/226] add logging --- tests/gh-actions-repl.ps1 | 171 +++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 93 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 9930ea05a7..438bd88c81 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -22,7 +22,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' } - Describe "Enable\Disable Functions" -Tag ReplSetup { + Describe "Publishing\Distribution Functions" -Tag ReplSetup { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -179,24 +179,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Describe "Publication commands" { - Context "Get-DbaReplPublisher works" { - BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - } - It "gets a publisher" { - (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" - } - - } Context "Get-DbaReplPublication works" { BeforeAll { @@ -410,95 +393,97 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty } } - } - Context "Remove-DbaReplArticle works" -Tag ArtTestGet { - BeforeAll { - # we need some articles too remove - $article = 'ReplicateMe' + Context "Remove-DbaReplArticle works" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } - $pubname = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot -EnableException)) { + write-hose 'creating snapshot publication' + New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname -EnableException + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException)) { + # write-host 'adding article to snapshot publication' + Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException + } - $pubname = 'TestMerge' - if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } - } + } - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $pubname = 'TestTrans' - $Name = "ReplicateMe" - $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $rm.IsRemoved | Should -Be $true - $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty - } + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubname = 'TestTrans' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } - It "Remove-DbaReplArticle removes an article from a Snapshot publication" { - $pubname = 'TestSnap ' - $Name = "ReplicateMe" - $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $rm.IsRemoved | Should -Be $true - $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty - } + It "Remove-DbaReplArticle removes an article from a Snapshot publication" { + $pubname = 'TestSnap ' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } - It "Remove-DbaReplArticle removes an article from a Merge publication" { - $pubname = 'TestMerge' - $Name = "ReplicateMe" - $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $rm.IsRemoved | Should -Be $true - $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty + It "Remove-DbaReplArticle removes an article from a Merge publication" { + $pubname = 'TestMerge' + $Name = "ReplicateMe" + $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $rm.IsRemoved | Should -Be $true + $rm.Status | Should -Be 'Removed' + $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $article | Should -BeNullOrEmpty + } } - } - Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { - BeforeAll { - # we need some articles too remove - $article = 'ReplicateMe' + Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { + BeforeAll { + # we need some articles too remove + $article = 'ReplicateMe' - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } } - } - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $PublicationName = 'TestTrans' - $Name = "ReplicateMe" + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $PublicationName = 'TestTrans' + $Name = "ReplicateMe" - $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false - $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } - $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name - $article | Should -BeNullOrEmpty + $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + $article | Should -BeNullOrEmpty + } } } } From b78d274165f7530b02b0bc323ed6526d37dd1c31 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 12:04:07 +0100 Subject: [PATCH 129/226] fixed now? --- tests/gh-actions-repl.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 438bd88c81..0ab9a7bbdf 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -325,7 +325,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Add-DbaReplArticle adds an article to a Snapshot publication" { $pubname = 'TestSnap' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName @@ -333,7 +333,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -SqlInstance mssql1 -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName @@ -341,7 +341,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Get-DbaReplArticle works" -Tag ArtTestGet { + Context "Get-DbaReplArticle works" { BeforeAll { # we need some articles too remove $article = 'ReplicateMe' @@ -394,7 +394,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Remove-DbaReplArticle works" -Tag ArtTestGet { + Context "Remove-DbaReplArticle works" { BeforeAll { # we need some articles too remove $article = 'ReplicateMe' @@ -459,7 +459,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Remove-DbaReplArticle works with piping" -Tag ArtTestGet { + Context "Remove-DbaReplArticle works with piping" { BeforeAll { # we need some articles too remove $article = 'ReplicateMe' @@ -485,5 +485,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $article | Should -BeNullOrEmpty } } + + Context "Get-DbaReplArticleColumn works" { + # TODO: + } } } From b393e206a185194cfce29de22e53db9b7cbf8869 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 1 Jun 2023 12:16:18 +0100 Subject: [PATCH 130/226] tests --- tests/gh-actions-repl.ps1 | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 0ab9a7bbdf..e42646de12 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -409,17 +409,15 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } $pubname = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot -EnableException)) { - write-hose 'creating snapshot publication' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname -EnableException + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException)) { - # write-host 'adding article to snapshot publication' - Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article -EnableException + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article } $pubname = 'TestMerge' - if (-not (Get-DbaReplPublication $pubname $name -Type Merge)) { + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { @@ -439,7 +437,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Remove-DbaReplArticle removes an article from a Snapshot publication" { - $pubname = 'TestSnap ' + $pubname = 'TestSnap' $Name = "ReplicateMe" $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name $rm.IsRemoved | Should -Be $true From d6793d8cdfe8f2db08f6f38406b65d963aad84db Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:27:35 +0100 Subject: [PATCH 131/226] add more Add-DbaReplArticle tests --- tests/gh-actions-repl.ps1 | 125 +++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index e42646de12..15137eab31 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -19,7 +19,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Import-Module ./dbatools.psd1 -Force $null = New-DbaDatabase -Name ReplDb - $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) )' + $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' + } Describe "Publishing\Distribution Functions" -Tag ReplSetup { @@ -280,7 +281,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name } - $articleName = 'ReplicateMe' + $article = 'ReplicateMe' + $article2 = 'ReplicateMeToo' } Context "New-DbaReplCreationScriptOptions works" { @@ -309,89 +311,130 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Add-DbaReplArticle works" { + Context "Add-DbaReplArticle works" -tag test{ BeforeAll { - $articleName = 'ReplicateMe' + # remove all articles + $null = Get-DbaReplArticle -Database ReplDb | Remove-DbaReplArticle -Confirm:$false } It "Add-DbaReplArticle adds an article to a Transactional publication" { $pubName = 'TestPub' - { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $article + } + + It "Add-DbaReplArticle adds an article to a Snapshot publication and specifies create script options" { + $pubname = 'TestPub' + $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics + { Add-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubname -CreationScriptOptions $cso -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $articleName + $art.Name | Should -Be $article2 } It "Add-DbaReplArticle adds an article to a Snapshot publication" { $pubname = 'TestSnap' - { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $articleName + $art.Name | Should -Be $article } + + It "Add-DbaReplArticle adds an article to a Snapshot publication with a filter" { + $pubName = 'TestSnap' + { Add-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName -Filter "col1 = 'test'" -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName + $art | Should -Not -BeNullOrEmpty + $art.PublicationName | Should -Be $pubName + $art.Name | Should -Be $article2 + $art.FilterClause | Should -Be "col1 = 'test'" + } + It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $articleName + $art.Name | Should -Be $article } } Context "Get-DbaReplArticle works" { BeforeAll { - # we need some articles too remove + # we need some articles too get $article = 'ReplicateMe' + $article2 = 'ReplicateMeToo' # we need some publications too - $name = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $name -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubName } - $name = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article } - $name = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article2 } - } - It "Get-DbaReplArticle gets the article from a Transactional publication" { - $PublicationName = 'TestTrans' - $Name = "ReplicateMe" - Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + } - $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName - $TransArticle.Count | Should -Be 1 - $TransArticle.Name | Should -Be $Name - $TransArticle.PublicationName | Should -Be $PublicationName + It "Get-DbaReplArticle gets all the articles from a server" { + $getArt = Get-DbaReplArticle + $getArt | Should -Not -BeNullOrEmpty + $t | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } } - It "Piping from Connect-DbaInstance works" -skip { - Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + It "Get-DbaReplArticle gets all the articles from a particular database on a server" { + $getArt = Get-DbaReplArticle -Database ReplDb + $getArt | Should -Not -BeNullOrEmpty + $getArt | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } + $getArt | ForEach-Object { $_.DatabaseName | Should -Be 'ReplDb' } } + It "Get-DbaReplArticle gets all the articles from a specific publication" { + $pubName = 'TestSnap' + $arts = $article, $article2 + $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName + $getArt.Count | Should -Be 2 + $getArt.Name | Should -Be $arts + $getArt | Foreach-Object {$_.PublicationName | Should -Be $pubName } + } - It "Get-DbaReplArticle gets the article from a Transactional publication" { - $PublicationName = 'TestTrans' + It "Get-DbaReplArticle gets a certain article from a specific publication" { + $pubName = 'TestTrans' $Name = "ReplicateMe" - Add-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name - $TransArticle = Get-DbaReplArticle -Database ReplDb -Type Transactional -Publication $PublicationName - $TransArticle.Count | Should -Be 1 - $TransArticle.Name | Should -Be $Name - $TransArticle.PublicationName | Should -Be $PublicationName + $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $Name + $getArt.Count | Should -Be 1 + $getArt.Name | Should -Be $Name + $getArt.PublicationName | Should -Be $pubName } It "Piping from Connect-DbaInstance works" -skip { Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty } + } Context "Remove-DbaReplArticle works" { From 8c628898562b3ed8bc42274e959f63f9e4d961a0 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:28:02 +0100 Subject: [PATCH 132/226] add examples, tidy up --- public/Add-DbaReplArticle.ps1 | 12 +++++++++--- public/Get-DbaReplArticle.ps1 | 4 +--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index d0343cb437..d642b8d6e0 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -68,7 +68,14 @@ function Add-DbaReplArticle { .EXAMPLE - PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Pubs -PublicationName TestPub -Name publishers -Filter "city = 'seattle'" + PS C:\> $article = @{ + SqlInstance = "mssql1" + Database = "pubs" + PublicationName = "testPub" + Name = "publishers" + Filter = "city = 'seattle'" + } + PS C:\> Add-DbaReplArticle @article -EnableException Adds the publishers table to the TestPub publication from mssql1.Pubs with a horizontal filter of only rows where city = 'seattle. @@ -81,7 +88,7 @@ function Add-DbaReplArticle { Name = 'stores' CreationScriptOptions = $cso } - Add-DbaReplArticle @article -EnableException + PS C:\> Add-DbaReplArticle @article -EnableException Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set includes default options. @@ -106,7 +113,6 @@ function Add-DbaReplArticle { [String]$Filter, - #TODO: Build a New-DbaReplArticleOptions function [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, [Switch]$EnableException diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 4462f09851..767b804da5 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -6,7 +6,7 @@ function Get-DbaReplArticle { .DESCRIPTION This function locates and enumerates articles' information. - Can specify a database, publication or article name or publication type. + Can specify a database, publication or article name. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -71,8 +71,6 @@ function Get-DbaReplArticle { [PSCredential]$SqlCredential, [object[]]$Database, [object[]]$Publication, - [ValidateSet("Transactional", "Merge", "Snapshot")] - [String]$Type, [string[]]$Name, [switch]$EnableException ) From fb934e00372435bff0b1297b9ae2d4a03b8afc33 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:28:10 +0100 Subject: [PATCH 133/226] remove a bug with piping --- public/Remove-DbaReplArticle.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 9e28049a0a..0f85065673 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -109,21 +109,22 @@ function Remove-DbaReplArticle { Stop-Function -Message "You must specify either SqlInstance or InputObject" return } - if ($SqlInstance) { + + if ($InputObject) { + $articles += $InputObject + } else { $params = $PSBoundParameters $null = $params.Remove('InputObject') $null = $params.Remove('WhatIf') $null = $params.Remove('Confirm') $articles = Get-DbaReplArticle @params - } else { - $articles += $InputObject } } end { # We have to delete in the end block to prevent "Collection was modified; enumeration operation may not execute." if directly piped from Get-DbaReplArticle. foreach ($art in $articles) { - if ($PSCmdlet.ShouldProcess($art.Name, "Removing the article $($art.SourceObjectOwner).$($art.SourceObjectName) from the $($art.PublicationName) publication on $($art.SqlServerName)")) { + if ($PSCmdlet.ShouldProcess($art.Name, "Removing the article $($art.SourceObjectOwner).$($art.SourceObjectName) from the $($art.PublicationName) publication on $($art.SqlInstance)")) { $output = [pscustomobject]@{ ComputerName = $art.ComputerName InstanceName = $art.InstanceName From 1b2ddc382e72c4d56c7ded4cf24728a22b3087e7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:29:02 +0100 Subject: [PATCH 134/226] spelling word added --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7744d49149..c44f3d5962 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,6 +57,7 @@ "Kokkinos", "Kravtsov", "Mikey", + "mssql", "nchar", "niphlod", "ntext", From 608fc9e9956be6c196034f376e2b702d9fe66bc1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:32:49 +0100 Subject: [PATCH 135/226] typos --- tests/gh-actions-repl.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 15137eab31..513d14d372 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -401,7 +401,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Get-DbaReplArticle gets all the articles from a server" { $getArt = Get-DbaReplArticle $getArt | Should -Not -BeNullOrEmpty - $t | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } + $getArt | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } } It "Get-DbaReplArticle gets all the articles from a particular database on a server" { From 3a78f7fc3256fd01f02e54ecb56a1c327121e842 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:43:37 +0100 Subject: [PATCH 136/226] more examples, cleaned up help --- public/New-DbaReplPublication.ps1 | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 7f0464f672..572e21e7d4 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -19,17 +19,14 @@ function New-DbaReplPublication { For MFA support, please use Connect-DbaInstance. .PARAMETER Database - The database that will be replicated. + The database that contains the articles to be replicated. .PARAMETER PublicationName - The name of the replication publication + The name of the replication publication. .PARAMETER Type The flavour of replication. - - Currently supported 'Transactional' - - Coming soon 'Snapshot', 'Merge' + Options are Transactional, Snapshot, Merge .PARAMETER LogReaderAgentCredential Used to provide the credentials for the Microsoft Windows account under which the Log Reader Agent runs @@ -37,7 +34,7 @@ function New-DbaReplPublication { Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - TODO: Implement & test this + TODO: test this .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -55,7 +52,7 @@ function New-DbaReplPublication { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -66,6 +63,15 @@ function New-DbaReplPublication { Creates a transactional publication called PubFromPosh for the Northwind database on mssql1 + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName snapPub -Type Snapshot + + Creates a snapshot publication called snapPub for the pubs database on mssql1 + + .EXAMPLE + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName mergePub -Type Merge + + Creates a merge publication called mergePub for the pubs database on mssql1 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( @@ -74,6 +80,7 @@ function New-DbaReplPublication { [PSCredential]$SqlCredential, + [parameter(Mandatory)] [String]$Database, [parameter(Mandatory)] From 245aecb86cdec493b814081e95b8fb0f256fcd62 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 10:50:47 +0100 Subject: [PATCH 137/226] tidy help and examples --- public/Disable-DbaReplPublishing.ps1 | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 7a2b95376b..5b7676e4da 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -1,10 +1,10 @@ function Disable-DbaReplPublishing { <# .SYNOPSIS - Disables publication for the target SQL instances. + Disables publishing for the target SQL instances. .DESCRIPTION - Disables publication for the target SQL instances. + Disables publishing for the target SQL instances. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -17,13 +17,13 @@ function Disable-DbaReplPublishing { For MFA support, please use Connect-DbaInstance. .PARAMETER Force - Boolean value that specifies whether or not replication objects are removed from the server, - even if a remote Distributor cannot be reached. + A Boolean value that specifies whether the Publisher is uninstalled from the Distributor without verifying that + Publisher has also uninstalled the Distributor, if the Publisher is on a separate server. - If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or - not dependent publishing and distribution objects are uninstalled. + If true, all the replication objects associated with the Publisher are dropped even if the Publisher is on a remote server + that cannot be reached. - If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + If false, replication first verifies that the remote Publisher has uninstalled the Distributor. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -41,7 +41,7 @@ function Disable-DbaReplPublishing { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -57,8 +57,9 @@ function Disable-DbaReplPublishing { PS C:\> Disable-DbaReplPublishing -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force Disables replication distribution for the mssql1 and mssql2 instances using a sql login. - Specifies force so the publishing and Distributor configuration at the current server is uninstalled - regardless of whether or not dependent publishing and distribution objects are uninstalled. + + Specifies force so all the replication objects associated with the Publisher are dropped even + if the Publisher is on a remote server that cannot be reached. #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] @@ -81,7 +82,6 @@ function Disable-DbaReplPublishing { if ($replServer.IsPublisher) { try { if ($PSCmdlet.ShouldProcess($instance, "Disabling publishing on $instance")) { - #Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess # uninstall distribution $replServer.DistributionPublishers.Remove($Force) } @@ -95,12 +95,6 @@ function Disable-DbaReplPublishing { } else { Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category InvalidData } - - #$replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force - #$replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force - #$replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force - #Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, Status, WorkingDirectory, DistributionDatabase, DistributionPublications, PublisherType, Name - } } } From 675fb9190e623a82adbc506830e4607e0fc7e238 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 11:50:32 +0100 Subject: [PATCH 138/226] tidy help --- public/Disable-DbaReplDistributor.ps1 | 14 +++++++------- public/Disable-DbaReplPublishing.ps1 | 5 ++++- public/Enable-DbaReplDistributor.ps1 | 5 +++-- public/Enable-DbaReplPublishing.ps1 | 10 +++++----- public/Get-DbaReplDistributor.ps1 | 1 - public/Get-DbaReplServer.ps1 | 3 --- public/Remove-DbaReplPublication.ps1 | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 0f9e61ff37..34848f0af9 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -20,10 +20,11 @@ function Disable-DbaReplDistributor { Boolean value that specifies whether or not replication objects are removed from the server, even if a remote Distributor cannot be reached. - If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or - not dependent publishing and distribution objects are uninstalled. + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of + whether or not dependent publishing and distribution objects are uninstalled. - If false, all dependent publishing and distribution objects are dropped before the Distributor is uninstalled. + If false, the publisher and distribution databases must already be uninstalled, and no local databases + are enabled for publishing. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -41,7 +42,7 @@ function Disable-DbaReplDistributor { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -66,8 +67,7 @@ function Disable-DbaReplDistributor { [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - - [switch]$force, + [switch]$Force, [switch]$EnableException ) process { @@ -85,7 +85,7 @@ function Disable-DbaReplDistributor { # remove any connections to the distribution database Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess # uninstall distribution - $replServer.UninstallDistributor($force) + $replServer.UninstallDistributor($Force) } } catch { Stop-Function -Message "Unable to disable replication distribution" -ErrorRecord $_ -Target $instance -Continue diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 5b7676e4da..a3b2104871 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -66,8 +66,11 @@ function Disable-DbaReplPublishing { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, - [switch]$force, + + [switch]$Force, + [switch]$EnableException ) process { diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 020b734ec1..93c025c8b2 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -37,7 +37,7 @@ function Enable-DbaReplDistributor { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -76,7 +76,8 @@ function Enable-DbaReplDistributor { $distributionDb = New-Object Microsoft.SqlServer.Replication.DistributionDatabase $distributionDb.ConnectionContext = $replServer.ConnectionContext $distributionDb.Name = $DistributionDatabase - # lots more properties to add as params + + #TODO: lots more properties to add as params $replServer.InstallDistributor($null, $distributionDb) } } catch { diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 444f93eae0..39ec195e48 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -21,7 +21,7 @@ function Enable-DbaReplPublishing { .PARAMETER PublisherSqlLogin If this is used the PublisherSecurity will be set to use this. - If not specified WindowsAuthentication can will used - this is the default, and recommended method. + If not specified WindowsAuthentication will be used - this is the default, and recommended method. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -39,7 +39,7 @@ function Enable-DbaReplPublishing { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -56,7 +56,7 @@ function Enable-DbaReplPublishing { [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - $SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? + [string]$SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? can we get the default? [PSCredential]$PublisherSqlLogin, [switch]$EnableException ) @@ -93,7 +93,7 @@ function Enable-DbaReplPublishing { } else { Write-Message -Level Verbose -Message "Configuring with WindowsAuth for PublisherSecurity" - $distPublisher.PublisherSecurity.WindowsAuthentication = $true # TODO: test with windows auth + $distPublisher.PublisherSecurity.WindowsAuthentication = $true } Write-Message -Level Debug -Message $distPublisher @@ -108,7 +108,7 @@ function Enable-DbaReplPublishing { } $replServer.Refresh() - $replServer # TODO: Standard output + $replServer } } diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index 58a76e0e69..040f1af13a 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -67,7 +67,6 @@ function Get-DbaReplDistributor { } Write-Message -Level Verbose -Message "Getting publisher for $server" - Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index e9ac8f5897..c82da3b2d1 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -6,9 +6,6 @@ function Get-DbaReplServer { .DESCRIPTION Gets a replication server object - All replication commands need SQL Server Management Studio installed and are therefore currently not supported. - Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 - .PARAMETER SqlInstance The target SQL Server instance or instances diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index f6183dca39..1353d173eb 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -109,7 +109,7 @@ function Remove-DbaReplPublication { $pubDatabase.EnabledTransPublishing = $false } } - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure + # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure } elseif ($pub.Type -eq 'Merge') { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication From ac5804095a1c4b1c0fda96f02237b317797ebbb3 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 11:50:48 +0100 Subject: [PATCH 139/226] add check for publishing and log reader job not for merge --- public/New-DbaReplPublication.ps1 | 43 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 572e21e7d4..4edf87db81 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -98,6 +98,11 @@ function New-DbaReplPublication { foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + + if (-not $replServer.IsPublisher) { + Stop-Function -Message "Instance $instance is not a publisher, run Enable-DbaReplPublishing to set this up" -Target $instance -Continue + } + } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -106,7 +111,8 @@ function New-DbaReplPublication { try { if ($PSCmdlet.ShouldProcess($instance, "Creating publication on $instance")) { - #TODO: could replace this with call to Connect-ReplicationDB + + $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $replServer.ConnectionContext $pubDatabase.Name = $Database @@ -118,30 +124,29 @@ function New-DbaReplPublication { Write-Message -Level Verbose -Message "Enable trans publishing publication on $instance.$Database" $pubDatabase.EnabledTransPublishing = $true $pubDatabase.CommitPropertyChanges() + # log reader agent is only needed for transactional and snapshot replication. + if (-not $pubDatabase.LogReaderAgentExists) { + Write-Message -Level Verbose -Message "Create log reader agent job for $Database on $instance" + if ($LogReaderAgentCredential) { + #TODO: Test this + $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName + $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password + } + + #(Optional) Set the SqlStandardLogin and SqlStandardPassword or + # SecureSqlStandardPassword fields of LogReaderAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. + + $pubDatabase.CreateLogReaderAgent() + } else { + Write-Message -Level Verbose -Message "Log reader agent job already exists for $Database on $instance" + } + } elseif ($Type -eq 'Merge') { Write-Message -Level Verbose -Message "Enable merge publishing publication on $instance.$Database" $pubDatabase.EnabledMergePublishing = $true $pubDatabase.CommitPropertyChanges() } - if (-not $pubDatabase.LogReaderAgentExists) { - #TODO: if this needed for merge? - - Write-Message -Level Verbose -Message "Create Log Read Agent job for $Database on $instance" - if ($LogReaderAgentCredential) { - #TODO: Test this - $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName - $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password - } - - #(Optional) Set the SqlStandardLogin and SqlStandardPassword or - # SecureSqlStandardPassword fields of LogReaderAgentPublisherSecurity when using SQL Server Authentication to connect to the Publisher. - - $pubDatabase.CreateLogReaderAgent() - } else { - Write-Message -Level Verbose -Message "Log Read Agent job already exists for $Database on $instance" - } - if ($Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication From 8093aafe322a6c168b95434d544706672d0acaf9 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 11:50:55 +0100 Subject: [PATCH 140/226] added tests --- tests/gh-actions-repl.ps1 | 59 +++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 513d14d372..b06011b3fc 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -23,7 +23,29 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Describe "Publishing\Distribution Functions" -Tag ReplSetup { + Describe "General commands" { + + Context "Get-DbaReplServer works" -tag test { + + It "Doesn't throw errors" { + { Get-DbaReplServer -EnableException } | Should -Not -Throw + } + + It "Returns a ReplicationObject" { + (Get-DbaReplServer).GetType().BaseType | Should -Be "Microsoft.SqlServer.Replication.ReplicationObject" + } + + It "Gets a replication server" { + (Get-DbaReplServer).SqlInstance | Should -Be 'mssql1' + (Get-DbaReplServer).DistributorInstalled | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).DistributorAvailable | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).IsDistributor | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).IsPublisher | Should -Not -BeNullOrEmpty + } + } + } + + Describe "Publishing\Distribution commands" { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -35,6 +57,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Enable-DbaReplDistributor } + It "gets a distributor without error" { + { Get-DbaReplDistributor -EnableException } | Should -Not -Throw + } + It "gets a distributor" { (Get-DbaReplDistributor).IsDistributor | Should -Be $true } @@ -148,7 +174,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is enabled" { - Enable-DbaReplPublishing -EnableException + { Enable-DbaReplPublishing -EnableException } | Should -Not -Throw (Get-DbaReplServer).IsPublisher | Should -Be $true } } @@ -173,7 +199,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "publishing is disabled" { - Disable-DbaReplPublishing -EnableException + { Disable-DbaReplPublishing -EnableException } | Should -Not -Throw (Get-DbaReplServer).IsPublisher | Should -Be $false } } @@ -181,7 +207,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Describe "Publication commands" { - Context "Get-DbaReplPublication works" { BeforeAll { # if distribution is disabled - enable it @@ -235,26 +260,29 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "New-DbaReplPublication creates a Transactional publication" { $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + { New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { $name = 'Snappy' - New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name + { New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } It "New-DbaReplPublication creates a Merge publication" { $name = 'Mergey' - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name + { New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' } + } + Context "Remove-DbaReplPublication works" { + # TODO: } } @@ -311,7 +339,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Add-DbaReplArticle works" -tag test{ + Context "Add-DbaReplArticle works" { BeforeAll { # remove all articles $null = Get-DbaReplArticle -Database ReplDb | Remove-DbaReplArticle -Confirm:$false @@ -531,4 +559,19 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # TODO: } } + + Describe "Subscription commands" { + BeforeAll { + + } + + Context "New-DbaReplSubscription works" { + # TODO: + } + + Context "Remove-DbaReplSubscription works" { + # TODO: + } + + } } From 675383cca00cb99a7eb4d7c7d790dc40259cb02a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 12:50:46 +0100 Subject: [PATCH 141/226] remove hard coded default for snapshot --- public/Enable-DbaReplPublishing.ps1 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 39ec195e48..b184208d0f 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -17,7 +17,9 @@ function Enable-DbaReplPublishing { For MFA support, please use Connect-DbaInstance. .PARAMETER SnapshotShare - The share used to access snapshot files. + The share used to access snapshot files. + + The default is the ReplData folder within the InstallDataDirectory for the instance. .PARAMETER PublisherSqlLogin If this is used the PublisherSecurity will be set to use this. @@ -56,7 +58,7 @@ function Enable-DbaReplPublishing { [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - [string]$SnapshotShare = '/var/opt/mssql/ReplData', # TODO: default should handle linux\windows? can we get the default? + [string]$SnapshotShare, [PSCredential]$PublisherSqlLogin, [switch]$EnableException ) @@ -79,10 +81,11 @@ function Enable-DbaReplPublishing { $distPublisher.Name = $instance #- name of the Publisher. $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name #- the name of the database created in step 5. - #TODO: test snapshot path and warn\error? - #if (Test-DbaPath -SqlInstance mssql1 -Path $SnapshotShare) { - # Stop-Function -Message ("Snapshot path '{0}' does not exist - will attempt to create it" -f $SnapshotShare) -ErrorRecord $_ -Target $instance -Continue - #} + if (-not $PSBoundParameters.SnapshotShare) { + $SnapshotShare = Join-Path (Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential).InstallDataDirectory 'ReplData' + Write-Message -Level Verbose -Message ('No snapshot share specified, using default of {0}' -f $SnapshotShare) + } + $distPublisher.WorkingDirectory = $SnapshotShare if ($PublisherSqlLogin) { From 4af3054410626856681762209e96938270f77104 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 16:45:43 +0100 Subject: [PATCH 142/226] add get-replsubscription --- dbatools.psd1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbatools.psd1 b/dbatools.psd1 index c8d63ede33..6bc77af190 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -744,7 +744,8 @@ 'Remove-DbaReplPublication', 'New-DbaReplSubscription', 'Remove-DbaReplSubscription', - 'New-DbaReplCreationScriptOptions' + 'New-DbaReplCreationScriptOptions', + 'Get-DbaReplSubscription' ) # Cmdlets to export from this module From 84f4fcadc4070d55af3004f293e3e69f865789e0 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 16:46:04 +0100 Subject: [PATCH 143/226] spacing and year --- public/Add-DbaReplArticle.ps1 | 10 +-- public/Disable-DbaReplPublishing.ps1 | 3 - public/Get-DbaReplArticle.ps1 | 2 +- public/Get-DbaReplArticleColumn.ps1 | 91 +++++++++++++-------- public/Get-DbaReplSubscription.ps1 | 34 ++------ public/New-DbaReplCreationScriptOptions.ps1 | 1 - public/New-DbaReplPublication.ps1 | 6 -- public/New-DbaReplSubscription.ps1 | 18 +--- public/Remove-DbaReplArticle.ps1 | 14 +--- public/Remove-DbaReplPublication.ps1 | 6 +- public/Remove-DbaReplSubscription.ps1 | 11 +-- 11 files changed, 73 insertions(+), 123 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index d642b8d6e0..a130c04c4f 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -53,7 +53,7 @@ function Add-DbaReplArticle { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/define-an-article?view=sql-server-ver16#RMOProcedure @@ -97,24 +97,16 @@ function Add-DbaReplArticle { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [parameter(Mandatory)] [String]$Database, - [parameter(Mandatory)] [String]$Publication, - [String]$Schema = 'dbo', - [parameter(Mandatory)] [String]$Name, - [String]$Filter, - [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, - [Switch]$EnableException ) process { diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index a3b2104871..eaba0e2b30 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -66,11 +66,8 @@ function Disable-DbaReplPublishing { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [switch]$Force, - [switch]$EnableException ) process { diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 767b804da5..b6774e0086 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -37,7 +37,7 @@ function Get-DbaReplArticle { Author: Cláudio Silva (@claudioessilva), claudioessilva.eu Website: https://dbatools.io - Copyright: (c) 2018 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 index 46ec46bd52..592bdf1378 100644 --- a/public/Get-DbaReplArticleColumn.ps1 +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -1,10 +1,10 @@ function Get-DbaReplArticleColumn { <# .SYNOPSIS - Gets the information about publication article columns. + Gets the information about replicated article columns. .DESCRIPTION - This function enumerates columns information for a given articles. + This function enumerates column information for given articles. .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -19,12 +19,9 @@ function Get-DbaReplArticleColumn { .PARAMETER Database Specifies one or more database(s) to process. If unspecified, all databases will be processed. - .PARAMETER PublicationName + .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. - .PARAMETER PublicationType - Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot - .PARAMETER Article Specifies one or more article(s) to process. If unspecified, all articles will be processed. @@ -41,17 +38,37 @@ function Get-DbaReplArticleColumn { Author: Cláudio Silva (@claudioessilva), claudioessilva.eu Website: https://dbatools.io - Copyright: (c) 2018 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK https://dbatools.io/Get-DbaReplArticleColumn .EXAMPLE - PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs -Publication PubName -PublicationType Transactional -Article sales + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 + + Retrieve information of all replicated columns in any publications on server sqlserver2019. + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs + + Retrieve information of all replicated columns in any publications from the pubs database on server sqlserver2019. + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Publication test + + Retrieve information of all replicated columns in the test publication on server sqlserver2019. + + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Database pubs -Publication PubName -Article sales Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + .EXAMPLE + PS C:\> Get-DbaReplArticleColumn -SqlInstance sqlserver2019 -Column state + + Retrieve information for the state column in any publication from any database on server sqlserver2019. + #> [CmdletBinding()] param ( @@ -61,43 +78,45 @@ function Get-DbaReplArticleColumn { [object[]]$Database, [parameter(ValueFromPipeline)] [object[]]$Publication, - [String]$PublicationType, # Snapshot, Transactional, Merge [string[]]$Article, [string[]]$Column, [switch]$EnableException ) - begin { - #TODO - Still needed? - Add-ReplicationLibrary - } process { if (Test-FunctionInterrupt) { return } - $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -PublicationType $PublicationType -Article $Article + $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -Name $Article foreach ($art in $articles) { - $columns = $art.ListReplicatedColumns() - - if ($Column) { - $columns = $columns | Where-Object { $_ -In $Column } - } - - foreach ($col in $columns) { - - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $art.ComputerName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $art.InstanceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $art.SqlInstance - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleName -Value $art.Name - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleId -Value $art.ArticleId - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Description -Value $art.Description - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Type -Value $art.Type - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name VerticalPartition -Value $art.VerticalPartition - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectOwner -Value $art.SourceObjectOwner - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectName -Value $art.SourceObjectName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ColumnName -Value $col - - Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, ArticleName, ArticleId, Description, ColumnName #, DestinationObjectOwner, DestinationObjectName + try { + + $columns = $art.ListReplicatedColumns() + + if ($Column) { + $columns = $columns | Where-Object { $_ -In $Column } + } + + foreach ($col in $columns) { + + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $art.ComputerName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $art.InstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $art.SqlInstance + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name DatabaseName -Value $art.DatabaseName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name PublicationName -Value $art.PublicationName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleName -Value $art.Name + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ArticleId -Value $art.ArticleId + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Description -Value $art.Description + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name Type -Value $art.Type + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name VerticalPartition -Value $art.VerticalPartition + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectOwner -Value $art.SourceObjectOwner + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SourceObjectName -Value $art.SourceObjectName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ColumnName -Value $col + + Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, ArticleName, ArticleId, ColumnName #, DestinationObjectOwner, DestinationObjectName + } + } catch { + Stop-Function -Message "Error occurred while getting article columns from $instance" -ErrorRecord $_ -Target $instance -Continue } } } -} \ No newline at end of file +} diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index e50b89e52e..81858f8674 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -32,34 +32,18 @@ function Get-DbaReplSubscription { .NOTES Tags: Replication - Author: Colin Douglas + Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2018 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/Get-DbaReplPublication + https://dbatools.io/Get-DbaReplSubscription .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008, sqlserver2012 + PS C:\> #TODO: add example - Return all publications for servers sql2008 and sqlserver2012. - - .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Database TestDB - - Return all publications on server sql2008 for only the TestDB database - - .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance sql2008 -Type Transactional - - Return all publications on server sql2008 for all databases that have Transactional publications - - .EXAMPLE - PS C:\> Get-DbaReplPublication -SqlInstance mssql1 -Name Mergey - - Returns the Mergey publications on server mssql1 #> [CmdletBinding()] param ( @@ -69,20 +53,17 @@ function Get-DbaReplSubscription { [PSCredential]$SqlCredential, [String]$Name, [Alias("PublicationType")] - [ValidateSet("Transactional", "Merge", "Snapshot")] + [ValidateSet("Push","Pull")] [object[]]$Type, [switch]$EnableException ) - begin { - Add-ReplicationLibrary - } process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { # Connect to Publisher try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $PublisherSqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -94,6 +75,9 @@ function Get-DbaReplSubscription { #TODO: finish this function + # can we get subscriptions by passing in subscription server mssql2 ... or do we need to start at the publisher + # get-publications --> subscriptions info is in there + } } diff --git a/public/New-DbaReplCreationScriptOptions.ps1 b/public/New-DbaReplCreationScriptOptions.ps1 index 23caf8b2a7..14956b98b4 100644 --- a/public/New-DbaReplCreationScriptOptions.ps1 +++ b/public/New-DbaReplCreationScriptOptions.ps1 @@ -63,7 +63,6 @@ function New-DbaReplCreationScriptOptions { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] param ( [String[]]$Options, - [switch]$NoDefaults ) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 4edf87db81..9ba9f8185b 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -77,21 +77,15 @@ function New-DbaReplPublication { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [parameter(Mandatory)] [String]$Database, - [parameter(Mandatory)] [String]$PublicationName, - [parameter(Mandatory)] [ValidateSet("Snapshot", "Transactional", "Merge")] [String]$Type, - [PSCredential]$LogReaderAgentCredential, - [Switch]$EnableException ) process { diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index c363514a49..7a2e7df162 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -41,14 +41,14 @@ function New-DbaReplSubscription { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK - https://dbatools.io/New-DbaReplPublication + https://dbatools.io/New-DbaReplSubscription .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> New-DbaReplSubscription -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh Creates a publication called PubFromPosh for the Northwind database on mssql1 @@ -57,28 +57,19 @@ function New-DbaReplSubscription { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [String]$Database, - [parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, - [PSCredential]$PublisherSqlCredential, - [String]$PublicationDatabase, - [parameter(Mandatory)] [String]$PublicationName, - [PSCredential] # this will be saved as the 'subscriber credential' in the subscription properties $SubscriptionSqlCredential, - [parameter(Mandatory)] [ValidateSet("Push", "Pull")] [String]$Type, - [Switch]$EnableException ) begin { @@ -93,8 +84,6 @@ function New-DbaReplSubscription { try { $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName - - } catch { Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue } @@ -106,7 +95,6 @@ function New-DbaReplSubscription { foreach ($instance in $SqlInstance) { try { - $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 0f85065673..da614d2a38 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -76,27 +76,15 @@ function Remove-DbaReplArticle { #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] param ( - # [parameter(Mandatory, ParameterSetName = "Default")] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - - #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Database, - - #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Publication, - [String]$Schema = 'dbo', - - #[parameter(Mandatory, ParameterSetName = "Default")] [String]$Name, - [Switch]$DropObjectOnSubscriber, - - [Parameter(ValueFromPipeline)] # , Mandatory, ParameterSetName = "input")] + [Parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Article[]]$InputObject, - [Switch]$EnableException ) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 1353d173eb..0a53e617ee 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -40,7 +40,7 @@ function Remove-DbaReplPublication { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -56,14 +56,10 @@ function Remove-DbaReplPublication { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [String]$Database, - [parameter(Mandatory)] [String]$Name, - [Switch]$EnableException ) process { diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 3c1d0dbac3..88b8a7296a 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -1,7 +1,7 @@ function Remove-DbaReplSubscription { <# .SYNOPSIS - Removes a subscription for the target SQL instances. + Removes a subscription \for the target SQL instances. .DESCRIPTION Removes a subscription for the target SQL instances. @@ -54,7 +54,7 @@ function Remove-DbaReplSubscription { Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io - Copyright: (c) 2022 by dbatools, licensed under MIT + Copyright: (c) 2023 by dbatools, licensed under MIT License: MIT https://opensource.org/licenses/MIT .LINK @@ -77,21 +77,14 @@ function Remove-DbaReplSubscription { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [PSCredential]$SqlCredential, - [parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, - [PSCredential]$PublisherSqlCredential, - [String]$PublicationDatabase, - [parameter(Mandatory)] [String]$PublicationName, - [String]$SubscriptionDatabase, - [Switch]$EnableException ) begin { From c9f7fa399b3e846b2f930ca97ae02a4459d8aaa3 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 2 Jun 2023 16:46:11 +0100 Subject: [PATCH 144/226] tests --- tests/gh-actions-repl.ps1 | 131 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 6 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index b06011b3fc..39f04542c2 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -5,6 +5,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred + $PSDefaultParameterValues["*:SubscriptionSqlCredential1"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" @@ -25,7 +26,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Describe "General commands" { - Context "Get-DbaReplServer works" -tag test { + Context "Get-DbaReplServer works" { It "Doesn't throw errors" { { Get-DbaReplServer -EnableException } | Should -Not -Throw @@ -554,23 +555,141 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $article | Should -BeNullOrEmpty } } + } + Describe "Article Column commands" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $article = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + } Context "Get-DbaReplArticleColumn works" { - # TODO: + It "Gets all column information for a server" { + $cols = Get-DbaReplArticleColumn + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + } + + It "Gets all column information for specific database on a server" { + $cols = Get-DbaReplArticleColumn -Database ReplDb + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + + It "Gets all column information for specific publication on a server" { + $pubname = 'TestTrans' + $cols = Get-DbaReplArticleColumn -Publication $pubname + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.PublicationName | ForEach-Object { $_ | Should -Be $pubname } + } + + It "Gets all column information for specific article on a server" { + $pubname = 'TestTrans' + $cols = Get-DbaReplArticleColumn -Publication $pubname -Article $article + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.ArticleName | ForEach-Object { $_ | Should -Be $article } + } + + It "Gets all column information for specific column on a server" { + $pubname = 'TestTrans' + $cols = Get-DbaReplArticleColumn -Publication $pubname -Column 'col1' + $cols | Should -Not -BeNullOrEmpty + $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.ColumnName | ForEach-Object { $_ | Should -Be 'col1' } + } } } Describe "Subscription commands" { BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $article = 'ReplicateMe' + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } } - Context "New-DbaReplSubscription works" { - # TODO: + Context "New-DbaReplSubscription works" -tag test -skip { + It "Adds a subscription" { + { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' -EnableException } | Should -Not -Throw + + #TODO: waiting on get-dbareplsubscription to be implemented + } } - Context "Remove-DbaReplSubscription works" { - # TODO: + Context "Remove-DbaReplSubscription works" -tag test -skip{ + BeforeEach { + #TODO: check it doesn't exist with get-dbareplsubscription + New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' + } + It "Removes a subscription" { + { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + + #TODO: waiting on get-dbareplsubscription to be implemented + } } } From 52f0163d859210cc520d1831db89a965274f82a6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 5 Jun 2023 11:07:01 +0100 Subject: [PATCH 145/226] add note about ReplicationDatabases property --- public/Get-DbaReplServer.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index c82da3b2d1..2632ab287d 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -4,7 +4,10 @@ function Get-DbaReplServer { Gets a replication server object .DESCRIPTION - Gets a replication server object + Gets a replication server object. + + Note: The ReplicationDatabases property gets the databases enabled for replication in the connected instance of Microsoft SQL Server/. + Not necessarily the databases that are actually replicated. .PARAMETER SqlInstance The target SQL Server instance or instances @@ -71,6 +74,4 @@ function Get-DbaReplServer { } } } -} - -# TODO: Replication databases are shown even if they have no pubs \ No newline at end of file +} \ No newline at end of file From 2ce1c17edd58bbe902ce77f1d32f3aefbdebcd7f Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 5 Jun 2023 13:38:23 +0100 Subject: [PATCH 146/226] change to allow piping --- public/Remove-DbaReplPublication.ps1 | 106 +++++++++++++++------------ 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 0a53e617ee..2d1050b148 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -54,50 +54,63 @@ function Remove-DbaReplPublication { #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [String]$Database, - [parameter(Mandatory)] [String]$Name, + [parameter(ValueFromPipeline)] + [Microsoft.SqlServer.Replication.Publication[]]$InputObject, [Switch]$EnableException ) + begin { + $publications = @( ) + } process { - foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } - try { - if ($PSCmdlet.ShouldProcess($instance, "Removing publication on $instance")) { - - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Name -Database $Database + if (-not $PSBoundParameters.SqlInstance -and -not $PSBoundParameters.InputObject) { + Stop-Function -Message "You must specify either SqlInstance or InputObject" + return + } - if (-not $pub) { - Write-Warning "Didn't find $Name on $Instance.$Database" - } + if ($InputObject) { + $publications += $InputObject + } else { + $params = $PSBoundParameters + $null = $params.Remove('InputObject') + $null = $params.Remove('WhatIf') + $null = $params.Remove('Confirm') + $publications = Get-DbaReplPublication @params + } + } + end { + # We have to delete in the end block to prevent "Collection was modified; enumeration operation may not execute." if directly piped from Get-DbaReplArticle. + foreach ($pub in $publications) { + if ($PSCmdlet.ShouldProcess($pub.Name, "Removing the publication $($pub.Name) on $($pub.SqlInstance)")) { + $output = [PSCustomObject]@{ + ComputerName = $pub.ComputerName + InstanceName = $pub.InstanceName + SqlInstance = $pub.SqlInstance + Database = $pub.DatabaseName + Name = $pub.Name + Type = $pub.Type + Status = $null + IsRemoved = $false + } + try { if ($pub.Type -in ('Transactional', 'Snapshot')) { - $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication - $transPub.ConnectionContext = $replServer.ConnectionContext - $transPub.DatabaseName = $Database - $transPub.Name = $Name - - if ($transPub.IsExistingObject) { - Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" - $transPub.Remove() + if ($pub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + $pub.Remove() } # If no other transactional publications exist for this database, the database can be disabled for transactional publishing - #TODO: transactional & snapshot.. or just trans? - if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Transactional, Snapshot)) { + if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Transactional, Snapshot)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase - $pubDatabase.ConnectionContext = $replServer.ConnectionContext - $pubDatabase.Name = $Database + $pubDatabase.ConnectionContext = $pub.ConnectionContext + $pubDatabase.Name = $pub.DatabaseName if (-not $pubDatabase.LoadProperties()) { - throw "Database $Database not found on $instance" + throw "Database $Database not found on $($pub.SqlInstance)" } if ($pubDatabase.EnabledTransPublishing) { @@ -105,44 +118,41 @@ function Remove-DbaReplPublication { $pubDatabase.EnabledTransPublishing = $false } } - # https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/delete-a-publication?view=sql-server-ver16#RMOProcedure } elseif ($pub.Type -eq 'Merge') { - $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication - $mergePub.ConnectionContext = $replServer.ConnectionContext - $mergePub.DatabaseName = $Database - $mergePub.Name = $Name - - if ($mergePub.IsExistingObject) { - Write-Message -Level Verbose -Message "Removing $Name from $Instance.$Database" - $mergePub.Remove() + + if ($pub.IsExistingObject) { + Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + $pub.Remove() } else { - Write-Warning "Didn't find $Name on $Instance.$Database" + Write-Warning "Didn't find $($pub.Name) on $($pub.SqlInstance).$($pub.DatabaseName)" } # If no other merge publications exist for this database, the database can be disabled for merge publishing - if(-not (Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Type Merge)) { + if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Merge)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase - $pubDatabase.ConnectionContext = $replServer.ConnectionContext - $pubDatabase.Name = $Database + $pubDatabase.ConnectionContext = $pub.ConnectionContext + $pubDatabase.Name = $pub.DatabaseName if (-not $pubDatabase.LoadProperties()) { throw "Database $Database not found on $instance" } - if($pubDatabase.EnabledTransPublishing) { + if ($pubDatabase.EnabledTransPublishing) { Write-Message -Level Verbose -Message "No merge publications on $Instance.$Database so disabling merge publishing" $pubDatabase.EnabledMergePublishing = $false } } } + $output.Status = "Removed" + $output.IsRemoved = $true + } catch { + Stop-Function -Message "Failed to remove the article from publication" -ErrorRecord $_ + $output.Status = (Get-ErrorMessage -Record $_) + $output.IsRemoved = $false } - } catch { - Stop-Function -Message ("Unable to remove publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + $output } } } -} - - - +} \ No newline at end of file From e90fcfa5cfde9a09ded4ff0fe2c3444d5d837132 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 5 Jun 2023 13:39:08 +0100 Subject: [PATCH 147/226] change publicationname --> name --- public/Get-DbaReplDistributor.ps1 | 4 -- public/Get-DbaReplPublication.ps1 | 8 +--- public/New-DbaReplPublication.ps1 | 29 ++++++-------- public/New-DbaReplSubscription.ps1 | 10 ++--- public/Remove-DbaReplArticle.ps1 | 61 ++---------------------------- 5 files changed, 18 insertions(+), 94 deletions(-) diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index 040f1af13a..646a9d1b74 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -6,10 +6,6 @@ function Get-DbaReplDistributor { .DESCRIPTION This function locates and enumerates distributor information for a given SQL Server instance. - TODO: I think we can remove this? - All replication commands need SQL Server Management Studio installed and are therefore currently not supported. - Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 - .PARAMETER SqlInstance The target SQL Server instance or instances. diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index fc1967f2e6..4e4e080488 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -6,10 +6,6 @@ function Get-DbaReplPublication { .DESCRIPTION Quickly find all transactional, merge, and snapshot publications on a server or filter by database, name or type. - TODO: is this still true? remove? - All replication commands need SQL Server Management Studio installed and are therefore currently not supported. - Have a look at this issue to get more information: https://github.com/dataplat/dbatools/issues/7428 - .PARAMETER SqlInstance The target SQL Server instance or instances. @@ -127,7 +123,6 @@ function Get-DbaReplPublication { $pubTypes = $pubTypes | Where-Object Name -in $Name } - #TODO: Check why if -Database is not passed, I can't see the articles (JP - this works for me... 🤔) foreach ($pub in $pubTypes) { if ($pub.Type -eq 'Merge') { $articles = $pub.MergeArticles @@ -145,8 +140,7 @@ function Get-DbaReplPublication { Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Subscriptions -Value $subscriptions Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles, Subscriptions - #TODO: breaking change from PublicationName to Name - #TODO: breaking change from PublicationType to Type + } } } catch { diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 9ba9f8185b..a32551d593 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -21,7 +21,7 @@ function New-DbaReplPublication { .PARAMETER Database The database that contains the articles to be replicated. - .PARAMETER PublicationName + .PARAMETER Name The name of the replication publication. .PARAMETER Type @@ -34,7 +34,7 @@ function New-DbaReplPublication { Setting LogReaderAgentProcessSecurity is not required when the publication is created by a member of the sysadmin fixed server role. In this case, the agent will impersonate the SQL Server Agent account. For more information, see Replication Agent Security Model. - TODO: test this + TODO: test LogReaderAgentCredential parameters .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -59,17 +59,17 @@ function New-DbaReplPublication { https://dbatools.io/New-DbaReplPublication .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Type Transactional + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database Northwind -Name PubFromPosh -Type Transactional Creates a transactional publication called PubFromPosh for the Northwind database on mssql1 .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName snapPub -Type Snapshot + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -Name snapPub -Type Snapshot Creates a snapshot publication called snapPub for the pubs database on mssql1 .EXAMPLE - PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -PublicationName mergePub -Type Merge + PS C:\> New-DbaReplPublication -SqlInstance mssql1 -Database pubs -Name mergePub -Type Merge Creates a merge publication called mergePub for the pubs database on mssql1 #> @@ -81,7 +81,7 @@ function New-DbaReplPublication { [parameter(Mandatory)] [String]$Database, [parameter(Mandatory)] - [String]$PublicationName, + [String]$Name, [parameter(Mandatory)] [ValidateSet("Snapshot", "Transactional", "Merge")] [String]$Type, @@ -122,7 +122,6 @@ function New-DbaReplPublication { if (-not $pubDatabase.LogReaderAgentExists) { Write-Message -Level Verbose -Message "Create log reader agent job for $Database on $instance" if ($LogReaderAgentCredential) { - #TODO: Test this $pubDatabase.LogReaderAgentProcessSecurity.Login = $LogReaderAgentCredential.UserName $pubDatabase.LogReaderAgentProcessSecurity.Password = $LogReaderAgentCredential.Password } @@ -146,7 +145,7 @@ function New-DbaReplPublication { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication $transPub.ConnectionContext = $replServer.ConnectionContext $transPub.DatabaseName = $Database - $transPub.Name = $PublicationName + $transPub.Name = $Name $transPub.Type = $Type $transPub.Create() @@ -154,7 +153,7 @@ function New-DbaReplPublication { $transPub.CreateSnapshotAgent() <# - TODO: add these in? + TODO: add SnapshotGenerationAgentProcessSecurity creds in? The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. @@ -170,14 +169,14 @@ function New-DbaReplPublication { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication $mergePub.ConnectionContext = $replServer.ConnectionContext $mergePub.DatabaseName = $Database - $mergePub.Name = $PublicationName + $mergePub.Name = $Name $mergePub.Create() # create the Snapshot Agent job $mergePub.CreateSnapshotAgent() <# - TODO: add these in? + TODO: add SnapshotGenerationAgentProcessSecurity creds in? The Login and Password fields of SnapshotGenerationAgentProcessSecurity to provide the credentials for the Windows account under which the Snapshot Agent runs. This account is also used when the Snapshot Agent makes connections to the local Distributor and for any remote connections when using Windows Authentication. @@ -190,18 +189,12 @@ function New-DbaReplPublication { to set the PublicationAttributes values for the Attributes property. #> - } - - - } } catch { Stop-Function -Message ("Unable to create publication - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } - - #TODO: What to return - + Get-DbaRepPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Name $Name } } } diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 7a2e7df162..aa6156e308 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -162,8 +162,6 @@ function New-DbaReplSubscription { $transSub.DatabaseName = $PublicationDatabase $transSub.PublicationName = $PublicationName - $transSub - #TODO: <# @@ -202,7 +200,7 @@ function New-DbaReplSubscription { 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 ($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' @@ -212,7 +210,7 @@ function New-DbaReplSubscription { } 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 ($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' @@ -265,9 +263,7 @@ function New-DbaReplSubscription { } catch { Stop-Function -Message ("Unable to create subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } - - #TODO: What to return - + #TODO: call Get-DbaReplSubscription when it's done } } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index da614d2a38..108104e475 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -7,7 +7,8 @@ function Remove-DbaReplArticle { Removes an article from a publication for the database on the target SQL instances. Dropping an article from a publication does not remove the object from the publication database or the corresponding object from the subscription database. - Use DROP <Object> to remove these objects if necessary. #TODO: add a param for this DropObjectOnSubscriber + Use DROP <Object> to remove these objects if necessary. + #TODO: add a param for this DropObjectOnSubscriber Dropping an article invalidates the current snapshot; therefore a new snapshot must be created. @@ -82,7 +83,7 @@ function Remove-DbaReplArticle { [String]$Publication, [String]$Schema = 'dbo', [String]$Name, - [Switch]$DropObjectOnSubscriber, + #[Switch]$DropObjectOnSubscriber, [Parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Article[]]$InputObject, [Switch]$EnableException @@ -148,60 +149,4 @@ function Remove-DbaReplArticle { } } } - - <# - foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } - Write-Message -Level Verbose -Message "Removing article $Name from publication $PublicationName on $instance" - - try { - if ($PSCmdlet.ShouldProcess($instance, "Removing an article from $PublicationName")) { - - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $PublicationName - - if ($pub.Type -in ('Transactional', 'Snapshot')) { - $article = New-Object Microsoft.SqlServer.Replication.TransArticle - } elseif ($pub.Type -eq 'Merge') { - $article = New-Object Microsoft.SqlServer.Replication.MergeArticle - } else { - Stop-Function -Message "Publication is not a supported type, currently only Transactional and Merge publications are supported" -ErrorRecord $_ -Target $instance -Continue - } - - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $PublicationName - $article.DatabaseName = $Database - - #TODO: change to RMO? if it has a subscription, we need to drop it first = can't work it out with RMO - if ($pub.Subscriptions) { - Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $Name, $pub.Subscriptions.SubscriberName) - $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $PublicationName, $Name, $pub.Subscriptions.SubscriberName - Invoke-DbaQuery -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -query $query - } - - if (($article.IsExistingObject)) { - $article.Remove() - } else { - Stop-Function -Message "Article doesn't exist in $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } - - if ($DropObjectOnSubscriber) { - - } - } - } catch { - Stop-Function -Message "Unable to remove article $ArticleName from $PublicationName on $instance" -ErrorRecord $_ -Target $instance -Continue - } - } - }#> - - } - - - From 54035772a059794eb62d791b0a0acbf4e9ad46fd Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 6 Jun 2023 20:05:44 +0100 Subject: [PATCH 148/226] sort out piping --- public/Remove-DbaReplPublication.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 2d1050b148..42f56722c0 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -24,6 +24,11 @@ function Remove-DbaReplPublication { .PARAMETER Name The name of the replication publication + .PARAMETER InputObject + + .PARAMETER Force + If this switch is enabled, this command will look for the REPL-LogReader SQL Agent Job for this database and if it's running, stop the job. + .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. @@ -60,6 +65,7 @@ function Remove-DbaReplPublication { [String]$Name, [parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Publication[]]$InputObject, + [Switch]$Force, [Switch]$EnableException ) begin { @@ -77,6 +83,7 @@ function Remove-DbaReplPublication { $params = $PSBoundParameters $null = $params.Remove('InputObject') $null = $params.Remove('WhatIf') + $null = $params.Remove('Force') $null = $params.Remove('Confirm') $publications = Get-DbaReplPublication @params } @@ -101,6 +108,9 @@ function Remove-DbaReplPublication { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + if ($Force) { + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob + } $pub.Remove() } @@ -123,6 +133,9 @@ function Remove-DbaReplPublication { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" + if ($Force) { + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob + } $pub.Remove() } else { Write-Warning "Didn't find $($pub.Name) on $($pub.SqlInstance).$($pub.DatabaseName)" From 1d72564b36aa71136740688b1459db70e3dbfcc2 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 6 Jun 2023 20:07:04 +0100 Subject: [PATCH 149/226] fix piping issue --- public/Get-DbaReplPublisher.ps1 | 2 +- public/Get-DbaReplServer.ps1 | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 846cdf64e6..2824f1beeb 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -53,7 +53,7 @@ function Get-DbaReplPublisher { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $server } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue } diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index 2632ab287d..b79d0ddf27 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -61,9 +61,8 @@ function Get-DbaReplServer { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $sqlCon = New-SqlConnection -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer $sqlCon - + $replServer = New-Object Microsoft.SqlServer.Replication.ReplicationServer + $replServer.ConnectionContext = $Server.ConnectionContext.SqlConnectionObject $replServer | Add-Member -Type NoteProperty -Name ComputerName -Value $server.ComputerName -Force $replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force $replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force From 243b1a12d23b355fb6c081b9bb2b5f547d1bf15a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 6 Jun 2023 20:07:19 +0100 Subject: [PATCH 150/226] tests --- tests/gh-actions-repl.ps1 | 228 +++++++++++++++++++++++++------------- 1 file changed, 154 insertions(+), 74 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 39f04542c2..0c6da59f32 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -8,20 +8,13 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SubscriptionSqlCredential1"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" - - #TODO: To be removed? - $PSDefaultParameterValues["*:-SnapshotShare"] = "/shared" $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" $global:ProgressPreference = "SilentlyContinue" - #$null = Get-XPlatVariable | Where-Object { $PSItem -notmatch "Copy-", "Migration" } | Sort-Object - # load dbatools-lib - #Import-Module dbatools-core-library Import-Module ./dbatools.psd1 -Force $null = New-DbaDatabase -Name ReplDb $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' - } Describe "General commands" { @@ -70,9 +63,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' } - It "can pipe a sql server object to it" -skip { - Connect-DbaInstance | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty - } + } Context "Get-DbaReplPublisher works" { @@ -92,9 +83,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" } - It "gets a publisher using piping" -skip { - (Connect-DbaInstance | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" - } } @@ -222,10 +210,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # create a publication $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName ('{0}-Trans' -f $Name) - New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName ('{0}-Merge' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Transactional -Name ('{0}-Trans' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Merge -Name ('{0}-Merge' -f $Name) $null = New-DbaDatabase -Name Test - New-DbaReplPublication -Database Test -Type Snapshot -PublicationName ('{0}-Snapshot' -f $Name) + New-DbaReplPublication -Database Test -Type Snapshot -Name ('{0}-Snapshot' -f $Name) } It "gets all publications" { @@ -242,9 +230,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } } - It "works with piping" -skip { - Connect-DbaInstance | Get-DbaReplPublication | Should -Not -BeNullOrEmpty - } } Context "New-DbaReplPublication works" { @@ -261,21 +246,21 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "New-DbaReplPublication creates a Transactional publication" { $name = 'TestPub' - { New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name -EnableException } | Should -Not -Throw + { New-DbaReplPublication -Database ReplDb -Type Transactional -Name $Name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' } It "New-DbaReplPublication creates a Snapshot publication" { $name = 'Snappy' - { New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $name -EnableException } | Should -Not -Throw + { New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' } It "New-DbaReplPublication creates a Merge publication" { $name = 'Mergey' - { New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $name -EnableException } | Should -Not -Throw + { New-DbaReplPublication -Database ReplDb -Type Merge -Name $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' @@ -283,7 +268,48 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Context "Remove-DbaReplPublication works" { - # TODO: + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $article = 'ReplicateMe' + + # we need some publications too + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName + } + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName + } + } + + It "Remove-DbaReplPublication removes a publication that has articles" { + $name = 'TestTrans' + { Remove-DbaReplPublication -Name $name -EnableException -Force } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty + } + + It "Remove-DbaReplPublication removes a publication that has no articles" { + $name = 'TestSnap' + { Remove-DbaReplPublication -Name $name -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty + } + } } @@ -300,15 +326,15 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications too $name = 'TestTrans' if (-not (Get-DbaReplPublication -Name $name -Type Transactional )) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $Name } $name = 'TestSnap' if (-not (Get-DbaReplPublication -Name $name -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $Name + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $Name } $name = 'TestMerge' if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $Name + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $Name } $article = 'ReplicateMe' $article2 = 'ReplicateMeToo' @@ -403,7 +429,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications too $pubName = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article @@ -411,7 +437,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubName = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -420,7 +446,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubName = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -447,7 +473,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName $getArt.Count | Should -Be 2 $getArt.Name | Should -Be $arts - $getArt | Foreach-Object {$_.PublicationName | Should -Be $pubName } + $getArt | Foreach-Object { $_.PublicationName | Should -Be $pubName } } It "Get-DbaReplArticle gets a certain article from a specific publication" { @@ -459,11 +485,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $getArt.Name | Should -Be $Name $getArt.PublicationName | Should -Be $pubName } - - It "Piping from Connect-DbaInstance works" -skip { - Connect-DbaInstance -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty - } - } Context "Remove-DbaReplArticle works" { @@ -474,7 +495,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -482,7 +503,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -490,7 +511,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -529,33 +550,9 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "Remove-DbaReplArticle works with piping" { - BeforeAll { - # we need some articles too remove - $article = 'ReplicateMe' - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $Name - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - } - } - - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $PublicationName = 'TestTrans' - $Name = "ReplicateMe" - - $rm = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name | Remove-DbaReplArticle -Confirm:$false - $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } - $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - $article = Get-DbaReplArticle -Database ReplDb -Publication $PublicationName -Name $Name - $article | Should -BeNullOrEmpty - } - } } + Describe "Article Column commands" { BeforeAll { # if replication is disabled - enable it @@ -571,7 +568,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -579,7 +576,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -587,7 +584,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -649,7 +646,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -657,7 +654,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article @@ -665,32 +662,115 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -PublicationName $pubname + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article } } - Context "New-DbaReplSubscription works" -tag test -skip { + Context "New-DbaReplSubscription works" -skip { It "Adds a subscription" { - { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' -EnableException } | Should -Not -Throw + { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -Type 'Push' -EnableException } | Should -Not -Throw #TODO: waiting on get-dbareplsubscription to be implemented } } - Context "Remove-DbaReplSubscription works" -tag test -skip{ + Context "Remove-DbaReplSubscription works" -skip{ BeforeEach { #TODO: check it doesn't exist with get-dbareplsubscription - New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -Type 'Push' + New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -Type 'Push' } It "Removes a subscription" { - { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -EnableException } | Should -Not -Throw #TODO: waiting on get-dbareplsubscription to be implemented } } } + + Describe "Piping" -tag test { + BeforeAll { + # we need some articles too get + $article = 'ReplicateMe' + $article2 = 'ReplicateMeToo' + + # we need some publications too + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article2 + } + + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + } + + # piping doesn't work well if there are PSDefaultParameterValues set + $PSDefaultParameterValues = $null + + } + + Context "Get-DbaReplPublisher works with piping" { + It "gets a publisher using piping" { + (Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + } + + Context "Get-DbaReplPublication works with piping" { + It "works with piping" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + } + + Context "Get-DbaReplDistributor works with piping" { + It "can pipe a sql server object to it" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty + } + } + + Context "Get-DbaReplArticle works with piping" { + It "Piping from Connect-DbaInstance to works" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + } + + Context "Remove-DbaReplArticle works with piping" { + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubName = 'TestTrans' + $Name = "ReplicateMe" + + $rm = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + #$article = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name + #$article | Should -BeNullOrEmpty + } + } + + Context "Remove-DbaReplPublication works with piping" { + It "Remove-DbaReplPublication removes a publication using piping" { + $name = 'TestMerge' + { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name | Remove-DbaReplPublication -EnableException } | Should -Not -Throw + #(Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name) | Should -BeNullOrEmpty + } + } + } } From 69c2558ec7f200ea055cccb67b3150a492dc7b5c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 09:56:40 +0100 Subject: [PATCH 151/226] formatting --- public/Add-DbaReplArticle.ps1 | 17 +++++++---------- public/Disable-DbaReplDistributor.ps1 | 2 +- public/Disable-DbaReplPublishing.ps1 | 2 +- public/Enable-DbaReplDistributor.ps1 | 5 +---- public/Enable-DbaReplPublishing.ps1 | 5 +---- public/Get-DbaReplArticleColumn.ps1 | 2 +- public/Get-DbaReplPublisher.ps1 | 2 +- public/Get-DbaReplSubscription.ps1 | 2 +- public/New-DbaReplPublication.ps1 | 5 +---- public/New-DbaReplSubscription.ps1 | 2 +- public/Remove-DbaReplArticle.ps1 | 2 +- public/Remove-DbaReplSubscription.ps1 | 5 +---- 12 files changed, 18 insertions(+), 33 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index a130c04c4f..6b34dfbfd7 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -134,12 +134,12 @@ function Add-DbaReplArticle { $article.Type = $ArticleOptions::TableBased } - $article.ConnectionContext = $replServer.ConnectionContext - $article.Name = $Name - $article.DatabaseName = $Database - $article.SourceObjectName = $Name - $article.SourceObjectOwner = $Schema - $article.PublicationName = $Publication + $article.ConnectionContext = $replServer.ConnectionContext + $article.Name = $Name + $article.DatabaseName = $Database + $article.SourceObjectName = $Name + $article.SourceObjectOwner = $Schema + $article.PublicationName = $Publication if ($CreationScriptOptions) { $article.SchemaOption = $CreationScriptOptions @@ -171,7 +171,4 @@ function Add-DbaReplArticle { Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $Publication -Name $Name } } -} - - - +} \ No newline at end of file diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 34848f0af9..a58695d846 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -99,4 +99,4 @@ function Disable-DbaReplDistributor { } } } -} +} \ No newline at end of file diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index eaba0e2b30..f6be3a5d0b 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -97,4 +97,4 @@ function Disable-DbaReplPublishing { } } } -} +} \ No newline at end of file diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 93c025c8b2..0ccc47f0c1 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -89,7 +89,4 @@ function Enable-DbaReplDistributor { } } -} - - - +} \ No newline at end of file diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index b184208d0f..9358988e66 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -115,7 +115,4 @@ function Enable-DbaReplPublishing { } } -} - - - +} \ No newline at end of file diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 index 592bdf1378..1bc8ac21ca 100644 --- a/public/Get-DbaReplArticleColumn.ps1 +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -119,4 +119,4 @@ function Get-DbaReplArticleColumn { } } } -} +} \ No newline at end of file diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 2824f1beeb..1249d99778 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -76,4 +76,4 @@ function Get-DbaReplPublisher { } } -} +} \ No newline at end of file diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index 81858f8674..c0c4b22226 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -53,7 +53,7 @@ function Get-DbaReplSubscription { [PSCredential]$SqlCredential, [String]$Name, [Alias("PublicationType")] - [ValidateSet("Push","Pull")] + [ValidateSet("Push", "Pull")] [object[]]$Type, [switch]$EnableException ) diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index a32551d593..9ff16ed143 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -197,7 +197,4 @@ function New-DbaReplPublication { Get-DbaRepPublication -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database -Name $Name } } -} - - - +} \ No newline at end of file diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index aa6156e308..74e183f779 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -266,4 +266,4 @@ function New-DbaReplSubscription { #TODO: call Get-DbaReplSubscription when it's done } } -} +} \ No newline at end of file diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 108104e475..1f86b64dbb 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -149,4 +149,4 @@ function Remove-DbaReplArticle { } } } -} +} \ No newline at end of file diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 88b8a7296a..b3e3f18912 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -146,7 +146,4 @@ function Remove-DbaReplSubscription { } } } -} - - - +} \ No newline at end of file From 61404d7ef260c7822016239e566581f346d47d19 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 10:27:45 +0100 Subject: [PATCH 152/226] rename test files --- ... => Export-DbaReplServerSetting.tests.ps1} | 0 tests/Get-DbaRepPublication.Tests.ps1 | 80 ------------------- tests/Get-DbaRepServer.Tests.ps1 | 19 ----- tests/Test-DbaRepLatency.Tests.ps1 | 14 ---- 4 files changed, 113 deletions(-) rename tests/{Export-DbaRepServerSetting.Tests.ps1 => Export-DbaReplServerSetting.tests.ps1} (100%) delete mode 100644 tests/Get-DbaRepPublication.Tests.ps1 delete mode 100644 tests/Get-DbaRepServer.Tests.ps1 delete mode 100644 tests/Test-DbaRepLatency.Tests.ps1 diff --git a/tests/Export-DbaRepServerSetting.Tests.ps1 b/tests/Export-DbaReplServerSetting.tests.ps1 similarity index 100% rename from tests/Export-DbaRepServerSetting.Tests.ps1 rename to tests/Export-DbaReplServerSetting.tests.ps1 diff --git a/tests/Get-DbaRepPublication.Tests.ps1 b/tests/Get-DbaRepPublication.Tests.ps1 deleted file mode 100644 index 3206515248..0000000000 --- a/tests/Get-DbaRepPublication.Tests.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") -Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan -. "$PSScriptRoot\constants.ps1" - -Describe "$commandname Unit Tests" -Tag 'UnitTests' { - Context "Validate parameters" { - [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} - [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'Type', '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 - } - } - - InModuleScope dbatools { - Context "Code Validation" { - - Mock Connect-ReplicationDB -MockWith { - [object]@{ - Name = 'TestDB' - TransPublications = @{ - Name = 'TestDB_pub' - Type = 'Transactional' - } - MergePublications = @{} - } - } - - Mock Connect-DbaInstance -MockWith { - [object]@{ - Name = "MockServerName" - ComputerName = 'MockComputerName' - Databases = @{ - Name = 'TestDB' - #state - #status - ID = 5 - ReplicationOptions = 'Published' - } - ConnectionContext = @{ - SqlConnectionObject = 'FakeConnectionContext' - } - } - } - - It "Honors the SQLInstance parameter" { - $Results = Get-DbaRepPublication -SqlInstance MockServerName - $Results.Server | Should Be "MockServerName" - } - - It "Honors the Database parameter" { - $Results = Get-DbaRepPublication -SqlInstance MockServerName -Database TestDB - $Results.Database | Should Be "TestDB" - } - - It "Honors the Type parameter" { - - Mock Connect-ReplicationDB -MockWith { - [object]@{ - Name = 'TestDB' - TransPublications = @{ - Name = 'TestDB_pub' - Type = 'Snapshot' - } - MergePublications = @{} - } - } - - $Results = Get-DbaRepPublication -SqlInstance MockServerName -Database TestDB -Type Snapshot - $Results.Type | Should Be "Snapshot" - } - - It "Stops if validate set for Type is not met" { - - { Get-DbaRepPublication -SqlInstance MockServerName -Type NotAPubType } | should Throw - - } - } - } -} \ No newline at end of file diff --git a/tests/Get-DbaRepServer.Tests.ps1 b/tests/Get-DbaRepServer.Tests.ps1 deleted file mode 100644 index 43b16dc2ce..0000000000 --- a/tests/Get-DbaRepServer.Tests.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") -Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan -. "$PSScriptRoot\constants.ps1" - -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', '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 - } - } -} -<# - Integration test should appear below and are custom to the command you are writing. - Read https://github.com/dataplat/dbatools/blob/development/contributing.md#tests - for more guidence. -#> \ No newline at end of file diff --git a/tests/Test-DbaRepLatency.Tests.ps1 b/tests/Test-DbaRepLatency.Tests.ps1 deleted file mode 100644 index de02df1513..0000000000 --- a/tests/Test-DbaRepLatency.Tests.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") -Write-Host -Object "Running $PSCommandpath" -ForegroundColor Cyan -. "$PSScriptRoot\constants.ps1" - -Describe "$commandname Unit Tests" -Tag 'UnitTests' { - Context "Validate parameters" { - [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} - [object[]]$knownParameters = 'SqlInstance', 'Database', 'SqlCredential', 'PublicationName', 'TimeToLive', 'RetainToken', 'DisplayTokenHistory', '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 - } - } -} \ No newline at end of file From 5a83896f6cd7b94c0bea2038e4dd8d0ed46e32c0 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 10:46:10 +0100 Subject: [PATCH 153/226] add unit tests --- public/Get-DbaReplSubscription.ps1 | 2 +- tests/Add-DbaReplArticle.Tests.ps1 | 17 ++++++++++++++++ tests/Disable-DbaReplDistributor.tests.ps1 | 20 +++++++++++++++++++ tests/Disable-DbaReplPublishing.tests.ps1 | 20 +++++++++++++++++++ tests/Enable-DbaReplDistributor.tests.ps1 | 20 +++++++++++++++++++ tests/Enable-DbaReplPublishing.tests.ps1 | 20 +++++++++++++++++++ tests/Get-DbaReplArticle.tests.ps1 | 20 +++++++++++++++++++ tests/Get-DbaReplArticleColumn.tests.ps1 | 20 +++++++++++++++++++ tests/Get-DbaReplPublisher.tests.ps1 | 20 +++++++++++++++++++ tests/Get-DbaReplSubscription.tests.ps1 | 20 +++++++++++++++++++ ...New-DbaReplCreationScriptOptions.tests.ps1 | 20 +++++++++++++++++++ tests/New-DbaReplPublication.tests.ps1 | 20 +++++++++++++++++++ tests/New-DbaReplSubscription.tests.ps1 | 20 +++++++++++++++++++ tests/Remove-DbaReplArticle.tests.ps1 | 20 +++++++++++++++++++ tests/Remove-DbaReplPublication.tests.ps1 | 20 +++++++++++++++++++ tests/Remove-DbaReplSubscription.tests.ps1 | 20 +++++++++++++++++++ 16 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 tests/Add-DbaReplArticle.Tests.ps1 create mode 100644 tests/Disable-DbaReplDistributor.tests.ps1 create mode 100644 tests/Disable-DbaReplPublishing.tests.ps1 create mode 100644 tests/Enable-DbaReplDistributor.tests.ps1 create mode 100644 tests/Enable-DbaReplPublishing.tests.ps1 create mode 100644 tests/Get-DbaReplArticle.tests.ps1 create mode 100644 tests/Get-DbaReplArticleColumn.tests.ps1 create mode 100644 tests/Get-DbaReplPublisher.tests.ps1 create mode 100644 tests/Get-DbaReplSubscription.tests.ps1 create mode 100644 tests/New-DbaReplCreationScriptOptions.tests.ps1 create mode 100644 tests/New-DbaReplPublication.tests.ps1 create mode 100644 tests/New-DbaReplSubscription.tests.ps1 create mode 100644 tests/Remove-DbaReplArticle.tests.ps1 create mode 100644 tests/Remove-DbaReplPublication.tests.ps1 create mode 100644 tests/Remove-DbaReplSubscription.tests.ps1 diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index c0c4b22226..b79b72d083 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -49,8 +49,8 @@ function Get-DbaReplSubscription { param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, - [object[]]$Database, [PSCredential]$SqlCredential, + [object[]]$Database, [String]$Name, [Alias("PublicationType")] [ValidateSet("Push", "Pull")] diff --git a/tests/Add-DbaReplArticle.Tests.ps1 b/tests/Add-DbaReplArticle.Tests.ps1 new file mode 100644 index 0000000000..e8e4147db3 --- /dev/null +++ b/tests/Add-DbaReplArticle.Tests.ps1 @@ -0,0 +1,17 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + +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', 'Publication', 'Schema', 'Name', 'Filter', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> diff --git a/tests/Disable-DbaReplDistributor.tests.ps1 b/tests/Disable-DbaReplDistributor.tests.ps1 new file mode 100644 index 0000000000..97dae718e4 --- /dev/null +++ b/tests/Disable-DbaReplDistributor.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Force', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Disable-DbaReplPublishing.tests.ps1 b/tests/Disable-DbaReplPublishing.tests.ps1 new file mode 100644 index 0000000000..b6e7b33b74 --- /dev/null +++ b/tests/Disable-DbaReplPublishing.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Force', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> diff --git a/tests/Enable-DbaReplDistributor.tests.ps1 b/tests/Enable-DbaReplDistributor.tests.ps1 new file mode 100644 index 0000000000..bb78d5ff7c --- /dev/null +++ b/tests/Enable-DbaReplDistributor.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', '$DistributionDatabase', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Enable-DbaReplPublishing.tests.ps1 b/tests/Enable-DbaReplPublishing.tests.ps1 new file mode 100644 index 0000000000..f421f1a310 --- /dev/null +++ b/tests/Enable-DbaReplPublishing.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'SnapshotShare', 'PublisherSqlLogin', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Get-DbaReplArticle.tests.ps1 b/tests/Get-DbaReplArticle.tests.ps1 new file mode 100644 index 0000000000..2cde5a6b19 --- /dev/null +++ b/tests/Get-DbaReplArticle.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Publication', 'Name', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Get-DbaReplArticleColumn.tests.ps1 b/tests/Get-DbaReplArticleColumn.tests.ps1 new file mode 100644 index 0000000000..4742a574a0 --- /dev/null +++ b/tests/Get-DbaReplArticleColumn.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Publication', 'Article', 'Column', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Get-DbaReplPublisher.tests.ps1 b/tests/Get-DbaReplPublisher.tests.ps1 new file mode 100644 index 0000000000..9974307be5 --- /dev/null +++ b/tests/Get-DbaReplPublisher.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Get-DbaReplSubscription.tests.ps1 b/tests/Get-DbaReplSubscription.tests.ps1 new file mode 100644 index 0000000000..8343c4ac17 --- /dev/null +++ b/tests/Get-DbaReplSubscription.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Name', 'Type', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/New-DbaReplCreationScriptOptions.tests.ps1 b/tests/New-DbaReplCreationScriptOptions.tests.ps1 new file mode 100644 index 0000000000..04dd3412ce --- /dev/null +++ b/tests/New-DbaReplCreationScriptOptions.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +Describe "$CommandName Unit Tests" -Tag 'UnitTests' { + Context "Validate parameters" { + [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} + [object[]]$knownParameters = 'Options', 'NoDefaults' + $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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/New-DbaReplPublication.tests.ps1 b/tests/New-DbaReplPublication.tests.ps1 new file mode 100644 index 0000000000..a385b860fb --- /dev/null +++ b/tests/New-DbaReplPublication.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Name', 'Type', 'LogReaderAgentCredential', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> diff --git a/tests/New-DbaReplSubscription.tests.ps1 b/tests/New-DbaReplSubscription.tests.ps1 new file mode 100644 index 0000000000..04b2443010 --- /dev/null +++ b/tests/New-DbaReplSubscription.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'PublisherSqlInstance', 'PublisherSqlCredential', 'PublicationDatabase', 'PublicationName', 'SubscriptionSqlCredential', 'Type', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> diff --git a/tests/Remove-DbaReplArticle.tests.ps1 b/tests/Remove-DbaReplArticle.tests.ps1 new file mode 100644 index 0000000000..ca30e7e8ee --- /dev/null +++ b/tests/Remove-DbaReplArticle.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Publication', 'Schema', 'Name', 'InputObject', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Remove-DbaReplPublication.tests.ps1 b/tests/Remove-DbaReplPublication.tests.ps1 new file mode 100644 index 0000000000..36d344f56e --- /dev/null +++ b/tests/Remove-DbaReplPublication.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'Name', 'InputObject', 'Force', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file diff --git a/tests/Remove-DbaReplSubscription.tests.ps1 b/tests/Remove-DbaReplSubscription.tests.ps1 new file mode 100644 index 0000000000..b173eace5b --- /dev/null +++ b/tests/Remove-DbaReplSubscription.tests.ps1 @@ -0,0 +1,20 @@ +$CommandName = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") +Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan +. "$PSScriptRoot\constants.ps1" + + +Add-ReplicationLibrary + +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', 'PublisherSqlInstance', 'PublisherSqlCredential', 'PublicationDatabase', 'PublicationName', 'SubscriptionDatabase', '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 + } + } +} +<# + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 +#> \ No newline at end of file From 5a5edfbb860cb9036678d5174ebc3b30614377ab Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 11:48:46 +0100 Subject: [PATCH 154/226] change to psobject with a check --- public/Add-DbaReplArticle.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 6b34dfbfd7..55a3beea7d 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -106,11 +106,16 @@ function Add-DbaReplArticle { [parameter(Mandatory)] [String]$Name, [String]$Filter, - [Microsoft.SqlServer.Replication.CreationScriptOptions]$CreationScriptOptions, + [PSObject]$CreationScriptOptions, [Switch]$EnableException ) process { + # Check that $CreationScriptOptions is a valid object + if ($CreationScriptOptions -and ($CreationScriptOptions -isnot [Microsoft.SqlServer.Replication.CreationScriptOptions])) { + Stop-Function -Message "CreationScriptOptions should be the right type. Use New-DbaReplCreationScriptOptions to create the object" -ErrorRecord $_ -Target $instance -Continue + } + foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential From afabc0aa4361423e6739400b3780aefcbda7a449 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 12:03:58 +0100 Subject: [PATCH 155/226] change tests to Tests --- ...Distributor.tests.ps1 => Disable-DbaReplDistributor.Tests.ps1} | 0 ...plPublishing.tests.ps1 => Disable-DbaReplPublishing.Tests.ps1} | 0 ...lDistributor.tests.ps1 => Enable-DbaReplDistributor.Tests.ps1} | 0 ...eplPublishing.tests.ps1 => Enable-DbaReplPublishing.Tests.ps1} | 0 ...verSetting.tests.ps1 => Export-DbaReplServerSetting.Tests.ps1} | 0 ...{Get-DbaReplArticle.tests.ps1 => Get-DbaReplArticle.Tests.ps1} | 0 ...ArticleColumn.tests.ps1 => Get-DbaReplArticleColumn.Tests.ps1} | 0 ...-DbaReplPublisher.tests.ps1 => Get-DbaReplPublisher.Tests.ps1} | 0 ...plSubscription.tests.ps1 => Get-DbaReplSubscription.Tests.ps1} | 0 ...tions.tests.ps1 => New-DbaReplCreationScriptOptions.Tests.ps1} | 0 ...ReplPublication.tests.ps1 => New-DbaReplPublication.Tests.ps1} | 0 ...plSubscription.tests.ps1 => New-DbaReplSubscription.Tests.ps1} | 0 ...e-DbaReplArticle.tests.ps1 => Remove-DbaReplArticle.Tests.ps1} | 0 ...lPublication.tests.ps1 => Remove-DbaReplPublication.Tests.ps1} | 0 ...ubscription.tests.ps1 => Remove-DbaReplSubscription.Tests.ps1} | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename tests/{Disable-DbaReplDistributor.tests.ps1 => Disable-DbaReplDistributor.Tests.ps1} (100%) rename tests/{Disable-DbaReplPublishing.tests.ps1 => Disable-DbaReplPublishing.Tests.ps1} (100%) rename tests/{Enable-DbaReplDistributor.tests.ps1 => Enable-DbaReplDistributor.Tests.ps1} (100%) rename tests/{Enable-DbaReplPublishing.tests.ps1 => Enable-DbaReplPublishing.Tests.ps1} (100%) rename tests/{Export-DbaReplServerSetting.tests.ps1 => Export-DbaReplServerSetting.Tests.ps1} (100%) rename tests/{Get-DbaReplArticle.tests.ps1 => Get-DbaReplArticle.Tests.ps1} (100%) rename tests/{Get-DbaReplArticleColumn.tests.ps1 => Get-DbaReplArticleColumn.Tests.ps1} (100%) rename tests/{Get-DbaReplPublisher.tests.ps1 => Get-DbaReplPublisher.Tests.ps1} (100%) rename tests/{Get-DbaReplSubscription.tests.ps1 => Get-DbaReplSubscription.Tests.ps1} (100%) rename tests/{New-DbaReplCreationScriptOptions.tests.ps1 => New-DbaReplCreationScriptOptions.Tests.ps1} (100%) rename tests/{New-DbaReplPublication.tests.ps1 => New-DbaReplPublication.Tests.ps1} (100%) rename tests/{New-DbaReplSubscription.tests.ps1 => New-DbaReplSubscription.Tests.ps1} (100%) rename tests/{Remove-DbaReplArticle.tests.ps1 => Remove-DbaReplArticle.Tests.ps1} (100%) rename tests/{Remove-DbaReplPublication.tests.ps1 => Remove-DbaReplPublication.Tests.ps1} (100%) rename tests/{Remove-DbaReplSubscription.tests.ps1 => Remove-DbaReplSubscription.Tests.ps1} (100%) diff --git a/tests/Disable-DbaReplDistributor.tests.ps1 b/tests/Disable-DbaReplDistributor.Tests.ps1 similarity index 100% rename from tests/Disable-DbaReplDistributor.tests.ps1 rename to tests/Disable-DbaReplDistributor.Tests.ps1 diff --git a/tests/Disable-DbaReplPublishing.tests.ps1 b/tests/Disable-DbaReplPublishing.Tests.ps1 similarity index 100% rename from tests/Disable-DbaReplPublishing.tests.ps1 rename to tests/Disable-DbaReplPublishing.Tests.ps1 diff --git a/tests/Enable-DbaReplDistributor.tests.ps1 b/tests/Enable-DbaReplDistributor.Tests.ps1 similarity index 100% rename from tests/Enable-DbaReplDistributor.tests.ps1 rename to tests/Enable-DbaReplDistributor.Tests.ps1 diff --git a/tests/Enable-DbaReplPublishing.tests.ps1 b/tests/Enable-DbaReplPublishing.Tests.ps1 similarity index 100% rename from tests/Enable-DbaReplPublishing.tests.ps1 rename to tests/Enable-DbaReplPublishing.Tests.ps1 diff --git a/tests/Export-DbaReplServerSetting.tests.ps1 b/tests/Export-DbaReplServerSetting.Tests.ps1 similarity index 100% rename from tests/Export-DbaReplServerSetting.tests.ps1 rename to tests/Export-DbaReplServerSetting.Tests.ps1 diff --git a/tests/Get-DbaReplArticle.tests.ps1 b/tests/Get-DbaReplArticle.Tests.ps1 similarity index 100% rename from tests/Get-DbaReplArticle.tests.ps1 rename to tests/Get-DbaReplArticle.Tests.ps1 diff --git a/tests/Get-DbaReplArticleColumn.tests.ps1 b/tests/Get-DbaReplArticleColumn.Tests.ps1 similarity index 100% rename from tests/Get-DbaReplArticleColumn.tests.ps1 rename to tests/Get-DbaReplArticleColumn.Tests.ps1 diff --git a/tests/Get-DbaReplPublisher.tests.ps1 b/tests/Get-DbaReplPublisher.Tests.ps1 similarity index 100% rename from tests/Get-DbaReplPublisher.tests.ps1 rename to tests/Get-DbaReplPublisher.Tests.ps1 diff --git a/tests/Get-DbaReplSubscription.tests.ps1 b/tests/Get-DbaReplSubscription.Tests.ps1 similarity index 100% rename from tests/Get-DbaReplSubscription.tests.ps1 rename to tests/Get-DbaReplSubscription.Tests.ps1 diff --git a/tests/New-DbaReplCreationScriptOptions.tests.ps1 b/tests/New-DbaReplCreationScriptOptions.Tests.ps1 similarity index 100% rename from tests/New-DbaReplCreationScriptOptions.tests.ps1 rename to tests/New-DbaReplCreationScriptOptions.Tests.ps1 diff --git a/tests/New-DbaReplPublication.tests.ps1 b/tests/New-DbaReplPublication.Tests.ps1 similarity index 100% rename from tests/New-DbaReplPublication.tests.ps1 rename to tests/New-DbaReplPublication.Tests.ps1 diff --git a/tests/New-DbaReplSubscription.tests.ps1 b/tests/New-DbaReplSubscription.Tests.ps1 similarity index 100% rename from tests/New-DbaReplSubscription.tests.ps1 rename to tests/New-DbaReplSubscription.Tests.ps1 diff --git a/tests/Remove-DbaReplArticle.tests.ps1 b/tests/Remove-DbaReplArticle.Tests.ps1 similarity index 100% rename from tests/Remove-DbaReplArticle.tests.ps1 rename to tests/Remove-DbaReplArticle.Tests.ps1 diff --git a/tests/Remove-DbaReplPublication.tests.ps1 b/tests/Remove-DbaReplPublication.Tests.ps1 similarity index 100% rename from tests/Remove-DbaReplPublication.tests.ps1 rename to tests/Remove-DbaReplPublication.Tests.ps1 diff --git a/tests/Remove-DbaReplSubscription.tests.ps1 b/tests/Remove-DbaReplSubscription.Tests.ps1 similarity index 100% rename from tests/Remove-DbaReplSubscription.tests.ps1 rename to tests/Remove-DbaReplSubscription.Tests.ps1 From 09e651768fef950124fa41951fcc39b2d62fde72 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 12:43:29 +0100 Subject: [PATCH 156/226] fixing some tests --- public/Add-DbaReplArticle.ps1 | 8 ++++---- public/Get-DbaReplPublication.ps1 | 4 ++-- public/New-DbaReplSubscription.ps1 | 18 +++++++++++++++++- tests/Add-DbaReplArticle.Tests.ps1 | 4 ++-- tests/Enable-DbaReplDistributor.Tests.ps1 | 2 +- tests/Get-DbaReplPublication.Tests.ps1 | 2 +- tests/InModule.Help.Tests.ps1 | 4 +++- .../New-DbaReplCreationScriptOptions.Tests.ps1 | 1 - 8 files changed, 30 insertions(+), 13 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 55a3beea7d..8cf7abc56b 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -19,7 +19,7 @@ function Add-DbaReplArticle { .PARAMETER Database The database on the publisher that contains the article to be replicated. - .PARAMETER PublicationName + .PARAMETER Publication The name of the replication publication. .PARAMETER Schema @@ -62,7 +62,7 @@ function Add-DbaReplArticle { https://dbatools.io/Add-DbaReplArticle .EXAMPLE - PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh -Name TableToRepl + PS C:\> Add-DbaReplArticle -SqlInstance mssql1 -Database Northwind -Publication PubFromPosh -Name TableToRepl Adds the TableToRepl table to the PubFromPosh publication from mssql1.Northwind @@ -71,7 +71,7 @@ function Add-DbaReplArticle { PS C:\> $article = @{ SqlInstance = "mssql1" Database = "pubs" - PublicationName = "testPub" + Publication = "testPub" Name = "publishers" Filter = "city = 'seattle'" } @@ -84,7 +84,7 @@ function Add-DbaReplArticle { PS C:\> $article = @{ SqlInstance = 'mssql1' Database = 'pubs' - PublicationName = 'testPub' + Publication = 'testPub' Name = 'stores' CreationScriptOptions = $cso } diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 4e4e080488..34a580052e 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -135,11 +135,11 @@ function Get-DbaReplPublication { Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName - Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SQLInstance -Value $server.DomainInstanceName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Articles -Value $articles Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Subscriptions -Value $subscriptions - Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, Name, Type, Articles, Subscriptions + Select-DefaultView -InputObject $pub -Property ComputerName, InstanceName, SQLInstance, DatabaseName, Name, Type, Articles, Subscriptions } } diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 74e183f779..918ef7ee13 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -19,9 +19,25 @@ function New-DbaReplSubscription { .PARAMETER Database The database that will be replicated. + .PARAMETER PublisherSqlInstance + The publisher SQL instance. + + .PARAMETER PublisherSqlCredential + Login to the publisher 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 PublicationDatabase + The database on the publisher that is replicated. + .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. @@ -65,7 +81,7 @@ function New-DbaReplSubscription { [String]$PublicationDatabase, [parameter(Mandatory)] [String]$PublicationName, - [PSCredential] # this will be saved as the 'subscriber credential' in the subscription properties + [PSCredential] $SubscriptionSqlCredential, [parameter(Mandatory)] [ValidateSet("Push", "Pull")] diff --git a/tests/Add-DbaReplArticle.Tests.ps1 b/tests/Add-DbaReplArticle.Tests.ps1 index e8e4147db3..7ac56a19a0 100644 --- a/tests/Add-DbaReplArticle.Tests.ps1 +++ b/tests/Add-DbaReplArticle.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', 'Publication', 'Schema', 'Name', 'Filter', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'Publication', 'Schema', 'Name', 'Filter', 'CreationScriptOptions', '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 @@ -14,4 +14,4 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } <# Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 -#> +#> \ No newline at end of file diff --git a/tests/Enable-DbaReplDistributor.Tests.ps1 b/tests/Enable-DbaReplDistributor.Tests.ps1 index bb78d5ff7c..61cc486970 100644 --- a/tests/Enable-DbaReplDistributor.Tests.ps1 +++ b/tests/Enable-DbaReplDistributor.Tests.ps1 @@ -8,7 +8,7 @@ Add-ReplicationLibrary 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', '$DistributionDatabase', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'DistributionDatabase', '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 diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 index 7b303a7a4b..03a37e4505 100644 --- a/tests/Get-DbaReplPublication.Tests.ps1 +++ b/tests/Get-DbaReplPublication.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', 'Database', 'SqlCredential', 'Type', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'Name', 'Type', '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 diff --git a/tests/InModule.Help.Tests.ps1 b/tests/InModule.Help.Tests.ps1 index a9df2bc916..c0df047350 100644 --- a/tests/InModule.Help.Tests.ps1 +++ b/tests/InModule.Help.Tests.ps1 @@ -18,7 +18,9 @@ if ($env:appveyor) { 'Microsoft.SqlServer.Management.XEvent', 'Microsoft.SqlServer.Management.XEventDbScoped', 'Microsoft.SqlServer.Management.XEventDbScopedEnum', - 'Microsoft.SqlServer.Management.XEventEnum' + 'Microsoft.SqlServer.Management.XEventEnum', + 'Microsoft.SqlServer.Replication.dll', + 'Microsoft.SqlServer.Rmo.dll' ) foreach ($name in $names) { diff --git a/tests/New-DbaReplCreationScriptOptions.Tests.ps1 b/tests/New-DbaReplCreationScriptOptions.Tests.ps1 index 04dd3412ce..9f319380ed 100644 --- a/tests/New-DbaReplCreationScriptOptions.Tests.ps1 +++ b/tests/New-DbaReplCreationScriptOptions.Tests.ps1 @@ -9,7 +9,6 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { Context "Validate parameters" { [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm')} [object[]]$knownParameters = 'Options', 'NoDefaults' - $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 } From e39637e832f017e3c1e37390336f2df548429299 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 12:48:33 +0100 Subject: [PATCH 157/226] variables and scopes oh my --- tests/gh-actions-repl.ps1 | 140 +++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 0c6da59f32..c291c47b0a 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -277,15 +277,15 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplServer).IsPublisher) { Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } - $article = 'ReplicateMe' + $articleName = 'ReplicateMe' # we need some publications too $pubName = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName } $pubName = 'TestSnap' @@ -336,8 +336,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $name -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $Name } - $article = 'ReplicateMe' - $article2 = 'ReplicateMeToo' + $articleName = 'ReplicateMe' + $articleName2 = 'ReplicateMeToo' } Context "New-DbaReplCreationScriptOptions works" { @@ -374,82 +374,82 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Add-DbaReplArticle adds an article to a Transactional publication" { $pubName = 'TestPub' - { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $article + $art.Name | Should -Be $articleName } It "Add-DbaReplArticle adds an article to a Snapshot publication and specifies create script options" { $pubname = 'TestPub' $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics - { Add-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubname -CreationScriptOptions $cso -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $articleName2 -Publication $pubname -CreationScriptOptions $cso -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName2 -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $article2 + $art.Name | Should -Be $articleName2 } It "Add-DbaReplArticle adds an article to a Snapshot publication" { $pubname = 'TestSnap' - { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubname -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $article + $art.Name | Should -Be $articleName } It "Add-DbaReplArticle adds an article to a Snapshot publication with a filter" { $pubName = 'TestSnap' - { Add-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName -Filter "col1 = 'test'" -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $article2 -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $articleName2 -Publication $pubName -Filter "col1 = 'test'" -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName2 -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $article2 + $art.Name | Should -Be $articleName2 $art.FilterClause | Should -Be "col1 = 'test'" } It "Add-DbaReplArticle adds an article to a Merge publication" { $pubname = 'TestMerge' - { Add-DbaReplArticle -Database ReplDb -Name $article -Publication $pubname -EnableException } | Should -not -throw - $art = Get-DbaReplArticle -Database ReplDb -Name $article -Publication $pubName + { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubname -EnableException } | Should -not -throw + $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty $art.PublicationName | Should -Be $pubName - $art.Name | Should -Be $article + $art.Name | Should -Be $articleName } } Context "Get-DbaReplArticle works" { BeforeAll { # we need some articles too get - $article = 'ReplicateMe' - $article2 = 'ReplicateMeToo' + $articleName = 'ReplicateMe' + $articleName2 = 'ReplicateMeToo' # we need some publications too $pubName = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName } $pubName = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article2 + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName2 } $pubName = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } } @@ -468,7 +468,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Get-DbaReplArticle gets all the articles from a specific publication" { $pubName = 'TestSnap' - $arts = $article, $article2 + $arts = $articleName, $articleName2 $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName $getArt.Count | Should -Be 2 @@ -490,31 +490,31 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Remove-DbaReplArticle works" { BeforeAll { # we need some articles too remove - $article = 'ReplicateMe' + $articleName = 'ReplicateMe' # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } } @@ -525,8 +525,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name $rm.IsRemoved | Should -Be $true $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty + $articleName = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $articleName | Should -BeNullOrEmpty } It "Remove-DbaReplArticle removes an article from a Snapshot publication" { @@ -535,8 +535,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name $rm.IsRemoved | Should -Be $true $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty + $articleName = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $articleName | Should -BeNullOrEmpty } It "Remove-DbaReplArticle removes an article from a Merge publication" { @@ -545,8 +545,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $rm = Remove-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name $rm.IsRemoved | Should -Be $true $rm.Status | Should -Be 'Removed' - $article = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name - $article | Should -BeNullOrEmpty + $articleName = Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $Name + $articleName | Should -BeNullOrEmpty } } @@ -563,31 +563,31 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplServer).IsPublisher) { Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } - $article = 'ReplicateMe' + $articleName = 'ReplicateMe' # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } } @@ -615,10 +615,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Gets all column information for specific article on a server" { $pubname = 'TestTrans' - $cols = Get-DbaReplArticleColumn -Publication $pubname -Article $article + $cols = Get-DbaReplArticleColumn -Publication $pubname -Article $articleName $cols | Should -Not -BeNullOrEmpty $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } - $cols.ArticleName | ForEach-Object { $_ | Should -Be $article } + $cols.ArticleName | ForEach-Object { $_ | Should -Be $articleName } } It "Gets all column information for specific column on a server" { @@ -641,31 +641,31 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplServer).IsPublisher) { Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException } - $article = 'ReplicateMe' + $articleName = 'ReplicateMe' # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } $pubname = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } $pubname = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } } @@ -694,33 +694,33 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Describe "Piping" -tag test { BeforeAll { # we need some articles too get - $article = 'ReplicateMe' - $article2 = 'ReplicateMeToo' + $articleName = 'ReplicateMe' + $articleName2 = 'ReplicateMeToo' # we need some publications too $pubName = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName } $pubName = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article2 + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName2 } $pubName = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $article + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName } # piping doesn't work well if there are PSDefaultParameterValues set @@ -760,8 +760,8 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $rm = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name | Remove-DbaReplArticle -Confirm:$false $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - #$article = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name - #$article | Should -BeNullOrEmpty + #$articleName = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name + #$articleName | Should -BeNullOrEmpty } } From 3fcf91b7ddfcf74041180514ce1b30b388442e11 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 14:09:08 +0100 Subject: [PATCH 158/226] ghaction test failure --- tests/gh-actions-repl.ps1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index c291c47b0a..4a41c4e66e 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -478,11 +478,10 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Get-DbaReplArticle gets a certain article from a specific publication" { $pubName = 'TestTrans' - $Name = "ReplicateMe" - $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $Name + $getArt = Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName $getArt.Count | Should -Be 1 - $getArt.Name | Should -Be $Name + $getArt.Name | Should -Be $ArticleName $getArt.PublicationName | Should -Be $pubName } } From e20eab1516dcae60c7f11ae2bc54bc262f73c8fa Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 8 Jun 2023 15:05:48 +0100 Subject: [PATCH 159/226] too many dlls --- tests/InModule.Help.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/InModule.Help.Tests.ps1 b/tests/InModule.Help.Tests.ps1 index c0df047350..277981cc47 100644 --- a/tests/InModule.Help.Tests.ps1 +++ b/tests/InModule.Help.Tests.ps1 @@ -19,8 +19,8 @@ if ($env:appveyor) { 'Microsoft.SqlServer.Management.XEventDbScoped', 'Microsoft.SqlServer.Management.XEventDbScopedEnum', 'Microsoft.SqlServer.Management.XEventEnum', - 'Microsoft.SqlServer.Replication.dll', - 'Microsoft.SqlServer.Rmo.dll' + 'Microsoft.SqlServer.Replication', + 'Microsoft.SqlServer.Rmo' ) foreach ($name in $names) { From 3da4ac4512f9ffdb847d05909fce42efbc4057d3 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Sun, 18 Jun 2023 17:28:39 +0100 Subject: [PATCH 160/226] remove unneeded test setup files --- .github/workflows/integration-tests-repl.yml | 2 - bin/Replication/Invoke-ReplicationSetup.ps1 | 13 ------- bin/Replication/setup-test-replication.sql | 40 -------------------- 3 files changed, 55 deletions(-) delete mode 100644 bin/Replication/Invoke-ReplicationSetup.ps1 delete mode 100644 bin/Replication/setup-test-replication.sql diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 45c162b89e..d95fdfc76d 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -47,8 +47,6 @@ jobs: Import-Module ./dbatools.psd1 -Force # need some folders for our repl stuff docker exec mssql1 mkdir /shared/data /shared/repldata /var/opt/mssql/ReplData - # setup distribution, 1xPublication with 1xSubscription - # $null = .\bin\Replication\Invoke-ReplicationSetup.ps1 - name: Run tests run: | diff --git a/bin/Replication/Invoke-ReplicationSetup.ps1 b/bin/Replication/Invoke-ReplicationSetup.ps1 deleted file mode 100644 index 0636a538b9..0000000000 --- a/bin/Replication/Invoke-ReplicationSetup.ps1 +++ /dev/null @@ -1,13 +0,0 @@ -$password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force -$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password - -$PSDefaultParameterValues["*:SqlInstance"] = "localhost" -$PSDefaultParameterValues["*:SqlCredential"] = $cred -$PSDefaultParameterValues["*:Confirm"] = $false -$PSDefaultParameterValues["*:SharedPath"] = "/shared" -##$PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" -#$global:ProgressPreference = "SilentlyContinue" - - - -Invoke-DbaQuery -File .\bin\Replication\setup-test-replication.sql \ No newline at end of file diff --git a/bin/Replication/setup-test-replication.sql b/bin/Replication/setup-test-replication.sql deleted file mode 100644 index 9ac6fcb442..0000000000 --- a/bin/Replication/setup-test-replication.sql +++ /dev/null @@ -1,40 +0,0 @@ --- Set up distribution - use master - exec sp_adddistributor @distributor = N'mssql1', @password = N'dbatools.IO' - GO - exec sp_adddistributiondb @database = N'distribution', @data_folder = N'/shared/data/', @log_folder = N'/shared/data/', @log_file_size = 2, @min_distretention = 0, @max_distretention = 72, @history_retention = 48, @deletebatchsize_xact = 5000, @deletebatchsize_cmd = 2000, @security_mode = 1 - GO - - use [distribution] - if (not exists (select * from sysobjects where name = 'UIProperties' and type = 'U ')) - create table UIProperties(id int) - if (exists (select * from ::fn_listextendedproperty('SnapshotFolder', 'user', 'dbo', 'table', 'UIProperties', null, null))) - EXEC sp_updateextendedproperty N'SnapshotFolder', N'/shared/ReplData', 'user', dbo, 'table', 'UIProperties' - else - EXEC sp_addextendedproperty N'SnapshotFolder', N'/shared/ReplData', 'user', dbo, 'table', 'UIProperties' - GO - - exec sp_adddistpublisher @publisher = N'mssql1', @distribution_db = N'distribution', @security_mode = 0, @login = N'sqladmin', @password = N'', @working_directory = N'/shared/ReplData', @trusted = N'false', @thirdparty_flag = 0, @publisher_type = N'MSSQLSERVER' - GO - --- set up publication - use [pubs] - exec sp_replicationdboption @dbname = N'pubs', @optname = N'publish', @value = N'true' - GO - -- Adding the transactional publication - use [pubs] - exec sp_addpublication @publication = N'DMMRepl', @description = N'Transactional publication of database ''pubs'' from Publisher ''mssql1''.', @sync_method = N'concurrent', @retention = 0, @allow_push = N'true', @allow_pull = N'true', @allow_anonymous = N'true', @enabled_for_internet = N'false', @snapshot_in_defaultfolder = N'true', @compress_snapshot = N'false', @ftp_port = 21, @allow_subscription_copy = N'false', @add_to_active_directory = N'false', @repl_freq = N'continuous', @status = N'active', @independent_agent = N'true', @immediate_sync = N'true', @allow_sync_tran = N'false', @allow_queued_tran = N'false', @allow_dts = N'false', @replicate_ddl = 1, @allow_initialize_from_backup = N'false', @enabled_for_p2p = N'false', @enabled_for_het_sub = N'false' - exec sp_addpublication_snapshot @publication = N'DMMRepl', @frequency_type = 1, @frequency_interval = 1, @frequency_relative_interval = 1, @frequency_recurrence_factor = 0, @frequency_subday = 8, @frequency_subday_interval = 1, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 0, @active_end_date = 0, @job_login = null, @job_password = null, @publisher_security_mode = 1 - exec sp_addarticle @publication = N'DMMRepl', @article = N'authors', @source_owner = N'dbo', @source_object = N'authors', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'authors', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dboauthors', @del_cmd = N'CALL sp_MSdel_dboauthors', @upd_cmd = N'SCALL sp_MSupd_dboauthors' - exec sp_addarticle @publication = N'DMMRepl', @article = N'employee', @source_owner = N'dbo', @source_object = N'employee', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'employee', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dboemployee', @del_cmd = N'CALL sp_MSdel_dboemployee', @upd_cmd = N'SCALL sp_MSupd_dboemployee' - exec sp_addarticle @publication = N'DMMRepl', @article = N'jobs', @source_owner = N'dbo', @source_object = N'jobs', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'jobs', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbojobs', @del_cmd = N'CALL sp_MSdel_dbojobs', @upd_cmd = N'SCALL sp_MSupd_dbojobs' - exec sp_addarticle @publication = N'DMMRepl', @article = N'pub_info', @source_owner = N'dbo', @source_object = N'pub_info', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'pub_info', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbopub_info', @del_cmd = N'CALL sp_MSdel_dbopub_info', @upd_cmd = N'SCALL sp_MSupd_dbopub_info' - exec sp_addarticle @publication = N'DMMRepl', @article = N'publishers', @source_owner = N'dbo', @source_object = N'publishers', @type = N'logbased', @description = null, @creation_script = null, @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'publishers', @destination_owner = N'dbo', @vertical_partition = N'false', @ins_cmd = N'CALL sp_MSins_dbopublishers', @del_cmd = N'CALL sp_MSdel_dbopublishers', @upd_cmd = N'SCALL sp_MSupd_dbopublishers' - GO - --- add a subscription - use [pubs] - exec sp_addsubscription @publication = N'DMMRepl', @subscriber = N'mssql2', @destination_db = N'pubs', @subscription_type = N'Push', @sync_type = N'automatic', @article = N'all', @update_mode = N'read only', @subscriber_type = 0 - exec sp_addpushsubscription_agent @publication = N'DMMRepl', @subscriber = N'mssql2', @subscriber_db = N'pubs', @job_login = null, @job_password = null, @subscriber_security_mode = 0, @subscriber_login = N'sqladmin', @subscriber_password = 'dbatools.IO', @frequency_type = 64, @frequency_interval = 0, @frequency_relative_interval = 0, @frequency_recurrence_factor = 0, @frequency_subday = 0, @frequency_subday_interval = 0, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 20221101, @active_end_date = 99991231, @enabled_for_syncmgr = N'False', @dts_package_location = N'Distributor' - GO - From 373cd378e6dc7889f56eba2f0d01ee5bd886339c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Sun, 18 Jun 2023 17:28:59 +0100 Subject: [PATCH 161/226] moved to be issue #8995 --- ReplicationCommands.md | 80 ------------------------------------------ 1 file changed, 80 deletions(-) delete mode 100644 ReplicationCommands.md diff --git a/ReplicationCommands.md b/ReplicationCommands.md deleted file mode 100644 index 933a9f5ada..0000000000 --- a/ReplicationCommands.md +++ /dev/null @@ -1,80 +0,0 @@ -# Replication Work - -## Commands to Create - -List to keep track of commands we need and who's working on them, most of the names are being pulled from thin air so if you don't agree with new vs add they can all be discussed\changed. - -Meaning of the checkmarks: -- [X] Done -- [ ] not done -- [-] in progress by... - - -### General - -- [X] Get-DbaReplServer -- [X] Export-DbaReplServerSetting - -### Distribution - -- [X] Get-DbaReplDistributor -- [X] Disable-DbaReplDistributor -- [X] Enable-DbaReplDistributor -- [ ] Set-DbaReplDistributor (updating properties?) - -### Publishing - -- [-] Get-DbaReplPublisher - Mikey -- [ ] Set-DbaReplPublisher (updating properties?) -- [X] Get-DbaReplPublication -- #TODO: Exists but needs some love -- [X] Disable-DbaReplPublishing -- [X] Enable-DbaReplPublishing -- [X] New-DbaReplPublication - Jess -- [X] Remove-DbaReplPublication - -### Articles -- [X] Add-DbaReplArticle - Jess -- [X] Remove-DbaReplArticle - Jess -- [-] Get-DbaReplArticle - Cláudio -- [ ] Set-DbaReplArticle - -### Columns -- [-] Get-DbaReplArticleColumn -- [ ] Add-DbaReplArticleColumn -- [ ] Remove-DbaReplArticleColumn - -### Subscriptions -- [ ] Get-DbaDbSubscription -- [ ] Set-DbaReplDistributor (update properties) -- [X] New-DbaDbSubscription -- [X] Remove-DbaReplSubscription - -### Monitoring\Troubleshooting - -- [X] Test-DbaReplLatency -- [ ] Run-DbaReplSnapshotAgent ? -- [ ] Get-DbaReplSnapshotAgentStatus -- [ ] Get-DbaReplLogReaderAgentStatus -- [ ] Test-DbaReplSnapFolder - similar to Test-DbaPath but from replication service account perspective or something similar to check If the share (UNC or Local) is accessible from both, publisher and subscriber side -- [ ] Reinitialise-? - what do we need here -## How to run pester tests locally - -```PowerShell - # run this against fresh containers to setup replication as it would be in gh action - #.\bin\Replication\Invoke-ReplicationSetup.ps1 - # commented out - - #run the tests -Show All will caus - invoke-pester .\tests\gh-actions-repl.ps1 - -``` - -## Testing - -Some additional scenarios for us to test commands against. - -- how the commands work when we have a "third site" involved , i mean if we have the distribution db not on the Publication-Server and not on the Subscriber-Server (thats not so common, but it is a thing imo) - I saw some unusual behaviour with replcation commands when the setup is with a seperate Distribution-DB-Server. - -## Questions - -- Should parameter be `PublicationType` or `Type` and `PublicationName` or `Name` From 340455aa861f4ff25d261fd11274dc6229608d37 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jpomfret7@gmail.com> Date: Sun, 18 Jun 2023 17:36:34 +0100 Subject: [PATCH 162/226] Apply suggestions from code review Co-authored-by: Shawn Melton <11204251+wsmelton@users.noreply.github.com> --- public/Add-DbaReplArticle.ps1 | 40 ++++++++++----------- public/Disable-DbaReplDistributor.ps1 | 10 +++--- public/Disable-DbaReplPublishing.ps1 | 2 +- public/Enable-DbaReplDistributor.ps1 | 2 +- public/Enable-DbaReplPublishing.ps1 | 2 +- public/Get-DbaReplArticle.ps1 | 2 +- public/Get-DbaReplArticleColumn.ps1 | 2 +- public/Get-DbaReplPublication.ps1 | 2 +- public/Get-DbaReplPublisher.ps1 | 2 +- public/Get-DbaReplSubscription.ps1 | 2 +- public/New-DbaReplCreationScriptOptions.ps1 | 2 +- public/New-DbaReplPublication.ps1 | 2 +- public/New-DbaReplSubscription.ps1 | 2 +- public/Remove-DbaReplArticle.ps1 | 2 +- public/Remove-DbaReplPublication.ps1 | 2 +- public/Remove-DbaReplSubscription.ps1 | 2 +- 16 files changed, 39 insertions(+), 39 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 8cf7abc56b..8d0bab12bf 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -1,13 +1,13 @@ function Add-DbaReplArticle { <# .SYNOPSIS - Adds an article to a publication for the database on the target SQL instances. + Add an article configuration to a publication in a database on the SQL Server instance(s). .DESCRIPTION - Adds an article to a publication for the database on the target SQL instances. + Add an article configuration to a publication in a database on the SQL Server instance(s). .PARAMETER SqlInstance - The target SQL Server instance or instances. + The SQL Server instance(s) for the publication. .PARAMETER SqlCredential Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). @@ -17,13 +17,13 @@ function Add-DbaReplArticle { For MFA support, please use Connect-DbaInstance. .PARAMETER Database - The database on the publisher that contains the article to be replicated. + The publication database to apply the article configuration to be replicated. .PARAMETER Publication - The name of the replication publication. + The name of the publication. .PARAMETER Schema - The schema name that contains the object to add as an article. + Schema where the article to be added is found. Default is dbo. .PARAMETER Name @@ -49,7 +49,7 @@ function Add-DbaReplArticle { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io @@ -93,21 +93,21 @@ function Add-DbaReplArticle { Adds the stores table to the testPub publication from mssql1.pubs with the NonClusteredIndexes and Statistics options set includes default options. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [parameter(Mandatory)] - [String]$Database, - [parameter(Mandatory)] - [String]$Publication, - [String]$Schema = 'dbo', - [parameter(Mandatory)] - [String]$Name, - [String]$Filter, + [string]$Database, + [Parameter(Mandatory)] + [string]$Publication, + [string]$Schema = 'dbo', + [Parameter(Mandatory)] + [string]$Name, + [string]$Filter, [PSObject]$CreationScriptOptions, - [Switch]$EnableException + [switch]$EnableException ) process { @@ -118,7 +118,7 @@ function Add-DbaReplArticle { foreach ($instance in $SqlInstance) { try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -127,7 +127,7 @@ function Add-DbaReplArticle { try { if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $Publication")) { - $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication + $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication -EnableException:$EnableException $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions @@ -173,7 +173,7 @@ function Add-DbaReplArticle { } catch { Stop-Function -Message "Unable to add article $Name to $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue } - Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $Publication -Name $Name + Get-DbaReplArticle -SqlInstance $instance -SqlCredential $SqlCredential -Publication $Publication -Name $Name -EnableException:$EnableException } } } \ No newline at end of file diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index a58695d846..97adc2b1a6 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -38,7 +38,7 @@ function Disable-DbaReplDistributor { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io @@ -62,9 +62,9 @@ function Disable-DbaReplDistributor { regardless of whether or not dependent publishing and distribution objects are uninstalled. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [switch]$Force, @@ -73,7 +73,7 @@ function Disable-DbaReplDistributor { process { foreach ($instance in $SqlInstance) { try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } @@ -83,7 +83,7 @@ function Disable-DbaReplDistributor { try { if ($PSCmdlet.ShouldProcess($instance, "Disabling distribution on $instance")) { # remove any connections to the distribution database - Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name | Stop-DbaProcess + Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name -EnableException:$EnableException | Stop-DbaProcess -EnableException:$EnableException # uninstall distribution $replServer.UninstallDistributor($Force) } diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index f6be3a5d0b..280fce2e95 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -37,7 +37,7 @@ function Disable-DbaReplPublishing { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 0ccc47f0c1..8c4b7092a8 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -33,7 +33,7 @@ function Enable-DbaReplDistributor { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 9358988e66..96825f5aa1 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -37,7 +37,7 @@ function Enable-DbaReplPublishing { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index b6774e0086..f3ccc1a7de 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -33,7 +33,7 @@ function Get-DbaReplArticle { Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES - Tags: Replication + Tags: repl, Replication Author: Cláudio Silva (@claudioessilva), claudioessilva.eu Website: https://dbatools.io diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 index 1bc8ac21ca..972593421c 100644 --- a/public/Get-DbaReplArticleColumn.ps1 +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -34,7 +34,7 @@ function Get-DbaReplArticleColumn { Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES - Tags: Replication + Tags: repl, Replication Author: Cláudio Silva (@claudioessilva), claudioessilva.eu Website: https://dbatools.io diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 34a580052e..237275a446 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -31,7 +31,7 @@ function Get-DbaReplPublication { Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES - Tags: Replication + Tags: repl, Replication Author: Colin Douglas Website: https://dbatools.io diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index 1249d99778..c17e58c642 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -22,7 +22,7 @@ function Get-DbaReplPublisher { Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES - Tags: Replication + Tags: repl, Replication Author: Mikey Bronowski (@MikeyBronowski), bronowski.it Website: https://dbatools.io diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index b79b72d083..f31654e7dc 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -31,7 +31,7 @@ function Get-DbaReplSubscription { Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/New-DbaReplCreationScriptOptions.ps1 b/public/New-DbaReplCreationScriptOptions.ps1 index 14956b98b4..20edf0629c 100644 --- a/public/New-DbaReplCreationScriptOptions.ps1 +++ b/public/New-DbaReplCreationScriptOptions.ps1 @@ -22,7 +22,7 @@ function New-DbaReplCreationScriptOptions { MarkReplicatedForeignKeyConstraintsAsNotForReplication, and Schema .NOTES - Tags: Replication, Script + Tags: repl, Replication, Script Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index 9ff16ed143..e2b064a461 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -48,7 +48,7 @@ function New-DbaReplPublication { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 918ef7ee13..49b26c3afa 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -53,7 +53,7 @@ function New-DbaReplSubscription { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 1f86b64dbb..83fc087009 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -52,7 +52,7 @@ function Remove-DbaReplArticle { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 42f56722c0..9860b2ae40 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -41,7 +41,7 @@ function Remove-DbaReplPublication { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index b3e3f18912..ea3cd7fe70 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -50,7 +50,7 @@ function Remove-DbaReplSubscription { If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES - Tags: Replication + Tags: repl, Replication Author: Jess Pomfret (@jpomfret), jesspomfret.com Website: https://dbatools.io From c35829e603553411ea53039420de5484397663ba Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jpomfret7@gmail.com> Date: Tue, 4 Jul 2023 14:46:47 +0100 Subject: [PATCH 163/226] Update public/Disable-DbaReplPublishing.ps1 Co-authored-by: Shawn Melton <11204251+wsmelton@users.noreply.github.com> --- public/Disable-DbaReplPublishing.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 280fce2e95..6be5830072 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -62,7 +62,7 @@ function Disable-DbaReplPublishing { if the Publisher is on a remote server that cannot be reached. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param ( [parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, From d446664a243ec312f4d5a498c7562f772d69ed22 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 4 Jul 2023 15:19:43 +0100 Subject: [PATCH 164/226] responding to review comments. thanks! --- public/Add-DbaReplArticle.ps1 | 4 ---- public/Disable-DbaReplDistributor.ps1 | 13 ++++--------- public/Disable-DbaReplPublishing.ps1 | 17 ++++++----------- public/Enable-DbaReplDistributor.ps1 | 7 +++---- public/Enable-DbaReplPublishing.ps1 | 4 ++-- public/Export-DbaReplServerSetting.ps1 | 2 +- public/Get-DbaReplArticle.ps1 | 5 ++--- public/Remove-DbaReplPublication.ps1 | 1 + 8 files changed, 19 insertions(+), 34 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 8d0bab12bf..27466c665b 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -66,7 +66,6 @@ function Add-DbaReplArticle { Adds the TableToRepl table to the PubFromPosh publication from mssql1.Northwind - .EXAMPLE PS C:\> $article = @{ SqlInstance = "mssql1" @@ -163,9 +162,6 @@ function Add-DbaReplArticle { Stop-Function -Message "Article already exists in $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue } - # need to refresh subscriptions so they know about new articles - # only on trans\snap publications - # (Method invocation failed because [Microsoft.SqlServer.Replication.MergePublication] does not contain a method named 'RefreshSubscriptions'.) if ($pub.Type -in ('Transactional', 'Snapshot')) { $pub.RefreshSubscriptions() } diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 97adc2b1a6..8cbdf3014b 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -17,14 +17,11 @@ function Disable-DbaReplDistributor { For MFA support, please use Connect-DbaInstance. .PARAMETER Force - Boolean value that specifies whether or not replication objects are removed from the server, - even if a remote Distributor cannot be reached. + Specify whether or not replication objects are removed from the server, even if a remote Distributor cannot be reached. - If true, the publishing and Distributor configuration at the current server is uninstalled regardless of - whether or not dependent publishing and distribution objects are uninstalled. + If true, the publishing and Distributor configuration at the current server is uninstalled regardless of whether or not dependent publishing and distribution objects are uninstalled. - If false, the publisher and distribution databases must already be uninstalled, and no local databases - are enabled for publishing. + If false, the publisher and distribution databases must already be uninstalled, and no local databases are enabled for publishing. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -57,9 +54,7 @@ function Disable-DbaReplDistributor { PS C:\> $cred = Get-Credential sqladmin PS C:\> Disable-DbaReplDistributor -SqlInstance mssql1, mssql2 -SqlCredential $cred -Force - Disables replication distribution for the mssql1 and mssql2 instances using a sql login. - Specifies force so the publishing and Distributor configuration at the current server is uninstalled - regardless of whether or not dependent publishing and distribution objects are uninstalled. + Disables replication distribution for the mssql1 and mssql2 instances using a sql login. Specifies force so the publishing and Distributor configuration at the current server is uninstalled regardless of whether or not dependent publishing and distribution objects are uninstalled. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 6be5830072..e2f95454bd 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -17,12 +17,8 @@ function Disable-DbaReplPublishing { For MFA support, please use Connect-DbaInstance. .PARAMETER Force - A Boolean value that specifies whether the Publisher is uninstalled from the Distributor without verifying that - Publisher has also uninstalled the Distributor, if the Publisher is on a separate server. - - If true, all the replication objects associated with the Publisher are dropped even if the Publisher is on a remote server - that cannot be reached. - + Specifies whether the Publisher is uninstalled from the Distributor without verifying that Publisher has also uninstalled the Distributor, if the Publisher is on a separate server. + If true, all the replication objects associated with the Publisher are dropped even if the Publisher is on a remote server that cannot be reached. If false, replication first verifies that the remote Publisher has uninstalled the Distributor. .PARAMETER EnableException @@ -82,16 +78,15 @@ function Disable-DbaReplPublishing { if ($replServer.IsPublisher) { try { if ($PSCmdlet.ShouldProcess($instance, "Disabling publishing on $instance")) { - # uninstall distribution $replServer.DistributionPublishers.Remove($Force) } + + $replServer.Refresh() + $replServer + } catch { Stop-Function -Message "Unable to disable replication publishing" -ErrorRecord $_ -Target $instance -Continue } - - $replServer.Refresh() - $replServer - } else { Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category InvalidData } diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 8c4b7092a8..a46aa623c0 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -79,14 +79,13 @@ function Enable-DbaReplDistributor { #TODO: lots more properties to add as params $replServer.InstallDistributor($null, $distributionDb) + + $replServer.Refresh() + $replServer } } catch { Stop-Function -Message "Unable to enable replication distributor" -ErrorRecord $_ -Target $instance -Continue } - - $replServer.Refresh() - $replServer - } } } \ No newline at end of file diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 96825f5aa1..f2aa349c1b 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -78,8 +78,8 @@ function Enable-DbaReplPublishing { $distPublisher = New-Object Microsoft.SqlServer.Replication.DistributionPublisher $distPublisher.ConnectionContext = $replServer.ConnectionContext - $distPublisher.Name = $instance #- name of the Publisher. - $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name #- the name of the database created in step 5. + $distPublisher.Name = $instance + $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name if (-not $PSBoundParameters.SnapshotShare) { $SnapshotShare = Join-Path (Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential).InstallDataDirectory 'ReplData' diff --git a/public/Export-DbaReplServerSetting.ps1 b/public/Export-DbaReplServerSetting.ps1 index 8ab1b71a23..e05b6a9e86 100644 --- a/public/Export-DbaReplServerSetting.ps1 +++ b/public/Export-DbaReplServerSetting.ps1 @@ -59,7 +59,7 @@ function Export-DbaReplServerSetting { Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES - Tags: Replication + Tags: Replication, Repl Author: Chrissy LeMaire (@cl), netnerds.net Website: https://dbatools.io diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index f3ccc1a7de..e7bb820cbd 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -81,7 +81,6 @@ function Get-DbaReplArticle { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - # Connect to the distributor of the instance try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential } catch { @@ -91,7 +90,7 @@ function Get-DbaReplArticle { try { $databases = $server.Databases | Where-Object IsAccessible -eq $true if ($Database) { - $databases = $databases | Where-Object Name -In $Database + $databases = $databases | Where-Object Name -in $Database } } catch { Stop-Function -Message "Error occurred while getting databases from $instance" -ErrorRecord $_ -Target $instance -Continue @@ -109,7 +108,7 @@ function Get-DbaReplArticle { $articles = $publications.Articles if ($Name) { - $articles = $articles | Where-Object Name -In $Name + $articles = $articles | Where-Object Name -in $Name } foreach ($art in $articles) { diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 9860b2ae40..8f8c4c4217 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -25,6 +25,7 @@ function Remove-DbaReplPublication { The name of the replication publication .PARAMETER InputObject + A publication object retrieved from Get-DbaReplPublication. Enables piping from Get-DbaReplPublication. .PARAMETER Force If this switch is enabled, this command will look for the REPL-LogReader SQL Agent Job for this database and if it's running, stop the job. From 6fcdae82ff4f6cb3a1649f704410f74868d35401 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 4 Jul 2023 15:20:04 +0100 Subject: [PATCH 165/226] fix for pull sub --- public/New-DbaReplSubscription.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 49b26c3afa..26bec03117 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -148,7 +148,7 @@ function New-DbaReplSubscription { 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) { + 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' ) { @@ -161,7 +161,7 @@ function New-DbaReplSubscription { } } else { # Perform a bitwise logical AND (& in Visual C# and And in Visual Basic) between the Attributes property and AllowPull. - if ($transPub.Attributes -band 'AllowPull' -eq 'None' ) { + 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' From 8f6e6ae0dfd86b3f1fb6aad389537cb8791d8684 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jpomfret7@gmail.com> Date: Thu, 6 Jul 2023 09:32:01 +0100 Subject: [PATCH 166/226] Update public/Add-DbaReplArticle.ps1 Co-authored-by: Shawn Melton <11204251+wsmelton@users.noreply.github.com> --- public/Add-DbaReplArticle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 8d0bab12bf..0165d64d3a 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -30,7 +30,7 @@ function Add-DbaReplArticle { The name of the object to add as an article. .PARAMETER Filter - Horizontal filter for replication, implemented as a where clause, but don't include the word WHERE> + Sets the where clause used to filter the article horizontally, e.g., DiscontinuedDate IS NULL E.g. City = 'Seattle' .PARAMETER CreationScriptOptions From 7cbd2db1d1a027684be89d19f8a5bc748ec883bb Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 09:44:52 +0100 Subject: [PATCH 167/226] improve whatif messaging --- public/Add-DbaReplArticle.ps1 | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index 74f63e572e..feb10a603f 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -124,9 +124,12 @@ function Add-DbaReplArticle { Write-Message -Level Verbose -Message "Adding article $Name to publication $Publication on $instance" try { - if ($PSCmdlet.ShouldProcess($instance, "Adding an article to $Publication")) { + if ($PSCmdlet.ShouldProcess($instance, "Get the publication details for $Publication")) { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication -EnableException:$EnableException + } + + if ($PSCmdlet.ShouldProcess($instance, "Create an article object for $Publication which is a $($pub.Type) publication")) { $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions @@ -144,18 +147,24 @@ function Add-DbaReplArticle { $article.SourceObjectName = $Name $article.SourceObjectOwner = $Schema $article.PublicationName = $Publication + } - if ($CreationScriptOptions) { + if ($CreationScriptOptions) { + if ($PSCmdlet.ShouldProcess($instance, "Add creation options for article: $Name")) { $article.SchemaOption = $CreationScriptOptions } + } - if ($Filter) { + if ($Filter) { + if ($PSCmdlet.ShouldProcess($instance, "Add filter for article: $Name")) { if ($Filter -like 'WHERE*') { Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue } $article.FilterClause = $Filter } + } + if ($PSCmdlet.ShouldProcess($instance, "Create article: $Name")) { if (-not ($article.IsExistingObject)) { $article.Create() } else { From 103b334e3da28e4a1ac8c3ff9d91f9d60d01e209 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 09:48:34 +0100 Subject: [PATCH 168/226] move filter like where to top --- public/Add-DbaReplArticle.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index feb10a603f..e296361e46 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -115,6 +115,10 @@ function Add-DbaReplArticle { Stop-Function -Message "CreationScriptOptions should be the right type. Use New-DbaReplCreationScriptOptions to create the object" -ErrorRecord $_ -Target $instance -Continue } + if ($Filter -like 'WHERE*') { + Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue + } + foreach ($instance in $SqlInstance) { try { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException @@ -157,9 +161,6 @@ function Add-DbaReplArticle { if ($Filter) { if ($PSCmdlet.ShouldProcess($instance, "Add filter for article: $Name")) { - if ($Filter -like 'WHERE*') { - Stop-Function -Message "Filter should not include the word 'WHERE'" -ErrorRecord $_ -Target $instance -Continue - } $article.FilterClause = $Filter } } From f93ee70da2067fc81be6122f7011f8dcead05db4 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 09:51:05 +0100 Subject: [PATCH 169/226] split try catch into more sections --- public/Add-DbaReplArticle.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index e296361e46..adecad1797 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -132,7 +132,11 @@ function Add-DbaReplArticle { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication -EnableException:$EnableException } + } catch { + Stop-Function -Message "Unable to get publication $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue + } + try { if ($PSCmdlet.ShouldProcess($instance, "Create an article object for $Publication which is a $($pub.Type) publication")) { $articleOptions = New-Object Microsoft.SqlServer.Replication.ArticleOptions @@ -152,7 +156,11 @@ function Add-DbaReplArticle { $article.SourceObjectOwner = $Schema $article.PublicationName = $Publication } + } catch { + Stop-Function -Message "Unable to create article object for $Name to add to $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue + } + try { if ($CreationScriptOptions) { if ($PSCmdlet.ShouldProcess($instance, "Add creation options for article: $Name")) { $article.SchemaOption = $CreationScriptOptions From fba4040f278baf4e57dea3a27c130187e3477588 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 09:55:34 +0100 Subject: [PATCH 170/226] remove try\ catch for get --- public/Disable-DbaReplDistributor.ps1 | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 8cbdf3014b..72a460413e 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -67,11 +67,9 @@ function Disable-DbaReplDistributor { ) process { foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } + + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException + Write-Message -Level Verbose -Message "Disabling replication distribution for $instance" if ($replServer.IsDistributor) { From 30bc26b1325aaea314cdb6e2876665875e977d12 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 10:12:18 +0100 Subject: [PATCH 171/226] working on reviwe --- public/Disable-DbaReplDistributor.ps1 | 2 +- public/Disable-DbaReplPublishing.ps1 | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 72a460413e..3274b6ed08 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -88,7 +88,7 @@ function Disable-DbaReplDistributor { $replServer } else { - Stop-Function -Message "$instance isn't currently enabled for distributing." -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "$instance isn't currently enabled for distributing." -Target $instance -Continue } } } diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index e2f95454bd..b66881aed0 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -56,11 +56,10 @@ function Disable-DbaReplPublishing { Specifies force so all the replication objects associated with the Publisher are dropped even if the Publisher is on a remote server that cannot be reached. - #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [switch]$Force, @@ -68,11 +67,9 @@ function Disable-DbaReplPublishing { ) process { foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } + + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + Write-Message -Level Verbose -Message "Disabling publishing for $instance" if ($replServer.IsPublisher) { @@ -88,7 +85,7 @@ function Disable-DbaReplPublishing { Stop-Function -Message "Unable to disable replication publishing" -ErrorRecord $_ -Target $instance -Continue } } else { - Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category InvalidData + Stop-Function -Message "$instance isn't currently enabled for publishing." -Continue -ContinueLabel main -Target $instance -Category ObjectNotFound } } } From ac8d20be569b6aab5f00eb2e1f997c6905e42e29 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 10:13:34 +0100 Subject: [PATCH 172/226] review fixes --- public/Enable-DbaReplDistributor.ps1 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index a46aa623c0..8fc62f6bfd 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -54,9 +54,9 @@ function Enable-DbaReplDistributor { Enables distribution for the mssql1 instance and names the distribution database repDatabase. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [string]$DistributionDatabase = 'distribution', @@ -64,11 +64,9 @@ function Enable-DbaReplDistributor { ) process { foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } + + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + Write-Message -Level Verbose -Message "Enabling replication distribution for $instance" try { From b1ae839debbfe2983c98d177940a71e363e2d265 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 12:32:11 +0100 Subject: [PATCH 173/226] fix review, make whatif more verbose --- public/Enable-DbaReplPublishing.ps1 | 41 +++++++++++++++-------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index f2aa349c1b..35a0f807a7 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -53,9 +53,9 @@ function Enable-DbaReplPublishing { Attempts to set the procedure '[dbo].[StartUpProc1]' in the master database of SqlBox1\Instance2 for automatic execution when the instance is started. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [string]$SnapshotShare, @@ -64,30 +64,29 @@ function Enable-DbaReplPublishing { ) process { foreach ($instance in $SqlInstance) { - try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } - Write-Message -Level Verbose -Message "Enabling replication publishing for $instance" - try { - if ($PSCmdlet.ShouldProcess($instance, "Enabling publishing on $instance")) { + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - if ($replServer.IsDistributor) { + Write-Message -Level Verbose -Message "Enabling replication publishing for $instance" + + if ($replServer.IsDistributor) { + try { + if ($PSCmdlet.ShouldProcess($instance, "Getting distribution information on $instance")) { $distPublisher = New-Object Microsoft.SqlServer.Replication.DistributionPublisher $distPublisher.ConnectionContext = $replServer.ConnectionContext $distPublisher.Name = $instance $distPublisher.DistributionDatabase = $replServer.DistributionDatabases.Name - if (-not $PSBoundParameters.SnapshotShare) { + if (Test-Bound SnapshotShare -Not) { $SnapshotShare = Join-Path (Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential).InstallDataDirectory 'ReplData' Write-Message -Level Verbose -Message ('No snapshot share specified, using default of {0}' -f $SnapshotShare) } $distPublisher.WorkingDirectory = $SnapshotShare + } + if ($PSCmdlet.ShouldProcess($instance, "Configuring PublisherSecurity on $instance")) { if ($PublisherSqlLogin) { Write-Message -Level Verbose -Message "Configuring with a SQLLogin for PublisherSecurity" $distPublisher.PublisherSecurity.WindowsAuthentication = $false @@ -98,21 +97,23 @@ function Enable-DbaReplPublishing { Write-Message -Level Verbose -Message "Configuring with WindowsAuth for PublisherSecurity" $distPublisher.PublisherSecurity.WindowsAuthentication = $true } + } + if ($PSCmdlet.ShouldProcess($instance, "Enable publishing on $instance")) { Write-Message -Level Debug -Message $distPublisher # lots more properties to add as params $distPublisher.Create() - } else { - Stop-Function -Message "$instance isn't currently enabled for distributing. Please enable that first." -ErrorRecord $_ -Target $instance -Continue + + $replServer.Refresh() + $replServer } + + } catch { + Stop-Function -Message "Unable to enable replication publishing" -ErrorRecord $_ -Target $instance -Continue } - } catch { - Stop-Function -Message "Unable to enable replication publishing" -ErrorRecord $_ -Target $instance -Continue + } else { + Stop-Function -Message "$instance isn't currently enabled for distributing. Please enable that first." -ErrorRecord $_ -Target $instance -Continue } - - $replServer.Refresh() - $replServer - } } } \ No newline at end of file From 79bcaed98a8ac9be93d4564e1caad127a730dc0e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 12:44:02 +0100 Subject: [PATCH 174/226] changes from review --- public/Get-DbaReplDistributor.ps1 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index 646a9d1b74..68f6e54253 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -56,17 +56,12 @@ function Get-DbaReplDistributor { # Connect to the distributor of the instance try { - $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential $distributor = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential } catch { - Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Error occurred getting information about $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } Write-Message -Level Verbose -Message "Getting publisher for $server" - Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName - Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName - Add-Member -Force -InputObject $distributor -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName - Select-DefaultView -InputObject $distributor -Property ComputerName, InstanceName, SqlInstance, IsPublisher, IsDistributor, DistributionServer, DistributionDatabase, DistributorInstalled, DistributorAvailable, HasRemotePublisher } } From 885ec50af11b13b8e92d21a4f3b49056854989fb Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 13:05:36 +0100 Subject: [PATCH 175/226] review fixes --- public/Get-DbaReplServer.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index b79d0ddf27..b7880ebcc0 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -67,7 +67,7 @@ function Get-DbaReplServer { $replServer | Add-Member -Type NoteProperty -Name InstanceName -Value $server.ServiceName -Force $replServer | Add-Member -Type NoteProperty -Name SqlInstance -Value $server.DomainInstanceName -Force - Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, DistributorInstalled, DistributorAvailable, IsDistributor, IsPublisher, HasRemotePublisher, DistributionServer, DistributionDatabase, WorkingDirectory, AgentCheckupInterval, DistributionDatabases, DistributionPublishers, ReplicationDatabases, RegisteredSubscribers + Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, IsDistributor, IsPublisher, DistributionServer, DistributionDatabase } catch { Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } From 4e88ff9af5e513cab7d9fe874646bc13648b7221 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 13:06:24 +0100 Subject: [PATCH 176/226] change serverconnection standard message --- public/Get-DbaReplServer.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplServer.ps1 b/public/Get-DbaReplServer.ps1 index b7880ebcc0..89c6ef0a6d 100644 --- a/public/Get-DbaReplServer.ps1 +++ b/public/Get-DbaReplServer.ps1 @@ -69,7 +69,7 @@ function Get-DbaReplServer { Select-DefaultView -InputObject $replServer -Property ComputerName, InstanceName, SqlInstance, IsDistributor, IsPublisher, DistributionServer, DistributionDatabase } catch { - Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } } } From 44be61e17ee1159a8f4c9e6c37dabb9c844b7c14 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 14:22:14 +0100 Subject: [PATCH 177/226] add props to mocked objects --- tests/Get-DbaReplPublication.Tests.ps1 | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 index 03a37e4505..e72d07319a 100644 --- a/tests/Get-DbaReplPublication.Tests.ps1 +++ b/tests/Get-DbaReplPublication.Tests.ps1 @@ -19,8 +19,9 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { [object]@{ Name = 'TestDB' TransPublications = @{ - Name = 'TestDB_pub' - Type = 'Transactional' + Name = 'TestDB_pub' + Type = 'Transactional' + DatabaseName = 'TestDB' } MergePublications = @{} } @@ -28,16 +29,20 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { Mock Connect-DbaInstance -MockWith { [object]@{ - Name = "MockServerName" - ComputerName = 'MockComputerName' - Databases = @{ + Name = "MockServerName" + ServiceName = 'MSSQLSERVER' + DomainInstanceName = 'MockServerName' + ComputerName = 'MockComputerName' + Databases = @{ Name = 'TestDB' #state #status ID = 5 ReplicationOptions = 'Published' + IsAccessible = $true + IsSystemObject = $false } - ConnectionContext = @{ + ConnectionContext = @{ SqlConnectionObject = 'FakeConnectionContext' } } @@ -45,12 +50,12 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { It "Honors the SQLInstance parameter" { $Results = Get-DbaReplPublication -SqlInstance MockServerName - $Results.Server | Should Be "MockServerName" + $Results.SqlInstance | Should Be "MockServerName" } It "Honors the Database parameter" { $Results = Get-DbaReplPublication -SqlInstance MockServerName -Database TestDB - $Results.Database | Should Be "TestDB" + $Results.DatabaseName | Should Be "TestDB" } It "Honors the Type parameter" { From 068981b309c66e31c9567ec72a9c60089e42cd74 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 14:25:20 +0100 Subject: [PATCH 178/226] format doc --- tests/Get-DbaReplPublication.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 index e72d07319a..59ff6dc6a3 100644 --- a/tests/Get-DbaReplPublication.Tests.ps1 +++ b/tests/Get-DbaReplPublication.Tests.ps1 @@ -4,11 +4,11 @@ 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[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object { $_ -notin ('whatif', 'confirm') } [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'Name', 'Type', '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 + (@(Compare-Object -ReferenceObject ($knownParameters | Where-Object { $_ }) -DifferenceObject $params).Count ) | Should Be 0 } } From 681a1378520f118996fb910a96cc98e457325930 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 6 Jul 2023 14:56:12 +0100 Subject: [PATCH 179/226] improve confirm messaging for disable commands --- public/Disable-DbaReplDistributor.ps1 | 4 ++-- public/Disable-DbaReplPublishing.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index 3274b6ed08..fe8159e06d 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -70,11 +70,11 @@ function Disable-DbaReplDistributor { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException - Write-Message -Level Verbose -Message "Disabling replication distribution for $instance" + Write-Message -Level Verbose -Message "Disabling and removing replication distribution for $instance" if ($replServer.IsDistributor) { try { - if ($PSCmdlet.ShouldProcess($instance, "Disabling distribution on $instance")) { + if ($PSCmdlet.ShouldProcess($instance, "Disabling and removing distribution on $instance")) { # remove any connections to the distribution database Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name -EnableException:$EnableException | Stop-DbaProcess -EnableException:$EnableException # uninstall distribution diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index b66881aed0..1e6e126470 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -70,11 +70,11 @@ function Disable-DbaReplPublishing { $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential - Write-Message -Level Verbose -Message "Disabling publishing for $instance" + Write-Message -Level Verbose -Message "Disabling and removing publishing for $instance" if ($replServer.IsPublisher) { try { - if ($PSCmdlet.ShouldProcess($instance, "Disabling publishing on $instance")) { + if ($PSCmdlet.ShouldProcess($instance, "Disabling and removing publishing on $instance")) { $replServer.DistributionPublishers.Remove($Force) } From e90cf4aad6bbae8c7b585f47d4662db290212811 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 7 Jul 2023 16:20:51 +0100 Subject: [PATCH 180/226] bug when there aren't subscriptiosns --- public/Remove-DbaReplArticle.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 83fc087009..5e9ec99f25 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -128,7 +128,7 @@ function Remove-DbaReplArticle { $pub = Get-DbaReplPublication -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -Name $art.PublicationName - if ($pub.Subscriptions) { + if (($pub.Subscriptions | Measure-Object).count -gt 0 ) { Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $art.Name, $pub.Subscriptions.SubscriberName) $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $art.PublicationName, $art.Name, $pub.Subscriptions.SubscriberName Invoke-DbaQuery -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -query $query From 0e0b21c08253cf2359990e3a6041296452a84ca3 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 7 Jul 2023 16:21:02 +0100 Subject: [PATCH 181/226] add examples --- public/Get-DbaReplSubscription.ps1 | 61 +++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index f31654e7dc..6a31baf8bb 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -42,7 +42,24 @@ function Get-DbaReplSubscription { https://dbatools.io/Get-DbaReplSubscription .EXAMPLE - PS C:\> #TODO: add example + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 + + Return all subscriptions for all publications on server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -Database TestDB + + Return all subscriptions for all publications on server mssql1 for only the TestDB database. + + .EXAMPLE + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -Name Mergey + + Return all subscriptions for the publication Mergey on server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -Type Transactional + + Return all subscriptions for all transactional publications on server mssql1. #> [CmdletBinding()] @@ -51,7 +68,7 @@ function Get-DbaReplSubscription { [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [object[]]$Database, - [String]$Name, + [String[]]$Name, [Alias("PublicationType")] [ValidateSet("Push", "Pull")] [object[]]$Type, @@ -59,26 +76,44 @@ function Get-DbaReplSubscription { ) process { if (Test-FunctionInterrupt) { return } - foreach ($instance in $SqlInstance) { - # Connect to Publisher + foreach ($instance in $SqlInstance) { try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } - # Get all subscriptions - $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription - $transSub.ConnectionContext = $replServer.ConnectionContext - $transSub.EnumSubscriptions() + try { + $publications = Get-DbaReplPublication -SqlInstance $server + + if ($Database) { + $publications = $publications | Where-Object DatabaseName -in $Database + } + + if ($Name) { + $publications = $publications | Where-Object Name -in $Name + } + } catch { + Stop-Function -Message "Error occurred while getting publications from $instance" -ErrorRecord $_ -Target $instance -Continue + } - #TODO: finish this function - # can we get subscriptions by passing in subscription server mssql2 ... or do we need to start at the publisher - # get-publications --> subscriptions info is in there + try { + foreach ($subs in $publications.Subscriptions) { + Write-Message -Level Verbose -Message ('Get subscriptions for {0}' -f $sub.PublicationName) + foreach ($sub in $subs) { + Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName + Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName + Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Select-DefaultView -InputObject $sub -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, SubscriberName, SubscriptionDBName, SubscriptionType + } + } + } catch { + Stop-Function -Message "Error occurred while getting subscriptions from $instance" -ErrorRecord $_ -Target $instance -Continue + } } } } \ No newline at end of file From 9b09acdfb1d49ce3bc94c01a5dd7181d0f35afab Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 7 Jul 2023 16:21:23 +0100 Subject: [PATCH 182/226] should we use the sqlinstance object so piping works --- public/Get-DbaReplArticle.ps1 | 2 +- public/Get-DbaReplPublication.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index e7bb820cbd..012faf8b2e 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -114,7 +114,7 @@ function Get-DbaReplArticle { foreach ($art in $articles) { Add-Member -Force -InputObject $art -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $art -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName - Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $art -MemberType NoteProperty -Name SqlInstance -Value $server Select-DefaultView -InputObject $art -Property ComputerName, InstanceName, SqlInstance, DatabaseName, PublicationName, Name, Type, VerticalPartition, SourceObjectOwner, SourceObjectName #, DestinationObjectOwner, DestinationObjectName } diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 237275a446..254783a823 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -135,7 +135,7 @@ function Get-DbaReplPublication { Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName - Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SQLInstance -Value $server.DomainInstanceName + Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name SQLInstance -Value $server Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Articles -Value $articles Add-Member -Force -InputObject $pub -MemberType NoteProperty -Name Subscriptions -Value $subscriptions From 1d907d5e79dc4710d34da31e2ce77b4f286bed1e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 7 Jul 2023 16:21:33 +0100 Subject: [PATCH 183/226] wip remove-replsub --- public/Remove-DbaReplSubscription.ps1 | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index ea3cd7fe70..52b6bca120 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -73,16 +73,16 @@ function Remove-DbaReplSubscription { Removes a subscription for the testPub publication on mssql2.pubs. #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - [parameter(Mandatory)] + [Parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, [PSCredential]$PublisherSqlCredential, [String]$PublicationDatabase, - [parameter(Mandatory)] + [Parameter(Mandatory)] [String]$PublicationName, [String]$SubscriptionDatabase, [Switch]$EnableException @@ -95,12 +95,6 @@ function Remove-DbaReplSubscription { Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$Database" } - try { - $replServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential - } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue - } - } process { foreach ($instance in $SqlInstance) { @@ -108,17 +102,16 @@ function Remove-DbaReplSubscription { try { if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $instance.$SubscriptionDatabase")) { - if ($pub.Type -in ('Transactional', 'Snapshot')) { #TODO: Only handles push subscriptions at the moment - need to add pull subscriptions # https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription - $transSub.ConnectionContext = $replServer.ConnectionContext + $transSub.ConnectionContext = $pub.ConnectionContext $transSub.DatabaseName = $PublicationDatabase $transSub.PublicationName = $PublicationName $transSub.SubscriptionDBName = $SubscriptionDatabase - $transSub.SubscriberName = $instance + $transSub.SubscriberName = $instance.Name if ($transSub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing the subscription" @@ -127,22 +120,22 @@ function Remove-DbaReplSubscription { } elseif ($pub.Type -eq 'Merge') { $mergeSub = New-Object Microsoft.SqlServer.Replication.MergeSubscription - $mergeSub.ConnectionContext = $replServer.ConnectionContext + $mergeSub.ConnectionContext = $pub.ConnectionContext $mergeSub.DatabaseName = $PublicationDatabase $mergeSub.PublicationName = $PublicationName $mergeSub.SubscriptionDBName = $SubscriptionDatabase - $mergeSub.SubscriberName = $instance + $mergeSub.SubscriberName = $instance.Name if ($mergeSub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing the merge subscription" $mergeSub.Remove() } else { - Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$SubscriptionDatabase" + Write-Warning "Didn't find a subscription to $PublicationName on $($Instance.Name).$SubscriptionDatabase" } } } } catch { - Stop-Function -Message ("Unable to remove subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message ("Unable to remove subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance.Name -Continue } } } From 0f3c4a6f8487f15caa1e8e89d6327dbb98ede012 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 12 Jul 2023 15:45:51 +0100 Subject: [PATCH 184/226] improve help for new sub --- public/New-DbaReplSubscription.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 26bec03117..1f08c7e533 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -64,9 +64,14 @@ function New-DbaReplSubscription { https://dbatools.io/New-DbaReplSubscription .EXAMPLE - PS C:\> New-DbaReplSubscription -SqlInstance mssql1 -Database Northwind -PublicationName PubFromPosh + PS C:\> New-DbaReplicationSubscription -SqlInstance sql2017 -Database pubs -PublisherSqlInstance sql2016 -PublicationDatabase pubs -PublicationName testPub -Type Push - Creates a publication called PubFromPosh for the Northwind database on mssql1 + Creates a push subscription for the pubs database on sql2017 to the testPub publication on sql2016 + + .EXAMPLE + PS C:\> New-DbaReplicationSubscription -SqlInstance sql2017 -Database pubs -PublisherSqlInstance sql2016 -PublicationDatabase pubs -PublicationName testPub -Type Pull + + Creates a pull subscription for the pubs database on sql2017 to the testPub publication on sql2016 #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] From 5242d09cd491fdcb4aae14ca9286efb2e58fd15b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jpomfret7@gmail.com> Date: Wed, 12 Jul 2023 15:49:57 +0100 Subject: [PATCH 185/226] Update public/Get-DbaReplSubscription.ps1 Co-authored-by: Shawn Melton <11204251+wsmelton@users.noreply.github.com> --- public/Get-DbaReplSubscription.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index 6a31baf8bb..eb9641cf16 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -68,7 +68,7 @@ function Get-DbaReplSubscription { [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [object[]]$Database, - [String[]]$Name, + [string[]]$Name, [Alias("PublicationType")] [ValidateSet("Push", "Pull")] [object[]]$Type, From 54bd532862ca2289a3c3ab9a0c295e79058e3679 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 12 Jul 2023 16:19:48 +0100 Subject: [PATCH 186/226] add some params for filterign --- public/Get-DbaReplSubscription.ps1 | 46 +++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index eb9641cf16..9cd7b92658 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -9,18 +9,24 @@ function Get-DbaReplSubscription { .PARAMETER SqlInstance The target SQL Server instance or instances. + .PARAMETER SqlCredential + Login to the target 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(s) to process. If unspecified, all databases will be processed. .PARAMETER Name The name of the publication. - .PARAMETER SqlCredential - Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). - - Windows Authentication, SQL Server Authentication, Active Directory - Password, and Active Directory - Integrated are all supported. + .PARAMETER SubscriberName + The subscriber SQL Server instance name. - For MFA support, please use Connect-DbaInstance. + .PARAMETER SubscriptionDatabase + The name of the subscription database. .PARAMETER Type Limit by specific type of publication. Valid choices include: Transactional, Merge, Snapshot @@ -61,18 +67,30 @@ function Get-DbaReplSubscription { Return all subscriptions for all transactional publications on server mssql1. + .EXAMPLE + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -SubscriberName mssql2 + + Return all subscriptions for all publications on server mssql1 where the subscriber is mssql2. + + .EXAMPLE + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase TestDB + + Return all subscriptions for all publications on server mssql1 where the subscription database is TestDB. + #> [CmdletBinding()] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, - [object[]]$Database, - [string[]]$Name, + [Object[]]$Database, + [String[]]$Name, + [DbaInstanceParameter[]]$SubscriberName, + [Object[]]$SubscriptionDatabase, [Alias("PublicationType")] [ValidateSet("Push", "Pull")] - [object[]]$Type, - [switch]$EnableException + [Object[]]$Type, + [Switch]$EnableException ) process { if (Test-FunctionInterrupt) { return } @@ -103,6 +121,14 @@ function Get-DbaReplSubscription { foreach ($subs in $publications.Subscriptions) { Write-Message -Level Verbose -Message ('Get subscriptions for {0}' -f $sub.PublicationName) + if ($SubscriberName) { + $subs = $subs | Where-Object SubscriberName -eq $SubscriberName + } + + if ($SubscriptionDatabase) { + $subs = $subs | Where-Object SubscriptionDBName -eq $SubscriptionDatabase + } + foreach ($sub in $subs) { Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName From 5fb6e58f0844d6458a4d2985e27b237cf5f0875f Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 12 Jul 2023 16:19:57 +0100 Subject: [PATCH 187/226] capital letters --- public/New-DbaReplSubscription.ps1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 1f08c7e533..183353e959 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -76,19 +76,19 @@ function New-DbaReplSubscription { #> [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( - [parameter(Mandatory, ValueFromPipeline)] + [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [String]$Database, - [parameter(Mandatory)] + [Parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, [PSCredential]$PublisherSqlCredential, [String]$PublicationDatabase, - [parameter(Mandatory)] + [Parameter(Mandatory)] [String]$PublicationName, [PSCredential] $SubscriptionSqlCredential, - [parameter(Mandatory)] + [Parameter(Mandatory)] [ValidateSet("Push", "Pull")] [String]$Type, [Switch]$EnableException @@ -100,13 +100,13 @@ function New-DbaReplSubscription { try { $pubReplServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $PublisherSqlInstance -Continue } try { - $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName -EnableException } catch { - Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $instance) -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $PublisherSqlInstance) -ErrorRecord $_ -Target $PublisherSqlInstance -Continue } } From d6ec1aba17d0ed259a026988defc6b1e17487822 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 14 Jul 2023 19:02:19 +0100 Subject: [PATCH 188/226] couple of fixes for subscriptions --- public/New-DbaReplSubscription.ps1 | 2 +- public/Remove-DbaReplSubscription.ps1 | 11 ++- tests/gh-actions-repl.ps1 | 128 +++++++++++++++++++------- 3 files changed, 103 insertions(+), 38 deletions(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 183353e959..34458e26ab 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -116,7 +116,7 @@ function New-DbaReplSubscription { foreach ($instance in $SqlInstance) { try { - $subReplServer = get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $subReplServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it - but you should check the settings!" diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 52b6bca120..c4f37082e1 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -81,6 +81,7 @@ function Remove-DbaReplSubscription { [Parameter(Mandatory)] [DbaInstanceParameter]$PublisherSqlInstance, [PSCredential]$PublisherSqlCredential, + [Parameter(Mandatory)] [String]$PublicationDatabase, [Parameter(Mandatory)] [String]$PublicationName, @@ -92,7 +93,7 @@ function Remove-DbaReplSubscription { $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName if (-not $pub) { - Write-Warning "Didn't find a subscription to $PublicationName on $Instance.$Database" + Write-Warning "Didn't find a subscription to the $PublicationName publication on $PublisherSqlInstance.$Database" } } @@ -111,7 +112,7 @@ function Remove-DbaReplSubscription { $transSub.DatabaseName = $PublicationDatabase $transSub.PublicationName = $PublicationName $transSub.SubscriptionDBName = $SubscriptionDatabase - $transSub.SubscriberName = $instance.Name + $transSub.SubscriberName = $instance if ($transSub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing the subscription" @@ -124,18 +125,18 @@ function Remove-DbaReplSubscription { $mergeSub.DatabaseName = $PublicationDatabase $mergeSub.PublicationName = $PublicationName $mergeSub.SubscriptionDBName = $SubscriptionDatabase - $mergeSub.SubscriberName = $instance.Name + $mergeSub.SubscriberName = $instance if ($mergeSub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing the merge subscription" $mergeSub.Remove() } else { - Write-Warning "Didn't find a subscription to $PublicationName on $($Instance.Name).$SubscriptionDatabase" + Write-Warning "Didn't find a subscription to $PublicationName on $($instance).$SubscriptionDatabase" } } } } catch { - Stop-Function -Message ("Unable to remove subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance.Name -Continue + Stop-Function -Message ("Unable to remove subscription - {0}" -f $_) -ErrorRecord $_ -Target $instance -Continue } } } diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index 4a41c4e66e..f42fa5f7b8 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -456,13 +456,13 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Get-DbaReplArticle gets all the articles from a server" { $getArt = Get-DbaReplArticle $getArt | Should -Not -BeNullOrEmpty - $getArt | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } + $getArt | ForEach-Object { $_.SqlInstance.name | Should -Be 'mssql1' } } It "Get-DbaReplArticle gets all the articles from a particular database on a server" { $getArt = Get-DbaReplArticle -Database ReplDb $getArt | Should -Not -BeNullOrEmpty - $getArt | ForEach-Object { $_.SqlInstance | Should -Be 'mssql1' } + $getArt | ForEach-Object { $_.SqlInstance.Name | Should -Be 'mssql1' } $getArt | ForEach-Object { $_.DatabaseName | Should -Be 'ReplDb' } } @@ -594,13 +594,13 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Gets all column information for a server" { $cols = Get-DbaReplArticleColumn $cols | Should -Not -BeNullOrEmpty - $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.SqlInstance | ForEach-Object { $_.Name | Should -Be 'mssql1' } } It "Gets all column information for specific database on a server" { $cols = Get-DbaReplArticleColumn -Database ReplDb $cols | Should -Not -BeNullOrEmpty - $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.SqlInstance | ForEach-Object { $_.Name | Should -Be 'mssql1' } $cols.DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } } @@ -608,7 +608,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestTrans' $cols = Get-DbaReplArticleColumn -Publication $pubname $cols | Should -Not -BeNullOrEmpty - $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.SqlInstance | ForEach-Object { $_.Name | Should -Be 'mssql1' } $cols.PublicationName | ForEach-Object { $_ | Should -Be $pubname } } @@ -616,7 +616,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestTrans' $cols = Get-DbaReplArticleColumn -Publication $pubname -Article $articleName $cols | Should -Not -BeNullOrEmpty - $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.SqlInstance | ForEach-Object { $_.Name | Should -Be 'mssql1' } $cols.ArticleName | ForEach-Object { $_ | Should -Be $articleName } } @@ -624,7 +624,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $pubname = 'TestTrans' $cols = Get-DbaReplArticleColumn -Publication $pubname -Column 'col1' $cols | Should -Not -BeNullOrEmpty - $cols.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $cols.SqlInstance | ForEach-Object { $_.Name | Should -Be 'mssql1' } $cols.ColumnName | ForEach-Object { $_ | Should -Be 'col1' } } } @@ -663,35 +663,101 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName - } } - Context "New-DbaReplSubscription works" -skip { + Context "New-DbaReplSubscription works" -tag sub { + BeforeAll { + if (Get-DbaReplSubscription -SqlInstance mssql1 -Name TestTrans -Database ReplDb -SubscriberName mssql2 -SubscriptionDatabase ReplDbTrans) { + Remove-DbaReplSubscription -SqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName TestTrans -Confirm:$false -EnableException + } + if (Get-DbaReplSubscription -SqlInstance mssql1 -Name TestSnap -Database ReplDb -SubscriberName mssql2 -SubscriptionDatabase ReplDbSnap) { + Remove-DbaReplSubscription -SqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName TestSnap -Confirm:$false -EnableException + } + } It "Adds a subscription" { - { New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -Type 'Push' -EnableException } | Should -Not -Throw + #TODO: we are here and broke + $pubName = 'TestTrans' + #transactional + { New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDbTrans -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw + + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Name $pubname + $sub | Should -Not -BeNullOrEmpty + $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } + $sub.PublicationName | ForEach-Object { $_ | Should -Be $pubname } + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } + } + + It "Adds a pull subscription" -tag sub { + $pubName = 'TestSnap' + { New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDbSnap -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw - #TODO: waiting on get-dbareplsubscription to be implemented + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Name $pubname + $sub | Should -Not -BeNullOrEmpty + $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } + $sub.PublicationName | ForEach-Object { $_ | Should -Be $pubname } + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } + } + + It "Throws an error if there are no articles in the publication" { + $pubName = 'TestMerge' + { New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw } } - Context "Remove-DbaReplSubscription works" -skip{ + Context "Remove-DbaReplSubscription works"{ BeforeEach { - #TODO: check it doesn't exist with get-dbareplsubscription - New-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -Type 'Push' + $pubName = 'TestTrans' + if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -Type Push + } } It "Removes a subscription" { - { Remove-DbaReplPublication -SqlInstance 'mssql2' -Database ReplDb -PublicationDatabase ReplDb -Name $pubname -EnableException } | Should -Not -Throw + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -Name $pubname -Type Push | Should -Not -BeNullOrEmpty + { Remove-DbaReplSubscription -SqlInstance mssql2 -SubscriptionDatabase ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty + } + } + - #TODO: waiting on get-dbareplsubscription to be implemented + Context "Get-DbaReplSubscription works" { + BeforeAll { + $pubName = 'TestTrans' + if (-not (Get-DbaReplSubscription -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -Type Push -enableException + } + $pubName = 'TestSnap' + if (-not (Get-DbaReplSubscription -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -Type Push -enableException + } + } + + It "Gets subscriptions" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 + $sub | Should -Not -BeNullOrEmpty + $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } } + + It "Gets subscriptions to a particular instance" { + + } + } } - Describe "Piping" -tag test { + Describe "Piping" { BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + # we need some articles too get $articleName = 'ReplicateMe' $articleName2 = 'ReplicateMeToo' @@ -699,32 +765,30 @@ Describe "Integration Tests" -Tag "IntegrationTests" { # we need some publications too $pubName = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName -EnableException } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName -EnableException } $pubName = 'TestSnap' if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName -EnableException } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName2 + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName -EnableException + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName2 -EnableException } $pubName = 'TestMerge' if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName -EnableException } if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName -EnableException } - # piping doesn't work well if there are PSDefaultParameterValues set $PSDefaultParameterValues = $null - } Context "Get-DbaReplPublisher works with piping" { @@ -759,16 +823,16 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $rm = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name | Remove-DbaReplArticle -Confirm:$false $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - #$articleName = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name - #$articleName | Should -BeNullOrEmpty + $articleName = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name + $articleName | Should -BeNullOrEmpty } } Context "Remove-DbaReplPublication works with piping" { It "Remove-DbaReplPublication removes a publication using piping" { $name = 'TestMerge' - { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name | Remove-DbaReplPublication -EnableException } | Should -Not -Throw - #(Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name) | Should -BeNullOrEmpty + { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException | Remove-DbaReplPublication -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException) | Should -BeNullOrEmpty } } } From 4f8f224db9e093bb295437d2c82426443cc89e18 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 21 Jul 2023 16:47:55 +0100 Subject: [PATCH 189/226] swap sqlinstance around to publisher for subscription commands --- public/Get-DbaReplSubscription.ps1 | 16 +++-- public/New-DbaReplSubscription.ps1 | 71 +++++++++++----------- public/Remove-DbaReplSubscription.ps1 | 49 +++++++-------- tests/Get-DbaReplSubscription.Tests.ps1 | 4 +- tests/New-DbaReplSubscription.Tests.ps1 | 2 +- tests/Remove-DbaReplSubscription.Tests.ps1 | 2 +- 6 files changed, 74 insertions(+), 70 deletions(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index 9cd7b92658..602ee62ca2 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -19,7 +19,7 @@ function Get-DbaReplSubscription { .PARAMETER Database The database(s) to process. If unspecified, all databases will be processed. - .PARAMETER Name + .PARAMETER PublicationName The name of the publication. .PARAMETER SubscriberName @@ -58,12 +58,12 @@ function Get-DbaReplSubscription { Return all subscriptions for all publications on server mssql1 for only the TestDB database. .EXAMPLE - PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -Name Mergey + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName Mergey Return all subscriptions for the publication Mergey on server mssql1. .EXAMPLE - PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -Type Transactional + PS C:\> Get-DbaReplSubscription -SqlInstance mssql1 -Type Push Return all subscriptions for all transactional publications on server mssql1. @@ -84,7 +84,7 @@ function Get-DbaReplSubscription { [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [Object[]]$Database, - [String[]]$Name, + [String[]]$PublicationName, [DbaInstanceParameter[]]$SubscriberName, [Object[]]$SubscriptionDatabase, [Alias("PublicationType")] @@ -109,8 +109,8 @@ function Get-DbaReplSubscription { $publications = $publications | Where-Object DatabaseName -in $Database } - if ($Name) { - $publications = $publications | Where-Object Name -in $Name + if ($PublicationName) { + $publications = $publications | Where-Object Name -in $PublicationName } } catch { @@ -129,6 +129,10 @@ function Get-DbaReplSubscription { $subs = $subs | Where-Object SubscriptionDBName -eq $SubscriptionDatabase } + if($Type) { + $subs = $subs | Where-Object SubscriptionType -eq $Type + } + foreach ($sub in $subs) { Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name ComputerName -Value $server.ComputerName Add-Member -Force -InputObject $sub -MemberType NoteProperty -Name InstanceName -Value $server.ServiceName diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 34458e26ab..a640d6f3a1 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -7,30 +7,30 @@ function New-DbaReplSubscription { Creates a subscription for the database on the target SQL instances. .PARAMETER SqlInstance - The target SQL Server instance or instances. + The target publishing SQL Server instance or instances. .PARAMETER SqlCredential - Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). + 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 that will be replicated. + The database on the publisher that will be replicated. - .PARAMETER PublisherSqlInstance - The publisher SQL instance. + .PARAMETER SubscriberSqlInstance + The subscriber SQL instance. - .PARAMETER PublisherSqlCredential - Login to the publisher instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). + .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 PublicationDatabase - The database on the publisher that is replicated. + .PARAMETER SubscriptionDatabase + The database on the subscriber that will be the target of the replicated data. .PARAMETER PublicationName The name of the replication publication @@ -64,26 +64,25 @@ function New-DbaReplSubscription { https://dbatools.io/New-DbaReplSubscription .EXAMPLE - PS C:\> New-DbaReplicationSubscription -SqlInstance sql2017 -Database pubs -PublisherSqlInstance sql2016 -PublicationDatabase pubs -PublicationName testPub -Type Push + PS C:\> New-DbaReplSubscription -SqlInstance sql2017 -Database pubs -SubscriberSqlInstance sql2019 -SubscriptionDatabase pubs -PublicationName testPub -Type Push - Creates a push subscription for the pubs database on sql2017 to the testPub publication on sql2016 + Creates a push subscription from sql2017 to sql2019 for the pubs database. .EXAMPLE - PS C:\> New-DbaReplicationSubscription -SqlInstance sql2017 -Database pubs -PublisherSqlInstance sql2016 -PublicationDatabase pubs -PublicationName testPub -Type Pull - - Creates a pull subscription for the pubs database on sql2017 to the testPub publication on sql2016 + 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, + [DbaInstanceParameter]$SqlInstance, [PSCredential]$SqlCredential, [String]$Database, [Parameter(Mandatory)] - [DbaInstanceParameter]$PublisherSqlInstance, - [PSCredential]$PublisherSqlCredential, - [String]$PublicationDatabase, + [DbaInstanceParameter[]]$SubscriberSqlInstance, + [PSCredential]$SubscriberSqlCredential, + [String]$SubscriptionDatabase, [Parameter(Mandatory)] [String]$PublicationName, [PSCredential] @@ -94,46 +93,46 @@ function New-DbaReplSubscription { [Switch]$EnableException ) begin { - Write-Message -Level Verbose -Message "Connecting to publisher: $PublisherSqlInstance" + Write-Message -Level Verbose -Message "Connecting to publisher: $SqlInstance" # connect to publisher and get the publication try { - $pubReplServer = Get-DbaReplServer -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential + $pubReplServer = Get-DbaReplServer -SqlInstance $SqlInstance -SqlCredential $SqlCredential } catch { - Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $PublisherSqlInstance -Continue + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $SqlInstance -Continue } try { - $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName -EnableException + $pub = Get-DbaReplPublication -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Name $PublicationName -EnableException } catch { - Stop-Function -Message ("Publication {0} not found on {1}" -f $PublicationName, $PublisherSqlInstance) -ErrorRecord $_ -Target $PublisherSqlInstance -Continue + 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 $SqlInstance) { + foreach ($instance in $SubscriberSqlInstance) { try { - $subReplServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $subReplServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SubscriberSqlCredential - if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SqlCredential -Database $Database)) { - Write-Message -Level Verbose -Message "Subscription database $Database not found on $instance - will create it - but you should check the settings!" + if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase)) { + 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 = $SqlCredential - Name = $Database + SqlCredential = $SubscriberSqlCredential + Name = $SubscriptionDatabase EnableException = $EnableException } $null = New-DbaDatabase @newSubDb } } } catch { - Stop-Function -Message ("Couldn't create the subscription database {0}.{1}" -f $instance, $Database) -ErrorRecord $_ -Target $instance -Continue + Stop-Function -Message ("Couldn't create the subscription database {0}.{1}" -f $instance, $SubscriptionDatabase) -ErrorRecord $_ -Target $instance -Continue } try { @@ -144,7 +143,7 @@ function New-DbaReplSubscription { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication $transPub.ConnectionContext = $pubReplServer.ConnectionContext - $transPub.DatabaseName = $PublicationDatabase + $transPub.DatabaseName = $Database $transPub.Name = $PublicationName # if LoadProperties returns then the publication was found @@ -178,9 +177,9 @@ function New-DbaReplSubscription { # create the subscription $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription $transSub.ConnectionContext = $pubReplServer.ConnectionContext - $transSub.SubscriptionDBName = $Database + $transSub.SubscriptionDBName = $SubscriptionDatabase $transSub.SubscriberName = $instance - $transSub.DatabaseName = $PublicationDatabase + $transSub.DatabaseName = $Database $transSub.PublicationName = $PublicationName #TODO: @@ -214,7 +213,7 @@ function New-DbaReplSubscription { $mergePub = New-Object Microsoft.SqlServer.Replication.MergePublication $mergePub.ConnectionContext = $pubReplServer.ConnectionContext - $mergePub.DatabaseName = $PublicationDatabase + $mergePub.DatabaseName = $Database $mergePub.Name = $PublicationName if ( $mergePub.LoadProperties() ) { @@ -248,9 +247,9 @@ function New-DbaReplSubscription { } $mergeSub.ConnectionContext = $pubReplServer.ConnectionContext - $mergeSub.SubscriptionDBName = $Database + $mergeSub.SubscriptionDBName = $SubscriptionDatabase $mergeSub.SubscriberName = $instance - $mergeSub.DatabaseName = $PublicationDatabase + $mergeSub.DatabaseName = $Database $mergeSub.PublicationName = $PublicationName #TODO: diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index c4f37082e1..1accebfd29 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -10,28 +10,28 @@ function Remove-DbaReplSubscription { https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 .PARAMETER SqlInstance - The target SQL Server instance or instances. + The target publisher SQL Server instance or instances. .PARAMETER SqlCredential - Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). + Login to the target publisher 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 PublisherSqlInstance - The publisher SQL Server instance. + .PARAMETER Database + The database where the publication is located. + + .PARAMETER SubscriberSqlInstance + The subscriber SQL Server instance. - .PARAMETER PublisherSqlCredential - Login to the publisher instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). + .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 PublicationDatabase - The database where the publication is located. - .PARAMETER PublicationName The name of the publication. @@ -62,11 +62,11 @@ function Remove-DbaReplSubscription { .EXAMPLE PS C:\> $sub = @{ - SqlInstance = 'mssql2' - SubscriptionDatabase = 'pubs' - PublisherSqlInstance = 'mssql1' - PublicationDatabase = 'pubs' - PublicationName = 'testPub' + SqlInstance = 'mssql1' + Database = 'pubs' + PublicationName = 'testPub' + SubscriberSqlInstance = 'mssql2' + SubscriptionDatabase = 'pubs' } PS C:\> Remove-DbaReplSubscription @sub @@ -79,29 +79,30 @@ function Remove-DbaReplSubscription { [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, [Parameter(Mandatory)] - [DbaInstanceParameter]$PublisherSqlInstance, - [PSCredential]$PublisherSqlCredential, - [Parameter(Mandatory)] - [String]$PublicationDatabase, + [String]$Database, [Parameter(Mandatory)] [String]$PublicationName, + [Parameter(Mandatory)] + [DbaInstanceParameter]$SubscriberSqlInstance, + [PSCredential]$SubscriberSqlCredential, + [Parameter(Mandatory)] [String]$SubscriptionDatabase, [Switch]$EnableException ) begin { - $pub = Get-DbaReplPublication -SqlInstance $PublisherSqlInstance -SqlCredential $PublisherSqlCredential -Name $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Name $PublicationName if (-not $pub) { - Write-Warning "Didn't find a subscription to the $PublicationName publication on $PublisherSqlInstance.$Database" + Write-Warning "Didn't find a subscription to the $PublicationName publication on $SqlInstance.$Database" } } process { - foreach ($instance in $SqlInstance) { + foreach ($instance in $SubscriberSqlInstance) { try { - if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $instance.$SubscriptionDatabase")) { + if ($PSCmdlet.ShouldProcess($instance, "Removing subscription to $PublicationName from $SqlInstance.$SubscriptionDatabase")) { if ($pub.Type -in ('Transactional', 'Snapshot')) { @@ -109,7 +110,7 @@ function Remove-DbaReplSubscription { # https://learn.microsoft.com/en-us/sql/relational-databases/replication/delete-a-pull-subscription?view=sql-server-ver16 $transSub = New-Object Microsoft.SqlServer.Replication.TransSubscription $transSub.ConnectionContext = $pub.ConnectionContext - $transSub.DatabaseName = $PublicationDatabase + $transSub.DatabaseName = $Database $transSub.PublicationName = $PublicationName $transSub.SubscriptionDBName = $SubscriptionDatabase $transSub.SubscriberName = $instance @@ -122,7 +123,7 @@ function Remove-DbaReplSubscription { } elseif ($pub.Type -eq 'Merge') { $mergeSub = New-Object Microsoft.SqlServer.Replication.MergeSubscription $mergeSub.ConnectionContext = $pub.ConnectionContext - $mergeSub.DatabaseName = $PublicationDatabase + $mergeSub.DatabaseName = $Database $mergeSub.PublicationName = $PublicationName $mergeSub.SubscriptionDBName = $SubscriptionDatabase $mergeSub.SubscriberName = $instance diff --git a/tests/Get-DbaReplSubscription.Tests.ps1 b/tests/Get-DbaReplSubscription.Tests.ps1 index 8343c4ac17..2c1d56a748 100644 --- a/tests/Get-DbaReplSubscription.Tests.ps1 +++ b/tests/Get-DbaReplSubscription.Tests.ps1 @@ -7,8 +7,8 @@ Add-ReplicationLibrary 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', 'Name', 'Type', 'EnableException' + [object[]]$params = (Get-Command $CommandName).Parameters.Keys | Where-Object {$_ -notin ('whatif', 'confirm') } + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'PublicationName', 'Type', 'SubscriberName', 'SubscriptionDatabase', 'Type', '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 diff --git a/tests/New-DbaReplSubscription.Tests.ps1 b/tests/New-DbaReplSubscription.Tests.ps1 index 04b2443010..d0d001c2da 100644 --- a/tests/New-DbaReplSubscription.Tests.ps1 +++ b/tests/New-DbaReplSubscription.Tests.ps1 @@ -8,7 +8,7 @@ Add-ReplicationLibrary 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', 'PublisherSqlInstance', 'PublisherSqlCredential', 'PublicationDatabase', 'PublicationName', 'SubscriptionSqlCredential', 'Type', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'SubscriberSqlInstance', 'SubscriberSqlCredential', 'SubscriptionDatabase', 'PublicationName', 'SubscriptionSqlCredential', 'Type', '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 diff --git a/tests/Remove-DbaReplSubscription.Tests.ps1 b/tests/Remove-DbaReplSubscription.Tests.ps1 index b173eace5b..a6c35c4085 100644 --- a/tests/Remove-DbaReplSubscription.Tests.ps1 +++ b/tests/Remove-DbaReplSubscription.Tests.ps1 @@ -8,7 +8,7 @@ Add-ReplicationLibrary 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', 'PublisherSqlInstance', 'PublisherSqlCredential', 'PublicationDatabase', 'PublicationName', 'SubscriptionDatabase', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'PublicationName', 'SubscriberSqlInstance', 'SubscriberSqlCredential', 'SubscriptionDatabase', '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 From 635e4cdb7fc6eed1973399d82a4da82e5382ef8a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 28 Jul 2023 13:10:53 +0100 Subject: [PATCH 190/226] formatter --- public/Get-DbaReplSubscription.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index 602ee62ca2..96c63eab42 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -129,7 +129,7 @@ function Get-DbaReplSubscription { $subs = $subs | Where-Object SubscriptionDBName -eq $SubscriptionDatabase } - if($Type) { + if ($Type) { $subs = $subs | Where-Object SubscriptionType -eq $Type } From 85930c35e9e05858be1a398dec8d07bd8cbf0516 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 31 Jul 2023 15:32:09 +0100 Subject: [PATCH 191/226] remove dupe param name --- tests/Get-DbaReplSubscription.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Get-DbaReplSubscription.Tests.ps1 b/tests/Get-DbaReplSubscription.Tests.ps1 index 2c1d56a748..86483c26b2 100644 --- a/tests/Get-DbaReplSubscription.Tests.ps1 +++ b/tests/Get-DbaReplSubscription.Tests.ps1 @@ -8,7 +8,7 @@ Add-ReplicationLibrary 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', 'PublicationName', 'Type', 'SubscriberName', 'SubscriptionDatabase', 'Type', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'PublicationName', 'SubscriberName', 'SubscriptionDatabase', 'Type', '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 From 5857426f9ec9864ced4ef10f175b06d433ce4078 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 31 Jul 2023 15:32:33 +0100 Subject: [PATCH 192/226] add tests for subscriptions --- tests/gh-actions-repl.ps1 | 92 +++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index f42fa5f7b8..a742d18298 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -5,7 +5,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred - $PSDefaultParameterValues["*:SubscriptionSqlCredential1"] = $cred + $PSDefaultParameterValues["*:SubscriberSqlCredential1"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" @@ -630,7 +630,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "Subscription commands" { + Describe "Subscription commands" -tag sub { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -665,22 +665,24 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "New-DbaReplSubscription works" -tag sub { + Context "New-DbaReplSubscription works" { BeforeAll { - if (Get-DbaReplSubscription -SqlInstance mssql1 -Name TestTrans -Database ReplDb -SubscriberName mssql2 -SubscriptionDatabase ReplDbTrans) { - Remove-DbaReplSubscription -SqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName TestTrans -Confirm:$false -EnableException + if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans) { + (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans).foreach{ + Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException + } } - if (Get-DbaReplSubscription -SqlInstance mssql1 -Name TestSnap -Database ReplDb -SubscriberName mssql2 -SubscriptionDatabase ReplDbSnap) { - Remove-DbaReplSubscription -SqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName TestSnap -Confirm:$false -EnableException + if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestSnap) { + (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestSnap).foreach{ + Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException + } } } It "Adds a subscription" { - #TODO: we are here and broke $pubName = 'TestTrans' - #transactional - { New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDbTrans -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw + { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Name $pubname + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname $sub | Should -Not -BeNullOrEmpty $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } @@ -688,11 +690,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } } - It "Adds a pull subscription" -tag sub { + It "Adds a pull subscription" -skip { + #TODO: Fix pull subscriptions in New-DbaReplSubscription command $pubName = 'TestSnap' - { New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDbSnap -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw + { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Name $pubname + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname $sub | Should -Not -BeNullOrEmpty $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } @@ -702,21 +705,27 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Throws an error if there are no articles in the publication" { $pubName = 'TestMerge' - { New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw + { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw } } Context "Remove-DbaReplSubscription works"{ BeforeEach { $pubName = 'TestTrans' - if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -Type Push + if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql1 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push } } - It "Removes a subscription" { - Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -Name $pubname -Type Push | Should -Not -BeNullOrEmpty - { Remove-DbaReplSubscription -SqlInstance mssql2 -SubscriptionDatabase ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw - Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty + It "Removes a push subscription" { + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Should -Not -BeNullOrEmpty + { Remove-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDb -SubscriberSqlInstance mssql2 -Database ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty + } + It "Removes a pull subscription" -skip { + #TODO: Fix pull subscriptions in New-DbaReplSubscription command + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Pull | Should -Not -BeNullOrEmpty + { Remove-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDb -SubscriberSqlInstance mssql2 -Database ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Pull | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty } } @@ -724,12 +733,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Get-DbaReplSubscription works" { BeforeAll { $pubName = 'TestTrans' - if (-not (Get-DbaReplSubscription -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -Type Push -enableException + if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException } $pubName = 'TestSnap' - if (-not (Get-DbaReplSubscription -Name $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql2 -Database ReplDb -PublisherSqlInstance mssql1 -PublicationDatabase ReplDb -PublicationName $pubname -Type Push -enableException + if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException } } @@ -739,12 +748,41 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } } - It "Gets subscriptions to a particular instance" { + It "Gets subscriptions for a particular database" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb + $sub | Should -Not -BeNullOrEmpty + $sub.DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + It "Gets subscriptions by publication name" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans + $sub | Should -Not -BeNullOrEmpty + $sub.PublicationName | ForEach-Object { $_ | Should -Be 'TestTrans' } } - } + It "Gets subscriptions by type" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Type Push + $sub | Should -Not -BeNullOrEmpty + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Type Pull + if($sub) { + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } + } + } + + It "Gets subscriptions by subscriber name" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -SubscriberName mssql2 + $sub | Should -Not -BeNullOrEmpty + $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } + } + + It "Gets subscriptions by subscription database name" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDbTrans + $sub | Should -Not -BeNullOrEmpty + $sub.SubscriptionDBName | ForEach-Object { $_ | Should -Be 'ReplDbTrans' } + } + } } Describe "Piping" { From 14863f017c33655c78cdb099ab4d68c67a996dda Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 1 Aug 2023 14:31:09 +0100 Subject: [PATCH 193/226] note about pull subs --- public/New-DbaReplSubscription.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index a640d6f3a1..cc192887f1 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -164,6 +164,8 @@ function New-DbaReplSubscription { $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. From 8d00ef7ca722d9a3ffa4cd13de684ff48f584bd6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Tue, 1 Aug 2023 15:03:56 +0100 Subject: [PATCH 194/226] fix test --- tests/Get-DbaReplPublication.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Get-DbaReplPublication.Tests.ps1 b/tests/Get-DbaReplPublication.Tests.ps1 index 59ff6dc6a3..fc06284fa7 100644 --- a/tests/Get-DbaReplPublication.Tests.ps1 +++ b/tests/Get-DbaReplPublication.Tests.ps1 @@ -50,7 +50,7 @@ Describe "$commandname Unit Tests" -Tag 'UnitTests' { It "Honors the SQLInstance parameter" { $Results = Get-DbaReplPublication -SqlInstance MockServerName - $Results.SqlInstance | Should Be "MockServerName" + $Results.SqlInstance.Name | Should Be "MockServerName" } It "Honors the Database parameter" { From 1995e72efac98a572f18598c43806fd1bcffae60 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 09:12:47 +0100 Subject: [PATCH 195/226] add schema to Get articles --- tests/Get-DbaReplArticle.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Get-DbaReplArticle.Tests.ps1 b/tests/Get-DbaReplArticle.Tests.ps1 index 2cde5a6b19..ec006fe8a7 100644 --- a/tests/Get-DbaReplArticle.Tests.ps1 +++ b/tests/Get-DbaReplArticle.Tests.ps1 @@ -8,7 +8,7 @@ Add-ReplicationLibrary 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', 'Publication', 'Name', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'Publication', 'Schema', 'Name', '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 From 59c2228ccd1107a6e14f31aa7a9d979f2d81d6d2 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 09:18:28 +0100 Subject: [PATCH 196/226] schema missed a file --- public/Get-DbaReplArticle.ps1 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index 012faf8b2e..bb4a2db8b7 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -24,6 +24,9 @@ function Get-DbaReplArticle { .PARAMETER Publication Specifies one or more publication(s) to process. If unspecified, all publications will be processed. + .PARAMETER Schema + Specifies one or more schema(s) to process. If unspecified, all schemas will be processed. + .PARAMETER Name Specify the name of one or more article(s) to process. If unspecified, all articles will be processed. @@ -59,9 +62,14 @@ function Get-DbaReplArticle { Retrieve information of all articles from 'PubName' on 'pubs' database for server mssql1. .EXAMPLE - PS C:\> Get-DbaReplArticle -SqlInstance sqlserver2019 -Database pubs -Publication PubName -Name sales + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database pubs -Schema sales + + Retrieve information of articles in the 'sales' schema on 'pubs' database for server mssql1. + + .EXAMPLE + PS C:\> Get-DbaReplArticle -SqlInstance mssql1 -Database pubs -Publication PubName -Name sales - Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server sqlserver2019. + Retrieve information of 'sales' article from 'PubName' on 'pubs' database for server mssql1. #> [CmdletBinding()] @@ -71,6 +79,7 @@ function Get-DbaReplArticle { [PSCredential]$SqlCredential, [object[]]$Database, [object[]]$Publication, + [string[]]$Schema, [string[]]$Name, [switch]$EnableException ) @@ -107,6 +116,10 @@ function Get-DbaReplArticle { } $articles = $publications.Articles + + if ($Schema) { + $articles = $articles | Where-Object SourceObjectOwner -in $Schema + } if ($Name) { $articles = $articles | Where-Object Name -in $Name } From 7ac55a59ee3099665b16b96b8080e458f8dfbdf2 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 10:53:29 +0100 Subject: [PATCH 197/226] create sub schema if it doesn't exist --- public/New-DbaReplSubscription.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index cc192887f1..5a0a93c793 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -139,6 +139,14 @@ function New-DbaReplSubscription { 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 (-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!" + New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Name $schema -EnableException + } + } + if ($pub.Type -in ('Transactional', 'Snapshot')) { $transPub = New-Object Microsoft.SqlServer.Replication.TransPublication From 966f56f75ec949b639e510633aa3d76e703925c8 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 11:00:42 +0100 Subject: [PATCH 198/226] param name incorrect --- public/New-DbaReplSubscription.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 5a0a93c793..016a5f5553 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -143,7 +143,7 @@ function New-DbaReplSubscription { foreach ($schema in $pub.articles.DestinationObjectOwner) { if (-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!" - New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Name $schema -EnableException + New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema -EnableException } } From 946ab837aff2e3b5c0d2cdc1556e85c9f9237c8e Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 11:02:11 +0100 Subject: [PATCH 199/226] set output to null when creating new schema --- public/New-DbaReplSubscription.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 016a5f5553..d65b5f376a 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -143,7 +143,7 @@ function New-DbaReplSubscription { foreach ($schema in $pub.articles.DestinationObjectOwner) { if (-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!" - New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema -EnableException + $null = New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema -EnableException } } From 3c5c254aceeb693f1e6e901d0e9b72dd91419613 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 11:05:03 +0100 Subject: [PATCH 200/226] not dbo schema --- public/New-DbaReplSubscription.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index d65b5f376a..8be0cdd6b6 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -141,7 +141,7 @@ function New-DbaReplSubscription { # check if needed schemas exist foreach ($schema in $pub.articles.DestinationObjectOwner) { - if (-not (Get-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema)) { + if (-not 'dbo' -or (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 } From 2eae1d5eb636f0ae3562193c6a714a8052d66446 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 11:10:17 +0100 Subject: [PATCH 201/226] conditions are hard --- public/New-DbaReplSubscription.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 8be0cdd6b6..c225ffa437 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -141,7 +141,7 @@ function New-DbaReplSubscription { # check if needed schemas exist foreach ($schema in $pub.articles.DestinationObjectOwner) { - if (-not 'dbo' -or (Get-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema)) { + 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 } From 2051a6ba24271b5c3ef3e85b8d85f26ce956b5c1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 12:08:03 +0100 Subject: [PATCH 202/226] better error handling --- public/Remove-DbaReplPublication.ps1 | 38 ++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 8f8c4c4217..f6318ef809 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -104,17 +104,26 @@ function Remove-DbaReplPublication { Status = $null IsRemoved = $false } - try { - if ($pub.Type -in ('Transactional', 'Snapshot')) { + if ($pub.Type -in ('Transactional', 'Snapshot')) { + try { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" if ($Force) { $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob } $pub.Remove() + + $output.Status = "Removed" + $output.IsRemoved = $true } + } catch { + Stop-Function -Message "Failed to remove the publication from $($pub.SqlInstance)" -ErrorRecord $_ + $output.Status = (Get-ErrorMessage -Record $_) + $output.IsRemoved = $false + } + try { # If no other transactional publications exist for this database, the database can be disabled for transactional publishing if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Transactional, Snapshot)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase @@ -129,19 +138,31 @@ function Remove-DbaReplPublication { $pubDatabase.EnabledTransPublishing = $false } } + } catch { + Stop-Function -Message "Failed to disable transactional publishing on $($pub.SqlInstance)" -ErrorRecord $_ + } - } elseif ($pub.Type -eq 'Merge') { - + } elseif ($pub.Type -eq 'Merge') { + try { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" if ($Force) { $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob } $pub.Remove() + + $output.Status = "Removed" + $output.IsRemoved = $true } else { Write-Warning "Didn't find $($pub.Name) on $($pub.SqlInstance).$($pub.DatabaseName)" } + } catch { + Stop-Function -Message "Failed to remove the publication from $($pub.SqlInstance)" -ErrorRecord $_ + $output.Status = (Get-ErrorMessage -Record $_) + $output.IsRemoved = $false + } + try { # If no other merge publications exist for this database, the database can be disabled for merge publishing if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Merge)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase @@ -157,14 +178,11 @@ function Remove-DbaReplPublication { $pubDatabase.EnabledMergePublishing = $false } } + } catch { + Stop-Function -Message "Failed to disable transactional publishing on $($pub.SqlInstance)" -ErrorRecord $_ } - $output.Status = "Removed" - $output.IsRemoved = $true - } catch { - Stop-Function -Message "Failed to remove the article from publication" -ErrorRecord $_ - $output.Status = (Get-ErrorMessage -Record $_) - $output.IsRemoved = $false } + $output } } From b21cea5e07f07e6a63c99899a61c36c84e4f95c8 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 12:20:05 +0100 Subject: [PATCH 203/226] always stop job (it'll restart) --- public/Remove-DbaReplPublication.ps1 | 10 +++------- tests/Remove-DbaReplPublication.Tests.ps1 | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index f6318ef809..9e0c36291c 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -27,9 +27,6 @@ function Remove-DbaReplPublication { .PARAMETER InputObject A publication object retrieved from Get-DbaReplPublication. Enables piping from Get-DbaReplPublication. - .PARAMETER Force - If this switch is enabled, this command will look for the REPL-LogReader SQL Agent Job for this database and if it's running, stop the job. - .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. @@ -66,7 +63,6 @@ function Remove-DbaReplPublication { [String]$Name, [parameter(ValueFromPipeline)] [Microsoft.SqlServer.Replication.Publication[]]$InputObject, - [Switch]$Force, [Switch]$EnableException ) begin { @@ -84,7 +80,6 @@ function Remove-DbaReplPublication { $params = $PSBoundParameters $null = $params.Remove('InputObject') $null = $params.Remove('WhatIf') - $null = $params.Remove('Force') $null = $params.Remove('Confirm') $publications = Get-DbaReplPublication @params } @@ -109,7 +104,8 @@ function Remove-DbaReplPublication { try { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" - if ($Force) { + + if ($PSCmdlet.ShouldProcess($pub.Name, "Stopping the REPL-LogReader job for the database $($pub.DatabaseName) on $($pub.SqlInstance)")) { $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob } $pub.Remove() @@ -146,7 +142,7 @@ function Remove-DbaReplPublication { try { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" - if ($Force) { + if ($PSCmdlet.ShouldProcess($pub.Name, "Stopping the REPL-LogReader job for the database $($pub.DatabaseName) on $($pub.SqlInstance)")) { $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob } $pub.Remove() diff --git a/tests/Remove-DbaReplPublication.Tests.ps1 b/tests/Remove-DbaReplPublication.Tests.ps1 index 36d344f56e..68d9490f72 100644 --- a/tests/Remove-DbaReplPublication.Tests.ps1 +++ b/tests/Remove-DbaReplPublication.Tests.ps1 @@ -8,7 +8,7 @@ Add-ReplicationLibrary 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', 'Name', 'InputObject', 'Force', 'EnableException' + [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'Name', 'InputObject', '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 From 6acc361239e694ba1375d58a6434a426fa3f3fe0 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 12:21:07 +0100 Subject: [PATCH 204/226] change to high impact --- public/Remove-DbaReplPublication.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index 9e0c36291c..a56a9f1679 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -55,7 +55,7 @@ function Remove-DbaReplPublication { Removes a publication called PubFromPosh from the Northwind database on mssql1 #> - [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')] param ( [DbaInstanceParameter[]]$SqlInstance, [PSCredential]$SqlCredential, From cb0c1d9da3ba6a2ddc4a3365c89936f67750aec2 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Wed, 9 Aug 2023 12:23:09 +0100 Subject: [PATCH 205/226] don't output killing --- public/Disable-DbaReplDistributor.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/Disable-DbaReplDistributor.ps1 b/public/Disable-DbaReplDistributor.ps1 index fe8159e06d..f7a4e3bd4a 100644 --- a/public/Disable-DbaReplDistributor.ps1 +++ b/public/Disable-DbaReplDistributor.ps1 @@ -76,7 +76,7 @@ function Disable-DbaReplDistributor { try { if ($PSCmdlet.ShouldProcess($instance, "Disabling and removing distribution on $instance")) { # remove any connections to the distribution database - Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name -EnableException:$EnableException | Stop-DbaProcess -EnableException:$EnableException + $null = Get-DbaProcess -SqlInstance $instance -SqlCredential $SqlCredential -Database $replServer.DistributionDatabases.name -EnableException:$EnableException | Stop-DbaProcess -EnableException:$EnableException # uninstall distribution $replServer.UninstallDistributor($Force) } From 9d8f2f67a03fbd282486c1750cad4defa58db690 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 21 Aug 2023 13:47:36 +0100 Subject: [PATCH 206/226] ensure enableexception is passed through --- public/Disable-DbaReplPublishing.ps1 | 2 +- public/Enable-DbaReplDistributor.ps1 | 2 +- public/Enable-DbaReplPublishing.ps1 | 2 +- public/Export-DbaReplServerSetting.ps1 | 2 +- public/Get-DbaReplArticle.ps1 | 2 +- public/Get-DbaReplArticleColumn.ps1 | 2 +- public/Get-DbaReplDistributor.ps1 | 2 +- public/Get-DbaReplPublication.ps1 | 3 ++- public/Get-DbaReplPublisher.ps1 | 2 +- public/Get-DbaReplSubscription.ps1 | 2 +- public/New-DbaReplPublication.ps1 | 2 +- public/New-DbaReplSubscription.ps1 | 10 +++++----- public/Remove-DbaReplArticle.ps1 | 4 ++-- public/Remove-DbaReplPublication.ps1 | 8 ++++---- public/Remove-DbaReplSubscription.ps1 | 4 ++-- 15 files changed, 25 insertions(+), 24 deletions(-) diff --git a/public/Disable-DbaReplPublishing.ps1 b/public/Disable-DbaReplPublishing.ps1 index 1e6e126470..1970881893 100644 --- a/public/Disable-DbaReplPublishing.ps1 +++ b/public/Disable-DbaReplPublishing.ps1 @@ -68,7 +68,7 @@ function Disable-DbaReplPublishing { process { foreach ($instance in $SqlInstance) { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException Write-Message -Level Verbose -Message "Disabling and removing publishing for $instance" diff --git a/public/Enable-DbaReplDistributor.ps1 b/public/Enable-DbaReplDistributor.ps1 index 8fc62f6bfd..902d3abbf8 100644 --- a/public/Enable-DbaReplDistributor.ps1 +++ b/public/Enable-DbaReplDistributor.ps1 @@ -65,7 +65,7 @@ function Enable-DbaReplDistributor { process { foreach ($instance in $SqlInstance) { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException Write-Message -Level Verbose -Message "Enabling replication distribution for $instance" diff --git a/public/Enable-DbaReplPublishing.ps1 b/public/Enable-DbaReplPublishing.ps1 index 35a0f807a7..5995d335d5 100644 --- a/public/Enable-DbaReplPublishing.ps1 +++ b/public/Enable-DbaReplPublishing.ps1 @@ -65,7 +65,7 @@ function Enable-DbaReplPublishing { process { foreach ($instance in $SqlInstance) { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException Write-Message -Level Verbose -Message "Enabling replication publishing for $instance" diff --git a/public/Export-DbaReplServerSetting.ps1 b/public/Export-DbaReplServerSetting.ps1 index e05b6a9e86..77f59ca3f3 100644 --- a/public/Export-DbaReplServerSetting.ps1 +++ b/public/Export-DbaReplServerSetting.ps1 @@ -104,7 +104,7 @@ function Export-DbaReplServerSetting { process { if (Test-FunctionInterrupt) { return } foreach ($instance in $SqlInstance) { - $InputObject += Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $InputObject += Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException } foreach ($repserver in $InputObject) { diff --git a/public/Get-DbaReplArticle.ps1 b/public/Get-DbaReplArticle.ps1 index bb4a2db8b7..21da21b046 100644 --- a/public/Get-DbaReplArticle.ps1 +++ b/public/Get-DbaReplArticle.ps1 @@ -109,7 +109,7 @@ function Get-DbaReplArticle { foreach ($db in $databases) { Write-Message -Level Verbose -Message ('Working on {0}' -f $db.Name) - $publications = Get-DbaReplPublication -SqlInstance $server -Database $db.Name + $publications = Get-DbaReplPublication -SqlInstance $server -Database $db.Name -EnableException:$EnableException if ($Publication) { $publications = $publications | Where-Object Name -in $Publication diff --git a/public/Get-DbaReplArticleColumn.ps1 b/public/Get-DbaReplArticleColumn.ps1 index 972593421c..9f2814ee6e 100644 --- a/public/Get-DbaReplArticleColumn.ps1 +++ b/public/Get-DbaReplArticleColumn.ps1 @@ -85,7 +85,7 @@ function Get-DbaReplArticleColumn { process { if (Test-FunctionInterrupt) { return } - $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -Name $Article + $articles = Get-DbaReplArticle -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $Database -Publication $Publication -Name $Article -EnableException:$EnableException foreach ($art in $articles) { try { diff --git a/public/Get-DbaReplDistributor.ps1 b/public/Get-DbaReplDistributor.ps1 index 68f6e54253..16f1fd9a96 100644 --- a/public/Get-DbaReplDistributor.ps1 +++ b/public/Get-DbaReplDistributor.ps1 @@ -56,7 +56,7 @@ function Get-DbaReplDistributor { # Connect to the distributor of the instance try { - $distributor = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $distributor = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException } catch { Stop-Function -Message "Error occurred getting information about $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue } diff --git a/public/Get-DbaReplPublication.ps1 b/public/Get-DbaReplPublication.ps1 index 254783a823..434c444a62 100644 --- a/public/Get-DbaReplPublication.ps1 +++ b/public/Get-DbaReplPublication.ps1 @@ -111,7 +111,8 @@ function Get-DbaReplPublication { continue } - $repDB = Connect-ReplicationDB -Server $server -Database $db + + $repDB = Connect-ReplicationDB -Server $server -Database $db -EnableException:$EnableException $pubTypes = $repDB.TransPublications + $repDB.MergePublications diff --git a/public/Get-DbaReplPublisher.ps1 b/public/Get-DbaReplPublisher.ps1 index c17e58c642..3db1b106af 100644 --- a/public/Get-DbaReplPublisher.ps1 +++ b/public/Get-DbaReplPublisher.ps1 @@ -53,7 +53,7 @@ function Get-DbaReplPublisher { foreach ($instance in $SqlInstance) { try { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential - $replServer = Get-DbaReplServer -SqlInstance $server + $replServer = Get-DbaReplServer -SqlInstance $server -EnableException:$EnableException } catch { Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $server -Continue } diff --git a/public/Get-DbaReplSubscription.ps1 b/public/Get-DbaReplSubscription.ps1 index 96c63eab42..3169ffe18e 100644 --- a/public/Get-DbaReplSubscription.ps1 +++ b/public/Get-DbaReplSubscription.ps1 @@ -103,7 +103,7 @@ function Get-DbaReplSubscription { } try { - $publications = Get-DbaReplPublication -SqlInstance $server + $publications = Get-DbaReplPublication -SqlInstance $server -EnableException:$EnableException if ($Database) { $publications = $publications | Where-Object DatabaseName -in $Database diff --git a/public/New-DbaReplPublication.ps1 b/public/New-DbaReplPublication.ps1 index e2b064a461..7c538626fc 100644 --- a/public/New-DbaReplPublication.ps1 +++ b/public/New-DbaReplPublication.ps1 @@ -91,7 +91,7 @@ function New-DbaReplPublication { process { foreach ($instance in $SqlInstance) { try { - $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential + $replServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SqlCredential -EnableException:$EnableException if (-not $replServer.IsPublisher) { Stop-Function -Message "Instance $instance is not a publisher, run Enable-DbaReplPublishing to set this up" -Target $instance -Continue diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index c225ffa437..7876ed63c8 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -97,13 +97,13 @@ function New-DbaReplSubscription { # connect to publisher and get the publication try { - $pubReplServer = Get-DbaReplServer -SqlInstance $SqlInstance -SqlCredential $SqlCredential + $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 + $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 } @@ -115,9 +115,9 @@ function New-DbaReplSubscription { foreach ($instance in $SubscriberSqlInstance) { try { - $subReplServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SubscriberSqlCredential + $subReplServer = Get-DbaReplServer -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -EnableException:$EnableException - if (-not (Get-DbaDatabase -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase)) { + 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")) { @@ -143,7 +143,7 @@ function New-DbaReplSubscription { 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 + $null = New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema -EnableException:$EnableException } } diff --git a/public/Remove-DbaReplArticle.ps1 b/public/Remove-DbaReplArticle.ps1 index 5e9ec99f25..a4354240a4 100644 --- a/public/Remove-DbaReplArticle.ps1 +++ b/public/Remove-DbaReplArticle.ps1 @@ -126,12 +126,12 @@ function Remove-DbaReplArticle { } try { - $pub = Get-DbaReplPublication -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -Name $art.PublicationName + $pub = Get-DbaReplPublication -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -Name $art.PublicationName -EnableException:$EnableException if (($pub.Subscriptions | Measure-Object).count -gt 0 ) { Write-Message -Level Verbose -Message ("There is a subscription so remove article {0} from subscription on {1}" -f $art.Name, $pub.Subscriptions.SubscriberName) $query = "exec sp_dropsubscription @publication = '{0}', @article= '{1}',@subscriber = '{2}'" -f $art.PublicationName, $art.Name, $pub.Subscriptions.SubscriberName - Invoke-DbaQuery -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -query $query + Invoke-DbaQuery -SqlInstance $art.SqlInstance -SqlCredential $SqlCredential -Database $art.DatabaseName -query $query -EnableException:$EnableException } if (($art.IsExistingObject)) { $art.Remove() diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index a56a9f1679..cd036bb97e 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -106,7 +106,7 @@ function Remove-DbaReplPublication { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" if ($PSCmdlet.ShouldProcess($pub.Name, "Stopping the REPL-LogReader job for the database $($pub.DatabaseName) on $($pub.SqlInstance)")) { - $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader -EnableException:$EnableException | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob -EnableException:$EnableException } $pub.Remove() @@ -121,7 +121,7 @@ function Remove-DbaReplPublication { try { # If no other transactional publications exist for this database, the database can be disabled for transactional publishing - if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Transactional, Snapshot)) { + if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Transactional, Snapshot -EnableException:$EnableException)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $pub.ConnectionContext $pubDatabase.Name = $pub.DatabaseName @@ -143,7 +143,7 @@ function Remove-DbaReplPublication { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" if ($PSCmdlet.ShouldProcess($pub.Name, "Stopping the REPL-LogReader job for the database $($pub.DatabaseName) on $($pub.SqlInstance)")) { - $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader -EnableException:$EnableException| Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob -EnableException:$EnableException } $pub.Remove() @@ -160,7 +160,7 @@ function Remove-DbaReplPublication { try { # If no other merge publications exist for this database, the database can be disabled for merge publishing - if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Merge)) { + if (-not (Get-DbaReplPublication -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Database $pub.DatabaseName -Type Merge -EnableException:$EnableException)) { $pubDatabase = New-Object Microsoft.SqlServer.Replication.ReplicationDatabase $pubDatabase.ConnectionContext = $pub.ConnectionContext $pubDatabase.Name = $pub.DatabaseName diff --git a/public/Remove-DbaReplSubscription.ps1 b/public/Remove-DbaReplSubscription.ps1 index 1accebfd29..b9cd288961 100644 --- a/public/Remove-DbaReplSubscription.ps1 +++ b/public/Remove-DbaReplSubscription.ps1 @@ -73,7 +73,7 @@ function Remove-DbaReplSubscription { Removes a subscription for the testPub publication on mssql2.pubs. #> - [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param ( [Parameter(Mandatory, ValueFromPipeline)] [DbaInstanceParameter[]]$SqlInstance, @@ -91,7 +91,7 @@ function Remove-DbaReplSubscription { ) begin { - $pub = Get-DbaReplPublication -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Name $PublicationName + $pub = Get-DbaReplPublication -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Name $PublicationName -EnableException:$EnableException if (-not $pub) { Write-Warning "Didn't find a subscription to the $PublicationName publication on $SqlInstance.$Database" From b577aee85128d9252a27c0106b71562d49240786 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 21 Aug 2023 14:23:16 +0100 Subject: [PATCH 207/226] but not for jobs.. this is just best effort --- public/Remove-DbaReplPublication.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/Remove-DbaReplPublication.ps1 b/public/Remove-DbaReplPublication.ps1 index cd036bb97e..4959879e67 100644 --- a/public/Remove-DbaReplPublication.ps1 +++ b/public/Remove-DbaReplPublication.ps1 @@ -106,7 +106,7 @@ function Remove-DbaReplPublication { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" if ($PSCmdlet.ShouldProcess($pub.Name, "Stopping the REPL-LogReader job for the database $($pub.DatabaseName) on $($pub.SqlInstance)")) { - $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader -EnableException:$EnableException | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob -EnableException:$EnableException + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob } $pub.Remove() @@ -143,7 +143,7 @@ function Remove-DbaReplPublication { if ($pub.IsExistingObject) { Write-Message -Level Verbose -Message "Removing $($pub.Name) from $($pub.SqlInstance).$($pub.DatabaseName)" if ($PSCmdlet.ShouldProcess($pub.Name, "Stopping the REPL-LogReader job for the database $($pub.DatabaseName) on $($pub.SqlInstance)")) { - $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader -EnableException:$EnableException| Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob -EnableException:$EnableException + $null = Get-DbaAgentJob -SqlInstance $pub.SqlInstance -SqlCredential $SqlCredential -Category REPL-LogReader | Where-Object { $_.Name -like ('*{0}*' -f $pub.DatabaseName) } | Stop-DbaAgentJob } $pub.Remove() From d27969c70facaa9fea5a19663ce524240f996ac7 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 21 Aug 2023 14:52:07 +0100 Subject: [PATCH 208/226] remove one enableexception option --- public/New-DbaReplSubscription.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/New-DbaReplSubscription.ps1 b/public/New-DbaReplSubscription.ps1 index 7876ed63c8..37ffff9b25 100644 --- a/public/New-DbaReplSubscription.ps1 +++ b/public/New-DbaReplSubscription.ps1 @@ -118,6 +118,7 @@ function New-DbaReplSubscription { $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")) { @@ -143,7 +144,7 @@ function New-DbaReplSubscription { 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:$EnableException + $null = New-DbaDbSchema -SqlInstance $instance -SqlCredential $SubscriberSqlCredential -Database $SubscriptionDatabase -Schema $schema -EnableException } } From 38c43205ed10a105b8e122612597951174ee60b1 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Mon, 21 Aug 2023 15:03:41 +0100 Subject: [PATCH 209/226] remove force add tags --- tests/gh-actions-repl.ps1 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl.ps1 index a742d18298..f55c000266 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl.ps1 @@ -5,7 +5,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" $PSDefaultParameterValues["*:SqlCredential"] = $cred - $PSDefaultParameterValues["*:SubscriberSqlCredential1"] = $cred + $PSDefaultParameterValues["*:SubscriberSqlCredential"] = $cred $PSDefaultParameterValues["*:Confirm"] = $false $PSDefaultParameterValues["*:SharedPath"] = "/shared" $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" @@ -17,7 +17,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' } - Describe "General commands" { + Describe "General commands" -Tag general { Context "Get-DbaReplServer works" { @@ -39,7 +39,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "Publishing\Distribution commands" { + Describe "Publishing\Distribution commands" -tag pub { Context "Get-DbaReplDistributor works" { BeforeAll { @@ -194,7 +194,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "Publication commands" { + Describe "Publication commands" -tag pub { Context "Get-DbaReplPublication works" { BeforeAll { @@ -313,7 +313,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "Article commands" { + Describe "Article commands" -tag art { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -552,7 +552,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Describe "Article Column commands" { + Describe "Article Column commands" -tag art { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -785,7 +785,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "Piping" { + Describe "Piping" -tag pipe { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -869,7 +869,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Remove-DbaReplPublication works with piping" { It "Remove-DbaReplPublication removes a publication using piping" { $name = 'TestMerge' - { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException | Remove-DbaReplPublication -EnableException } | Should -Not -Throw + { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException | Remove-DbaReplPublication -Confirm:$false -EnableException } | Should -Not -Throw (Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException) | Should -BeNullOrEmpty } } From 25e97cfe7ce3490d67bd7baab6a8f407f4dc4c53 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 14:18:12 +0100 Subject: [PATCH 210/226] break repl tests into two files --- tests/gh-actions-repl-1.ps1 | 315 ++++++++++++++++++ ...actions-repl.ps1 => gh-actions-repl-2.ps1} | 296 ---------------- 2 files changed, 315 insertions(+), 296 deletions(-) create mode 100644 tests/gh-actions-repl-1.ps1 rename tests/{gh-actions-repl.ps1 => gh-actions-repl-2.ps1} (72%) diff --git a/tests/gh-actions-repl-1.ps1 b/tests/gh-actions-repl-1.ps1 new file mode 100644 index 0000000000..14cbb10dff --- /dev/null +++ b/tests/gh-actions-repl-1.ps1 @@ -0,0 +1,315 @@ +Describe "Integration Tests" -Tag "IntegrationTests" { + BeforeAll { + $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force + $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password + + $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" + $PSDefaultParameterValues["*:SqlCredential"] = $cred + $PSDefaultParameterValues["*:SubscriberSqlCredential"] = $cred + $PSDefaultParameterValues["*:Confirm"] = $false + $PSDefaultParameterValues["*:SharedPath"] = "/shared" + $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" + $global:ProgressPreference = "SilentlyContinue" + + Import-Module ./dbatools.psd1 -Force + + $null = New-DbaDatabase -Name ReplDb + $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' + } + + Describe "General commands" -Tag general { + + Context "Get-DbaReplServer works" { + + It "Doesn't throw errors" { + { Get-DbaReplServer -EnableException } | Should -Not -Throw + } + + It "Returns a ReplicationObject" { + (Get-DbaReplServer).GetType().BaseType | Should -Be "Microsoft.SqlServer.Replication.ReplicationObject" + } + + It "Gets a replication server" { + (Get-DbaReplServer).SqlInstance | Should -Be 'mssql1' + (Get-DbaReplServer).DistributorInstalled | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).DistributorAvailable | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).IsDistributor | Should -Not -BeNullOrEmpty + (Get-DbaReplServer).IsPublisher | Should -Not -BeNullOrEmpty + } + } + } + + Describe "Publishing\Distribution commands" -tag pub { + + Context "Get-DbaReplDistributor works" { + BeforeAll { + + # if distribution is enabled, disable it & enable it with defaults + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + Enable-DbaReplDistributor + } + + It "gets a distributor without error" { + { Get-DbaReplDistributor -EnableException } | Should -Not -Throw + } + + It "gets a distributor" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution database name is correct" { + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' + } + + + } + + Context "Get-DbaReplPublisher works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "gets a publisher" { + (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + + + } + + Context "Enable-DbaReplDistributor works" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + + It "distribution is enabled" { + Enable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + } + + Context "Enable-DbaReplDistributor works with specified database name" { + BeforeAll { + # if distribution is enabled - disable it + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + AfterAll { + if ((Get-DbaReplDistributor).IsDistributor) { + Disable-DbaReplDistributor + } + } + + It "distribution starts disabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + + It "distribution is enabled with specific database" { + $distDb = ('distdb-{0}' -f (Get-Random)) + Enable-DbaReplDistributor -DistributionDatabase $distDb + (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb + } + } + + Context "Disable-DbaReplDistributor works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + } + + It "distribution starts enabled" { + (Get-DbaReplDistributor).IsDistributor | Should -Be $true + } + + It "distribution is disabled" { + Disable-DbaReplDistributor + (Get-DbaReplDistributor).IsDistributor | Should -Be $false + } + } + + Context "Enable-DbaReplPublishing works" { + BeforeAll { + # if Publishing is enabled - disable it + if ((Get-DbaReplServer).IsPublisher) { + Disable-DbaReplPublishing + } + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + } + + It "publishing starts disabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $false + } + + It "publishing is enabled" { + { Enable-DbaReplPublishing -EnableException } | Should -Not -Throw + (Get-DbaReplServer).IsPublisher | Should -Be $true + } + } + + Context "Disable-DbaReplPublishing works" { + BeforeAll { + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + write-output -message 'I should enable publishing' + Enable-DbaReplPublishing -EnableException + } + + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + write-output -message 'I should enable distribution' + Enable-DbaReplDistributor -EnableException + } + } + + It "publishing starts enabled" { + (Get-DbaReplServer).IsPublisher | Should -Be $true + } + + It "publishing is disabled" { + { Disable-DbaReplPublishing -EnableException } | Should -Not -Throw + (Get-DbaReplServer).IsPublisher | Should -Be $false + } + } + } + + Describe "Publication commands" -tag pub { + + Context "Get-DbaReplPublication works" { + BeforeAll { + # if distribution is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + + # create a publication + $name = 'TestPub' + New-DbaReplPublication -Database ReplDb -Type Transactional -Name ('{0}-Trans' -f $Name) + New-DbaReplPublication -Database ReplDb -Type Merge -Name ('{0}-Merge' -f $Name) + $null = New-DbaDatabase -Name Test + New-DbaReplPublication -Database Test -Type Snapshot -Name ('{0}-Snapshot' -f $Name) + } + + It "gets all publications" { + Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + + It "gets publications for a specific database" { + Get-DbaReplPublication -Database ReplDb | Should -Not -BeNullOrEmpty + (Get-DbaRepPublication -Database ReplDb).DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + + It "gets publications for a specific type" { + Get-DbaReplPublication -Type Transactional | Should -Not -BeNullOrEmpty + (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } + } + + } + + Context "New-DbaReplPublication works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + } + + It "New-DbaReplPublication creates a Transactional publication" { + $name = 'TestPub' + { New-DbaReplPublication -Database ReplDb -Type Transactional -Name $Name -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' + } + It "New-DbaReplPublication creates a Snapshot publication" { + $name = 'Snappy' + { New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $name -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' + } + It "New-DbaReplPublication creates a Merge publication" { + $name = 'Mergey' + { New-DbaReplPublication -Database ReplDb -Type Merge -Name $name -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty + (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' + (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' + } + } + + Context "Remove-DbaReplPublication works" { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $articleName = 'ReplicateMe' + + # we need some publications too + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName + } + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName + } + } + + It "Remove-DbaReplPublication removes a publication that has articles" { + $name = 'TestTrans' + { Remove-DbaReplPublication -Name $name -EnableException -Force } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty + } + + It "Remove-DbaReplPublication removes a publication that has no articles" { + $name = 'TestSnap' + { Remove-DbaReplPublication -Name $name -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty + } + + } + } +} diff --git a/tests/gh-actions-repl.ps1 b/tests/gh-actions-repl-2.ps1 similarity index 72% rename from tests/gh-actions-repl.ps1 rename to tests/gh-actions-repl-2.ps1 index f55c000266..b9899c9972 100644 --- a/tests/gh-actions-repl.ps1 +++ b/tests/gh-actions-repl-2.ps1 @@ -17,302 +17,6 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' } - Describe "General commands" -Tag general { - - Context "Get-DbaReplServer works" { - - It "Doesn't throw errors" { - { Get-DbaReplServer -EnableException } | Should -Not -Throw - } - - It "Returns a ReplicationObject" { - (Get-DbaReplServer).GetType().BaseType | Should -Be "Microsoft.SqlServer.Replication.ReplicationObject" - } - - It "Gets a replication server" { - (Get-DbaReplServer).SqlInstance | Should -Be 'mssql1' - (Get-DbaReplServer).DistributorInstalled | Should -Not -BeNullOrEmpty - (Get-DbaReplServer).DistributorAvailable | Should -Not -BeNullOrEmpty - (Get-DbaReplServer).IsDistributor | Should -Not -BeNullOrEmpty - (Get-DbaReplServer).IsPublisher | Should -Not -BeNullOrEmpty - } - } - } - - Describe "Publishing\Distribution commands" -tag pub { - - Context "Get-DbaReplDistributor works" { - BeforeAll { - - # if distribution is enabled, disable it & enable it with defaults - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor - } - Enable-DbaReplDistributor - } - - It "gets a distributor without error" { - { Get-DbaReplDistributor -EnableException } | Should -Not -Throw - } - - It "gets a distributor" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } - - It "distribution database name is correct" { - (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be 'distribution' - } - - - } - - Context "Get-DbaReplPublisher works" { - BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - } - - It "gets a publisher" { - (Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" - } - - - } - - Context "Enable-DbaReplDistributor works" { - BeforeAll { - # if distribution is enabled - disable it - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor - } - } - - It "distribution starts disabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } - - It "distribution is enabled" { - Enable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } - } - - Context "Enable-DbaReplDistributor works with specified database name" { - BeforeAll { - # if distribution is enabled - disable it - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor - } - } - AfterAll { - if ((Get-DbaReplDistributor).IsDistributor) { - Disable-DbaReplDistributor - } - } - - It "distribution starts disabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } - - It "distribution is enabled with specific database" { - $distDb = ('distdb-{0}' -f (Get-Random)) - Enable-DbaReplDistributor -DistributionDatabase $distDb - (Get-DbaReplDistributor).DistributionDatabases.Name | Should -Be $distDb - } - } - - Context "Disable-DbaReplDistributor works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - } - - It "distribution starts enabled" { - (Get-DbaReplDistributor).IsDistributor | Should -Be $true - } - - It "distribution is disabled" { - Disable-DbaReplDistributor - (Get-DbaReplDistributor).IsDistributor | Should -Be $false - } - } - - Context "Enable-DbaReplPublishing works" { - BeforeAll { - # if Publishing is enabled - disable it - if ((Get-DbaReplServer).IsPublisher) { - Disable-DbaReplPublishing - } - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - } - - It "publishing starts disabled" { - (Get-DbaReplServer).IsPublisher | Should -Be $false - } - - It "publishing is enabled" { - { Enable-DbaReplPublishing -EnableException } | Should -Not -Throw - (Get-DbaReplServer).IsPublisher | Should -Be $true - } - } - - Context "Disable-DbaReplPublishing works" { - BeforeAll { - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - write-output -message 'I should enable publishing' - Enable-DbaReplPublishing -EnableException - } - - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - write-output -message 'I should enable distribution' - Enable-DbaReplDistributor -EnableException - } - } - - It "publishing starts enabled" { - (Get-DbaReplServer).IsPublisher | Should -Be $true - } - - It "publishing is disabled" { - { Disable-DbaReplPublishing -EnableException } | Should -Not -Throw - (Get-DbaReplServer).IsPublisher | Should -Be $false - } - } - } - - Describe "Publication commands" -tag pub { - - Context "Get-DbaReplPublication works" { - BeforeAll { - # if distribution is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - - # create a publication - $name = 'TestPub' - New-DbaReplPublication -Database ReplDb -Type Transactional -Name ('{0}-Trans' -f $Name) - New-DbaReplPublication -Database ReplDb -Type Merge -Name ('{0}-Merge' -f $Name) - $null = New-DbaDatabase -Name Test - New-DbaReplPublication -Database Test -Type Snapshot -Name ('{0}-Snapshot' -f $Name) - } - - It "gets all publications" { - Get-DbaReplPublication | Should -Not -BeNullOrEmpty - } - - It "gets publications for a specific database" { - Get-DbaReplPublication -Database ReplDb | Should -Not -BeNullOrEmpty - (Get-DbaRepPublication -Database ReplDb).DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } - } - - It "gets publications for a specific type" { - Get-DbaReplPublication -Type Transactional | Should -Not -BeNullOrEmpty - (Get-DbaRepPublication -Type Transactional).Type | ForEach-Object { $_ | Should -Be 'Transactional' } - } - - } - - Context "New-DbaReplPublication works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - } - - It "New-DbaReplPublication creates a Transactional publication" { - $name = 'TestPub' - { New-DbaReplPublication -Database ReplDb -Type Transactional -Name $Name -EnableException } | Should -Not -Throw - (Get-DbaReplPublication -Name $Name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $Name).DatabaseName | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $Name).Type | Should -Be 'Transactional' - } - It "New-DbaReplPublication creates a Snapshot publication" { - $name = 'Snappy' - { New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $name -EnableException } | Should -Not -Throw - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Snapshot' - } - It "New-DbaReplPublication creates a Merge publication" { - $name = 'Mergey' - { New-DbaReplPublication -Database ReplDb -Type Merge -Name $name -EnableException } | Should -Not -Throw - (Get-DbaReplPublication -Name $name) | Should -Not -BeNullOrEmpty - (Get-DbaReplPublication -Name $name).DatabaseName | Should -Be 'ReplDb' - (Get-DbaReplPublication -Name $name).Type | Should -Be 'Merge' - } - } - - Context "Remove-DbaReplPublication works" { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - $articleName = 'ReplicateMe' - - # we need some publications too - $pubName = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName - } - - $pubName = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName - } - $pubName = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName - } - } - - It "Remove-DbaReplPublication removes a publication that has articles" { - $name = 'TestTrans' - { Remove-DbaReplPublication -Name $name -EnableException -Force } | Should -Not -Throw - (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty - } - - It "Remove-DbaReplPublication removes a publication that has no articles" { - $name = 'TestSnap' - { Remove-DbaReplPublication -Name $name -EnableException } | Should -Not -Throw - (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty - } - - } - } - Describe "Article commands" -tag art { BeforeAll { # if replication is disabled - enable it From 0b3b8325508b3931ec3edd59f7b427dc5bcb339c Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 14:21:38 +0100 Subject: [PATCH 211/226] call the new file names would be nice --- .github/workflows/integration-tests-repl.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index d95fdfc76d..0242ce11ab 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -48,9 +48,16 @@ jobs: # need some folders for our repl stuff docker exec mssql1 mkdir /shared/data /shared/repldata /var/opt/mssql/ReplData - - name: Run tests + - name: Run replication tests part 1 run: | Import-Module ./dbatools.psd1 -Force Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning - $null = Invoke-Pester ./tests/gh-actions-repl.ps1 -Output Detailed -PassThru -Verbose + $null = Invoke-Pester ./tests/gh-actions-repl-1.ps1 -Output Detailed -PassThru -Verbose + + - name: Run replication tests part 2 + run: | + Import-Module ./dbatools.psd1 -Force + Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning + Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + $null = Invoke-Pester ./tests/gh-actions-repl-2.ps1 -Output Detailed -PassThru -Verbose From 9d815e0c65f388681281386c3912abec13d48311 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 14:21:48 +0100 Subject: [PATCH 212/226] update comment --- tests/Add-DbaReplArticle.Tests.ps1 | 2 +- tests/Disable-DbaReplDistributor.Tests.ps1 | 2 +- tests/Disable-DbaReplPublishing.Tests.ps1 | 2 +- tests/Enable-DbaReplDistributor.Tests.ps1 | 2 +- tests/Enable-DbaReplPublishing.Tests.ps1 | 2 +- tests/Get-DbaReplArticle.Tests.ps1 | 2 +- tests/Get-DbaReplArticleColumn.Tests.ps1 | 2 +- tests/Get-DbaReplPublisher.Tests.ps1 | 2 +- tests/Get-DbaReplSubscription.Tests.ps1 | 2 +- tests/New-DbaReplCreationScriptOptions.Tests.ps1 | 2 +- tests/New-DbaReplPublication.Tests.ps1 | 2 +- tests/New-DbaReplSubscription.Tests.ps1 | 2 +- tests/Remove-DbaReplArticle.Tests.ps1 | 2 +- tests/Remove-DbaReplPublication.Tests.ps1 | 2 +- tests/Remove-DbaReplSubscription.Tests.ps1 | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/Add-DbaReplArticle.Tests.ps1 b/tests/Add-DbaReplArticle.Tests.ps1 index 7ac56a19a0..78d16d32ff 100644 --- a/tests/Add-DbaReplArticle.Tests.ps1 +++ b/tests/Add-DbaReplArticle.Tests.ps1 @@ -13,5 +13,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Disable-DbaReplDistributor.Tests.ps1 b/tests/Disable-DbaReplDistributor.Tests.ps1 index 97dae718e4..8707c37e5a 100644 --- a/tests/Disable-DbaReplDistributor.Tests.ps1 +++ b/tests/Disable-DbaReplDistributor.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Disable-DbaReplPublishing.Tests.ps1 b/tests/Disable-DbaReplPublishing.Tests.ps1 index b6e7b33b74..db1d3ce2fd 100644 --- a/tests/Disable-DbaReplPublishing.Tests.ps1 +++ b/tests/Disable-DbaReplPublishing.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> diff --git a/tests/Enable-DbaReplDistributor.Tests.ps1 b/tests/Enable-DbaReplDistributor.Tests.ps1 index 61cc486970..c1f08019a0 100644 --- a/tests/Enable-DbaReplDistributor.Tests.ps1 +++ b/tests/Enable-DbaReplDistributor.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Enable-DbaReplPublishing.Tests.ps1 b/tests/Enable-DbaReplPublishing.Tests.ps1 index f421f1a310..08143c6619 100644 --- a/tests/Enable-DbaReplPublishing.Tests.ps1 +++ b/tests/Enable-DbaReplPublishing.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Get-DbaReplArticle.Tests.ps1 b/tests/Get-DbaReplArticle.Tests.ps1 index ec006fe8a7..11bdb49fd2 100644 --- a/tests/Get-DbaReplArticle.Tests.ps1 +++ b/tests/Get-DbaReplArticle.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Get-DbaReplArticleColumn.Tests.ps1 b/tests/Get-DbaReplArticleColumn.Tests.ps1 index 4742a574a0..3a5f07cf69 100644 --- a/tests/Get-DbaReplArticleColumn.Tests.ps1 +++ b/tests/Get-DbaReplArticleColumn.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Get-DbaReplPublisher.Tests.ps1 b/tests/Get-DbaReplPublisher.Tests.ps1 index 9974307be5..dde5fa4f51 100644 --- a/tests/Get-DbaReplPublisher.Tests.ps1 +++ b/tests/Get-DbaReplPublisher.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Get-DbaReplSubscription.Tests.ps1 b/tests/Get-DbaReplSubscription.Tests.ps1 index 86483c26b2..bee78c532f 100644 --- a/tests/Get-DbaReplSubscription.Tests.ps1 +++ b/tests/Get-DbaReplSubscription.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/New-DbaReplCreationScriptOptions.Tests.ps1 b/tests/New-DbaReplCreationScriptOptions.Tests.ps1 index 9f319380ed..c7e06f9e13 100644 --- a/tests/New-DbaReplCreationScriptOptions.Tests.ps1 +++ b/tests/New-DbaReplCreationScriptOptions.Tests.ps1 @@ -15,5 +15,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/New-DbaReplPublication.Tests.ps1 b/tests/New-DbaReplPublication.Tests.ps1 index a385b860fb..7306059d09 100644 --- a/tests/New-DbaReplPublication.Tests.ps1 +++ b/tests/New-DbaReplPublication.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> diff --git a/tests/New-DbaReplSubscription.Tests.ps1 b/tests/New-DbaReplSubscription.Tests.ps1 index d0d001c2da..64176e3048 100644 --- a/tests/New-DbaReplSubscription.Tests.ps1 +++ b/tests/New-DbaReplSubscription.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> diff --git a/tests/Remove-DbaReplArticle.Tests.ps1 b/tests/Remove-DbaReplArticle.Tests.ps1 index ca30e7e8ee..3df7559a0f 100644 --- a/tests/Remove-DbaReplArticle.Tests.ps1 +++ b/tests/Remove-DbaReplArticle.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Remove-DbaReplPublication.Tests.ps1 b/tests/Remove-DbaReplPublication.Tests.ps1 index 68d9490f72..7914ec229d 100644 --- a/tests/Remove-DbaReplPublication.Tests.ps1 +++ b/tests/Remove-DbaReplPublication.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file diff --git a/tests/Remove-DbaReplSubscription.Tests.ps1 b/tests/Remove-DbaReplSubscription.Tests.ps1 index a6c35c4085..730d6870a6 100644 --- a/tests/Remove-DbaReplSubscription.Tests.ps1 +++ b/tests/Remove-DbaReplSubscription.Tests.ps1 @@ -16,5 +16,5 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { } } <# - Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl.ps1 + Integration tests for replication are in GitHub Actions and run from \tests\gh-actions-repl-*.ps1.ps1 #> \ No newline at end of file From 76c86614d2059486d1fd67ecdea47c5d74ffa8f5 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 14:27:51 +0100 Subject: [PATCH 213/226] lets have 2 nicely named jobs --- .github/workflows/integration-tests-repl.yml | 50 ++++++++++++++++++-- tests/gh-actions-repl-1.ps1 | 2 +- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 0242ce11ab..ce9e850faa 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -4,7 +4,7 @@ defaults: run: shell: pwsh jobs: - linux-tests: + repl-tests-part1: runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} @@ -51,13 +51,53 @@ jobs: - name: Run replication tests part 1 run: | Import-Module ./dbatools.psd1 -Force - Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning - Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning $null = Invoke-Pester ./tests/gh-actions-repl-1.ps1 -Output Detailed -PassThru -Verbose - - name: Run replication tests part 2 + repl-tests-part2: +runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + steps: + - uses: actions/checkout@v3 + + - name: Install and cache PowerShell modules + uses: potatoqualitee/psmodulecache@v5.2 + with: + modules-to-cache: dbatools.library:2023.5.5 + + - name: Set encryption values run: | Import-Module ./dbatools.psd1 -Force - Get-DbatoolsConfigValue -FullName sql.connection.trustcert | Write-Warning + Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register + Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -Register Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + + - name: Setup docker images + run: | + # create a shared network + docker network create localnet + # Expose engine and endpoint then setup a shared path for migrations + docker run -p 1433:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance + # Expose second engine and endpoint on different port + docker run -p 14333:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + + - name: Add hostname to hosts file + run: | + echo "127.0.0.1 mssql1 mssql2" | sudo tee -a /etc/hosts + + - name: 👥 Clone appveyor repo + working-directory: /tmp + run: | + gh repo clone dataplat/appveyor-lab + + - name: Setup Replication + run: | + Import-Module ./dbatools.psd1 -Force + # need some folders for our repl stuff + docker exec mssql1 mkdir /shared/data /shared/repldata /var/opt/mssql/ReplData + + - name: Run replication tests part 2 + run: | + Import-Module ./dbatools.psd1 -Force $null = Invoke-Pester ./tests/gh-actions-repl-2.ps1 -Output Detailed -PassThru -Verbose diff --git a/tests/gh-actions-repl-1.ps1 b/tests/gh-actions-repl-1.ps1 index 14cbb10dff..e925b6a295 100644 --- a/tests/gh-actions-repl-1.ps1 +++ b/tests/gh-actions-repl-1.ps1 @@ -300,7 +300,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Remove-DbaReplPublication removes a publication that has articles" { $name = 'TestTrans' - { Remove-DbaReplPublication -Name $name -EnableException -Force } | Should -Not -Throw + { Remove-DbaReplPublication -Name $name -EnableException } | Should -Not -Throw (Get-DbaReplPublication -Name $name) | Should -BeNullOrEmpty } From 1523fb65225214b3b6cec9bbb66c3bcb2b17e535 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 14:29:03 +0100 Subject: [PATCH 214/226] yaml! --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index ce9e850faa..199ed2a9e8 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -54,7 +54,7 @@ jobs: $null = Invoke-Pester ./tests/gh-actions-repl-1.ps1 -Output Detailed -PassThru -Verbose repl-tests-part2: -runs-on: ubuntu-latest + runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From abb472d4298d504cb68a48e6c67fba9e5c3d05a6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 15:51:35 +0100 Subject: [PATCH 215/226] couple of bug fixes --- public/Add-DbaReplArticle.ps1 | 3 +++ tests/gh-actions-repl-2.ps1 | 26 ++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/public/Add-DbaReplArticle.ps1 b/public/Add-DbaReplArticle.ps1 index adecad1797..3fb0ac4ac6 100644 --- a/public/Add-DbaReplArticle.ps1 +++ b/public/Add-DbaReplArticle.ps1 @@ -131,6 +131,9 @@ function Add-DbaReplArticle { if ($PSCmdlet.ShouldProcess($instance, "Get the publication details for $Publication")) { $pub = Get-DbaReplPublication -SqlInstance $instance -SqlCredential $SqlCredential -Name $Publication -EnableException:$EnableException + if (-not $pub) { + Stop-Function -Message "Publication $Publication does not exist on $instance" -ErrorRecord $_ -Target $instance -Continue + } } } catch { Stop-Function -Message "Unable to get publication $Publication on $instance" -ErrorRecord $_ -Target $instance -Continue diff --git a/tests/gh-actions-repl-2.ps1 b/tests/gh-actions-repl-2.ps1 index b9899c9972..f3584ac764 100644 --- a/tests/gh-actions-repl-2.ps1 +++ b/tests/gh-actions-repl-2.ps1 @@ -77,7 +77,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Add-DbaReplArticle adds an article to a Transactional publication" { - $pubName = 'TestPub' + $pubName = 'TestTrans' { Add-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName -EnableException } | Should -not -throw $art = Get-DbaReplArticle -Database ReplDb -Name $articleName -Publication $pubName $art | Should -Not -BeNullOrEmpty @@ -86,7 +86,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Add-DbaReplArticle adds an article to a Snapshot publication and specifies create script options" { - $pubname = 'TestPub' + $pubname = 'TestTrans' $cso = New-DbaReplCreationScriptOptions -Options NonClusteredIndexes, Statistics { Add-DbaReplArticle -Database ReplDb -Name $articleName2 -Publication $pubname -CreationScriptOptions $cso -EnableException } | Should -not -throw $art = Get-DbaReplArticle -Database ReplDb -Name $articleName2 -Publication $pubName @@ -381,6 +381,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException } } + Get-DbaReplArticle -Publication TestSnap | Remove-DbaReplArticle -Confirm:$false } It "Adds a subscription" { $pubName = 'TestTrans' @@ -396,7 +397,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { It "Adds a pull subscription" -skip { #TODO: Fix pull subscriptions in New-DbaReplSubscription command - $pubName = 'TestSnap' + $pubName = 'TestMerge' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname @@ -408,12 +409,12 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } It "Throws an error if there are no articles in the publication" { - $pubName = 'TestMerge' + $pubName = 'TestSnap' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw } } - Context "Remove-DbaReplSubscription works"{ + Context "Remove-DbaReplSubscription works" { BeforeEach { $pubName = 'TestTrans' if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { @@ -436,11 +437,24 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Get-DbaReplSubscription works" { BeforeAll { - $pubName = 'TestTrans' + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + } if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException } + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + } if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException } From bc8285c22871ca966665c2bc949cbb66925370e9 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 16:12:59 +0100 Subject: [PATCH 216/226] subscriber wrong --- tests/gh-actions-repl-2.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl-2.ps1 b/tests/gh-actions-repl-2.ps1 index f3584ac764..9397675cb9 100644 --- a/tests/gh-actions-repl-2.ps1 +++ b/tests/gh-actions-repl-2.ps1 @@ -418,7 +418,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { BeforeEach { $pubName = 'TestTrans' if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql1 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push } } It "Removes a push subscription" { From 8f12cf824574fc6cb98712f3e2adabeecbb6f3f6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 16:20:56 +0100 Subject: [PATCH 217/226] skip New-DbaReplSubscription and see if it works --- tests/gh-actions-repl-2.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl-2.ps1 b/tests/gh-actions-repl-2.ps1 index 9397675cb9..b11dc2f8b3 100644 --- a/tests/gh-actions-repl-2.ps1 +++ b/tests/gh-actions-repl-2.ps1 @@ -369,7 +369,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "New-DbaReplSubscription works" { + Context "New-DbaReplSubscription works" -skip { BeforeAll { if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans) { (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans).foreach{ From 0dadcd108e2c0b32efa7912567f5e1462ed22c7f Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 16:24:56 +0100 Subject: [PATCH 218/226] split into 3 repl gh jobs --- .github/workflows/integration-tests-repl.yml | 49 ++++ tests/gh-actions-repl-2.ps1 | 258 ----------------- tests/gh-actions-repl-3.ps1 | 279 +++++++++++++++++++ 3 files changed, 328 insertions(+), 258 deletions(-) create mode 100644 tests/gh-actions-repl-3.ps1 diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 199ed2a9e8..6392c8f3f1 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -101,3 +101,52 @@ jobs: run: | Import-Module ./dbatools.psd1 -Force $null = Invoke-Pester ./tests/gh-actions-repl-2.ps1 -Output Detailed -PassThru -Verbose + + repl-tests-part3: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + steps: + - uses: actions/checkout@v3 + + - name: Install and cache PowerShell modules + uses: potatoqualitee/psmodulecache@v5.2 + with: + modules-to-cache: dbatools.library:2023.5.5 + + - name: Set encryption values + run: | + Import-Module ./dbatools.psd1 -Force + Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register + Set-DbatoolsConfig -FullName sql.connection.encrypt -Value Optional -Register + Get-DbatoolsConfigValue -FullName sql.connection.encrypt | Write-Warning + + - name: Setup docker images + run: | + # create a shared network + docker network create localnet + # Expose engine and endpoint then setup a shared path for migrations + docker run -p 1433:1433 --volume shared:/shared:z --name mssql1 --hostname mssql1 --network localnet -d dbatools/sqlinstance + # Expose second engine and endpoint on different port + docker run -p 14333:1433 --volume shared:/shared:z --name mssql2 --hostname mssql2 --network localnet -d dbatools/sqlinstance2 + + - name: Add hostname to hosts file + run: | + echo "127.0.0.1 mssql1 mssql2" | sudo tee -a /etc/hosts + + - name: 👥 Clone appveyor repo + working-directory: /tmp + run: | + gh repo clone dataplat/appveyor-lab + + - name: Setup Replication + run: | + Import-Module ./dbatools.psd1 -Force + # need some folders for our repl stuff + docker exec mssql1 mkdir /shared/data /shared/repldata /var/opt/mssql/ReplData + + - name: Run replication tests part 3 + run: | + Import-Module ./dbatools.psd1 -Force + $null = Invoke-Pester ./tests/gh-actions-repl-3.ps1 -Output Detailed -PassThru -Verbose diff --git a/tests/gh-actions-repl-2.ps1 b/tests/gh-actions-repl-2.ps1 index b11dc2f8b3..d80d258350 100644 --- a/tests/gh-actions-repl-2.ps1 +++ b/tests/gh-actions-repl-2.ps1 @@ -334,262 +334,4 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Describe "Subscription commands" -tag sub { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - $articleName = 'ReplicateMe' - - # we need some publications with articles too - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName - } - - $pubname = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName - } - - $pubname = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname - } - } - - Context "New-DbaReplSubscription works" -skip { - BeforeAll { - if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans) { - (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans).foreach{ - Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException - } - } - if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestSnap) { - (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestSnap).foreach{ - Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException - } - } - Get-DbaReplArticle -Publication TestSnap | Remove-DbaReplArticle -Confirm:$false - } - It "Adds a subscription" { - $pubName = 'TestTrans' - { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw - - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname - $sub | Should -Not -BeNullOrEmpty - $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } - $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } - $sub.PublicationName | ForEach-Object { $_ | Should -Be $pubname } - $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } - } - - It "Adds a pull subscription" -skip { - #TODO: Fix pull subscriptions in New-DbaReplSubscription command - $pubName = 'TestMerge' - { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw - - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname - $sub | Should -Not -BeNullOrEmpty - $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } - $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } - $sub.PublicationName | ForEach-Object { $_ | Should -Be $pubname } - $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } - } - - It "Throws an error if there are no articles in the publication" { - $pubName = 'TestSnap' - { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw - } - } - - Context "Remove-DbaReplSubscription works" { - BeforeEach { - $pubName = 'TestTrans' - if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push - } - } - It "Removes a push subscription" { - Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Should -Not -BeNullOrEmpty - { Remove-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDb -SubscriberSqlInstance mssql2 -Database ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw - Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty - } - It "Removes a pull subscription" -skip { - #TODO: Fix pull subscriptions in New-DbaReplSubscription command - Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Pull | Should -Not -BeNullOrEmpty - { Remove-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDb -SubscriberSqlInstance mssql2 -Database ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw - Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Pull | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty - } - } - - - Context "Get-DbaReplSubscription works" { - BeforeAll { - $pubname = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName - } - if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException - } - - $pubName = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName - } - if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { - New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException - } - } - - It "Gets subscriptions" { - $sub = Get-DbaReplSubscription -SqlInstance mssql1 - $sub | Should -Not -BeNullOrEmpty - $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } - } - - It "Gets subscriptions for a particular database" { - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb - $sub | Should -Not -BeNullOrEmpty - $sub.DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } - } - - It "Gets subscriptions by publication name" { - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans - $sub | Should -Not -BeNullOrEmpty - $sub.PublicationName | ForEach-Object { $_ | Should -Be 'TestTrans' } - } - - It "Gets subscriptions by type" { - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Type Push - $sub | Should -Not -BeNullOrEmpty - $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } - - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Type Pull - if($sub) { - $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } - } - } - - It "Gets subscriptions by subscriber name" { - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -SubscriberName mssql2 - $sub | Should -Not -BeNullOrEmpty - $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } - } - - It "Gets subscriptions by subscription database name" { - $sub = Get-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDbTrans - $sub | Should -Not -BeNullOrEmpty - $sub.SubscriptionDBName | ForEach-Object { $_ | Should -Be 'ReplDbTrans' } - } - } - } - - Describe "Piping" -tag pipe { - BeforeAll { - # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - - # we need some articles too get - $articleName = 'ReplicateMe' - $articleName2 = 'ReplicateMeToo' - - # we need some publications too - $pubName = 'TestTrans' - if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { - $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName -EnableException - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName -EnableException - } - - $pubName = 'TestSnap' - if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { - $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName -EnableException - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName -EnableException - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName2 -EnableException - } - - $pubName = 'TestMerge' - if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { - $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName -EnableException - } - if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { - $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName -EnableException - } - # piping doesn't work well if there are PSDefaultParameterValues set - $PSDefaultParameterValues = $null - } - - Context "Get-DbaReplPublisher works with piping" { - It "gets a publisher using piping" { - (Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" - } - } - - Context "Get-DbaReplPublication works with piping" { - It "works with piping" { - Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublication | Should -Not -BeNullOrEmpty - } - } - - Context "Get-DbaReplDistributor works with piping" { - It "can pipe a sql server object to it" { - Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty - } - } - - Context "Get-DbaReplArticle works with piping" { - It "Piping from Connect-DbaInstance to works" { - Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty - } - } - - Context "Remove-DbaReplArticle works with piping" { - It "Remove-DbaReplArticle removes an article from a Transactional publication" { - $pubName = 'TestTrans' - $Name = "ReplicateMe" - - $rm = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name | Remove-DbaReplArticle -Confirm:$false - $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } - $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } - $articleName = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name - $articleName | Should -BeNullOrEmpty - } - } - - Context "Remove-DbaReplPublication works with piping" { - It "Remove-DbaReplPublication removes a publication using piping" { - $name = 'TestMerge' - { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException | Remove-DbaReplPublication -Confirm:$false -EnableException } | Should -Not -Throw - (Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException) | Should -BeNullOrEmpty - } - } - } } diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 new file mode 100644 index 0000000000..d089e6ff51 --- /dev/null +++ b/tests/gh-actions-repl-3.ps1 @@ -0,0 +1,279 @@ +Describe "Integration Tests" -Tag "IntegrationTests" { + BeforeAll { + $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force + $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password + + $PSDefaultParameterValues["*:SqlInstance"] = "mssql1" + $PSDefaultParameterValues["*:SqlCredential"] = $cred + $PSDefaultParameterValues["*:SubscriberSqlCredential"] = $cred + $PSDefaultParameterValues["*:Confirm"] = $false + $PSDefaultParameterValues["*:SharedPath"] = "/shared" + $PSDefaultParameterValues["*:WarningAction"] = "SilentlyContinue" + $global:ProgressPreference = "SilentlyContinue" + + Import-Module ./dbatools.psd1 -Force + + $null = New-DbaDatabase -Name ReplDb + $null = Invoke-DbaQuery -Database ReplDb -Query 'CREATE TABLE ReplicateMe ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) ); CREATE TABLE ReplicateMeToo ( id int identity (1,1) PRIMARY KEY, col1 varchar(10) );' + } + + + Describe "Subscription commands" -tag sub { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + $articleName = 'ReplicateMe' + + # we need some publications with articles too + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + } + + $pubname = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + } + + $pubname = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname + } + } + + Context "New-DbaReplSubscription works" -skip { + BeforeAll { + if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans) { + (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans).foreach{ + Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException + } + } + if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestSnap) { + (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestSnap).foreach{ + Remove-DbaReplSubscription -SqlInstance $psitem.SqlInstance -SubscriptionDatabase $psitem.SubscriptionDBName -SubscriberSqlInstance $psitem.SubscriberName -Database $psitem.DatabaseName -PublicationName $psitem.PublicationName -Confirm:$false -EnableException + } + } + Get-DbaReplArticle -Publication TestSnap | Remove-DbaReplArticle -Confirm:$false + } + It "Adds a subscription" { + $pubName = 'TestTrans' + { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw + + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname + $sub | Should -Not -BeNullOrEmpty + $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } + $sub.PublicationName | ForEach-Object { $_ | Should -Be $pubname } + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } + } + + It "Adds a pull subscription" -skip { + #TODO: Fix pull subscriptions in New-DbaReplSubscription command + $pubName = 'TestMerge' + { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw + + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName $pubname + $sub | Should -Not -BeNullOrEmpty + $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } + $sub.PublicationName | ForEach-Object { $_ | Should -Be $pubname } + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } + } + + It "Throws an error if there are no articles in the publication" { + $pubName = 'TestSnap' + { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw + } + } + + Context "Remove-DbaReplSubscription works" { + BeforeEach { + $pubName = 'TestTrans' + if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push + } + } + It "Removes a push subscription" { + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Should -Not -BeNullOrEmpty + { Remove-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDb -SubscriberSqlInstance mssql2 -Database ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty + } + It "Removes a pull subscription" -skip { + #TODO: Fix pull subscriptions in New-DbaReplSubscription command + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Pull | Should -Not -BeNullOrEmpty + { Remove-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDb -SubscriberSqlInstance mssql2 -Database ReplDb -PublicationName $pubname -EnableException } | Should -Not -Throw + Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Pull | Where-Object SubscriberName -eq mssql2 | Should -BeNullOrEmpty + } + } + + + Context "Get-DbaReplSubscription works" { + BeforeAll { + $pubname = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + } + if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubname -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubname + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName + } + if (-not (Get-DbaReplSubscription -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { + New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push -enableException + } + } + + It "Gets subscriptions" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 + $sub | Should -Not -BeNullOrEmpty + $sub.SqlInstance | ForEach-Object { $_ | Should -Be 'mssql1' } + } + + It "Gets subscriptions for a particular database" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb + $sub | Should -Not -BeNullOrEmpty + $sub.DatabaseName | ForEach-Object { $_ | Should -Be 'ReplDb' } + } + + It "Gets subscriptions by publication name" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans + $sub | Should -Not -BeNullOrEmpty + $sub.PublicationName | ForEach-Object { $_ | Should -Be 'TestTrans' } + } + + It "Gets subscriptions by type" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Type Push + $sub | Should -Not -BeNullOrEmpty + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } + + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -Type Pull + if($sub) { + $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } + } + } + + It "Gets subscriptions by subscriber name" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -SubscriberName mssql2 + $sub | Should -Not -BeNullOrEmpty + $sub.SubscriberName | ForEach-Object { $_ | Should -Be 'mssql2' } + } + + It "Gets subscriptions by subscription database name" { + $sub = Get-DbaReplSubscription -SqlInstance mssql1 -SubscriptionDatabase ReplDbTrans + $sub | Should -Not -BeNullOrEmpty + $sub.SubscriptionDBName | ForEach-Object { $_ | Should -Be 'ReplDbTrans' } + } + } + } + + Describe "Piping" -tag pipe { + BeforeAll { + # if replication is disabled - enable it + if (-not (Get-DbaReplDistributor).IsDistributor) { + Enable-DbaReplDistributor + } + # if publishing is disabled - enable it + if (-not (Get-DbaReplServer).IsPublisher) { + Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + } + + # we need some articles too get + $articleName = 'ReplicateMe' + $articleName2 = 'ReplicateMeToo' + + # we need some publications too + $pubName = 'TestTrans' + if (-not (Get-DbaReplPublication -Name $pubName -Type Transactional)) { + $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubName -EnableException + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubName -Name $articleName -EnableException + } + + $pubName = 'TestSnap' + if (-not (Get-DbaReplPublication -Name $pubName -Type Snapshot)) { + $null = New-DbaReplPublication -Database ReplDb -Type Snapshot -Name $pubName -EnableException + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName -EnableException + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName2 -EnableException + } + + $pubName = 'TestMerge' + if (-not (Get-DbaReplPublication -Name $pubName -Type Merge)) { + $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubName -EnableException + } + if (-not (Get-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName)) { + $null = Add-DbaReplArticle -Database ReplDb -Publication $pubname -Name $articleName -EnableException + } + # piping doesn't work well if there are PSDefaultParameterValues set + $PSDefaultParameterValues = $null + } + + Context "Get-DbaReplPublisher works with piping" { + It "gets a publisher using piping" { + (Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublisher).PublisherType | Should -Be "MSSQLSERVER" + } + } + + Context "Get-DbaReplPublication works with piping" { + It "works with piping" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplPublication | Should -Not -BeNullOrEmpty + } + } + + Context "Get-DbaReplDistributor works with piping" { + It "can pipe a sql server object to it" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred | Get-DbaReplDistributor | Should -Not -BeNullOrEmpty + } + } + + Context "Get-DbaReplArticle works with piping" { + It "Piping from Connect-DbaInstance to works" { + Connect-DbaInstance -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb | Get-DbaReplArticle | Should -Not -BeNullOrEmpty + } + } + + Context "Remove-DbaReplArticle works with piping" { + It "Remove-DbaReplArticle removes an article from a Transactional publication" { + $pubName = 'TestTrans' + $Name = "ReplicateMe" + + $rm = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name | Remove-DbaReplArticle -Confirm:$false + $rm.IsRemoved | ForEach-Object { $_ | Should -Be $true } + $rm.Status | ForEach-Object { $_ | Should -Be 'Removed' } + $articleName = Get-DbaReplArticle -SqlInstance 'mssql1' -SqlCredential $cred -Database ReplDb -Publication $pubName -Name $Name + $articleName | Should -BeNullOrEmpty + } + } + + Context "Remove-DbaReplPublication works with piping" { + It "Remove-DbaReplPublication removes a publication using piping" { + $name = 'TestMerge' + { Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException | Remove-DbaReplPublication -Confirm:$false -EnableException } | Should -Not -Throw + (Get-DbaReplPublication -SqlInstance 'mssql1' -SqlCredential $cred -Name $name -EnableException) | Should -BeNullOrEmpty + } + } + } +} From cf1512e15bbda4dc6c2129cb3f148163cf1ca66a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Thu, 21 Sep 2023 16:30:15 +0100 Subject: [PATCH 219/226] what is going on --- .github/workflows/integration-tests-repl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-repl.yml b/.github/workflows/integration-tests-repl.yml index 6392c8f3f1..d7371ad1aa 100644 --- a/.github/workflows/integration-tests-repl.yml +++ b/.github/workflows/integration-tests-repl.yml @@ -149,4 +149,4 @@ jobs: - name: Run replication tests part 3 run: | Import-Module ./dbatools.psd1 -Force - $null = Invoke-Pester ./tests/gh-actions-repl-3.ps1 -Output Detailed -PassThru -Verbose + Invoke-Pester ./tests/gh-actions-repl-3.ps1 -Output Detailed -PassThru -Verbose From 82244c491559836393ee3c5f3fa2ce54b6e91bb6 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 14:18:39 +0100 Subject: [PATCH 220/226] skip sub tests for now --- tests/gh-actions-repl-3.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index d089e6ff51..8b00249578 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -18,7 +18,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Describe "Subscription commands" -tag sub { + Describe "Subscription commands" -tag sub -skip { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -53,7 +53,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "New-DbaReplSubscription works" -skip { + Context "New-DbaReplSubscription works" { BeforeAll { if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans) { (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans).foreach{ From c7dbc4c29992855efedb529546d0ca2fc2d78958 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 14:22:07 +0100 Subject: [PATCH 221/226] skip tests --- tests/gh-actions-repl-3.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index 8b00249578..da1f30cdaf 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -18,7 +18,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Describe "Subscription commands" -tag sub -skip { + Describe "Subscription commands" -tag sub { BeforeAll { # if replication is disabled - enable it if (-not (Get-DbaReplDistributor).IsDistributor) { @@ -53,7 +53,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } } - Context "New-DbaReplSubscription works" { + Context "New-DbaReplSubscription works" -skip { BeforeAll { if (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans) { (Get-DbaReplSubscription -SqlInstance mssql1 -PublicationName TestTrans).foreach{ @@ -67,7 +67,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Get-DbaReplArticle -Publication TestSnap | Remove-DbaReplArticle -Confirm:$false } - It "Adds a subscription" { + It "Adds a subscription" -skip { $pubName = 'TestTrans' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw @@ -92,7 +92,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } } - It "Throws an error if there are no articles in the publication" { + It "Throws an error if there are no articles in the publication" -skip { $pubName = 'TestSnap' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw } From 45183e6932334d3e8444bf1a7636fff2d0323883 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 14:25:00 +0100 Subject: [PATCH 222/226] different skips --- tests/gh-actions-repl-3.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index da1f30cdaf..6059843381 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -67,7 +67,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } Get-DbaReplArticle -Publication TestSnap | Remove-DbaReplArticle -Confirm:$false } - It "Adds a subscription" -skip { + It "Adds a subscription" { $pubName = 'TestTrans' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbTrans -PublicationName $pubName -Type Push -EnableException } | Should -Not -Throw @@ -79,7 +79,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Push' } } - It "Adds a pull subscription" -skip { + It "Adds a pull subscription" { #TODO: Fix pull subscriptions in New-DbaReplSubscription command $pubName = 'TestMerge' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDbSnap -PublicationName $pubName -Type Pull -EnableException } | Should -Not -Throw @@ -92,13 +92,13 @@ Describe "Integration Tests" -Tag "IntegrationTests" { $sub.SubscriptionType | ForEach-Object { $_ | Should -Be 'Pull' } } - It "Throws an error if there are no articles in the publication" -skip { + It "Throws an error if there are no articles in the publication" { $pubName = 'TestSnap' { New-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriberSqlInstance mssql2 -SubscriptionDatabase ReplDb -PublicationName $pubName -Type Pull -EnableException } | Should -Throw } } - Context "Remove-DbaReplSubscription works" { + Context "Remove-DbaReplSubscription works" -skip { BeforeEach { $pubName = 'TestTrans' if (-not (Get-DbaReplSubscription -SqlInstance mssql1 -Database ReplDb -SubscriptionDatabase ReplDb -PublicationName $pubname -Type Push | Where-Object SubscriberName -eq mssql2)) { @@ -119,7 +119,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Get-DbaReplSubscription works" { + Context "Get-DbaReplSubscription works" -skip { BeforeAll { $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { From 60dfd5774a02652c56c679204d0516e0ee4e111a Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 14:27:27 +0100 Subject: [PATCH 223/226] how about get --- tests/gh-actions-repl-3.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index 6059843381..b5a575bcb6 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -119,7 +119,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } - Context "Get-DbaReplSubscription works" -skip { + Context "Get-DbaReplSubscription works" { BeforeAll { $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { From 8bffe4fcde77dfd0b1451c629fcce0244b96fd45 Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 14:31:00 +0100 Subject: [PATCH 224/226] comment some out --- tests/gh-actions-repl-3.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index b5a575bcb6..0b4c1451e4 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -30,6 +30,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { } $articleName = 'ReplicateMe' + <# # we need some publications with articles too $pubname = 'TestTrans' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { @@ -51,6 +52,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { if (-not (Get-DbaReplPublication -Name $pubname -Type Merge)) { $null = New-DbaReplPublication -Database ReplDb -Type Merge -Name $pubname } + #> } Context "New-DbaReplSubscription works" -skip { From 6e332eca6bde4795b2f76ce8e02a859afcf3f2aa Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 14:48:47 +0100 Subject: [PATCH 225/226] comment everything? --- tests/gh-actions-repl-3.ps1 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index 0b4c1451e4..a0f7c32b03 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -21,14 +21,14 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Describe "Subscription commands" -tag sub { BeforeAll { # if replication is disabled - enable it - if (-not (Get-DbaReplDistributor).IsDistributor) { - Enable-DbaReplDistributor - } - # if publishing is disabled - enable it - if (-not (Get-DbaReplServer).IsPublisher) { - Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException - } - $articleName = 'ReplicateMe' + #if (-not (Get-DbaReplDistributor).IsDistributor) { + # Enable-DbaReplDistributor + #} + ## if publishing is disabled - enable it + #if (-not (Get-DbaReplServer).IsPublisher) { + # Enable-DbaReplPublishing -PublisherSqlLogin $cred -EnableException + #} + #$articleName = 'ReplicateMe' <# # we need some publications with articles too From ef68ec70c68a0459298358d5db38a33be87db94b Mon Sep 17 00:00:00 2001 From: Jess Pomfret <jesspomfret@datamasterminds.io> Date: Fri, 22 Sep 2023 15:54:18 +0100 Subject: [PATCH 226/226] test fix --- tests/gh-actions-repl-3.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/gh-actions-repl-3.ps1 b/tests/gh-actions-repl-3.ps1 index a0f7c32b03..870d55485c 100644 --- a/tests/gh-actions-repl-3.ps1 +++ b/tests/gh-actions-repl-3.ps1 @@ -124,6 +124,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" { Context "Get-DbaReplSubscription works" { BeforeAll { $pubname = 'TestTrans' + $articleName = 'ReplicateMe' if (-not (Get-DbaReplPublication -Name $pubname -Type Transactional)) { $null = New-DbaReplPublication -Database ReplDb -Type Transactional -Name $pubname }