Home > DevOps > Deploy SQL Server 2019 with PowerShell DSC
Windows PowerShell

Deploy SQL Server 2019 with PowerShell DSC

This is still applicable for deploying SQL Server 2019 with PowerShell DSC onto Windows Server 2019, with and without Desktop Experience.

This post isn”t that different than the Deploy SQL Server 2017 with PowerShell DSC post found on this site. This configuration is for PowerShell DSC v1.1.

Install dependencies on the remote server and your local machine:

Install-Module -Name "ComputerManagementDsc" -RequiredVersion "8.0.0" -Scope AllUsers
Install-Module -Name "SqlServerDsc" -RequiredVersion "14.0.0" -Scope AllUsers
Install-Module -Name "StorageDsc" -RequiredVersion "4.4.0.0" -Scope AllUsers

The full configuration:

Configuration DBServer {

    param (
        [pscredential]$SACreds,
        [pscredential]$DeploymentCreds
    )

    Import-DscResource -ModuleName "PSDesiredStateConfiguration"
    Import-DscResource -ModuleName "SqlServerDsc" -ModuleVersion "14.0.0"
    Import-DscResource -ModuleName "ComputerManagementDsc" -ModuleVersion "8.0.0"
    Import-DscResource -ModuleName "StorageDsc" -moduleversion "4.4.0.0"


    Node $AllNodes.NodeName {

        LocalConfigurationManager {
            AllowModuleOverwrite = $true
            ActionAfterReboot    = "ContinueConfiguration"
            ConfigurationMode    = "ApplyAndMonitor"
            RebootNodeIfNeeded   = $true
        }

        TimeZone EastCoast {
            IsSingleInstance = "Yes"
            TimeZone         = "Eastern Standard Time"
        }

        PowerPlan HighPerformance {
            IsSingleInstance = "Yes"
            Name             = "High Performance"
        }

        RemoteDesktopAdmin RDC {
            IsSingleInstance   = "Yes"
            UserAuthentication = "Secure"
            Ensure             = "Present"
            DependsOn          = "[PowerPlan]HighPerformance"
        }

        VirtualMemory PageFileInVM {
            Drive       = "C"
            Type        = "CustomSize"
            DependsOn   = "[RemoteDesktopAdmin]RDC"
            InitialSize = 2048
            MaximumSize = 4096
        }

        PendingReboot RB {
            Name      = "RebootWhenNeeded"
            DependsOn = "[VirtualMemory]PageFileInVM"
        }

        OpticalDiskDriveLetter CDROM {
            DiskId      = "1"
            DriveLetter = "Z"
            Ensure      = "Present"
            DependsOn   = "[PendingReboot]RB"
        }

        WindowsFeature NetFramework45 {
            Name      = "NET-Framework-45-Core"
            Ensure    = "Present"
            DependsOn = "[OpticalDiskDriveLetter]CDROM"
        }

        # Sql Server Best Practices 64K Allocation Unit Size - https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2005/administrator/cc966412(v=technet.10)?redirectedfrom=MSDN
        Disk DATADrive {
            DiskId             = 1
            DriveLetter        = "E"
            FSFormat           = "NTFS"
            AllocationUnitSize = 65536
            FSLabel            = "DATA"
            PartitionStyle     = "GPT"
            DependsOn          = "[OpticalDiskDriveLetter]CDROM"
        }

        Disk DATADriveTwo {
            DiskId             = 2
            DriveLetter        = "F"
            FSFormat           = "NTFS"
            AllocationUnitSize = 65536
            FSLabel            = "LOGS"
            PartitionStyle     = "GPT"
            DependsOn          = "[OpticalDiskDriveLetter]CDROM"
        }
        Disk DATADriveThree {
            DiskId             = 3
            DriveLetter        = "G"
            FSFormat           = "NTFS"
            AllocationUnitSize = 65536
            FSLabel            = "TEMPDB"
            PartitionStyle     = "GPT"
            DependsOn          = "[OpticalDiskDriveLetter]CDROM"
        }
        Disk DATADriveFour {
            DiskId         = 4
            DriveLetter    = "H"
            FSFormat       = "NTFS"
            FSLabel        = "BACKUPS"
            PartitionStyle = "GPT"
            DependsOn      = "[OpticalDiskDriveLetter]CDROM"
        }

        WaitForVolume edrive {
            DriveLetter      = "E"
            DependsOn        = "[Disk]DATADrive"
            RetryIntervalSec = 20
            RetryCount       = 20
        }
        WaitForVolume fdrive {
            DriveLetter      = "F"
            DependsOn        = "[Disk]DATADriveTwo"
            RetryIntervalSec = 20
            RetryCount       = 20
        }
        WaitForVolume gdrive {
            DriveLetter      = "G"
            DependsOn        = "[Disk]DATADriveThree"
            RetryIntervalSec = 20
            RetryCount       = 20
        }
        WaitForVolume hdrive {
            DriveLetter      = "H"
            DependsOn        = "[Disk]DATADriveFour", "[WaitForVolume]fdrive", "[WaitForVolume]Edrive", "[WaitForVolume]gdrive"
            RetryIntervalSec = 20
            RetryCount       = 20
        }

        File MSSQLDBFolder1 {
            DestinationPath = "E:\Data"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[WaitForVolume]hdrive"
        }
        File MSSQLdatabuilder {
            DestinationPath = "E:\Data\databuilder"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLDBFolder1"
        }
        File MSSQLproduction {
            DestinationPath = "E:\Data\production"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLDBFolder1"
        }
        
        File MSSQLogsFolder1 {
            DestinationPath = "F:\MSSQL"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLDBFolder1"
        }
        File MSSQLLogsFolder2 {
            DestinationPath = "F:\MSSQL\Logs"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLogsFolder1"
        }
        File MSSQLTempDBFolder1 {
            DestinationPath = "G:\MSSQL"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLLogsFolder2"
        }
        File MSSQLTempDBFolder2 {
            DestinationPath = "G:\MSSQL\TempDB"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLTempDBFolder1"
        }
        File MSSQLBackupFolder {
            DestinationPath = "H:\Backups"
            Ensure          = "Present"
            Type            = "Directory"
            DependsOn       = "[File]MSSQLTempDBFolder2"
        }
        
        SmbShare BackupShare {
            Name       = "Backups"
            Path       = "H:\Backups"
            FullAccess = "Everyone"
            Ensure     = "Present"
            DependsOn  = "[File]MSSQLBackupFolder"
        }

        SqlSetup BaseInstall {
            InstanceName          = "MSSQLSERVER"
            Action                = "Install"
            SqlSvcStartupType     = "Automatic"
            BrowserSvcStartupType = "Automatic"
            Features              = "SQLEngine,FullText,Conn"
            ForceReboot           = $true
            SecurityMode          = "SQL"
            SAPwd                 = $saCreds
            SQLSysAdminAccounts   = @("Administrators")
            SourcePath            = "\\zm-fs-01\SoftwareRepo\Apps\SQLServer2019_Install"
            InstallSharedDir      = "C:\Program Files\Microsoft SQL Server"
            InstallSharedWOWDir   = "C:\Program Files (x86)\Microsoft SQL Server"
            InstanceDir           = "C:\Program Files\Microsoft SQL Server"
            InstallSQLDataDir     = "C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\Data"
            SQLUserDBDir          = "E:\Data"
            SQLUserDBLogDir       = "F:\MSSQL\Logs"
            SQLBackupDir          = "H:\Backups"
            SQLTempDBDir          = "G:\MSSQL\TempDB"
            SQLTempDBLogDir       = "G:\MSSQL\TempDB"
            UpdateEnabled         = "False"
            PsDscRunAsCredential  = $DeploymentCreds
            DependsOn             = "[SmbShare]BackupShare"
        }

        SqlMemory Set_SQLServerMaxMemory {
            Ensure               = "Present"
            DynamicAlloc         = $false
            MinMemory            = 1024
            MaxMemory            = 32768
            ServerName           = $Node.NodeName
            InstanceName         = "MSSQLSERVER"
            PsDscRunAsCredential = $DeploymentCreds
            DependsOn            = "[SqlSetup]BaseInstall"
        }

        SqlProtocol EnableTcpIp {
            InstanceName           = "MSSQLSERVER"
            ServerName             = $Node.NodeName
            ProtocolName           = "TcpIp"
            Enabled                = $true
            ListenOnAllIpAddresses = $true
            RestartTimeout         = 300
            PsDscRunAsCredential   = $DeploymentCreds
            DependsOn              = "[SqlMemory]Set_SQLServerMaxMemory"
        }
        
        SqlProtocol SharedMemory {
            InstanceName         = "MSSQLSERVER"
            ProtocolName         = "SharedMemory"
            Enabled              = $true
            PsDscRunAsCredential = $DeploymentCreds
            DependsOn            = "[SqlProtocol]EnableTcpIp"
        }

        SqlProtocol EnableNamedPipes {
            InstanceName   = "MSSQLSERVER"
            ServerName     = $Node.NodeName
            ProtocolName   = "NamedPipes"
            Enabled        = $true
            RestartTimeout = 300
            DependsOn      = "[SqlProtocol]SharedMemory"
        }


        Script ConfigureSqlServerAgentWindowsService {
            TestScript = {
                (Get-Service -Name SQLSERVERAGENT).StartType -eq "Automatic"
            }
            GetScript  = { @{ Result = ((Get-Service -Name SQLSERVERAGENT).StartType -eq "Automatic") } }
            SetScript  = {
                Set-Service -Name SQLSERVERAGENT -StartupType Automatic
                Start-Service -Name SQLSERVERAGENT
            }
            DependsOn  = "[SqlProtocol]EnableNamedPipes"
        }

    }
}

