DSCResources/DSC_SqlServerReplication/DSC_SqlServerReplication.psm1
$script:sqlServerDscHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\SqlServerDsc.Common' $script:resourceHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\DscResource.Common' Import-Module -Name $script:sqlServerDscHelperModulePath Import-Module -Name $script:resourceHelperModulePath $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [System.String] $InstanceName, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter(Mandatory = $true)] [ValidateSet('Local', 'Remote')] [System.String] $DistributorMode, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $AdminLinkCredentials, [Parameter()] [System.String] $DistributionDBName = 'distribution', [Parameter()] [System.String] $RemoteDistributor, [Parameter(Mandatory = $true)] [System.String] $WorkingDirectory, [Parameter()] [System.Boolean] $UseTrustedConnection = $true, [Parameter()] [System.Boolean] $UninstallWithForce = $true ) Write-Verbose -Message ( $script:localizedData.GetCurrentState -f $InstanceName ) $sqlMajorVersion = Get-SqlServerMajorVersion -InstanceName $InstanceName $localSqlName = Get-SqlLocalServerName -InstanceName $InstanceName $localServerConnection = New-ServerConnection -SqlMajorVersion $sqlMajorVersion -SqlServerName $localSqlName $localReplicationServer = New-ReplicationServer -SqlMajorVersion $sqlMajorVersion -ServerConnection $localServerConnection $currentEnsure = 'Present' if ($localReplicationServer.IsDistributor -eq $true) { $currentDistributorMode = 'Local' } elseif ($localReplicationServer.IsPublisher -eq $true) { $currentDistributorMode = 'Remote' } else { $currentEnsure = 'Absent' } if ($currentEnsure -eq 'Present') { Write-Verbose -Message ( $script:localizedData.DistributorMode -f $DistributorMode, $InstanceName ) $currentDistributionDBName = $localReplicationServer.DistributionDatabase $currentRemoteDistributor = $localReplicationServer.DistributionServer $currentWorkingDirectory = $localReplicationServer.WorkingDirectory } else { Write-Verbose -Message ( $script:localizedData.NoDistributorMode -f $InstanceName ) } $returnValue = @{ InstanceName = $InstanceName Ensure = $currentEnsure DistributorMode = $currentDistributorMode DistributionDBName = $currentDistributionDBName RemoteDistributor = $currentRemoteDistributor WorkingDirectory = $currentWorkingDirectory } return $returnValue } function Set-TargetResource { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $InstanceName, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter(Mandatory = $true)] [ValidateSet('Local', 'Remote')] [System.String] $DistributorMode, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $AdminLinkCredentials, [Parameter()] [System.String] $DistributionDBName = 'distribution', [Parameter()] [System.String] $RemoteDistributor, [Parameter(Mandatory = $true)] [System.String] $WorkingDirectory, [Parameter()] [System.Boolean] $UseTrustedConnection = $true, [Parameter()] [System.Boolean] $UninstallWithForce = $true ) if (($DistributorMode -eq 'Remote') -and (-not $RemoteDistributor)) { $errorMessage = $script:localizedData.NoRemoteDistributor New-InvalidArgumentException -ArgumentName 'RemoteDistributor' -Message $errorMessage } $sqlMajorVersion = Get-SqlServerMajorVersion -InstanceName $InstanceName $localSqlName = Get-SqlLocalServerName -InstanceName $InstanceName $localServerConnection = New-ServerConnection -SqlMajorVersion $sqlMajorVersion -SqlServerName $localSqlName $localReplicationServer = New-ReplicationServer -SqlMajorVersion $sqlMajorVersion -ServerConnection $localServerConnection if ($Ensure -eq 'Present') { if ($DistributorMode -eq 'Local' -and $localReplicationServer.IsDistributor -eq $false) { Write-Verbose -Message ( $script:localizedData.ConfigureLocalDistributor ) $distributionDB = New-DistributionDatabase ` -SqlMajorVersion $sqlMajorVersion ` -DistributionDBName $DistributionDBName ` -ServerConnection $localServerConnection Install-LocalDistributor ` -ReplicationServer $localReplicationServer ` -AdminLinkCredentials $AdminLinkCredentials ` -DistributionDB $distributionDB Register-DistributorPublisher ` -SqlMajorVersion $sqlMajorVersion ` -PublisherName $localSqlName ` -ServerConnection $localServerConnection ` -DistributionDBName $DistributionDBName ` -WorkingDirectory $WorkingDirectory ` -UseTrustedConnection $UseTrustedConnection } if ($DistributorMode -eq 'Remote' -and $localReplicationServer.IsPublisher -eq $false) { Write-Verbose -Message ( $script:localizedData.ConfigureRemoteDistributor ) $remoteConnection = New-ServerConnection -SqlMajorVersion $sqlMajorVersion -SqlServerName $RemoteDistributor Register-DistributorPublisher ` -SqlMajorVersion $sqlMajorVersion ` -PublisherName $localSqlName ` -ServerConnection $remoteConnection ` -DistributionDBName $DistributionDBName ` -WorkingDirectory $WorkingDirectory ` -UseTrustedConnection $UseTrustedConnection Install-RemoteDistributor ` -ReplicationServer $localReplicationServer ` -RemoteDistributor $RemoteDistributor ` -AdminLinkCredentials $AdminLinkCredentials } } else #'Absent' { if ($localReplicationServer.IsDistributor -eq $true -or $localReplicationServer.IsPublisher -eq $true) { Write-Verbose -Message ( $script:localizedData.RemoveDistributor ) Uninstall-Distributor -ReplicationServer $localReplicationServer -UninstallWithForce $UninstallWithForce } else { Write-Verbose -Message ( $script:localizedData.NoDistributorMode -f $InstanceName ) } } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $InstanceName, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter(Mandatory = $true)] [ValidateSet('Local', 'Remote')] [System.String] $DistributorMode, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $AdminLinkCredentials, [Parameter()] [System.String] $DistributionDBName = 'distribution', [Parameter()] [System.String] $RemoteDistributor, [Parameter(Mandatory = $true)] [System.String] $WorkingDirectory, [Parameter()] [System.Boolean] $UseTrustedConnection = $true, [Parameter()] [System.Boolean] $UninstallWithForce = $true ) Write-Verbose -Message ( $script:localizedData.TestingConfiguration ) $result = $false $state = Get-TargetResource @PSBoundParameters if ($Ensure -eq 'Absent' -and $state.Ensure -eq 'Absent') { $result = $true } elseif ($Ensure -eq 'Present' -and $state.Ensure -eq 'Present' -and $state.DistributorMode -eq $DistributorMode) { $result = $true } return $result } function New-ServerConnection { [CmdletBinding()] [OutputType([System.Object])] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, [Parameter(Mandatory = $true)] [System.String] $SqlServerName ) $connInfo = Get-ConnectionInfoAssembly -SqlMajorVersion $SqlMajorVersion $serverConnection = New-Object $connInfo.GetType('Microsoft.SqlServer.Management.Common.ServerConnection') $SqlServerName return $serverConnection } function New-ReplicationServer { [CmdletBinding()] [OutputType([System.Object])] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, [Parameter(Mandatory = $true)] [System.Object] $ServerConnection ) $rmo = Get-RmoAssembly -SqlMajorVersion $SqlMajorVersion $localReplicationServer = New-Object $rmo.GetType('Microsoft.SqlServer.Replication.ReplicationServer') $ServerConnection return $localReplicationServer; } function New-DistributionDatabase { [CmdletBinding()] [OutputType([System.Object])] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, [Parameter(Mandatory = $true)] [System.String] $DistributionDBName, [Parameter(Mandatory = $true)] [System.Object] $ServerConnection ) $rmo = Get-RmoAssembly -SqlMajorVersion $SqlMajorVersion Write-Verbose -Message ( $script:localizedData.CreateDistributionDatabase -f $DistributionDBName ) $distributionDB = New-Object $rmo.GetType('Microsoft.SqlServer.Replication.DistributionDatabase') $DistributionDBName, $ServerConnection return $distributionDB } function New-DistributionPublisher { [CmdletBinding()] [OutputType([System.Object])] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, [Parameter(Mandatory = $true)] [System.String] $PublisherName, [Parameter(Mandatory = $true)] [System.Object] $ServerConnection ) $rmo = Get-RmoAssembly -SqlMajorVersion $SqlMajorVersion try { $distributorPublisher = New-object $rmo.GetType('Microsoft.SqlServer.Replication.DistributionPublisher') $PublisherName, $ServerConnection } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'New-DistributionPublisher' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } return $distributorPublisher } function Install-RemoteDistributor { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.Object] $ReplicationServer, [Parameter(Mandatory = $true)] [System.String] $RemoteDistributor, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $AdminLinkCredentials ) Write-Verbose -Message ( $script:localizedData.InstallRemoteDistributor -f $RemoteDistributor ) try { $ReplicationServer.InstallDistributor($RemoteDistributor, $AdminLinkCredentials.Password) } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'Install-RemoteDistributor' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } function Install-LocalDistributor { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.Object] $ReplicationServer, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $AdminLinkCredentials, [Parameter(Mandatory = $true)] [System.Object] $DistributionDB ) Write-Verbose -Message ( $script:localizedData.InstallLocalDistributor ) try { $ReplicationServer.InstallDistributor($AdminLinkCredentials.Password, $DistributionDB) } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'Install-LocalDistributor' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } function Uninstall-Distributor { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.Object] $ReplicationServer, [Parameter(Mandatory = $true)] [System.Boolean] $UninstallWithForce ) Write-Verbose -Message ( $script:localizedData.UninstallDistributor ) try { $ReplicationServer.UninstallDistributor($UninstallWithForce) } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'Uninstall-Distributor' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } function Register-DistributorPublisher { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, [Parameter(Mandatory = $true)] [System.String] $PublisherName, [Parameter(Mandatory = $true)] [System.Object] $ServerConnection, [Parameter(Mandatory = $true)] [System.String] $DistributionDBName, [Parameter(Mandatory = $true)] [System.String] $WorkingDirectory, [Parameter(Mandatory = $true)] [System.Boolean] $UseTrustedConnection ) Write-Verbose -Message ( $script:localizedData.CreateDistributorPublisher -f $PublisherName, $ServerConnection.ServerInstance ) $distributorPublisher = New-DistributionPublisher ` -SqlMajorVersion $SqlMajorVersion ` -PublisherName $PublisherName ` -ServerConnection $ServerConnection $distributorPublisher.DistributionDatabase = $DistributionDBName $distributorPublisher.WorkingDirectory = $WorkingDirectory $distributorPublisher.PublisherSecurity.WindowsAuthentication = $UseTrustedConnection try { $distributorPublisher.Create() } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'Register-DistributorPublisher' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } <# .SYNOPSIS Returns a reference to the ConnectionInfo assembly. .DESCRIPTION Returns a reference to the ConnectionInfo assembly. .PARAMETER SqlMajorVersion Specifies the major version of the SQL Server instance, e.g. '14'. .OUTPUTS [System.Reflection.Assembly] Returns a reference to the ConnectionInfo assembly. .EXAMPLE Get-ConnectionInfoAssembly -SqlMajorVersion '14' .NOTES This should normally work using Import-Module and New-Object instead of using the method [System.Reflection.Assembly]::Load(). But due to a missing assembly in the module SqlServer ('Microsoft.SqlServer.Rmo') we cannot use this: Import-Module SqlServer $connectionInfo = New-Object -TypeName 'Microsoft.SqlServer.Management.Common.ServerConnection' -ArgumentList @('testclu01a\SQL2014') # Missing assembly 'Microsoft.SqlServer.Rmo' in module SqlServer prevents this call from working. $replication = New-Object -TypeName 'Microsoft.SqlServer.Replication.ReplicationServer' -ArgumentList @($connectionInfo) #> function Get-ConnectionInfoAssembly { [CmdletBinding()] [OutputType([System.Reflection.Assembly])] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion ) try { $connectionInfo = [System.Reflection.Assembly]::Load("Microsoft.SqlServer.ConnectionInfo, Version=$SqlMajorVersion.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91") Write-Verbose -Message ( $script:localizedData.LoadAssembly -f $connectionInfo.FullName ) } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'Get-ConnectionInfoAssembly' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } return $connectionInfo } <# .SYNOPSIS Returns a reference to the RMO assembly. .DESCRIPTION Returns a reference to the RMO assembly. .PARAMETER SqlMajorVersion Specifies the major version of the SQL Server instance, e.g. '14'. .OUTPUTS [System.Reflection.Assembly] Returns a reference to the RMO assembly. .EXAMPLE Get-RmoAssembly -SqlMajorVersion '14' .NOTES This should normally work using Import-Module and New-Object instead of using the method [System.Reflection.Assembly]::Load(). But due to a missing assembly in the module SqlServer ('Microsoft.SqlServer.Rmo') we cannot use this: Import-Module SqlServer $connectionInfo = New-Object -TypeName 'Microsoft.SqlServer.Management.Common.ServerConnection' -ArgumentList @('testclu01a\SQL2014') # Missing assembly 'Microsoft.SqlServer.Rmo' in module SqlServer prevents this call from working. $replication = New-Object -TypeName 'Microsoft.SqlServer.Replication.ReplicationServer' -ArgumentList @($connectionInfo) #> function Get-RmoAssembly { [CmdletBinding()] [OutputType([System.Reflection.Assembly])] param ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion ) try { $rmo = [System.Reflection.Assembly]::Load("Microsoft.SqlServer.Rmo, Version=$SqlMajorVersion.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91") Write-Verbose -Message ( $script:localizedData.LoadAssembly -f $rmo.FullName ) } catch { $errorMessage = $script:localizedData.FailedInFunction -f 'Get-RmoAssembly' New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } return $rmo } function Get-SqlServerMajorVersion { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.String] $InstanceName ) $instanceId = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL").$InstanceName $sqlVersion = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\Setup").Version $sqlMajorVersion = $sqlVersion.Split(".")[0] if (-not $sqlMajorVersion) { $errorMessage = $script:localizedData.FailedToDetectSqlVersion -f $InstanceName New-InvalidResultException -Message $errorMessage } return $sqlMajorVersion } function Get-SqlLocalServerName { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.String] $InstanceName ) if ($InstanceName -eq 'MSSQLSERVER') { return $env:COMPUTERNAME } else { return "$($env:COMPUTERNAME)\$InstanceName" } } Export-ModuleMember -Function *-TargetResource |