AddCustomAvailabilityDB.psm1

 #Requires -Version 3

 function Add-CustomAvailabilityDB{
 <# .SYNOPSIS
        Adds an existing Database to an existing Availabilty Group on all replicas provided
    .DESCRIPTION
        Utilizes SMO to access SQL Server
        If SQL Client Tools are not loaded on the machine it will error and fail.
        Verifys DB exists on first server in list which is requried to be the Primary server. If not Aborts
        Verifys DB doesnt exist in an availabilty database already. If it does Aborts.
        Verifys DB is in Full Recovery mode if not puts db in Full recovery.
    .PARAMETER Servers
        Servers participating in AlwaysOn, first server will be assumed to be where the database is which needs to be replicated.
    .PARAMETER SQLAgName
        Availability Group Name database will be created in
    .PARAMETER db
        Databases which will be added to the Availability Group
    .PARAMETER BackupDirectory
        Backup location which all nodes will have access to. Used to backup and restore database from.
        If Paramater is not passed function assumes Join Only operation and Backup and Restore operations are skipped.
    .PARAMETER Timeout
        Connection Timeout for SQL Server connections. Function defaults this to 0 so that backup and restore will run as long as needed, however you have the ability to override.
    .EXAMPLE
        Add-CustomAvailabilityDB -Servers TNSQL3001,WASQL3001 -SqlAgName AG-TNWA3004 -Databases Test16 -BackupDirectory \\ohnas001\SQLBackups -verbose
    .EXAMPLE
        Add-CustomAvailabilityDB -Servers TNSQL3001,WASQL3001 -SqlAgName AG-TNWA3004 -Databases Test16 -verbose
    .EXAMPLE
        Add-CustomAvailabilityDB -Servers TNSQL3001,WASQL3001 -SqlAgName AG-TNWA3004 -Databases Test16,Test17,Test18 -verbose
    .EXAMPLE
        Add-CustomAvailabilityDB -Servers TNSQL3001,WASQL3001,MISQL3001,OHSQL3001 -SqlAgName AG-TNWA3004 -Databases Test16,Test17,Test18 -verbose
 #>

   [CmdletBinding()]
      Param(
      [Parameter(Mandatory=$true)]
      [string[]]$Servers,
      [Parameter(Mandatory=$true)]
      [string]$SqlAgName,
      [string[]]$Databases,
      [string]$BackupDirectory,
      [int]$Timeout=0
    )

    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") |Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | out-null
    Write-Verbose -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": Done Loading SMO Assemblies ...");
    $SqlServerPrim = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $Servers[0]
    $SqlServerPrim.ConnectionContext.StatementTimeout = $Timeout

    #Loop through servers Backing up Database/Tranlog and Restore on each Secondary with NoRecovery
    $loopCnt = 0
    foreach ($Server in $Servers){
        $SqlConn = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $Server
        $SqlConn.ConnectionContext.StatementTimeout = $Timeout
        If($loopCnt -eq 0) #First Server is Primary Back up Full and TranLogs
        {
                         
            foreach ($db in $Databases){
            Try{
 
                    $DBcheck = $sqlconn.Databases | Where-Object {$_.name -eq $db}
        
                    If(!$DBcheck){
                        Throw "$db doesn't exist on $Server please verify Primary Server is first in the list"
                        exit
                    }

                    If($DBcheck.AvailabilityGroupName){
                        $DBAGCheck = $DBcheck.AvailabilityGroupName
                        Throw "$db exists in $DBAGCheck availability group already."
                        exit
                    } 
                    if ($SQLconn.Databases[$db].RecoveryModel -ne "FULL")
                    {
                        $sqlconn.Databases[$db].RecoveryModel = "Full"
                        $sqlconn.Databases[$db].Alter();
                        Write-Verbose -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) +": Database is not in Full Recovery Mode Setting to Full...");
                    }
                }
            Catch{
                   Throw "Failed to set $db to Full Recovery."
                   Exit
                }
            
            #If BackupDirectory is not provided We will assume you want to do a Join Only
            If ($BackupDirectory){        
                Try{
                        $DbBackup = New-Object -typename Microsoft.SqlServer.Management.Smo.Backup
                        $DbBackup.Database = $db
                        $DbBackup.Action = [Microsoft.SqlServer.Management.Smo.BackupActionType]::Database
                        $DbBackup.Initialize = $true
                        $DbBackup.Devices.AddDevice("$BackupDirectory\$($db)_AgSetup_full.bak", [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
                        $DbBackup.SqlBackup($SqlConn)
                        Write-Verbose -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": DbBackup Full for $db ...");
                        $DbBackup = New-Object -typename Microsoft.SqlServer.Management.Smo.Backup
                        $DbBackup.Database = $db
                        $DbBackup.Action = [Microsoft.SqlServer.Management.Smo.BackupActionType]::Log
                        $DbBackup.Initialize = $true
                        $DbBackup.Devices.AddDevice("$BackupDirectory\$($db)_AgSetup_log.trn", [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
                        $DbBackup.SqlBackup($SqlConn)
                        Write-Verbose -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": DbBackup TranLog for $db ...");           
                    }
                Catch{
                        Throw "Failed to backup $db"
                        Exit
                    }
            }
            
            Try{
                $AvailabilityGroup = $SqlConn.AvailabilityGroups | Where-Object {$_.Name -eq $SqlAgName}
                $AvailabilityDb = New-Object -typename Microsoft.SQLServer.Management.Smo.AvailabilityDatabase -ArgumentList $AvailabilityGroup,$db
                $AvailabilityGroup.AvailabilityDatabases.add($AvailabilityDb);
                $AvailabilityDb.create();
                $AvailabilityGroup.alter();
                Write-Verbose -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": Primary db $db added to AG...");  
            }

            Catch{
                Throw "Failed to Add $db on $SqlAgName..."
                Exit
            }
            
            }#For Each DB
        }
        else
        {
             foreach ($db in $Databases){
                #If BackupDirectory is not provided We will assume you want to do a Join Only
                If ($BackupDirectory){    
                try{
                    $DbRestore = New-Object -typename Microsoft.SqlServer.Management.Smo.Restore
                    
                    $DbRestore.Database = $db
                    $DbRestore.Action = [Microsoft.SqlServer.Management.Smo.RestoreActionType]::Database
                    
                    $DbRestore.Devices.AddDevice("$BackupDirectory\$($db)_AgSetup_full.bak",
                        [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
                    $DbRestore.NoRecovery = $true
                    $DbRestore.SqlRestore($SqlConn)
                    Write-Verbose -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": Restore Full for $db on $Server...");
                    $DbRestore = New-Object -typename Microsoft.SqlServer.Management.Smo.Restore
                    $DbRestore.Database = $db
                    $DbRestore.Action = [Microsoft.SqlServer.Management.Smo.RestoreActionType]::Log
                    $DbRestore.Devices.AddDevice("$BackupDirectory\$($db)_AgSetup_log.trn",
                        [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
                    $DbRestore.NoRecovery = $true
                    $DbRestore.SqlRestore($SqlConn)
                    Write-Verbose -Message  ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": Restore Tran Log for $db on $Server...");      
                    }
                
                catch{
                        Throw "Failed to Restore $db on $Server..."
                        Exit
                    } 
                }#End IF No BackupDir Join Only

                Try{
                While($true){

                    $AvailabilityGroup = $SqlConn.AvailabilityGroups | Where-Object {$_.Name -eq $SqlAgName}
                    $AvailabilityDb = $AvailabilityGroup.AvailabilityDatabases | Where-Object {$_.Name -eq $db}
                    $AvailabilityGroup = $SqlConn.AvailabilityGroups | Where-Object {$_.Name -eq $SqlAgName}
                    $AvailabilityGroup.AvailabilityDatabases.Refresh()
                    $AvailabilityDb=$AvailabilityGroup.AvailabilityDatabases | Where-Object {$_.Name -eq $db}
                    if ($AvailabilityDb)
                    {break}
                    Start-Sleep -Seconds 15
                    }

                    $AvailabilityDb.JoinAvailablityGroup();
                    Write-Verbose -Message  ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": $db Joined to $SqlAgName on $Server...");   
                }
                catch{
                      Throw "Failed to Join $db on to $SQLAgName on $Server..."
                      Exit
                }

            }#For each DB
        }#Else Secondary Servers
        $loopcnt=$loopCnt+1

    }#End For Each Server


    #Remove all Backup Files which were creating during this excersize
    If ($BackupDirectory){ 
     Try{
        $DBBackupFile = "$BackupDirectory\$($db)_AgSetup_full.bak"
        $DBTRNFile = "$BackupDirectory\$($db)_AgSetup_log.trn"
        If (Test-Path -Path $DBBackupFile){Remove-Item -Path $DBBackupFile}
        If (Test-Path -Path $DBTRNFile){Remove-Item -Path $DBTRNFile}
        }    
        Catch{
            Throw "Failed to Cleanup Backup Files..."
            Exit
        } 
        Write-Verbose -Message  ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": Done Cleaning Up Backup Files...");
    }
}#Function End


#Add-CustomAvailabilityDB -Servers TNSQL3001,WASQL3001 -SqlAgName AG-TNWA3004 -Databases Test18 -BackupDirectory \\ohnas001\SQLBackups -Timeout 10 -verbose