Let”s get the configuration data section together.

$cd = @{
    AllNodes = @(
        @{
            NodeName                    = "SQL1"
            PsDscAllowPlainTextPassword = $true
            PsDscAllowDomainUser        = $true
        }
    )
}

This deployment assumes you”ll be using a domain account for the run as credentials to install Microsoft SQL Server and change some of it”s configuration after install. Additionally, the installation is configured for Mixed mode authentication, so we”ll need credentials for the sa account.

$saCredObj = Get-Credential -username "sa"

$DeploymentCredObj = Get-Credential

Now let”s create a a place to save the mof files.

$MofLocation = "C:\dsc_files"

if ((Test-Path -Path $MofLocation) -eq $False) {
    New-Item -Path "C:\" -Name dsc_files -ItemType Directory
}

Now we compile the config.

DBServer -SaCreds $saCredObj -DeploymentCreds $DeploymentCredObj -ConfigurationData $cd -OutputPath $MofLocation -Verbose

After that we can test the configuration against the remote node.

$ServerName = $cd.AllNodes.Nodename

#region TestTheConfiguration
$output = Test-DscConfiguration -Path $MofLocation -ComputerName $ServerName -Verbose

# Then check out the output
$output

The Local Configuration Manager has been changed to reboot the node if needed, which is nice since the virtual memory is being configured and SQL Server is being installed.

Set-DscLocalConfigurationManager -Path $MOFlocation -ComputerName $ServerName -Verbose

Then we can push the configuration.

Start-DscConfiguration -Path $MOFlocation -ComputerName $ServerName -Verbose