########## BEGIN SCRIPT HEADER ########## $TITLE = "DATAPIPE SQL POWERSHELL PSM" # Authors: Justin Procacci, Shem Ongoro # Copyright Datapipe All rights reserved # No part of this publication may be reproduced, distributed, or transmitted in any form or by any means, # including photocopying, recording, or other electronic or mechanical methods, without the prior written permission of the publisher, # except in the case of brief quotations embodied in critical reviews and certain other noncommercial uses permitted by copyright law. $Global:Version = "2.0.5" $Date = "06/13/2017" ########## END SCRIPT HEADER ########## $host.ui.RawUI.WindowTitle = "DP Windows PSM | Version :$Version | Date: $Date" #Load SQL SMO if available [Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null; #Add SQLPS snapin Add-PSSnapin SqlServerCmdletSnapin100 -ErrorAction SilentlyContinue | Out-Null; Add-PSSnapin SqlServerProviderSnapin100 -ErrorAction SilentlyContinue | Out-Null; $WriteToHost = 'Y' #Clear any existing variables. "sqlcmd","SQLPSInstalled","SQLServerConfiguration","SQLFileConfiguration" | %{Clear-Variable -Name $($_) -Force -ErrorAction SilentlyContinue} ########## BEGIN Set-OutputPreferenceColor FUNCTION ########## Function Set-OutputPreferenceColor { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION Set Output Preferences AUTHOR: JUSTIN PROCACCI SUPPORTED VERSIONS: 2008 R2, 2012, 2012 R2 and 2016 CMDLET VERSION: 1.0.0 DATE: 3/22/2017 ======================================================================================== This function sets the preferences for the script color preferences EXAMPLE 1: Set-OutputPreferenceColor -InfoColor gray -WarningColor yellow -ErrorColor red -OutputColor cyan -BackGroundColor black -SuccessColor green #> [CMDLETBINDING()] param( [parameter(mandatory=$False)] [validateset('white','red','yellow','gray','cyan','black','green')] [string]$SuccessColor = 'green' , [parameter(mandatory=$False)] [validateset('red','yellow','gray','cyan','black','green')] [string]$InfoColor = 'gray' , [parameter(mandatory=$False)] [validateset('red','yellow','gray','cyan','black','green')] [string]$WarningColor = 'yellow' , [parameter(mandatory=$False)] [validateset('red','yellow','gray','cyan','black','green')] [string]$ErrorColor = 'red' , [parameter(mandatory=$False)] [validateset('red','yellow','gray','cyan','black','green')] [string]$OutputColor = 'cyan' , [parameter(mandatory=$False)] [validateset('red','yellow','gray','cyan','black','green')] [string]$BackGroundColor = 'black' , [parameter(mandatory=$False)] [switch]$Quiet , [parameter(mandatory=$False)] [validateset('red','yellow','gray','cyan','black','green')] [string]$FunctionColor = 'Yellow' ) BEGIN { if (!$Quiet) { Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting default output color scheme for messages" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor } } PROCESS { if (!$Quiet) { Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting Success to $($SuccessColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting Info to $($InfoColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting Warning to $($WarningColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting Error to $($ErrorColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting OutputColor to $($OutputColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting BackGroundColor to $($BackGroundColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor Write-Host "$(Get-Date -Format G) [" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor -NoNewline Write-Host "INFO" -ForegroundColor $InfoColor -BackgroundColor $BackGroundColor -NoNewline write-host "] `tSetting FunctioColor to $($FunctionColor)" -ForegroundColor $OutputColor -BackgroundColor $BackGroundColor } $Script:BackGroundColor = $BackGroundColor $Script:OutputColor = $OutputColor $Script:ErrorColor = $ErrorColor $Script:WarningColor = $WarningColor $Script:InfoColor = $InfoColor $Script:SuccessColor = $SuccessColor $Script:FunctionColor = $FunctionColor } END { } } ########## FINISH Set-OutputPreferenceColor FUNCTION ########## #Set default preferences Set-OutputPreferenceColor -InfoColor gray -WarningColor yellow -ErrorColor red -OutputColor cyan -BackGroundColor black -SuccessColor green -FunctionColor yellow -Quiet ########## BEGIN DPLOG FUNCTION ########## function DPLOG { [CMDLETBINDING()] param( [Parameter(Position=1, Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('SUCCESS','INFO','WARNING','ERROR','START','FINISH')] [string]$Type, [Parameter(Position=2, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [string]$LogFile = "C:\Windows\Temp\DPAutomation.log", [Parameter(Position=3, Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [string]$Message, [Parameter(Position=4, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y", [Parameter(Position=5, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteCallingFunction = "Y" ) <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION LOGGING MODULE AUTHOR: ANTHONY MARINO, JUSTIN PROCACCI SUPPORTED VERSIONS: 2003 R2, 2008 R2, 2008 R2 SP1, 2012 and 2012 R2 CMDLET VERSION: 1.0.5 DATE: 3/22/2017 ======================================================================================== Creates or appends to a log file with your specified log level, message and path. .DESCRIPTION REQUIRED - [-Type] - Severity level of your log entry. Accepted values: [SUCCESS],[INFO],[WARNING],[ERROR],[START],[FINISH] OPTIONAL - [-LogFile] - Full path to your log file. Default is C:\Windows\Temp\DPAutomation.log REQUIRED - [-Message] - Message you would like to include in the log. Variables are also accepted. OPTIONAL - [-WriteToHost] - Switch used to disable writing the message to the host. Default is Y. Accepted values: [Y],[N]. NOTE: You can set the log file location for the current PowerShell session by setting the variable: $Global:LogFileLocation within your automation script. This will need to be set everytime PowerShell opens or the server reboots. EXAMPLE 1: DPLOG -Type INFO -LogFile "C:\MyLog.log" -Message "MY MESSAGE" EXAMPLE 2: DPLOG -Type START -Message "MY SCRIPT STARTED" EXAMPLE 3: DPLOG -Type START -Message "MY SCRIPT STARTED" -WriteToHost Y #> ##### BEGIN SCRIPT # If the log file was not specified through this function or as a global variable, set the Default IF ($LogfileLocation.Length -gt "0") { $LogFile = $LogFileLocation } $Time = (Get-Date -Format G) #$Message = $Message.ToUpper() Add-Content $Logfile "$Time `t[$Type]$(if ($Type.length -lt 6){"`t"})`t$((Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name)$(if ((Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name.Length -gt 15) {"`t"}elseif((Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name.Length -le 10) {"`t`t"}else {"`t`t"})$Message" IF (($WriteToHost) -eq "Y") { switch ($Type) { 'SUCCESS' {$color = $script:SuccessColor} 'INFO' {$color = $script:InfoColor} 'WARNING' {$color = $script:WarningColor} 'Error' {$color = $script:ErrorColor} default {$color = $script:InfoColor} } Write-Host "$(Get-Date -Format G) [" -ForegroundColor $script:OutputColor -BackgroundColor $script:BackGroundColor -NoNewline Write-Host "$(($Type).ToUpper())" -ForegroundColor $color -BackgroundColor $script:BackGroundColor -NoNewline write-host "]`t" -ForegroundColor $script:OutputColor -BackgroundColor $script:BackGroundColor -NoNewline $callingFunction = "$((Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name)$(if ((Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name.Length -gt 15) {"`t"}elseif((Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name.Length -le 10) {"`t`t"}else {"`t`t"})" write-host "$(if ($WriteCallingFunction -eq "Y") {$callingFunction})" -ForegroundColor $script:functioncolor -BackgroundColor $script:BackGroundColor -NoNewline write-host "$Message" -ForegroundColor $script:OutputColor -BackgroundColor $script:BackGroundColor } ##### END SCRIPT } ########## END DPLOG FUNCTION ########## ########## BEGIN DP Ignore Cert Warnings FUNCTION ########## function DPIgnoreCertWarnings { <# .SYNOPSIS Ignores All SSL Certificate errors/warnings in the current session .INPUTS Revert will set the policy back to normal and no longer ignore warnings or errors .OUTPUTS Description of objects that are output by the script .EXAMPLE DPIgnoreCertWarnings This runs with the default setting .NOTES Ignoring cert errors with ServerCertificateValidationCallback does not work for all cert problems, like mismatched domain names or self signed Adapted / updated from http://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error #> [CmdletBinding()] param ( [Parameter(Position=1)] [switch]$Revert, [Parameter(Position=2, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) Try { $Provider = New-Object Microsoft.CSharp.CSharpCodeProvider $Compiler = $Provider.CreateCompiler() $Params = New-Object System.CodeDom.Compiler.CompilerParameters $Params.GenerateExecutable = $false $Params.GenerateInMemory = $true $Params.IncludeDebugInformation = $false $Params.ReferencedAssemblies.Add("System.DLL") > $null $TASource=@' namespace Local.ToolkitExtensions.Net.CertificatePolicy { public class TrustAll : System.Net.ICertificatePolicy { public bool CheckValidationResult(System.Net.ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem) { return true; } } } '@ $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource) $TAAssembly=$TAResults.CompiledAssembly $TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll") if($Revert) { [System.Net.ServicePointManager]::CertificatePolicy = $null } else { [System.Net.ServicePointManager]::CertificatePolicy = $TrustAll } }#Try Catch { DPLOG -Type ERROR -Message "Error: $_" -WriteToHost $WriteToHost DPLOG -Type FINISH -Message "Finished DPIgnoreCertWarnings with error." -WriteToHost $WriteToHost #DPSetFailureFlag return }#Catch If($?) { if([System.Net.ServicePointManager]::CertificatePolicy) { if($Revert) { DPLOG -Type WARNING -Message "DPIgnoreCertWarnings unable to set to revert back to default" -WriteToHost $WriteToHost } else { DPLOG -Type SUCCESS -Message "DPIgnoreCertWarnings successfully set to ignore cert errors and warnings" -WriteToHost $WriteToHost } } else { if($Revert) { DPLOG -Type SUCCESS -Message "DPIgnoreCertWarnings successfully set to revert back to default" -WriteToHost $WriteToHost } else { DPLOG -Type WARNING -Message "DPIgnoreCertWarnings unable to set to ignore cert errors and warnings" -WriteToHost $WriteToHost } } DPLOG -Type FINISH -Message "Finished DPIgnoreCertWarnings" -WriteToHost $WriteToHost } }# main function #---------------------------------------------------------[Helper Functions]--------------------------------------------------------- ########## END DPIgnoreCertWarnings ########## ########## BEGIN GET OS VERSION ########## function DPGetOSVersion( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION GET OS VERSION AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2003 R2, 2008, 2008 R2, 2012, 2012 R2 and 2016. CMDLET VERSION: 1.0.2 DATE: 9/7/2016 ======================================================================================== Detects the OS version of the server. Sets a global variable that can be used throughout the PSM and automation process: $OSVer Sets a global variable that can be used throughout the PSM and automation process: $OSVerFull EXAMPLE 1: DPGetOSVersion #> # Detect the OS version and set a global variable IF (((Get-WmiObject Win32_OperatingSystem).Version) -ne "10.0.14300") { $Global:OSVerNum = ((Get-WmiObject Win32_OperatingSystem).Version) } ELSE { $OSVerNum = "2016" } IF (Test-Path 'C:\Program Files (x86)' -ErrorAction SilentlyContinue) { $Global:OSArch = "x64" } ELSE { $Global:OSArch = "x86" } $SP = (Get-WmiObject Win32_OperatingSystem).ServicePackMajorVersion IF ($SP -gt "0") { $Global:OSVerFull = ((Get-WmiObject Win32_OperatingSystem).Caption) + "Service Pack: $SP" + " $OSArch" } ELSE { $Global:OSVerFull = ((Get-WmiObject Win32_OperatingSystem).Caption) + " $OSArch" } IF ($OSVerNum -ge "5.2" -and $OSVerNum -lt "6.0") { $Global:OSVer = "2003 R2" } IF ($OSVerNum -ge "6.0" -and $OSVerNum -lt "6.1") { $Global:OSVer = "2008" } IF ($OSVerNum -ge "6.1" -and $OSVerNum -lt "6.2") { $Global:OSVer = "2008 R2" } IF ($OSVerNum -ge "6.2" -and $OSVerNum -lt "6.3") { $Global:OSVer = "2012" } IF ($OSVerNum -ge "6.3" -and $OSVerNum -lt "6.4") { $Global:OSVer = "2012 R2" } IF ($OSVerNum -eq "2016") { $Global:OSVer = "SERVER 10" [int]$Global:OSVerNum = "10" } $Message = "SERVER OS: $OSVerFull" IF ($WriteToHost -eq "N") { DPLOG -Type INFO -Message $Message -WriteToHost "N" } ELSE { DPLOG -Type INFO -Message $Message } } ######### END GET OS VERSION ########## ##################################################################################### ##################################################################################### ########## BEGIN AWS CHECK SCRIPT ########## function DPAWSCheck( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION CHECKS IF THE SERVER IS AN AWS SERVER AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2008 R2, 2012, 012 R2 and 2016 CMDLET VERSION: 1.0.1 DATE: 9/29/2016 ======================================================================================== Checks if this is an AWS server. EXAMPLE 1: DPAWSCheck #> #DPClearFailureFlag $Message = "STARTING AWS CHECK SCRIPT." DPLOG -Type INFO -Message $Message -WriteToHost $WriteToHost # Check if the OS is supported IF ([version]$OSVerNum -lt "6.1") { # Unsupported OS $Message = "THIS OS IS NOT SUPPORTED BY THIS FUNCTION" DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost #DPSetFailureFlag return } # Check if this is an AWS server IF ((((Get-WmiObject Win32_ComputerSystem).PrimaryOwnerName) -eq "Amazon") -or (((Get-WmiObject Win32_ComputerSystem).PrimaryOwnerName) -eq "EC2")) { $Global:AWSServer = "Yes" $Message = "AWS SERVER DETECTED." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost } ELSE { $Global:AWSServer = "No" $Message = "AWS SERVER NOT DETECTED." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost } } ########## END AWS CHECK SCRIPT ########## ##################################################################################### ##################################################################################### ########## BEGIN STRAT SERVER CHECK SCRIPT ########## function DPStratCheck( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION CHECKS IF THE SERVER IS A STRAT SERVER AND DISPLAYS THE REGION AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2008 R2, 2012, 2012 R2 and 2016. CMDLET VERSION: 1.0.2 DATE: 9/29/2016 ======================================================================================== Checks if this is a Strat server. If it is a Strat server global variables will be set. $StratServer [Yes, No] $StratRegion [Region Name] EXAMPLE 1: DPStratCheck #> #DPClearFailureFlag $Message = "STARTING STRAT CHECK SCRIPT." DPLOG -Type INFO -Message $Message -WriteToHost $WriteToHost # Check if the OS is supported IF ([version]$OSVerNum -lt "6.1") { # Unsupported OS $Message = "THIS OS IS NOT SUPPORTED BY THIS FUNCTION" DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost #DPSetFailureFlag return } IF (!(Get-Service "Cloud.com Instance Manager" -ErrorAction SilentlyContinue | Out-Null)) { $Global:StratServer = "No" DPLOG -Type INFO -Message "THIS IS NOT A STRAT SERVER" -WriteToHost $WriteToHost return } # Check if this is an Strat server $DHCP_Temp = ipconfig /all | find /i "DHCP Server" IF (($DHCP_Temp).Length -gt "0") { $DHCP_Temp2 = ($DHCP_Temp.Split()) $DHCP_Server = ($DHCP_Temp2[$DHCP_Temp2.Length - 1]) $StratRegionTemp = (Invoke-RestMethod -Uri http://$DHCP_Server/latest/availability-zone) IF (($StratRegionTemp).Length -gt "0") { $Global:StratServer = "Yes" $Global:StratRegion = $StratRegionTemp DPLOG -Type INFO -Message "THIS IS A STRAT SERVER." -WriteToHost $WriteToHost DPLOG -Type INFO -Message "STRAT REGION: $StratRegion." -WriteToHost $WriteToHost } ELSE { $Global:StratServer = "No" DPLOG -Type INFO -Message "THIS IS NOT A STRAT SERVER" -WriteToHost $WriteToHost } } ELSE { $Global:StratServer = "No" DPLOG -Type INFO -Message "THIS IS NOT A STRAT SERVER" -WriteToHost $WriteToHost } } ########## END STRAT SERVER CHECK SCRIPT ########## ##################################################################################### ##################################################################################### ########## BEGIN AZURE SERVER CHECK SCRIPT ########## function DPAzureCheck( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION CHECKS IF THE SERVER IS AN AZURE INSTANCE AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2008 R2, 2012, 2012 R2 and 2016 CMDLET VERSION: 1.0.1 DATE: 10/29/2015 ======================================================================================== Checks if this is an Azure instance. EXAMPLE 1: DPAzureCheck #> #DPClearFailureFlag $Message = "STARTING AZURE CHECK SCRIPT." DPLOG -Type INFO -Message $Message -WriteToHost $WriteToHost # Check if the OS is supported IF ([version]$OSVerNum -lt "6.1") { # Unsupported OS $Message = "THIS OS IS NOT SUPPORTED BY THIS FUNCTION" DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost #DPSetFailureFlag return } # Check if this is an Azure instance IF ((((Get-WmiObject Win32_ComputerSystem).Manufacturer) -eq "Microsoft Corporation") -and (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows Azure")) { $Global:AzureServer = "Yes" $Message = "AZURE SERVER DETECTED." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost } ELSE { $Global:AzureServer = "No" $Message = "AZURE SERVER NOT DETECTED." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost } } ########## END AZURE CHECK SCRIPT ########## ##################################################################################### ##################################################################################### ########## BEGIN LAYERED TECH SERVER CHECK SCRIPT ########## function DPLayeredTechCheck( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION CHECKS IF THE SERVER IS A LAYERED TECH SERVER AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2008 R2, 2012, 2012 R2 and 2016 CMDLET VERSION: 1.0.1 DATE: 9/29/2016 ======================================================================================== Checks if this is a Layered Tech server. EXAMPLE 1: DPLayeredTechCheck #> ##DPClearFailureFlag $Message = "STARTING LAYERED TECH SERVER CHECK SCRIPT." DPLOG -Type INFO -Message $Message -WriteToHost $WriteToHost # Check if the OS is supported IF ([version]$OSVerNum -lt "6.1") { # Unsupported OS $Message = "THIS OS IS NOT SUPPORTED BY THIS FUNCTION" DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost ##DPSetFailureFlag return } # Check if the Layered Tech management service exists IF (Get-Service GSIManagementServiceUpdater -ErrorAction SilentlyContinue) { $Global:LayeredTechServer = "Yes" $Message = "LAYERED TECH SERVER DETECTED." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost } ELSE { $Global:LayeredTechServer = "No" $Message = "LAYERED TECH SERVER NOT DETECTED." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost } } ########## END LAYERED TECH SERVER CHECK SCRIPT ########## ##################################################################################### ##################################################################################### function DPConfirmInternet( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION CONFIRM INTERNET CONNECTION AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2003 R2, 2008, 2008 R2, 2012, 2012 R2 and 2016 CMDLET VERSION: 1.0.2 DATE: 10/21/2016 ======================================================================================== Legacy function. No longer checks for an internet connection. It sets itself to the value of RepoAccess EXAMPLE 1: DPConfirmInternet #> $Global:InternetAccess = $RepoAccess } ########## END CONFIRM INTERNET CONNECTION ########## ##################################################################################### ##################################################################################### ########## BEGIN TEST REPO ACCESS ########## function DPTestRepoAccess( [Parameter(Position=1, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) { <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION TEST REPO ACCESS AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2003 R2, 2008, 2008 R2, 2012 and 2012 R2 CMDLET VERSION: 1.0.1 DATE: 8/19/2015 ======================================================================================== Confirms the server has access to http://repo.datapipe.net. Sets a global variable that can be used throughout the PSM and automation process: $RepoAccess EXAMPLE 1: DPTestRepoAccess #> # Test repo connection $Time = (get-date -Format MMddyyhhmmss) $File = "C:\Windows\Temp\TestFile$time.txt" DPDownloadFile -Source "http://repo.datapipe.net/windows/windows-install-files/Misc/TestFile.txt" -Destination $File -WriteToHost N -UseDotNetDownloadMethod Y IF (($DownloadComplete) -eq "Yes") { # Confirmed $Global:RepoAccess = "Yes" $Message = "REPO ACCESS CONFIRMED." IF ($WriteToHost -eq "N") { DPLOG -Type INFO -Message $Message -WriteToHost "N" } ELSE { DPLOG -Type INFO -Message $Message } Remove-Item $File -Confirm:$false -Force -ErrorAction SilentlyContinue } ELSE { # No internet access $Global:RepoAccess = "No" $Message = "REPO ACCESS NOT CONFIRMED." IF ($WriteToHost -eq "N") { DPLOG -Type INFO -Message $Message -WriteToHost "N" } ELSE { DPLOG -Type INFO -Message $Message } } } ########## END TEST REPO ACCESS ########## function DPDownloadFile{ [CMDLETBINDING()] param( [Parameter(Position=1, Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [string]$Source, [Parameter(Position=2, Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [string]$Destination, [Parameter(Position=3, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y", [Parameter(Position=4, Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$UseDotNetDownloadMethod="N" ) <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION DOWNLOAD FILE AUTHOR: ANTHONY MARINO SUPPORTED VERSIONS: 2003 R2, 2008, 2008 R2, 2012, 2012 R2 and 2016 CMDLET VERSION: 1.0.7 DATE: 10/21/2016 ======================================================================================== Downloads a file. Automatically selects the correct download method based on the OS and PS versions. If you are downloading a file from repo.datapipe.net on a Layered Tech, AWS or Azure server, your download will be proxied from a Strat server. A global variable: $DownloadComplete is set to Yes or No depending on if the file download completes. Note: Due to issues with .NET 3 SSL downloads, any sources with https will automatically use the "-UseDotNetDownloadMethod switch" EXAMPLE 1: DPDownloadFile -Source "http://toolkit.datapipe.net/BesTasks/anthony/ServerSetupUtility/TestFile.txt" -Destination "C:\Windows\Temp\TestFile.txt" EXAMPLE 2: DPDownloadFile -Source "http://toolkit.datapipe.net/BesTasks/anthony/ServerSetupUtility/TestFile.txt" -Destination "C:\Windows\Temp\TestFile.txt" -UseDotNetDownloadMethod Y #> # Reset download complete variable $Global:DownloadComplete = "" # Servers with stale root certs can error out. This corrects the issue (Git #244) DPIgnoreCertWarnings -WriteToHost N # Invoke-Webrequest can encounter SSL errors. If the source contains https, use the .NET 2 download method IF ($Source -match "https") { $UseDotNetDownloadMethod = "Y" } IF (($Source -match "repo.datapipe.net") -and (($AWSServer -eq "Yes") -or ($AzureServer -eq "Yes") -or ($LayeredTechServer -eq "Yes"))) { # Use a proxy $Message = "LAYERED TECH, AWS OR AZURE SERVER DETECTED. DOWNLOADING USING A PROXY." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost $Message = "TESTING A CONNECTION TO THE SMQ PROXY." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost # Download a test file using the SMQ proxy $client = new-object System.Net.WebClient $proxy = new-object System.Net.WebProxy "64.106.186.109:8080" $proxy.Credentials = New-Object System.Net.NetworkCredential ("dpautomation", "f8xBPsUS^Q?apdXf?rDy") $client.proxy=$proxy $TestSource = "http://repo.datapipe.net/windows/windows-install-files/Misc/TestFile.txt" $Now = (Get-Date -Format MMddyyyyhhmm) $TestDestination = "C:\Windows\Temp\$Now.txt" Try { $client.DownloadFile($TestSource, $TestDestination) | Out-Null } catch { DPLOG -Type ERROR -Message "Error: $_" -WriteToHost $WriteToHost } # Check if the file downloaded IF (Test-Path $TestDestination) { $Message = "USING SMQ PROXY." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost # Remove the test file Remove-Item $TestDestination -Force # Rebuild the web client and download the requested file $client = new-object System.Net.WebClient $proxy = new-object System.Net.WebProxy "64.106.186.109:8080" $proxy.Credentials = New-Object System.Net.NetworkCredential ("dpautomation", "f8xBPsUS^Q?apdXf?rDy") $client.proxy=$proxy $Message = "DOWNLOADING FILE USING PRE PS3 METHOD." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost $client.DownloadFile($Source, $Destination) | Out-Null } ELSE { $Message = "UNABLE TO CONTACT TO THE SMQ PROXY" DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost $Message = "TESTING A CONNECTION TO THE SJC PROXY." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost # Download a test file using the SJC proxy $client = new-object System.Net.WebClient $proxy = new-object System.Net.WebProxy "66.70.101.47:8080" $proxy.Credentials = New-Object System.Net.NetworkCredential ("dpautomation", "f8xBPsUS^Q?apdXf?rDy") $client.proxy=$proxy $TestSource = "http://repo.datapipe.net/windows/windows-install-files/Misc/TestFile.txt" $Now = (Get-Date -Format MMddyyyyhhmm) $TestDestination = "C:\Windows\Temp\$Now.txt" $client.DownloadFile($TestSource, $TestDestination) | Out-Null IF (Test-Path $TestDestination) { $Message = "USING SJC PROXY." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost # Remove the test file Remove-Item $TestDestination -Force # Rebuild the web client and download the requested file $client = new-object System.Net.WebClient $proxy = new-object System.Net.WebProxy "66.70.101.47:8080" $proxy.Credentials = New-Object System.Net.NetworkCredential ("dpautomation", "f8xBPsUS^Q?apdXf?rDy") $client.proxy=$proxy $Message = "DOWNLOADING FILE USING PRE PS3 METHOD." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost $client.DownloadFile($Source, $Destination) | Out-Null } ELSE { $Message = "UNABLE TO CONTACT THE SMQ AND SJC PROXIES." DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost } } IF (Test-Path $Destination) { $Message = "CONFIRMED YOUR DOWNLOAD COMPLETED." DPLOG -type SUCCESS -Message $Message -WriteToHost $WriteToHost $Global:DownloadComplete = "Yes" } ELSE { $Message = "UNABLE TO CONFIRM YOUR DOWNLOAD COMPLETED." DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost $Global:DownloadComplete = "No" } } ELSE { IF (($OSVerNum -lt "6.1") -or ($PSVer -le "3") -or ($UseDotNetDownloadMethod -eq "Y")) { $Message = "DOWNLOADING FILE USING PRE PS3 METHOD." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost $client = new-object System.Net.WebClient $client.DownloadFile($Source, $Destination) | Out-Null } ELSE { $Message = "DOWNLOADING FILE USING PS3+ METHOD." DPLOG -type INFO -Message $Message -WriteToHost $WriteToHost Invoke-WebRequest $Source -OutFile $Destination } IF (Test-Path $Destination) { $Message = "CONFIRMED YOUR DOWNLOAD COMPLETED." DPLOG -type SUCCESS -Message $Message -WriteToHost $WriteToHost $Global:DownloadComplete = "Yes" } ELSE { $Message = "UNABLE TO CONFIRM YOUR DOWNLOAD COMPLETED." DPLOG -type ERROR -Message $Message -WriteToHost $WriteToHost $Global:DownloadComplete = "No" } } } ########## END DOWNLOAD FILE ########## DPLOG -Type INFO -Message "DPSQLPostInstall - Utility for configuration of SQL Server" DPLOG -Type INFO -Message "Author: Justin Procacci" DPLOG -Type INFO -Message "Build: $Version" DPLOG -Type INFO -Message "Date: $Date" DPGetOSVersion -WriteToHost N DPAWSCheck -WriteToHost N DPAzureCheck -WriteToHost N DPStratCheck -WriteToHost N DPLayeredTechCheck -WriteToHost N DPTestRepoAccess -WriteToHost N Push-Location try { if ((Get-Command -Module sqlps -Name invoke-sqlcmd | select dll).dll -match "\\Microsoft SQL Server\\1[0-9][0-9]\\") { $Global:QueryTimeout = 0; } else { $Global:QueryTimeout = 65535 } DPLOG -WriteToHost $WriteToHost -Type INFO -Message "SQLPS `$Global:QueryTimeout set to: $Global:QueryTimeout" } catch { DPLOG -WriteToHost $WriteToHost -Type WARNING -Message "SQLPS `$Global:QueryTimeout was unable to be set." } #SQLCMD command location setup $Global:sqlcmd = (gci -Recurse 'C:\Program Files\Microsoft SQL Server' -Filter sqlcmd.exe -ErrorAction SilentlyContinue | select fullname, @{expression={[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.fullname).productversion};label='ProductVersion'} | Sort-Object productversion -Descending | select -First 1 fullname).fullname if ($Global:sqlcmd) { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "SQLCMD installed: $Global:sqlcmd" } else { DPLOG -WriteToHost $WriteToHost -Type WARNING -Message "SQLCMD not installed. This is required for some functions" } $Global:SQLServerConfiguration = @() $Global:SQLFileConfiguration = @() [string]$Global:ErrorCatch = [string]::Empty [string]$Global:InstanceError = [string]::Empty if ($PSVersionTable.PSVersion.Major -lt 3){ DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "Powershell 3 is required for this module" } Pop-Location Function DPSetMonitoringScript { [CMDLETBINDING()] param ( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { DPLOG -Type START -Message " " -WriteToHost $WriteToHost $Blocking = "BEGIN TRY DECLARE @__RetVal nvarchar(4000) ,@SqlVersion NUMERIC(4,2) ,@BlockingThresholdMinute_Major smallint = 3 -- Set the major threshold here. critical threshold is set in the asset field of EM7 -- For testing --,@BlockingThresholdMinute smallint = 5 SET @__RetVal = N''; SET @SqlVersion = LEFT(CAST(SERVERPROPERTY('productversion') AS VARCHAR), 4) IF(@SqlVersion >= 11) BEGIN EXECUTE AS LOGIN = 'dp_mon'; END SELECT @__RetVal = @__RetVal + case WHEN ((wait_time / 1000 / 60) between @BlockingThresholdMinute_Major AND @BlockingThresholdMinute) THEN N'MAJOR session_ID ' + cast(session_id as nvarchar(100)) + N' is blocked by session_id ' + cast(blocking_session_id as Nvarchar(100)) + N' for ' + cast((wait_time / 1000 / 60) as nvarchar(100)) + N' minutes which has exceeded the threshold of ' + cast(@BlockingThresholdMinute_Major as nvarchar(100)) + N' minutes, ' WHEN ((wait_time / 1000 / 60) > @BlockingThresholdMinute) THEN N'CRITICAL session_ID ' + cast(session_id as nvarchar(100)) + N' is blocked by session_id ' + cast(blocking_session_id as Nvarchar(100)) + N' for ' + cast((wait_time / 1000 / 60) as nvarchar(100)) + N' minutes which has exceeded the threshold of ' + cast(@BlockingThresholdMinute as nvarchar(100)) + N' minutes, ' ELSE '' END FROM sys.dm_exec_requests WHERE blocking_session_id <> 0; IF (len(@__RetVal) = 0) BEGIN SET @__RetVal = 'OKAY No blocking sessions detected over the threshold.' END ELSE BEGIN SET @__RetVal = left(@__RetVal, len(@__RetVal)-1); END IF(@SqlVersion >= 11) BEGIN REVERT; END END TRY BEGIN CATCH SELECT 'CRITICAL ' + ERROR_MESSAGE(); END CATCH SELECT @__RetVal"; $Deadlock = "--Variable Declarations DECLARE @XMLDataEventTarget xml , @FileName sysname , @DeadLockCount int = 0 , @DeadLockCountMajor int = 10 , @DeadLockCountCritical int = 20 , @__RetVal nvarchar(2000) = '' , @SqlVersion NUMERIC(4,2); SELECT @SqlVersion = LEFT(CAST(SERVERPROPERTY('productversion') AS VARCHAR), 4); --For Testing --DECLARE @MinuteThreshold int = 60 IF (@MinuteThreshold < 60) BEGIN SET @__RetVal = N'CRITICAL Invalid minutethreshold parameter specified; Please select a value above 60.' GOTO exiter END IF(@SqlVersion >= 11) BEGIN EXECUTE AS LOGIN = 'dp_mon'; END; BEGIN TRY IF(@SqlVersion >= 11) BEGIN SELECT @XMLDataEventTarget = cast(target_data as xml) FROM sys.dm_xe_sessions [des] JOIN sys.dm_xe_session_targets [dxst] ON [des].[address] = [dxst].[event_session_address] WHERE [des].[name] = 'system_health'; --Get Directory of extended Event session for SYSTEM_Health SELECT @FileName = X.col.value('@name', 'sysname') FROM @XMLDataEventTarget.nodes ('//./File') as X(col) SELECT @FileName = LEFT(@FileName , LEN(@FileName) - charindex('\', reverse(@FileName))) + '\SYSTEM_health_*'; IF (@FileName is not null) BEGIN select @DeadLockCount = count(*) from (SELECT T.sdnodes.value('(/event/data/value/deadlock/victim-list/victimProcess/@id)[1]', 'nvarchar(20)') [Victim-process] , T.sdnodes.value('(event/@timestamp)[1]','datetimeoffset') as [timestamp] FROM (SELECT bpr.query('.') as sdnodes FROM (SELECT CAST(event_data AS XML) as target_data,* FROM sys.fn_xe_file_target_read_file(@FileName,NULL,NULL,NULL) WHERE object_name = 'xml_Deadlock_report') AS x CROSS APPLY target_data.nodes('/event') AS n(bpr)) as T) z WHERE z.timestamp > dateadd(minute, -@MinuteThreshold, SYSDATETIMEOFFSET()) and z.[Victim-process] is not null END ELSE BEGIN SET @__RetVal = 'CRITICAL Event file is empty' END END ELSE BEGIN --SQL 2008 from Ring buffer SELECT TOP 1 @XMLDataEventTarget = CAST(target_data AS XML) FROM sys.dm_xe_session_targets st JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address WHERE name = 'system_health' select @DeadLockCount = COUNT(*) from ( SELECT cast(x.col.value('(data/value)[1]', 'varchar(max)') as XML) [xml] -- XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)') AS XML FROM @XMLDataEventTarget.nodes ('//event') as X(col) WHERE x.col.value('@name', 'nvarchar(MAX)') = 'xml_deadlock_report' AND x.col.value('@timestamp', 'datetime') > dateadd(minute, -@MinuteThreshold, SYSDATETIMEOFFSET())) b where b.xml.value('(/deadlock/victim-list/victimProcess/@id)[1]', 'nvarchar(20)') is not null END IF (len(@__RetVal) > 0) --We have proper data BEGIN print @__RetVal END ELSE BEGIN IF (@DeadLockCount > @DeadLockCountMajor) BEGIN IF (@DeadLockCount > @DeadLockCountCritical) BEGIN SET @__RetVal = (N'CRITICAL ' + cast(@DeadLockCount as nvarchar(5))+ N' deadlocks have been reported within ' + cast(@MinuteThreshold as nvarchar(2000)) + N' minutes.'); END ELSE BEGIN SET @__RetVal = (N'MAJOR ' + cast(@DeadLockCount as nvarchar(5))+ N' deadlocks have been reported within ' + cast(@MinuteThreshold as nvarchar(2000)) + N' minutes.'); END END ELSE IF (@DeadLockCount < @DeadLockCountMajor) BEGIN SET @__RetVal = (N'OK ' + cast(@DeadLockCount as nvarchar(2000)) + ' deadlocks have been reported within ' + cast(@MinuteThreshold as nvarchar(2000)) + N' minutes.'); END ELSE BEGIN SET @__RetVal = (N'CRITICAL Invalid deadlock count reported'); END END END TRY BEGIN CATCH SET @__RetVal = 'CRITICAL ' + ERROR_MESSAGE(); END CATCH IF(@SqlVersion >= 11) BEGIN REVERT; END; exiter: SELECT @__RetVal"; $JobStatus = "SET NOCOUNT ON; DECLARE @SqlVersion NUMERIC(4,2); SELECT @SqlVersion = LEFT(CAST(SERVERPROPERTY('productversion') AS VARCHAR), 4); IF(@SqlVersion >= 11) BEGIN EXECUTE AS LOGIN = 'dp_mon'; END -- For testing -- DECLARE @ExpirationHours int = 0 DECLARE @Results TABLE ( [name] sysname, [last_run] datetime null, [run_status] sysname null ); IF(@ExpirationHours > 0) BEGIN INSERT INTO @Results SELECT [j].[name], MAX(CAST( STUFF(STUFF(CAST([hist].[run_date] as varchar),7,0,'-'),5,0,'-') + ' ' + STUFF(STUFF(REPLACE(STR([hist].[run_time],6,0),' ','0'),5,0,':'),3,0,':') as datetime)) AS [last_run], CASE [hist].[run_status] WHEN 0 THEN 'Failed' WHEN 1 THEN 'Success' WHEN 2 THEN 'Retry' WHEN 3 THEN 'Canceled' WHEN 4 THEN 'In progress' END AS [run_status] FROM [msdb].[dbo].[sysjobs] [j] OUTER APPLY ( SELECT TOP 1 [run_status], [run_date], [run_time] FROM [msdb].[dbo].[sysjobhistory] WHERE ([job_id] = [j].[job_id]) AND [run_status] = 1 AND [step_id] = 0 ORDER BY [run_date] DESC, [run_time] DESC ) [hist] WHERE [j].[enabled] = 1 GROUP BY [j].[name], [hist].[run_status] END ELSE BEGIN INSERT INTO @Results SELECT [j].[name], MAX(CAST( STUFF(STUFF(CAST([hist].[run_date] as varchar),7,0,'-'),5,0,'-') + ' ' + STUFF(STUFF(REPLACE(STR([hist].[run_time],6,0),' ','0'),5,0,':'),3,0,':') as datetime)) AS [last_run], CASE [hist].[run_status] WHEN 0 THEN 'Failed' WHEN 1 THEN 'Success' WHEN 2 THEN 'Retry' WHEN 3 THEN 'Canceled' WHEN 4 THEN 'In progress' END AS [run_status] --[hist].[run_status] FROM [msdb].[dbo].[sysjobs] [j] OUTER APPLY ( SELECT TOP 1 [run_status], [run_date], [run_time] FROM [msdb].[dbo].[sysjobhistory] WHERE ([job_id] = [j].[job_id]) AND [step_id] = 0 ORDER BY [run_date] DESC, [run_time] DESC ) [hist] WHERE [j].[enabled] = 1 AND [hist].[run_status] IS NOT NULL GROUP BY [j].[name], [hist].[run_status] END IF(@JobName IS NOT NULL) SELECT [name], [last_run], [run_status] FROM @Results WHERE [name] = @JobName; ELSE SELECT [name], [last_run], [run_status] FROM @Results IF(@SqlVersion >= 11) BEGIN REVERT; END"; $Backup = " SET NOCOUNT ON; DECLARE @SqlVersion NUMERIC(4,2); SELECT @SqlVersion = LEFT(CAST(SERVERPROPERTY('productversion') AS VARCHAR), 4); IF(@SqlVersion >= 11) BEGIN EXECUTE AS LOGIN = 'dp_mon'; END DECLARE @Results TABLE ( [BackupTime] datetime, [Name] nvarchar(100) ); --declare @hourthreshold int = 26,@snapshot bit = 0, @backuptype varchar(1) = 'D' --declare @hourthreshold int = 2,@snapshot bit = 0, @backuptype varchar(1) = 'L' --declare @hourthreshold int = 26,@snapshot bit = 0, @backuptype varchar(1) = 'I' declare @backupthreshold datetime = dateadd(HOUR, -@hourthreshold,getdate()), @backuptype2 varchar(1) = @backuptype IF(@backuptype2 = 'L') BEGIN INSERT INTO @Results SELECT c.backup_finish_date, c.name FROM (SELECT b.backup_finish_date , sd.name, sys.fn_hadr_backup_is_preferred_replica (sd.name) [preferredReplica] FROM ( SELECT RANK() OVER (partition by database_name order by backup_finish_date desc) [LatestBackup] , backup_finish_date , database_name FROM ( SELECT database_name, backup_finish_date FROM msdb.dbo.backupset WHERE [type] = @backuptype2 and is_snapshot = @snapshot )a )b right join master.sys.databases sd on sd.name = b.database_name left join sys.availability_databases_cluster d on d.database_name = sd.name left join sys.dm_hadr_availability_replica_states hars on d.group_id = hars.group_id WHERE (LatestBackup = 1 or LatestBackup is null) and sd.database_id <> 2 and (backup_finish_date <= @backupthreshold or backup_finish_date is null) and sys.fn_hadr_backup_is_preferred_replica (sd.name) = 1 and (hars.is_local = 1 or hars.is_local is null) and sd.recovery_model <= 2 and sd.is_read_only = 0 and DATEDIFF(HOUR, [sd].[create_date], GETDATE()) >= 24 and sd.[state] = 0) c where c.preferredReplica = 1 and c.name not in ('master','model','tempdb','msdb'); --List of databases to be excluded; END ELSE IF(@BackupType2 = 'I') BEGIN INSERT INTO @Results SELECT c.backup_finish_date, c.name FROM (SELECT b.backup_finish_date , sd.name, sys.fn_hadr_backup_is_preferred_replica (sd.name) [preferredReplica] FROM ( SELECT RANK() OVER (partition by database_name order by backup_finish_date desc) [LatestBackup] , backup_finish_date , database_name FROM ( SELECT database_name, backup_finish_date FROM msdb.dbo.backupset WHERE [type] = @backuptype2 and is_snapshot = @snapshot )a )b right join master.sys.databases sd on sd.name = b.database_name left join sys.availability_databases_cluster d on d.database_name = sd.name left join sys.dm_hadr_availability_replica_states hars on d.group_id = hars.group_id WHERE (LatestBackup = 1 or LatestBackup is null) and sd.database_id > 2 and (backup_finish_date <= @backupthreshold or backup_finish_date is null) and (hars.is_local = 1 or hars.is_local is null) and sys.fn_hadr_backup_is_preferred_replica (sd.name) = 1 and sd.is_read_only = 0 and DATEDIFF(HOUR, [sd].[create_date], GETDATE()) >= 24 and sd.[state] = 0) c where c.preferredReplica = 1 and c.name not in ('master','model','tempdb','msdb'); --List of databases to be excluded; END ELSE BEGIN INSERT INTO @Results SELECT c.backup_finish_date, c.name FROM (SELECT b.backup_finish_date , sd.name, sys.fn_hadr_backup_is_preferred_replica (sd.name) [preferredReplica] FROM ( SELECT RANK() OVER (partition by database_name order by backup_finish_date desc) [LatestBackup] , backup_finish_date , database_name FROM ( SELECT database_name, backup_finish_date FROM msdb.dbo.backupset WHERE [type] = @backuptype2 and is_snapshot = @snapshot )a )b right join master.sys.databases sd on sd.name = b.database_name left join sys.availability_databases_cluster d on d.database_name = sd.name left join sys.dm_hadr_availability_replica_states hars on d.group_id = hars.group_id WHERE (LatestBackup = 1 or LatestBackup is null) and sd.database_id <> 2 and (backup_finish_date <= @backupthreshold or backup_finish_date is null) and (hars.is_local = 1 or hars.is_local is null) and sys.fn_hadr_backup_is_preferred_replica (sd.name) = 1 and sd.is_read_only = 0 and DATEDIFF(HOUR, [sd].[create_date], GETDATE()) >= 24 and sd.[state] = 0) c where c.preferredReplica = 1 and c.name not in ('tempdb'); --List of databases to be excluded; END SET NOCOUNT OFF; SELECT * FROM @Results IF(@SqlVersion >= 11) BEGIN REVERT; END"; $backup_2008 = " SET NOCOUNT ON; DECLARE @SqlVersion NUMERIC(4,2); SELECT @SqlVersion = LEFT(CAST(SERVERPROPERTY('productversion') AS VARCHAR), 4); IF(@SqlVersion >= 11) BEGIN EXECUTE AS LOGIN = 'DP_MON'; END DECLARE @Results TABLE ( [BackupTime] datetime, [Name] nvarchar(100) ); IF(@BackupType = 'L') BEGIN INSERT INTO @Results SELECT MAX([msdb].[dbo].[backupset].[backup_finish_date]) AS [BackupTime], [msdb].[sys].[databases].[name] FROM [msdb].[sys].[databases] LEFT JOIN [msdb].[dbo].[backupset] ON [msdb].[dbo].[backupset].[database_name] = [msdb].[sys].[databases].[name] AND [msdb].[dbo].[backupset].[type] = @BackupType AND [msdb].[dbo].[backupset].[is_snapshot] = @SnapShot WHERE ([msdb].[sys].[databases].[name] NOT IN ('tempdb','model','msdb','master')) AND DATEDIFF(HOUR, [msdb].[sys].[databases].[create_date], GETDATE()) >= 24 AND [msdb].[sys].[databases].[recovery_model] < 3 and [msdb].[sys].[databases].[state] = 0 and [msdb].[sys].[databases].[is_in_standby] = 0 GROUP BY [msdb].[sys].[databases].[name] END ELSE IF (@BackupType = 'I') BEGIN INSERT INTO @Results SELECT MAX([msdb].[dbo].[backupset].[backup_finish_date]) AS [BackupTime], [msdb].[sys].[databases].[name] FROM [msdb].[sys].[databases] LEFT JOIN [msdb].[dbo].[backupset] ON [msdb].[dbo].[backupset].[database_name] = [msdb].[sys].[databases].[name] AND [msdb].[dbo].[backupset].[type] = @BackupType AND [msdb].[dbo].[backupset].[is_snapshot] = @SnapShot WHERE ([msdb].[sys].[databases].[name] NOT IN ('tempdb','model','msdb','master')) AND DATEDIFF(HOUR, [msdb].[sys].[databases].[create_date], GETDATE()) >= @HourThreshold and -- Exclude any new Databases [msdb].[sys].[databases].[state] = 0 and [msdb].[sys].[databases].[is_in_standby] = 0 GROUP BY [msdb].[sys].[databases].[name] END ELSE BEGIN INSERT INTO @Results SELECT MAX([msdb].[dbo].[backupset].[backup_finish_date]) AS [BackupTime], [msdb].[sys].[databases].[name] FROM [msdb].[sys].[databases] LEFT JOIN [msdb].[dbo].[backupset] ON [msdb].[dbo].[backupset].[database_name] = [msdb].[sys].[databases].[name] AND [msdb].[dbo].[backupset].[type] = @BackupType AND [msdb].[dbo].[backupset].[is_snapshot] = @SnapShot WHERE ([msdb].[sys].[databases].[name] NOT IN ('tempdb')) AND DATEDIFF(HOUR, [msdb].[sys].[databases].[create_date], GETDATE()) >= @HourThreshold and -- Exclude any new Databases [msdb].[sys].[databases].[state] = 0 and [msdb].[sys].[databases].[is_in_standby] = 0 GROUP BY [msdb].[sys].[databases].[name] END DELETE @Results WHERE DATEDIFF(HOUR, [BackupTime], GETDATE()) <= @HourThreshold SET NOCOUNT OFF; SELECT * FROM @Results IF(@SqlVersion >= 11) BEGIN REVERT; END" $AgentAlert = "SET NOCOUNT ON; DECLARE @SqlVersion NUMERIC(4,2); SELECT @SqlVersion = LEFT(CAST(SERVERPROPERTY('productversion') AS VARCHAR), 4); IF(@SqlVersion >= 11) BEGIN EXECUTE AS LOGIN = 'dp_mon'; END DECLARE @SQLAgentAlertList NVARCHAR(2000), @Split CHAR(1), @X XML, @__RetVal NVARCHAR(4000); DECLARE @SQLAgentAlertTable TABLE ( [ID] INT IDENTITY(1,1) PRIMARY KEY, [Name] SYSNAME ); INSERT INTO @SQLAgentAlertTable select name from msdb.dbo.sysalerts --where name not in ('') --Un-comment and update to exclude alerts by name. --Update this to the SQL Agent Alert Names that you wish to monitor SELECT @__RetVal = ''; IF EXISTS (SELECT 1 FROM MASTER.dbo.sysprocesses WHERE program_name = N'SQLAgent - Generic Refresher') BEGIN Print 'SQL Agent Running continue;' END ELSE BEGIN SELECT @__RetVal = ('CRITICAL ' + cast(@@SERVERNAME as nvarchar(100)) + ' SQL Agent is not running'); GOTO TheEnd; END --Table Exist check: Create and populate with valid alerts. IF NOT EXISTS(SELECT name FROM msdb.sys.tables WHERE name = 'SQLAgentAlerts') BEGIN CREATE TABLE msdb..SQLAgentAlerts ( [ID] INT IDENTITY(1,1) PRIMARY KEY, --adding for order! [AlertID] INT, [OccurrenceCount] INT ); --Populate table: Add the valid alerts defined. INSERT INTO msdb..SQLAgentAlerts SELECT sa.id, occurrence_count FROM msdb.dbo.sysalerts sa RIGHT JOIN @SQLAgentAlertTable saat ON sa.NAME = saat.Name WHERE sa.name is not null; END ELSE BEGIN --Add valid defined alerts to msdb..SQLAgentAlerts with their current occurrence count INSERT INTO msdb..SQLAgentAlerts SELECT sa.id, sa.occurrence_count FROM msdb.dbo.sysalerts sa RIGHT JOIN @SQLAgentAlertTable saat ON sa.name = saat.Name LEFT JOIN msdb.dbo.SQLAgentAlerts saa ON sa.id = saa.AlertID WHERE saa.id IS NULL AND sa.id IS NOT NULL; IF ((SELECT COUNT(*) FROM @SQLAgentAlertTable WHERE name != '') = 0) BEGIN SET @__RetVal = ' No Alerts Defined in SqlAgentAlertQuery.txt File,' print 'no alerts defined' END ELSE BEGIN PRINT 'alerts defined' SELECT @__RetVal = @__RetVal + CASE WHEN sa.name IS NULL THEN saat.name + ' Alert does not exist, ' WHEN sa.enabled = 0 THEN sa.name + ' Alert is disabled, ' WHEN sa.occurrence_count <> saa.OccurrenceCount THEN Sa.Name + ' occurence count has changed, ' END FROM msdb.dbo.sysalerts sa RIGHT JOIN @SQLAgentAlertTable saat ON sa.NAME = saat.Name LEFT JOIN msdb..SQLAgentAlerts saa ON saa.AlertID = sa.ID WHERE sa.name IS NULL or sa.enabled = 0 or (sa.occurrence_count <> saa.OccurrenceCount) ORDER BY sa.name ASC, sa.last_occurrence_date DESC END END --Check Return value to see if any errors have been accumlated IF (LEN(@__RetVal) > 0) BEGIN --Append CRITICAL so nagios can pick it up and clean the [,] at the end. SET @__RetVal = 'CRITICAL ' + LEFT(@__RetVal, LEN(@__RetVal) - 1) END ELSE BEGIN --SUCCESS no errors so return OK to nagios Set @__RetVal = 'OK No change in SQLAgent alert occurrences'; END TheEnd: SELECT @__RetVal IF(@SqlVersion >= 11) BEGIN REVERT; END SET NOCOUNT OFF; --How to clear the alert if Occurrence count has changed --UPDATE saa --SET saa.OccurrenceCount = sa.occurrence_count --FROM msdb.dbo.sysalerts sa --JOIN msdb..SQLAgentAlerts saa -- ON sa.id = saa.AlertID --WHERE sa.name = 'Error_18456' --SELECT * FROM msdb.dbo.sysalerts"; $instances = DPGetSQLInstances } PROCESS { #Observer $MSSQLScriptsObserver = 'C:\Program Files (x86)\DataPipe\easyAGENT\MSSQL Scripts' #If SQL 2012+ $instances | %{ if ([regex]::Match($_.identifier,"[0-9][0-9]\.") -replace "\.","" -lt 11) {$nohadr = 1;}} #check if Datapipe monitoring Agent has a \MSSQL Scripts\ folder if (test-path -Path $MSSQLScriptsObserver) { try { mkdir "$MSSQLScriptsObserver\original_$((get-date -Format 'MMddyyyy'))" -Force -ErrorAction SilentlyContinue | Out-Null DPLOG -Type INFO -Message "Backing Up *\easyAGENT\MSSQL Scripts\ to $("*\easyAGENT\MSSQL Scripts\original_$((get-date -Format 'MMddyyyy'))")" -WriteToHost $WriteToHost ls -Path $MSSQLScriptsObserver -Recurse -Filter *.txt | %{Copy-Item -Path $_.fullname -Destination "$MSSQLScriptsObserver\original_$((get-date -Format 'MMddyyyy'))\$($_.name)" -Force -ErrorAction SilentlyContinue | Out-Null;} if ($nohadr -ne 1){ DPLOG -Type INFO -Message "Updating SqlBackupQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MSSQLScriptsObserver\SqlBackupQuery.txt" -Value $Backup } else { DPLOG -Type INFO -Message "Updating SqlBackupQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MSSQLScriptsObserver\SqlBackupQuery.txt" -Value $backup_2008 } DPLOG -Type INFO -Message "Updating SqlBlockingSessionQuery.txt" -WriteToHost $WriteToHost $Blocking -replace 'major','WARNING' | Set-Content -Path "$MSSQLScriptsObserver\SqlBlockingSessionQuery.txt" DPLOG -Type INFO -Message "Updating SqlDeadlockQuery.txt" -WriteToHost $WriteToHost $Deadlock -replace 'major','WARNING' | Set-Content -Path "$MSSQLScriptsObserver\SqlDeadlockQuery.txt" DPLOG -Type INFO -Message "Updating SqlJobStatus.txt" -WriteToHost $WriteToHost $JobStatus -replace 'major','WARNING' | Set-Content -Path "$MSSQLScriptsObserver\SqlJobStatus.txt" DPLOG -Type INFO -Message "Updating SqlAgentAlertQuery.txt" -WriteToHost $WriteToHost $AgentAlert -replace 'major','WARNING' | Set-Content -Path "$MSSQLScriptsObserver\SqlAgentAlertQuery.txt" DPLOG -Type SUCCESS -Message "Updated Observer SQL Scripts completed" -WriteToHost Y; } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } #EM7 $MssqlScripts = 'C:\Program Files (x86)\DataPipe\Datapipe SSH Agent\MSSQL Scripts' #check if Datapipe monitoring Agent has a \MSSQL Scripts\ folder if (test-path -Path $MssqlScripts) { try { mkdir "$MssqlScripts\original_$((get-date -Format 'MMddyyyy'))" -Force -ErrorAction SilentlyContinue | Out-Null DPLOG -Type INFO -Message "Backing Up *\Datapipe SSH Agent\MSSQL Scripts\ to $("*\Datapipe SSH Agent\MSSQL Scripts\original_$((get-date -Format 'MMddyyyy'))")" -WriteToHost $WriteToHost ls -Path $MssqlScripts -Recurse -Filter *.txt | %{Copy-Item -Path $_.fullname -Destination "$MssqlScripts\original_$((get-date -Format 'MMddyyyy'))\$($_.name)" -Force -ErrorAction SilentlyContinue | Out-Null;} if ($nohadr -ne 1){ DPLOG -Type INFO -Message "Updating SqlBackupQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MssqlScripts\SqlBackupQuery.txt" -Value $backup_2008 } else { DPLOG -Type INFO -Message "Updating SqlBackupQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MssqlScripts\SqlBackupQuery.txt" -Value $backup } DPLOG -Type INFO -Message "Updating SqlBlockingSessionQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MssqlScripts\SqlBlockingSessionQuery.txt" -Value $Blocking DPLOG -Type INFO -Message "Updating SqlDeadlockQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MssqlScripts\SqlDeadlockQuery.txt" -Value $Deadlock DPLOG -Type INFO -Message "Updating SqlJobStatus.txt" -WriteToHost $WriteToHost Set-Content -Path "$MssqlScripts\SqlJobStatus.txt" -Value $JobStatus DPLOG -Type INFO -Message "Updating SqlAgentAlertQuery.txt" -WriteToHost $WriteToHost Set-Content -Path "$MssqlScripts\SqlAgentAlertQuery.txt" -Value $AgentAlert DPLOG -Type SUCCESS -Message "Updated EM7 SQL Scripts completed" -WriteToHost Y; } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else{ DPLOG -Type ERROR -Message "DatapipeMonitoringAgent is either not installed or not up to date" -WriteToHost Y } } END { DPLOG -Type FINISH -Message " " -WriteToHost $WriteToHost } } function DPEncodeString { <# .SYNOPSIS Decrypt or Encrypt sensitive string data .DESCRIPTION Decrypt or Encrypt sensitive string data Example use cases: To put a password in task manager without it being in clear text. .NOTES .PARAMETER Decrypt To decrypt a value from Base64Encoding. In parameter set Decrypt. .PARAMETER EncryptT To encrypt a value to Base64Encoding. In parameter set Encrypt .PARAMETER Value The string value to be decrypted or encrypted. Both parameter sets .EXAMPLE DPEncodeString -Value 'ClearTextPass123R#@' -Encrypt Q2xlYXJUZXh0UGFzczEyM1IjQA== .EXAMPLE DPEncodeString -Value Q2xlYXJUZXh0UGFzczEyM1IjQA== -Decrypt ClearTextPass123R#@ #> [CmdletBinding()] param( [Parameter(Mandatory = $True,Position = 0)] [string]$Value ,[Parameter(Mandatory = $True,Position = 1,ParameterSetName = 'Decrypt')] [switch]$Decrypt ,[Parameter(Mandatory = $True,Position = 1,ParameterSetName = 'Encrypt')] [switch]$Encrypt ) begin { } process { try { if ($Encrypt) { $enc = [System.Text.encoding]::UTF8 $data = $enc.GetBytes($Value) $__RetVal = [System.Convert]::ToBase64String($data); } if ($Decrypt) { [byte[]]$data = [System.Convert]::FromBase64String($Value); $__RetVal = [System.Text.ASCIIEncoding]::ASCII.GetString($data); } } catch { Write-Host ("Exception while executing: {0}" -f $_.exception.message) } } end { return $__RetVal; } } Function DPSQLInstallRedGate7 { <# .SYNOPSIS Install and configure RedGate SQLBackup 7 .DESCRIPTION Install and configure RedGate SQLBackup 7 Example use cases: Install and configure RedGate .NOTES .PARAMETER EncodedLicenseKey Encrypted key value .PARAMETER ServiceUser Service Account user name .PARAMETER ServicePassword Service account password .EXAMPLE DPSQLInstallRedGate -EncodedLicenseKey 'Somekey' -ServiceUser 'Username' -ServicePassword 'passwordsAreCool' #This example will install RedGate Gui and register the redgate components to the default instance. #> [CmdletBinding()] param( [Parameter(Mandatory = $True)] [string]$EncodedLicenseKey = '' ,[Parameter(Mandatory = $True)] [string]$ServiceUser = '' ,[Parameter(Mandatory = $True)] [string]$ServicePassword = '' ) begin { DPLog -Message "RedGate SQLBackup Install" -WriteToHost Y -Type START #Check if its installed already if (Get-Item -Path "${env:ProgramFiles(x86)}\Red Gate\SQL Backup 7\RedGate.SQLBackup.UI.exe" -ErrorAction Ignore) { DPLog -Message "RedGate GUI installed; Start to configure" -WriteToHost Y -Type INFO [switch]$GuiInstalled = $true } } process { $Login = "${env:COMPUTERNAME}\${ServiceUser}"; $SQLBackupInstaller = "${env:TMP}\SQL_Backup_7.7.0.18.exe" #download media DPLog -Message "Downloading RedGate SQLBackup 7.7.0.18 Media" -WriteToHost Y -Type INFO Invoke-WebRequest -Uri 'https://s3.amazonaws.com/dpdownload/SQL/media/ProductActivationCmd.exe' -Method Get -OutFile "${env:TEMP}\ProductActivationCmd.exe" if (!$GuiInstalled){ Invoke-WebRequest -Uri 'https://s3.amazonaws.com/dpdownload/SQL/media/SQL_Backup_7.7.0.18.exe' -Method Get -OutFile $SQLBackupInstaller #Run installer DPLog -Message "Downloading RedGate SQLBackup 7.7.0.18 Media" -WriteToHost Y -Type INFO ii $SQLBackupInstaller [int]$Retryinterval = 1; [int]$RetryCount = 5; [int]$cnter = 1; do { Start-Sleep -Seconds $Retryinterval; $cnter++; if ($cnter -eq $RetryCount) { DPLog -Message 'RedGate SQLBackup took longer than 5 seconds to install. Please check RedGate install' -typ INFO -WriteToHost Y break; } } until (Get-Item -Path "${env:ProgramFiles(x86)}\Red Gate\SQL Backup 7\RedGate.SQLBackup.UI.exe" -ErrorAction Ignore) } #License RedGate DPLog -Message "License RedGate SQLBackup" -WriteToHost Y -Type INFO $Key = DPEncodeString -Value $EncodedLicenseKey -Decrypt Invoke-Expression ". ${env:TEMP}\ProductActivationCmd.exe $Key" #Do not join customer improvement program $RegPath = "HKCU:\Software\Red Gate\SQL Backup 7" New-ItemProperty -Path $RegPath -Name "SmartAssemblyReportUsage" -Value "False" -PropertyType string -ErrorAction SilentlyContinue Start-Sleep -Seconds 5 #register user DPLog -Message "Register RedGate components" -WriteToHost Y -Type INFO $script = '. "C:\Program Files (x86)\Red Gate\SQL Backup 7\SQBServerSetup.exe" /VERYSILENT /SUPPRESSMSGBOXES /SVCUSER ${ServiceUser} /SVCPW "${ServicePassword}"' Invoke-Expression $script; } end { DPLog -Message "RedGate SQLBackup Install" -WriteToHost Y -Type FINISH } } Function DPSQLInstallRedGate8 { <# .SYNOPSIS Install and configure RedGate SQLBackup 8 .DESCRIPTION Install and configure RedGate SQLBackup 8 Example use cases: Install and configure RedGate .NOTES .PARAMETER EncodedLicenseKey Encrypted key value .PARAMETER ServiceUser Service Account user name .PARAMETER ServicePassword Service account password .EXAMPLE DPSQLInstallRedGate -EncodedLicenseKey 'Somekey' -ServiceUser 'Username' -ServicePassword 'passwordsAreCool' #This example will install RedGate Gui and register the redgate components to the default instance. #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$EncodedLicenseKey = 'MDEwLTAwMC0wNTY5NDYtQTk4MQ==' ,[Parameter(Mandatory = $false)] [string]$ServiceUser = '' ,[Parameter(Mandatory = $false)] [string]$ServicePassword = '' ) begin { DPLog -Message " " -WriteToHost Y -Type START #Check if its installed already if (Get-Item -Path "c:\ProgramFiles(x86)\Red Gate\SQL Backup 8\RedGate.SQLBackup.UI.exe" -ErrorAction Ignore) { DPLog -Message "RedGate 8 GUI installed; Start to configure" -WriteToHost Y -Type INFO [switch]$GuiInstalled = $true } } process { #$Login = "${env:COMPUTERNAME}\${ServiceUser}"; $SQLBackupInstaller = "$($env:TEMP)\SQL_Backup_8.4.1.527.exe" #download media DPLog -Message "Downloading RedGate SQL_Backup_8.4.1.527 Media" -WriteToHost Y -Type INFO DPDownloadFile -Source 'http://repo.datapipe.net/windows/windows-install-files/SQL/SQL_Backup_8.4.1.527.exe' -Destination "$($env:TEMP)\SQL_Backup_8.4.1.527.exe" DPDownloadFile -Source 'http://repo.datapipe.net/windows/windows-install-files/SQL/ProductActivationCmd.exe' -Destination "$($env:TEMP)\ProductActivationCmd.exe" if (!$GuiInstalled){ Start-Process $SQLBackupInstaller -PassThru -NoNewWindow -Wait } #License RedGate DPLog -Message "License RedGate SQLBackup" -WriteToHost Y -Type INFO $Key = DPEncodeString -Value $EncodedLicenseKey -Decrypt Invoke-Expression ". $($env:TEMP)\ProductActivationCmd.exe $Key" #Do not join customer improvement program $RegPath = "HKCU:\Software\Red Gate\SQL Backup 8" New-ItemProperty -Path $RegPath -Name "SmartAssemblyReportUsage" -Value "False" -PropertyType string -ErrorAction SilentlyContinue Start-Sleep -Seconds 5 <# #register user DPLog -Message "Register RedGate components" -WriteToHost Y -Type INFO $script = '. "C:\Program Files (x86)\Red Gate\SQL Backup 8\SQBServerSetup.exe" /VERYSILENT /SUPPRESSMSGBOXES /SVCUSER ${ServiceUser} /SVCPW "${ServicePassword}"' Invoke-Expression $script; #> } end { DPLog -Message " " -WriteToHost Y -Type FINISH } } ########## BEGIN GENERATE RANDOM PASSWORD SCRIPT ########## function DPGeneratePassword{ [CMDLETBINDING()] Param( [Parameter(Position=1,Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateRange(10,60)] [int]$Length=16, [Parameter(Position=2,Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$DisableOutput="N", [Parameter(Position=3,Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateRange(2,1000)] [int]$Quantity ) <# .SYNOPSIS ======================================================================================== DATAPIPE AUTOMATION GENERATE RANDOM PASSWORD AUTHOR: ANTHONY MARINO, Justin Procacci SUPPORTED VERSIONS: 2008, 2008 R2, 2008 R2 SP1, 2012, 2012 R2 and 2016. CMDLET VERSION: 1.0.4 DATE: 1/28/2016 ======================================================================================== Creates a random password. .DESCRIPTION OPTIONAL - [-Length] - Specify a password length (number only, between 1 and 60 characters). If this optional parameter is not specified, a random length 15-20 characters long will be used. OPTIONAL - [-DisableOutput] - Disables output of the password to the PS console. OPTIONAL - [-Quantity] - Allows you to generate more than 1 password (between 2 and 1000 passwords). Passwords will be displayed in a Powershell Gridview. EXAMPLE 1: DPGeneratePassword EXAMPLE 2: DPGeneratePassword -Length 30 EXAMPLE 3: DPGeneratePassword -Length 30 -DisableOutput Y EXAMPLE 4: DPGeneratePassword -Length 30 -Quantity 50 #> BEGIN{ IF ($Quantity -gt "1") { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Detected the option to generate $Quantity passwords." 1..$Quantity | % {DPGeneratePassword -Length $Length} | out-Gridview } ##DPClearFailureFlag $Lower = "a","b","c","d","e","f","g","h","i","j","k","m","n","o","p","q","r","s","t","u","v","w","x","y","z" $Upper = "A","B","C","D","E","F","G","H","J","K","M","N","P","Q","R","S","T","U","V","W","X","Y","Z" $Numbers = "1","2","3","4","5","6","7","8","9" $Special = "!","^",".","-","\","/","?","~" $Characters = $Lower+$Upper+$Numbers+$Special } PROCESS{ #This is to confirm that atleast 1 of type of character is added. $ResultSet = [string]::Join("",((Get-Random $Characters -Count ($Length - 5)) + (Get-Random -InputObject $Lower -Count 1) + (Get-Random -InputObject $Upper -Count 1) + (Get-Random -InputObject $Numbers -Count 1) + (Get-Random -InputObject $Special -Count 1))) $Random = New-Object Random $Password = [string]::join("",($ResultSet.ToCharArray()| sort {$Random.Next()})) $Letters = ($Lower + $Upper) $Letter = (Get-Random $Letters -Count 1) IF ($Quantity -gt "1") { $Password = [string]::Join("",(($Letter) + ($Password))) } ELSE { $Global:Password = [string]::Join("",(($Letter) + ($Password))) } } END{ IF (($DisableOutput -eq "N") -and (!($Quantity -gt "1"))) { #return the Global:password return $Global:Password } } } ########## END GENERATE RANDOM PASSWORD SCRIPT ########## Function DPSQLModifyXEvent { [CMDLETBINDING()] param( [parameter(mandatory=$false,position=0)] $TargetInstance ,[parameter(mandatory=$false,position=1)] [string]$Event = 'system_health' ,[parameter(mandatory=$false,position=1)] [int]$MaxFileSize = 25 ,[parameter(mandatory=$false,position=1)] [int]$MaxRollOverFiles = 5 ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { } PROCESS { $query = "ALTER EVENT SESSION [$($Event)] ON SERVER STATE = STOP ALTER EVENT SESSION [$($Event)] ON SERVER DROP TARGET package0.event_file ALTER EVENT SESSION [$($Event)] ON SERVER ADD TARGET package0.event_file (SET filename=N'$($Event).xel' ,max_file_size=($($MaxFileSize)), max_rollover_files=($($MaxRollOverFiles))) ALTER EVENT SESSION [$($Event)] ON SERVER STATE = START;" try { Invoke-Sqlcmd -ServerInstance $selection.fullname -Database master -Query $query -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Modified XEvent $($Event) added target filename = $($Event).xel,max_file_size = $MaxFileSize, max_rollover_files = $MaxRollOverFiles" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } END { } } Function DPSQLCreate_dp_mon { [CMDLETBINDING()] param( [parameter(mandatory=$false,position=0)] $TargetInstance ,[parameter(mandatory=$false,position=1)] $password = (DPGeneratePassword) ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$TargetInstance ) { DPSelectTargetInstance | Out-Null } else { #refresh or make a new smo $global:ServerInstanceSMO.Refresh() } } PROCESS { $query = " USE [master]; GO IF NOT exists(SELECT * FROM sys.server_principals WHERE name = 'dp_mon') BEGIN CREATE LOGIN [dp_mon] WITH PASSWORD=N'$($password)', DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=ON; ALTER LOGIN [dp_mon] DISABLE; GRANT IMPERSONATE ON LOGIN::[dp_mon] to [NT AUTHORITY\SYSTEM]; GRANT ALTER TRACE,VIEW ANY DEFINITION, VIEW SERVER STATE TO [dp_mon]; USE [msdb]; CREATE USER [dp_mon] FOR LOGIN [dp_mon]; GRANT CREATE TABLE, SELECT, INSERT to [dp_mon]; GRANT ALTER ON SCHEMA::dbo to [dp_mon]; END" if ($global:ServerInstanceSMO.Databases.name -contains 'distribution') { $query += "`rUSE [distribution]; CREATE USER [dp_mon] FOR LOGIN [dp_mon]; ALTER ROLE [replmonitor] ADD MEMBER [dp_mon];" } try { Invoke-Sqlcmd -ServerInstance $selection.fullname -Database master -Query $query -ErrorAction Stop -ConnectionTimeout 10; DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Add dp_mon without an error reported" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } END { } } Function DPSQLSetSystemProperty { <# .SYNOPSIS Sets System Properties for SQL .DESCRIPTION .PARAMETER TargetInstance .PARAMETER Configuration .PARAMETER Value .EXAMPLE DPSQLSetSystemProperty #> [CmdletBinding(DefaultParameterSetname = 'Static')] param( [parameter(mandatory=$false,Parametersetname='Custom')] [parameter(mandatory=$false,Parametersetname='Static')] $TargetInstance , [parameter(mandatory=$false,Parametersetname='Static')] [ValidateSet('All','Failure','None','Success')] $AuditLevel , [parameter(mandatory=$false,Parametersetname='Static')] $MaximumHistoryRows , [parameter(mandatory=$false,Parametersetname='Static')] $MaximumJobHistoryRows , [parameter(mandatory=$false,Parametersetname='Static')] $BackupDirectory , [parameter(mandatory=$false,Parametersetname='Static')] $DefaultFile , [parameter(mandatory=$false,Parametersetname='Static')] $DefaultLog , [parameter(mandatory=$false,Parametersetname='Static')] [ValidateSet('Integrated','Mixed','Normal')] $LoginMode , [parameter(mandatory=$false,Parametersetname='Static')] [ValidateRange(1,99)] $NumberOfLogFiles ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" <#, [parameter(mandatory=$True,Parametersetname='Custom')] [Validatescript({ if ($Global:ServerInstanceSMO.configuration.name -contains $_) {$true} else { throw "Select from one of the options in variable `$Global:ServerInstanceSMO.configuration.name"}})] [string]$CustomProperty_1 , [parameter(mandatory=$True)] [int]$Value_1#> ) BEGIN { if (!$TargetInstance ) { DPSelectTargetInstance | Out-Null } else { #refresh or make a new smo $global:ServerInstanceSMO = New-Object ('Microsoft.SQLServer.Management.SMO.Server') $selection.fullname } } PROCESS { if ($PSCmdlet.ParameterSetName -eq 'Static') { if ($AuditLevel) { #AuditLevel - Get existing $currentValue = $global:ServerInstanceSMO.auditlevel if ($currentValue -ne $AuditLevel) { try { $global:ServerInstanceSMO.AuditLevel = [Microsoft.SqlServer.Management.Smo.AuditLevel]::$AuditLevel $global:ServerInstanceSMO.Alter() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Auditlevel: was $currentvalue and is now $auditlevel" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "AuditLevel: was already $AuditLevel" } } if ($BackupDirectory) { #BackupDirectory - Get existing $currentValue = $global:ServerInstanceSMO.BackupDirectory #treat input with \ at the end the same as without if ([regex]::Match($currentValue ,"^.*[^\\]").captures.value -ne [regex]::Match($BackupDirectory ,"^.*[^\\]").captures.value) { try { $global:ServerInstanceSMO.BackupDirectory = $BackupDirectory $global:ServerInstanceSMO.Alter() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "BackupDirectory: was $currentvalue and is now $BackupDirectory" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "BackupDirectory: was already $BackupDirectory" } } if ($DefaultFile) { #DefaultFile - Get existing $currentValue = $global:ServerInstanceSMO.DefaultFile #treat input with \ at the end the same as without if ([regex]::Match($currentValue ,"^.*[^\\]").captures.value -ne [regex]::Match($DefaultFile ,"^.*[^\\]").captures.value) { try { $global:ServerInstanceSMO.DefaultFile = $DefaultFile $global:ServerInstanceSMO.Alter() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "DefaultFile: was $currentvalue and is now $DefaultFile" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { $action = 'No Change' DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "DefaultFile: was already $DefaultFile" } } if ($DefaultLog) { #DefaultLog - Get existing $currentValue = $global:ServerInstanceSMO.DefaultLog #treat input with \ at the end the same as without if ([regex]::Match($currentValue ,"^.*[^\\]").captures.value -ne [regex]::Match($DefaultLog ,"^.*[^\\]").captures.value) { try { $global:ServerInstanceSMO.DefaultLog = $DefaultLog $global:ServerInstanceSMO.Alter() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "DefaultLog: was $currentvalue and is now $DefaultLog" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "DefaultLog: was already $currentValue" } } if ($LoginMode) { #LoginMode - Get existing $currentValue = $global:ServerInstanceSMO.LoginMode #treat input with \ at the end the same as without if ([regex]::Match($currentValue ,"^.*[^\\]").captures.value -ne [regex]::Match($LoginMode ,"^.*[^\\]").captures.value) { try { $global:ServerInstanceSMO.LoginMode = $LoginMode $global:ServerInstanceSMO.Alter() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "LoginMode: was $currentValue; setting to $LoginMode" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "LoginMode: was already $currentvalue" } } if ($NumberOfLogFiles) { #NumberOfLogFiles - Get existing $currentValue = $global:ServerInstanceSMO.NumberOfLogFiles if ($currentValue -ne $NumberOfLogFiles) { try { $global:ServerInstanceSMO.NumberOfLogFiles = $NumberOfLogFiles $global:ServerInstanceSMO.Alter() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "NumberOfLogFiles: was $currentValue; setting to $NumberOfLogFiles" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException $Result = "Error: $($err.Message)" }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { $action = 'No Change' DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "NumberOfLogFiles: was already $NumberOfLogFiles" } } if ($MaximumHistoryRows) { $currentValue = $global:ServerInstanceSMO.jobserver.maximumhistoryrows if ($currentValue -ne $MaximumHistoryRows) { try { $global:ServerInstanceSMO.jobserver.maximumhistoryrows = $MaximumHistoryRows $global:ServerInstanceSMO.jobserver.Alter() $global:ServerInstanceSMO.jobserver.Refresh() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "SQL Agent: MaximumHistoryRows was $currentvalue and is now $MaximumHistoryRows" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" }; } } else { DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "SQL Agent: MaximumHistoryRows was already $currentvalue" } } if ($MaximumJobHistoryRows) { #MaximumHistoryRows - Get existing $currentValue = $global:ServerInstanceSMO.jobserver.MaximumJobHistoryRows if ($currentValue -ne $MaximumJobHistoryRows) { try { $global:ServerInstanceSMO.jobserver.MaximumJobHistoryRows = $MaximumJobHistoryRows $global:ServerInstanceSMO.jobserver.Alter() $global:ServerInstanceSMO.jobserver.Refresh() DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "SQL Agent: MaximumJobHistoryRows was $currentvalue and is now $MaximumJobHistoryRows" } catch { $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException }; DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.Message)" } } else { DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "SQL Agent: MaximumJobHistoryRows was already $currentvalue" } } } if ($PSCmdlet.ParameterSetName -eq 'Custom') { #show advanced options - Not required for SMO. #$Global:ServerInstanceSMO.Configuration.ShowAdvancedOptions.ConfigValue = 1 #$Global:ServerInstanceSMO.alter(); #get full detail of that option $Global:ServerInstanceSMO.Configuration.$CustomProperty_1 <# $SQLConfigurationFull = $SystemConfigurations | where name -eq $SQLConfiguration #Confirm if the $Value variable is between the min and max). If it is then set the new value if ($Value -ge $SQLConfigurationFull.minimum -and $Value -le $SQLConfigurationFull.maximum) { if ($value -eq $SQLConfigurationFull.value -or $value -eq $SQLConfigurationFull.value_in_use) { $action = 'No Action' } else { $action = 'Modify' (Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -ErrorAction Stop -Query "execute sp_configure '$($SQLConfigurationFull.name)',$value; GO RECONFIGURE; GO") } } else { $action = "The value provided is not within the valid range. Value: $Value | Min Value: $($SQLConfigurationFull.minimum) | Max Value: $($SQLConfigurationFull.maximum)" } #> } } END { $global:ServerInstanceSMO.Refresh(); } } Function DPSQLSetSizeAndGrowth { [CMDLETBINDING()] param( [parameter(mandatory=$false)] $TargetInstance , [parameter(mandatory=$true)] [string]$Database , [parameter(mandatory=$false)] [int]$GrowthMB = 64 , [parameter(mandatory=$false)] [int]$InitialSizeMB = 64 ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$TargetInstance ) { DPSelectTargetInstance | Out-Null } else { #refresh or make a new smo $global:ServerInstanceSMO.Refresh() # = New-Object ('Microsoft.SQLServer.Management.SMO.Server') $selection.fullname } } PROCESS { $Db = $global:ServerInstanceSMO.Databases[$Database] $FileNameList = '' #Set Log File growth if ($db.Status -eq 'Normal') { $l = $db.LogFiles[0] try { $l.GrowthType = "KB" $l.Growth = ($GrowthMB * 1024) if ($l.size -ne ($InitialSizeMB * 1024)){ $l.size = ($InitialSizeMB * 1024) } $l.Alter(); } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "$($db.logfiles[0]) to $InitialSizeMB MB with growth of $($GrowthMB)MB" $df = $db.FileGroups #Set data file growth foreach($fg in $df){ foreach ($f in $fg.Files) { $filenamelist += "$($f)," try { $f.GrowthType = "KB"; $f.Growth = ($GrowthMB * 1024) if ($f.size -ne ($InitialSizeMB * 1024)){ $f.size = ($InitialSizeMB * 1024) } $f.Alter(); } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } } DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "$($FileNameList) to $InitialSizeMB with growth of $($GrowthMB)MB" } } END { } } Function DPAddConfigurationObject { <# .SYNOPSIS Adds Configuration Object to Global:SQLServerConfiguration and returns back to screen .DESCRIPTION Adds Configuration Object to Global:SQLServerConfiguration and returns back to screen .PARAMETER Instance Works with DPSelectTargetInstance command. If not supplied you will be prompted .PARAMETER Configuration The function that is making the modification .PARAMETER CurrentValue The current setting .PARAMETER NewValue The value you want that setting to now be. .PARAMETER Action Action taken .PARAMETER Result The result of the action. .EXAMPLE DPAddConfigurationObject -Instance MSSQL1 -Configuration $configuration -CurrentValue $CurrentValue -NewValue $NewValue -action $action #> [CmdletBinding()] param( [parameter(mandatory=$True)] $Instance ,[parameter(mandatory=$False)] $Function = $MyInvocation.MyCommand.Name ,[parameter(mandatory=$False)] $Configuration ,[parameter(mandatory=$False)] $CurrentValue = '' ,[parameter(mandatory=$False)] $NewValue = '' ,[parameter(mandatory=$False)] $Action = '' ,[parameter(mandatory=$False)] $Result = '' ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { $ConfigObject = New-Object System.Object; } PROCESS { $ConfigObject | Add-Member -MemberType noteproperty -Name 'Instance' -Value $Instance $ConfigObject | Add-Member -MemberType noteproperty -Name 'Function' -Value $Function $ConfigObject | Add-Member -MemberType noteproperty -Name 'Configuration' -Value $Configuration $ConfigObject | Add-Member -MemberType noteproperty -Name 'CurrentValue' -Value $CurrentValue $ConfigObject | Add-Member -MemberType noteproperty -Name 'NewValue' -Value $NewValue $ConfigObject | Add-Member -MemberType noteproperty -Name 'Action' -Value $Action $ConfigObject | Add-Member -MemberType noteproperty -Name 'Result' -Value $Result $ConfigObject | Add-Member -MemberType noteproperty -Name 'Date' -Value (get-date -Format 'MM/dd/yyyy hh:mm:ss') } END { #Update global configuration object $Global:SQLServerConfiguration += $ConfigObject #return the configuration #return $ConfigObject } } Function DPSQLAddAgentAlerts { <# .SYNOPSIS Add the SQL Agent Alerts .DESCRIPTION Returns the SQLRoot,Data,Log,Backup default folders from registry .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLAddAgentAlerts #> [CmdletBinding()] param( [parameter(mandatory=$false,ParameterSetName='Severity')] [parameter(mandatory=$false,ParameterSetName='MessageID')] $TargetInstance , [parameter(mandatory=$True,ParameterSetName='Severity')] [ValidateRange(1,25)] [int[]]$Severity , [parameter(mandatory=$True,ParameterSetName='MessageID')] [int[]]$MessageID , [parameter(mandatory=$false,ParameterSetName='Severity')] [parameter(mandatory=$false,ParameterSetName='MessageID')] [string]$MessageText , [parameter(mandatory=$false,ParameterSetName='Severity')] [parameter(mandatory=$false,ParameterSetName='MessageID')] [string]$AlertNameRoot = 'DP_' , [parameter(mandatory=$false,ParameterSetName='Severity')] [parameter(mandatory=$false,ParameterSetName='MessageID')] $BuildFolder = $PSScriptRoot ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { DPLOG -WriteToHost $WriteToHost -Type START -Message " " if (!$TargetInstance ) { DPSelectTargetInstance -WriteToHost $WriteToHost | Out-Null } $svr = New-Object ('Microsoft.SQLServer.Management.SMO.Server') $selection.fullname #Get existing Alerts $ExistingAlerts = $svr.jobserver.Alerts $Option = $PSCmdlet.ParameterSetName } PROCESS{ if ($PSCmdlet.ParameterSetName -eq 'severity'){ $Severity | ForEach-Object { if ($Option -eq 'Severity' -and $_ -in $ExistingAlerts.severity) { $ExistsAlready += " $($_)," } else { #Set AlertName with the parametersetname $AlertName = "$($AlertNameRoot)$($PSCmdlet.ParameterSetName.ToString())_$($_)" $Alert = New-Object ('Microsoft.SqlServer.Management.Smo.Agent.Alert') ($svr.jobserver,$Alertname) #Set Severity $alert.severity = $_ try { $Alert.Create() $successAdd += " $($_)," } catch{ # Handle the error $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException $Result = "Error: $($err.Message)" DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.message)" }; } } } if ($ExistsAlready.Length -gt 1) { $ExistsAlready = $ExistsAlready -Replace ".$" DPLOG -WriteToHost Y -Type SUCCESS -Message "Severity(s) exist already: $ExistsAlready " } if ($Successadd.Length -gt 1) { $Successadd = $Successadd -Replace ".$" DPLOG -WriteToHost Y -Type SUCCESS -Message "Added Severity(s): $successAdd" } } else { $MessageID | ForEach-Object { if ($_ -in $ExistingAlerts.MessageID){ $ExistsAlready += " $($_)," } else { #Set AlertName with the parametersetname $Alertname = "$($AlertNameRoot)$($PSCmdlet.ParameterSetName.ToString())_$($_)" $Alert = New-Object ('Microsoft.SqlServer.Management.Smo.Agent.Alert') ($svr.jobserver,$Alertname) #Set Severity or MessageID depending on which parameter set was chosen $alert.messageid = $_ try { $Alert.Create() $successAdd += " $($_)," } catch{ # Handle the error $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException $Result = "Error: $($err.Message)" DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.message)" }; } } } if ($ExistsAlready.Length -gt 1) { $ExistsAlready = $ExistsAlready -Replace ".$" DPLOG -WriteToHost Y -Type SUCCESS -Message "MessageID(s) exist already: $ExistsAlready" } if ($Successadd.Length -gt 1) { $Successadd = $Successadd -Replace ".$" DPLOG -WriteToHost Y -Type SUCCESS -Message "Added MessageID(s): $Successadd" } } } END { DPLOG -WriteToHost $WriteToHost -Type FINISH -Message " " } } Function DPSQLGetDefaultFolders { <# .SYNOPSIS Gets the default folders of SQL server .DESCRIPTION Returns the SQLRoot,Data,Log,Backup default folders from registry .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLGetDefaultFolders .EXAMPLE DPSQLGetDefaultFolders -TargetInstance $selection #> [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$TargetInstance ) { DPSelectTargetInstance | Out-Null } } PROCESS{ $BaseFolders = @" EXEC xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\Setup','SQLDataRoot' EXEC xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer','DefaultData' EXEC xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer','Defaultlog' EXEC master.dbo.xp_instance_regread 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer', 'backupDirectory' "@ try { $Global:Folders = Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -Query $BaseFolders -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Getting Default folders" $action = 'Created `$Global:Folders' } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" $action = "Error: $($_.exception.message)" } } END{ #DPAddConfigurationObject -Instance $selection.Fullname -Function $MyInvocation.MyCommand.Name -Configuration '$Global:Folders' -CurrentValue '' -NewValue '`$Global:Folders' -Action $action } } Function DPSQLCreateAgentJob { <# .SYNOPSIS Create a SQL Job and its infrastructure .DESCRIPTION Create a SQL Job and its infrastructure .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLCreateAgentJob -DP_IndexOptimize -Disabled; Create the DP_IndexOptimize job and have the job Disabled .EXAMPLE DPSQLCreateAgentJob -DP_DatabaseIntegrityCheck -Disabled; Create the DP_DatabaseIntegrityCheck job and have the job Disabled .EXAMPLE DPSQLCreateAgentJob -DP_HistoryCleanup | DPSQLCreateJobSchedule -Weekly -DayOfWeek Friday -StartTime 01:15:00; Create the DP_HistoryCleanup job and attach a schedule weekly schedule on Friday at 1:15AM. .EXAMPLE DPSQLCreateAgentJob -DP_RedGateFullBackup -FullRetention 3 -Compression 4 | DPSQLCreateJobSchedule -Daily -StartTime 22:00:00; Create the DP_RedGateFullBackup job and attach a Daily schedule at 22:00:00 .EXAMPLE DPSQLCreateAgentJob -DP_RedGateLogBackup -Compression 4 -LogRetention 4 -FileCount 4 | DPSQLCreateJobSchedule -Daily -StartTime 00:30:00 -FrequencyMinutes 60 Create the DP_RedGateLogBackup job and attach a schedule #> [CmdletBinding(DefaultParameterSetName="All")] param( [parameter(mandatory=$false)] $TargetInstance , [parameter(mandatory=$false,ParameterSetName='DP_IndexOptimize')] [parameter(mandatory=$false,ParameterSetName='DP_DatabaseIntegrityCheck')] [ValidateSet('msdb','DBAdmin')] $InfrastructureDatabase = 'msdb' , [parameter(mandatory=$false,ParameterSetName='DP_IndexOptimize')] [switch]$DP_IndexOptimize , [parameter(mandatory=$false,ParameterSetName='DP_DatabaseIntegrityCheck')] [switch]$DP_DatabaseIntegrityCheck , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [switch]$DP_RedGateFullBackup , [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [switch]$DP_RedGateLogBackup , [parameter(mandatory=$false,ParameterSetName='DP_HistoryCleanup')] [switch]$DP_HistoryCleanup , [parameter(mandatory=$false,ParameterSetName='DP_IndexOptimize')] [parameter(mandatory=$false,ParameterSetName='DP_DatabaseIntegrityCheck')] [ValidateSet('Y','N')] $LogToTable = 'N' , [parameter(mandatory=$false,ParameterSetName='DP_IndexOptimize')] [parameter(mandatory=$false,ParameterSetName='DP_HistoryCleanup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [parameter(mandatory=$false,ParameterSetName='DP_DatabaseIntegrityCheck')] [switch]$Disabled , [parameter(mandatory=$false,ParameterSetName='DP_IndexOptimize')] [parameter(mandatory=$false,ParameterSetName='DP_HistoryCleanup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [parameter(mandatory=$false,ParameterSetName='DP_DatabaseIntegrityCheck')] [string]$JobOwner = 'sa' , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [string]$DefaultBackupDirectory = '' , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [string]$BackupFileName = '\\' , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [ValidateSet(1,2,3,4)] [int]$Compression = 4 , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [ValidateRange(1,365)] [int]$FullRetention = 3 , [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [ValidateRange(1,365)] [int]$LogRetention = 4 , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [ValidateSet(1,2,4,6,8,10,12)] [int]$FileCount=1 , [parameter(mandatory=$false,ParameterSetName='DP_IndexOptimize')] [parameter(mandatory=$false,ParameterSetName='DP_HistoryCleanup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [parameter(mandatory=$false,ParameterSetName='DP_RedGateLogBackup')] [parameter(mandatory=$false,ParameterSetName='DP_DatabaseIntegrityCheck')] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$TargetInstance ) { DPSelectTargetInstance | Out-Null } if ($InfrastructureDatabase -eq 'DBAdmin') { $DBAdminCreate = @" use [master]; go if not exists (select name from sys.databases where name = 'DBAdmin') BEGIN CREATE DATABASE [DBAdmin]; END go "@ Invoke-Sqlcmd -ServerInstance $selection.fullname -Query $DBAdminCreate -QueryTimeout $Global:QueryTimeout -ConnectionTimeout 120 -ErrorAction Stop } $DPSQLObjects = Invoke-Sqlcmd -ServerInstance $selection.fullname -ErrorAction Stop -Query "Select name from $InfrastructureDatabase.sys.objects where name like 'DP%' or name = 'Commandlog' union all select name from msdb.dbo.sysjobs where name like 'DP_%' order by 1 asc" #Base Setup $JobCreateBase = @" Declare @OutputFileDirectory nvarchar(max) , @TokenServer nvarchar(max) , @TokenDate nvarchar(max) , @TokenTime nvarchar(max) , @JobCategory nvarchar(max) , @JobOwner nvarchar(max) , @JobName nvarchar(max) , @JobDescription nvarchar(max) , @Job01Command01 nvarchar(max) , @Job01Command02 nvarchar(max) , @Job01Command03 nvarchar(max) , @Job01Command04 nvarchar(max) , @Job01Command05 nvarchar(max) , @OutputFile01 nvarchar(max) , @JobDescription02 nvarchar(max); --Default setups $(if (([regex]::Match(($selection.Identifier) ,'[0-9]\w+').Groups[0].Value) -gt 11) {'SELECT @OutputFileDirectory = [path] FROM sys.dm_os_server_diagnostics_log_configurations' } else {"SELECT @OutputFileDirectory = LEFT(CAST(SERVERPROPERTY('ErrorLogFileName') AS nvarchar(max)),LEN(CAST(SERVERPROPERTY('ErrorLogFileName') AS nvarchar(max))) - CHARINDEX('\',REVERSE(CAST(SERVERPROPERTY('ErrorLogFileName') AS nvarchar(max))))) + '\'"}) /************************************************* Edit the variables below to set a custom output file location By default this will be set to the default sql log location *************************************************/ -- SET @OutputFileDirectory = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Log' SET @TokenServer = '$' + '(ESCAPE_SQUOTE(SRVR))' SET @TokenDate = '$' + '(ESCAPE_SQUOTE(STRTDT))' SET @TokenTime = '$' + '(ESCAPE_SQUOTE(STRTTM))' -- Set category and owner for jobs SET @JobCategory = 'Database Maintenance' SET @JobOwner = 'sa' SET @OutputFile01 = @OutputFileDirectory + '$($PSCmdlet.ParameterSetName)_' + @TokenDate + '_' + @TokenTime + '.txt' IF LEN(@OutputFile01) > 200 SET @OutputFile01 = NULL -- Drop job if it exists and create it IF EXISTS( select name from msdb..sysjobs where name = '$($PSCmdlet.ParameterSetName)') BEGIN EXECUTE msdb.dbo.sp_delete_job @job_name = '$($PSCmdlet.ParameterSetName)' END SET @JobName = '$($PSCmdlet.ParameterSetName)' "@ #CommandExecute $CommandExecute = @" /***********Setup ***********/ SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON; USE [$InfrastructureDatabase]; GO IF OBJECT_ID('dbo.DPCommandExecute', 'P') IS NOT NULL DROP PROCEDURE dbo.DPCommandExecute; GO CREATE PROCEDURE [dbo].[DPCommandExecute] @Command nvarchar(max), @CommandType nvarchar(max), @Mode int, @Comment nvarchar(max) = NULL, @DatabaseName nvarchar(max) = NULL, @SchemaName nvarchar(max) = NULL, @ObjectName nvarchar(max) = NULL, @ObjectType nvarchar(max) = NULL, @IndexName nvarchar(max) = NULL, @IndexType int = NULL, @StatisticsName nvarchar(max) = NULL, @PartitionNumber int = NULL, @ExtendedInfo xml = NULL, @LogToTable nvarchar(max), @Execute nvarchar(max) AS BEGIN ---------------------------------------------------------------------------------------------------- --// Source: https://ola.hallengren.com //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON DECLARE @StartMessage nvarchar(max) DECLARE @EndMessage nvarchar(max) DECLARE @ErrorMessage nvarchar(max) DECLARE @ErrorMessageOriginal nvarchar(max) DECLARE @StartTime datetime DECLARE @EndTime datetime DECLARE @StartTimeSec datetime DECLARE @EndTimeSec datetime DECLARE @ID int DECLARE @Error int DECLARE @ReturnCode int SET @Error = 0 SET @ReturnCode = 0 ---------------------------------------------------------------------------------------------------- --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- IF @LogToTable = 'Y' AND NOT EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'U' AND schemas.[name] = 'dbo' AND objects.[name] = 'CommandLog') BEGIN SET @ErrorMessage = 'The table CommandLog is missing. Download https://ola.hallengren.com/scripts/CommandLog.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO ReturnCode END ---------------------------------------------------------------------------------------------------- --// Check input parameters //-- ---------------------------------------------------------------------------------------------------- IF @Command IS NULL OR @Command = '' BEGIN SET @ErrorMessage = 'The value for the parameter @Command is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @CommandType IS NULL OR @CommandType = '' OR LEN(@CommandType) > 60 BEGIN SET @ErrorMessage = 'The value for the parameter @CommandType is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Mode NOT IN(1,2) OR @Mode IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @Mode is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LogToTable NOT IN('Y','N') OR @LogToTable IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @LogToTable is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Execute NOT IN('Y','N') OR @Execute IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @Execute is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO ReturnCode END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- ---------------------------------------------------------------------------------------------------- SET @StartTime = GETDATE() SET @StartTimeSec = CONVERT(datetime,CONVERT(nvarchar,@StartTime,120),120) SET @StartMessage = 'Date and time: ' + CONVERT(nvarchar,@StartTimeSec,120) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Command: ' + @Command IF @Comment IS NOT NULL SET @StartMessage = @StartMessage + CHAR(13) + CHAR(10) + 'Comment: ' + @Comment SET @StartMessage = REPLACE(@StartMessage,'%','%%') RAISERROR(@StartMessage,10,1) WITH NOWAIT IF @LogToTable = 'Y' BEGIN INSERT INTO dbo.CommandLog (DatabaseName, SchemaName, ObjectName, ObjectType, IndexName, IndexType, StatisticsName, PartitionNumber, ExtendedInfo, CommandType, Command, StartTime) VALUES (@DatabaseName, @SchemaName, @ObjectName, @ObjectType, @IndexName, @IndexType, @StatisticsName, @PartitionNumber, @ExtendedInfo, @CommandType, @Command, @StartTime) END SET @ID = SCOPE_IDENTITY() ---------------------------------------------------------------------------------------------------- --// Execute command //-- ---------------------------------------------------------------------------------------------------- IF @Mode = 1 AND @Execute = 'Y' BEGIN EXECUTE(@Command) SET @Error = @@Error SET @ReturnCode = @Error END IF @Mode = 2 AND @Execute = 'Y' BEGIN BEGIN TRY EXECUTE(@Command) END TRY BEGIN CATCH SET @Error = ERROR_NUMBER() SET @ReturnCode = @Error SET @ErrorMessageOriginal = ERROR_MESSAGE() SET @ErrorMessage = 'Msg ' + CAST(@Error AS nvarchar) + ', ' + ISNULL(@ErrorMessageOriginal,'') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END CATCH END ---------------------------------------------------------------------------------------------------- --// Log completing information //-- ---------------------------------------------------------------------------------------------------- SET @EndTime = GETDATE() SET @EndTimeSec = CONVERT(datetime,CONVERT(varchar,@EndTime,120),120) SET @EndMessage = 'Outcome: ' + CASE WHEN @Execute = 'N' THEN 'Not Executed' WHEN @Error = 0 THEN 'Succeeded' ELSE 'Failed' END + CHAR(13) + CHAR(10) SET @EndMessage = @EndMessage + 'Duration: ' + CASE WHEN DATEDIFF(ss,@StartTimeSec, @EndTimeSec)/(24*3600) > 0 THEN CAST(DATEDIFF(ss,@StartTimeSec, @EndTimeSec)/(24*3600) AS nvarchar) + '.' ELSE '' END + CONVERT(nvarchar,@EndTimeSec - @StartTimeSec,108) + CHAR(13) + CHAR(10) SET @EndMessage = @EndMessage + 'Date and time: ' + CONVERT(nvarchar,@EndTimeSec,120) + CHAR(13) + CHAR(10) + ' ' SET @EndMessage = REPLACE(@EndMessage,'%','%%') RAISERROR(@EndMessage,10,1) WITH NOWAIT IF @LogToTable = 'Y' BEGIN UPDATE dbo.CommandLog SET EndTime = @EndTime, ErrorNumber = CASE WHEN @Execute = 'N' THEN NULL ELSE @Error END, ErrorMessage = @ErrorMessageOriginal WHERE ID = @ID END ReturnCode: IF @ReturnCode <> 0 BEGIN RETURN @ReturnCode END ---------------------------------------------------------------------------------------------------- END GO "@ #CommandLog $CommandLog = @" USE [$InfrastructureDatabase]; GO IF OBJECT_ID('[dbo].[CommandLog]') IS NULL AND OBJECT_ID('[dbo].[PK_CommandLog]') IS NULL BEGIN CREATE TABLE [dbo].[CommandLog]( [ID] int IDENTITY(1,1) NOT NULL CONSTRAINT [PK_CommandLog] PRIMARY KEY CLUSTERED, [DatabaseName] sysname NULL, [SchemaName] sysname NULL, [ObjectName] sysname NULL, [ObjectType] char(2) NULL, [IndexName] sysname NULL, [IndexType] tinyint NULL, [StatisticsName] sysname NULL, [PartitionNumber] int NULL, [ExtendedInfo] xml NULL, [Command] nvarchar(max) NOT NULL, [CommandType] nvarchar(60) NOT NULL, [StartTime] datetime NOT NULL, [EndTime] datetime NULL, [ErrorNumber] int NULL, [ErrorMessage] nvarchar(max) NULL ) END GO "@ #DPIndexOptimize $DPIndexOptimize = @" USE [$InfrastructureDatabase]; GO IF OBJECT_ID('dbo.DPIndexOptimize', 'P') IS NOT NULL DROP PROCEDURE dbo.DPIndexOptimize; GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[DPIndexOptimize] @Databases nvarchar(max), @FragmentationLow nvarchar(max) = NULL, @FragmentationMedium nvarchar(max) = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE', @FragmentationHigh nvarchar(max) = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE', @FragmentationLevel1 int = 5, @FragmentationLevel2 int = 30, @PageCountLevel int = 1000, @SortInTempdb nvarchar(max) = 'N', @MaxDOP int = NULL, @FillFactor int = NULL, @PadIndex nvarchar(max) = NULL, @LOBCompaction nvarchar(max) = 'Y', @UpdateStatistics nvarchar(max) = NULL, @OnlyModifiedStatistics nvarchar(max) = 'N', @StatisticsSample int = NULL, @StatisticsResample nvarchar(max) = 'N', @PartitionLevel nvarchar(max) = 'Y', @MSShippedObjects nvarchar(max) = 'N', @Indexes nvarchar(max) = NULL, @TimeLimit int = NULL, @Delay int = NULL, @WaitAtLowPriorityMaxDuration int = NULL, @WaitAtLowPriorityAbortAfterWait nvarchar(max) = NULL, @LockTimeout int = NULL, @LogToTable nvarchar(max) = 'N', @Execute nvarchar(max) = 'Y' AS BEGIN ---------------------------------------------------------------------------------------------------- --// Source: https://ola.hallengren.com Date: 1/28/2015 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON SET ARITHABORT ON SET NUMERIC_ROUNDABORT OFF DECLARE @StartMessage nvarchar(max) DECLARE @EndMessage nvarchar(max) DECLARE @DatabaseMessage nvarchar(max) DECLARE @ErrorMessage nvarchar(max) DECLARE @Version numeric(18,10) DECLARE @AmazonRDS bit DECLARE @Cluster nvarchar(max) DECLARE @StartTime datetime DECLARE @CurrentDBID int DECLARE @CurrentDatabaseID int DECLARE @CurrentDatabaseName nvarchar(max) DECLARE @CurrentIsDatabaseAccessible bit DECLARE @CurrentAvailabilityGroup nvarchar(max) DECLARE @CurrentAvailabilityGroupRole nvarchar(max) DECLARE @CurrentDatabaseMirroringRole nvarchar(max) DECLARE @CurrentCommand01 nvarchar(max) DECLARE @CurrentCommand02 nvarchar(max) DECLARE @CurrentCommand03 nvarchar(max) DECLARE @CurrentCommand04 nvarchar(max) DECLARE @CurrentCommand05 nvarchar(max) DECLARE @CurrentCommand06 nvarchar(max) DECLARE @CurrentCommand07 nvarchar(max) DECLARE @CurrentCommand08 nvarchar(max) DECLARE @CurrentCommand09 nvarchar(max) DECLARE @CurrentCommand10 nvarchar(max) DECLARE @CurrentCommand11 nvarchar(max) DECLARE @CurrentCommand12 nvarchar(max) DECLARE @CurrentCommand13 nvarchar(max) DECLARE @CurrentCommand14 nvarchar(max) DECLARE @CurrentCommandOutput13 int DECLARE @CurrentCommandOutput14 int DECLARE @CurrentCommandType13 nvarchar(max) DECLARE @CurrentCommandType14 nvarchar(max) DECLARE @CurrentIxID int DECLARE @CurrentSchemaID int DECLARE @CurrentSchemaName nvarchar(max) DECLARE @CurrentObjectID int DECLARE @CurrentObjectName nvarchar(max) DECLARE @CurrentObjectType nvarchar(max) DECLARE @CurrentIsMemoryOptimized bit DECLARE @CurrentIndexID int DECLARE @CurrentIndexName nvarchar(max) DECLARE @CurrentIndexType int DECLARE @CurrentStatisticsID int DECLARE @CurrentStatisticsName nvarchar(max) DECLARE @CurrentPartitionID bigint DECLARE @CurrentPartitionNumber int DECLARE @CurrentPartitionCount int DECLARE @CurrentIsPartition bit DECLARE @CurrentIndexExists bit DECLARE @CurrentStatisticsExists bit DECLARE @CurrentIsImageText bit DECLARE @CurrentIsNewLOB bit DECLARE @CurrentIsFileStream bit DECLARE @CurrentIsColumnStore bit DECLARE @CurrentAllowPageLocks bit DECLARE @CurrentNoRecompute bit DECLARE @CurrentStatisticsModified bit DECLARE @CurrentOnReadOnlyFileGroup bit DECLARE @CurrentFragmentationLevel float DECLARE @CurrentPageCount bigint DECLARE @CurrentFragmentationGroup nvarchar(max) DECLARE @CurrentAction nvarchar(max) DECLARE @CurrentMaxDOP int DECLARE @CurrentUpdateStatistics nvarchar(max) DECLARE @CurrentComment nvarchar(max) DECLARE @CurrentExtendedInfo xml DECLARE @CurrentDelay datetime DECLARE @tmpDatabases TABLE (ID int IDENTITY, DatabaseName nvarchar(max), DatabaseType nvarchar(max), Selected bit, Completed bit, PRIMARY KEY(Selected, Completed, ID)) DECLARE @tmpIndexesStatistics TABLE (ID int IDENTITY, SchemaID int, SchemaName nvarchar(max), ObjectID int, ObjectName nvarchar(max), ObjectType nvarchar(max), IsMemoryOptimized bit, IndexID int, IndexName nvarchar(max), IndexType int, StatisticsID int, StatisticsName nvarchar(max), PartitionID bigint, PartitionNumber int, PartitionCount int, Selected bit, Completed bit, PRIMARY KEY(Selected, Completed, ID)) DECLARE @SelectedDatabases TABLE (DatabaseName nvarchar(max), DatabaseType nvarchar(max), Selected bit) DECLARE @SelectedIndexes TABLE (DatabaseName nvarchar(max), SchemaName nvarchar(max), ObjectName nvarchar(max), IndexName nvarchar(max), Selected bit) DECLARE @Actions TABLE ([Action] nvarchar(max)) INSERT INTO @Actions([Action]) VALUES('INDEX_REBUILD_ONLINE') INSERT INTO @Actions([Action]) VALUES('INDEX_REBUILD_OFFLINE') INSERT INTO @Actions([Action]) VALUES('INDEX_REORGANIZE') DECLARE @ActionsPreferred TABLE (FragmentationGroup nvarchar(max), [Priority] int, [Action] nvarchar(max)) DECLARE @CurrentActionsAllowed TABLE ([Action] nvarchar(max)) DECLARE @Error int DECLARE @ReturnCode int SET @Error = 0 SET @ReturnCode = 0 SET @Version = CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - 1) + '.' + REPLACE(RIGHT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)), LEN(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)))),'.','') AS numeric(18,10)) SET @AmazonRDS = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- ---------------------------------------------------------------------------------------------------- SET @StartTime = CONVERT(datetime,CONVERT(nvarchar,GETDATE(),120),120) SET @StartMessage = 'Date and time: ' + CONVERT(nvarchar,@StartTime,120) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Server: ' + CAST(SERVERPROPERTY('ServerName') AS nvarchar) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Version: ' + CAST(SERVERPROPERTY('ProductVersion') AS nvarchar) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Edition: ' + CAST(SERVERPROPERTY('Edition') AS nvarchar) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + (SELECT QUOTENAME(schemas.name) FROM sys.schemas schemas INNER JOIN sys.objects objects ON schemas.[schema_id] = objects.[schema_id] WHERE [object_id] = @@PROCID) + '.' + QUOTENAME(OBJECT_NAME(@@PROCID)) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Parameters: @Databases = ' + ISNULL('''' + REPLACE(@Databases,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @FragmentationLow = ' + ISNULL('''' + REPLACE(@FragmentationLow,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @FragmentationMedium = ' + ISNULL('''' + REPLACE(@FragmentationMedium,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @FragmentationHigh = ' + ISNULL('''' + REPLACE(@FragmentationHigh,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @FragmentationLevel1 = ' + ISNULL(CAST(@FragmentationLevel1 AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @FragmentationLevel2 = ' + ISNULL(CAST(@FragmentationLevel2 AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @PageCountLevel = ' + ISNULL(CAST(@PageCountLevel AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @SortInTempdb = ' + ISNULL('''' + REPLACE(@SortInTempdb,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @MaxDOP = ' + ISNULL(CAST(@MaxDOP AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @FillFactor = ' + ISNULL(CAST(@FillFactor AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @PadIndex = ' + ISNULL('''' + REPLACE(@PadIndex,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @LOBCompaction = ' + ISNULL('''' + REPLACE(@LOBCompaction,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @UpdateStatistics = ' + ISNULL('''' + REPLACE(@UpdateStatistics,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @OnlyModifiedStatistics = ' + ISNULL('''' + REPLACE(@OnlyModifiedStatistics,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @StatisticsSample = ' + ISNULL(CAST(@StatisticsSample AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @StatisticsResample = ' + ISNULL('''' + REPLACE(@StatisticsResample,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @PartitionLevel = ' + ISNULL('''' + REPLACE(@PartitionLevel,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @MSShippedObjects = ' + ISNULL('''' + REPLACE(@MSShippedObjects,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @Indexes = ' + ISNULL('''' + REPLACE(@Indexes,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @TimeLimit = ' + ISNULL(CAST(@TimeLimit AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @Delay = ' + ISNULL(CAST(@Delay AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @WaitAtLowPriorityMaxDuration = ' + ISNULL(CAST(@WaitAtLowPriorityMaxDuration AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @WaitAtLowPriorityAbortAfterWait = ' + ISNULL('''' + REPLACE(@WaitAtLowPriorityAbortAfterWait,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @LockTimeout = ' + ISNULL(CAST(@LockTimeout AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @LogToTable = ' + ISNULL('''' + REPLACE(@LogToTable,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @Execute = ' + ISNULL('''' + REPLACE(@Execute,'''','''''') + '''','NULL') + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Source: https://ola.hallengren.com' + CHAR(13) + CHAR(10) SET @StartMessage = REPLACE(@StartMessage,'%','%%') + ' ' RAISERROR(@StartMessage,10,1) WITH NOWAIT ---------------------------------------------------------------------------------------------------- --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- IF NOT EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'P' AND schemas.[name] = 'dbo' AND objects.[name] = 'DPCommandExecute') BEGIN SET @ErrorMessage = 'The stored procedure DPCommandExecute is missing. Download https://ola.hallengren.com/scripts/CommandExecute.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'P' AND schemas.[name] = 'dbo' AND objects.[name] = 'DPCommandExecute' AND (OBJECT_DEFINITION(objects.[object_id]) NOT LIKE '%@LogToTable%' OR OBJECT_DEFINITION(objects.[object_id]) LIKE '%LOCK_TIMEOUT%')) BEGIN SET @ErrorMessage = 'The stored procedure DPCommandExecute needs to be updated. Download https://ola.hallengren.com/scripts/CommandExecute.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LogToTable = 'Y' AND NOT EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'U' AND schemas.[name] = 'dbo' AND objects.[name] = 'CommandLog') BEGIN SET @ErrorMessage = 'The table CommandLog is missing. Download https://ola.hallengren.com/scripts/CommandLog.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF SERVERPROPERTY('EngineEdition') = 5 AND @Version < 12 BEGIN SET @ErrorMessage = 'The stored procedure DPIndexOptimize is not supported on this version of Azure SQL Database.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO Logging END ---------------------------------------------------------------------------------------------------- --// Select databases //-- ---------------------------------------------------------------------------------------------------- SET @Databases = REPLACE(@Databases, ', ', ','); WITH Databases1 (StartPosition, EndPosition, DatabaseItem) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Databases, 1), 0), LEN(@Databases) + 1) AS EndPosition, SUBSTRING(@Databases, 1, ISNULL(NULLIF(CHARINDEX(',', @Databases, 1), 0), LEN(@Databases) + 1) - 1) AS DatabaseItem WHERE @Databases IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Databases, EndPosition + 1), 0), LEN(@Databases) + 1) AS EndPosition, SUBSTRING(@Databases, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @Databases, EndPosition + 1), 0), LEN(@Databases) + 1) - EndPosition - 1) AS DatabaseItem FROM Databases1 WHERE EndPosition < LEN(@Databases) + 1 ), Databases2 (DatabaseItem, Selected) AS ( SELECT CASE WHEN DatabaseItem LIKE '-%' THEN RIGHT(DatabaseItem,LEN(DatabaseItem) - 1) ELSE DatabaseItem END AS DatabaseItem, CASE WHEN DatabaseItem LIKE '-%' THEN 0 ELSE 1 END AS Selected FROM Databases1 ), Databases3 (DatabaseItem, DatabaseType, Selected) AS ( SELECT CASE WHEN DatabaseItem IN('ALL_DATABASES','SYSTEM_DATABASES','USER_DATABASES') THEN '%' ELSE DatabaseItem END AS DatabaseItem, CASE WHEN DatabaseItem = 'SYSTEM_DATABASES' THEN 'S' WHEN DatabaseItem = 'USER_DATABASES' THEN 'U' ELSE NULL END AS DatabaseType, Selected FROM Databases2 ), Databases4 (DatabaseName, DatabaseType, Selected) AS ( SELECT CASE WHEN LEFT(DatabaseItem,1) = '[' AND RIGHT(DatabaseItem,1) = ']' THEN PARSENAME(DatabaseItem,1) ELSE DatabaseItem END AS DatabaseItem, DatabaseType, Selected FROM Databases3 ) INSERT INTO @SelectedDatabases (DatabaseName, DatabaseType, Selected) SELECT DatabaseName, DatabaseType, Selected FROM Databases4 OPTION (MAXRECURSION 0) INSERT INTO @tmpDatabases (DatabaseName, DatabaseType, Selected, Completed) SELECT [name] AS DatabaseName, CASE WHEN name IN('master','msdb','model') THEN 'S' ELSE 'U' END AS DatabaseType, 0 AS Selected, 0 AS Completed FROM sys.databases WHERE [name] <> 'tempdb' AND source_database_id IS NULL ORDER BY [name] ASC UPDATE tmpDatabases SET tmpDatabases.Selected = SelectedDatabases.Selected FROM @tmpDatabases tmpDatabases INNER JOIN @SelectedDatabases SelectedDatabases ON tmpDatabases.DatabaseName LIKE REPLACE(SelectedDatabases.DatabaseName,'_','[_]') AND (tmpDatabases.DatabaseType = SelectedDatabases.DatabaseType OR SelectedDatabases.DatabaseType IS NULL) WHERE SelectedDatabases.Selected = 1 UPDATE tmpDatabases SET tmpDatabases.Selected = SelectedDatabases.Selected FROM @tmpDatabases tmpDatabases INNER JOIN @SelectedDatabases SelectedDatabases ON tmpDatabases.DatabaseName LIKE REPLACE(SelectedDatabases.DatabaseName,'_','[_]') AND (tmpDatabases.DatabaseType = SelectedDatabases.DatabaseType OR SelectedDatabases.DatabaseType IS NULL) WHERE SelectedDatabases.Selected = 0 IF @Databases IS NULL OR NOT EXISTS(SELECT * FROM @SelectedDatabases) OR EXISTS(SELECT * FROM @SelectedDatabases WHERE DatabaseName IS NULL OR DatabaseName = '') BEGIN SET @ErrorMessage = 'The value for the parameter @Databases is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END ---------------------------------------------------------------------------------------------------- --// Select indexes //-- ---------------------------------------------------------------------------------------------------- SET @Indexes = REPLACE(@Indexes, ', ', ','); WITH Indexes1 (StartPosition, EndPosition, IndexItem) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Indexes, 1), 0), LEN(@Indexes) + 1) AS EndPosition, SUBSTRING(@Indexes, 1, ISNULL(NULLIF(CHARINDEX(',', @Indexes, 1), 0), LEN(@Indexes) + 1) - 1) AS IndexItem WHERE @Indexes IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Indexes, EndPosition + 1), 0), LEN(@Indexes) + 1) AS EndPosition, SUBSTRING(@Indexes, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @Indexes, EndPosition + 1), 0), LEN(@Indexes) + 1) - EndPosition - 1) AS IndexItem FROM Indexes1 WHERE EndPosition < LEN(@Indexes) + 1 ), Indexes2 (IndexItem, Selected) AS ( SELECT CASE WHEN IndexItem LIKE '-%' THEN RIGHT(IndexItem,LEN(IndexItem) - 1) ELSE IndexItem END AS IndexItem, CASE WHEN IndexItem LIKE '-%' THEN 0 ELSE 1 END AS Selected FROM Indexes1 ), Indexes3 (IndexItem, Selected) AS ( SELECT CASE WHEN IndexItem = 'ALL_INDEXES' THEN '%.%.%.%' ELSE IndexItem END AS IndexItem, Selected FROM Indexes2 ), Indexes4 (DatabaseName, SchemaName, ObjectName, IndexName, Selected) AS ( SELECT CASE WHEN PARSENAME(IndexItem,4) IS NULL THEN PARSENAME(IndexItem,3) ELSE PARSENAME(IndexItem,4) END AS DatabaseName, CASE WHEN PARSENAME(IndexItem,4) IS NULL THEN PARSENAME(IndexItem,2) ELSE PARSENAME(IndexItem,3) END AS SchemaName, CASE WHEN PARSENAME(IndexItem,4) IS NULL THEN PARSENAME(IndexItem,1) ELSE PARSENAME(IndexItem,2) END AS ObjectName, CASE WHEN PARSENAME(IndexItem,4) IS NULL THEN '%' ELSE PARSENAME(IndexItem,1) END AS IndexName, Selected FROM Indexes3 ) INSERT INTO @SelectedIndexes (DatabaseName, SchemaName, ObjectName, IndexName, Selected) SELECT DatabaseName, SchemaName, ObjectName, IndexName, Selected FROM Indexes4 OPTION (MAXRECURSION 0); ---------------------------------------------------------------------------------------------------- --// Select actions //-- ---------------------------------------------------------------------------------------------------- WITH FragmentationLow (StartPosition, EndPosition, [Action]) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FragmentationLow, 1), 0), LEN(@FragmentationLow) + 1) AS EndPosition, SUBSTRING(@FragmentationLow, 1, ISNULL(NULLIF(CHARINDEX(',', @FragmentationLow, 1), 0), LEN(@FragmentationLow) + 1) - 1) AS [Action] WHERE @FragmentationLow IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FragmentationLow, EndPosition + 1), 0), LEN(@FragmentationLow) + 1) AS EndPosition, SUBSTRING(@FragmentationLow, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @FragmentationLow, EndPosition + 1), 0), LEN(@FragmentationLow) + 1) - EndPosition - 1) AS [Action] FROM FragmentationLow WHERE EndPosition < LEN(@FragmentationLow) + 1 ) INSERT INTO @ActionsPreferred(FragmentationGroup, [Priority], [Action]) SELECT 'Low' AS FragmentationGroup, ROW_NUMBER() OVER(ORDER BY StartPosition ASC) AS [Priority], [Action] FROM FragmentationLow OPTION (MAXRECURSION 0); WITH FragmentationMedium (StartPosition, EndPosition, [Action]) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FragmentationMedium, 1), 0), LEN(@FragmentationMedium) + 1) AS EndPosition, SUBSTRING(@FragmentationMedium, 1, ISNULL(NULLIF(CHARINDEX(',', @FragmentationMedium, 1), 0), LEN(@FragmentationMedium) + 1) - 1) AS [Action] WHERE @FragmentationMedium IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FragmentationMedium, EndPosition + 1), 0), LEN(@FragmentationMedium) + 1) AS EndPosition, SUBSTRING(@FragmentationMedium, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @FragmentationMedium, EndPosition + 1), 0), LEN(@FragmentationMedium) + 1) - EndPosition - 1) AS [Action] FROM FragmentationMedium WHERE EndPosition < LEN(@FragmentationMedium) + 1 ) INSERT INTO @ActionsPreferred(FragmentationGroup, [Priority], [Action]) SELECT 'Medium' AS FragmentationGroup, ROW_NUMBER() OVER(ORDER BY StartPosition ASC) AS [Priority], [Action] FROM FragmentationMedium OPTION (MAXRECURSION 0); WITH FragmentationHigh (StartPosition, EndPosition, [Action]) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FragmentationHigh, 1), 0), LEN(@FragmentationHigh) + 1) AS EndPosition, SUBSTRING(@FragmentationHigh, 1, ISNULL(NULLIF(CHARINDEX(',', @FragmentationHigh, 1), 0), LEN(@FragmentationHigh) + 1) - 1) AS [Action] WHERE @FragmentationHigh IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FragmentationHigh, EndPosition + 1), 0), LEN(@FragmentationHigh) + 1) AS EndPosition, SUBSTRING(@FragmentationHigh, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @FragmentationHigh, EndPosition + 1), 0), LEN(@FragmentationHigh) + 1) - EndPosition - 1) AS [Action] FROM FragmentationHigh WHERE EndPosition < LEN(@FragmentationHigh) + 1 ) INSERT INTO @ActionsPreferred(FragmentationGroup, [Priority], [Action]) SELECT 'High' AS FragmentationGroup, ROW_NUMBER() OVER(ORDER BY StartPosition ASC) AS [Priority], [Action] FROM FragmentationHigh OPTION (MAXRECURSION 0) ---------------------------------------------------------------------------------------------------- --// Check input parameters //-- ---------------------------------------------------------------------------------------------------- IF EXISTS (SELECT [Action] FROM @ActionsPreferred WHERE FragmentationGroup = 'Low' AND [Action] NOT IN(SELECT * FROM @Actions)) OR EXISTS(SELECT * FROM @ActionsPreferred WHERE FragmentationGroup = 'Low' GROUP BY [Action] HAVING COUNT(*) > 1) BEGIN SET @ErrorMessage = 'The value for the parameter @FragmentationLow is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS (SELECT [Action] FROM @ActionsPreferred WHERE FragmentationGroup = 'Medium' AND [Action] NOT IN(SELECT * FROM @Actions)) OR EXISTS(SELECT * FROM @ActionsPreferred WHERE FragmentationGroup = 'Medium' GROUP BY [Action] HAVING COUNT(*) > 1) BEGIN SET @ErrorMessage = 'The value for the parameter @FragmentationMedium is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS (SELECT [Action] FROM @ActionsPreferred WHERE FragmentationGroup = 'High' AND [Action] NOT IN(SELECT * FROM @Actions)) OR EXISTS(SELECT * FROM @ActionsPreferred WHERE FragmentationGroup = 'High' GROUP BY [Action] HAVING COUNT(*) > 1) BEGIN SET @ErrorMessage = 'The value for the parameter @FragmentationHigh is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @FragmentationLevel1 <= 0 OR @FragmentationLevel1 >= 100 OR @FragmentationLevel1 >= @FragmentationLevel2 OR @FragmentationLevel1 IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @FragmentationLevel1 is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @FragmentationLevel2 <= 0 OR @FragmentationLevel2 >= 100 OR @FragmentationLevel2 <= @FragmentationLevel1 OR @FragmentationLevel2 IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @FragmentationLevel2 is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @PageCountLevel < 0 OR @PageCountLevel IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @PageCountLevel is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @SortInTempdb NOT IN('Y','N') OR @SortInTempdb IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @SortInTempdb is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @MaxDOP < 0 OR @MaxDOP > 64 OR @MaxDOP > (SELECT cpu_count FROM sys.dm_os_sys_info) OR (@MaxDOP > 1 AND SERVERPROPERTY('EngineEdition') NOT IN (3,5)) BEGIN SET @ErrorMessage = 'The value for the parameter @MaxDOP is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @FillFactor <= 0 OR @FillFactor > 100 BEGIN SET @ErrorMessage = 'The value for the parameter @FillFactor is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @PadIndex NOT IN('Y','N') BEGIN SET @ErrorMessage = 'The value for the parameter @PadIndex is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LOBCompaction NOT IN('Y','N') OR @LOBCompaction IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @LOBCompaction is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @UpdateStatistics NOT IN('ALL','COLUMNS','INDEX') BEGIN SET @ErrorMessage = 'The value for the parameter @UpdateStatistics is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @OnlyModifiedStatistics NOT IN('Y','N') OR @OnlyModifiedStatistics IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @OnlyModifiedStatistics is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @StatisticsSample <= 0 OR @StatisticsSample > 100 BEGIN SET @ErrorMessage = 'The value for the parameter @StatisticsSample is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @StatisticsResample NOT IN('Y','N') OR @StatisticsResample IS NULL OR (@StatisticsResample = 'Y' AND @StatisticsSample IS NOT NULL) BEGIN SET @ErrorMessage = 'The value for the parameter @StatisticsResample is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @PartitionLevel NOT IN('Y','N') OR @PartitionLevel IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @PartitionLevel is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @MSShippedObjects NOT IN('Y','N') OR @MSShippedObjects IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @MSShippedObjects is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS(SELECT * FROM @SelectedIndexes WHERE DatabaseName IS NULL OR SchemaName IS NULL OR ObjectName IS NULL OR IndexName IS NULL) OR (@Indexes IS NOT NULL AND NOT EXISTS(SELECT * FROM @SelectedIndexes)) BEGIN SET @ErrorMessage = 'The value for the parameter @Indexes is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @TimeLimit < 0 BEGIN SET @ErrorMessage = 'The value for the parameter @TimeLimit is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Delay < 0 BEGIN SET @ErrorMessage = 'The value for the parameter @Delay is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @WaitAtLowPriorityMaxDuration < 0 OR (@WaitAtLowPriorityMaxDuration IS NOT NULL AND @Version < 12) OR (@WaitAtLowPriorityMaxDuration IS NOT NULL AND @WaitAtLowPriorityAbortAfterWait IS NULL) OR (@WaitAtLowPriorityMaxDuration IS NULL AND @WaitAtLowPriorityAbortAfterWait IS NOT NULL) BEGIN SET @ErrorMessage = 'The value for the parameter @WaitAtLowPriorityMaxDuration is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @WaitAtLowPriorityAbortAfterWait NOT IN('NONE','SELF','BLOCKERS') OR (@WaitAtLowPriorityAbortAfterWait IS NOT NULL AND @Version < 12) OR (@WaitAtLowPriorityAbortAfterWait IS NOT NULL AND @WaitAtLowPriorityMaxDuration IS NULL) OR (@WaitAtLowPriorityAbortAfterWait IS NULL AND @WaitAtLowPriorityMaxDuration IS NOT NULL) BEGIN SET @ErrorMessage = 'The value for the parameter @WaitAtLowPriorityAbortAfterWait is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LockTimeout < 0 BEGIN SET @ErrorMessage = 'The value for the parameter @LockTimeout is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LogToTable NOT IN('Y','N') OR @LogToTable IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @LogToTable is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Execute NOT IN('Y','N') OR @Execute IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @Execute is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Error <> 0 BEGIN SET @ErrorMessage = 'The documentation is available at https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @ReturnCode = @Error GOTO Logging END ---------------------------------------------------------------------------------------------------- --// Check Availability Group cluster name //-- ---------------------------------------------------------------------------------------------------- IF @Version >= 11 AND SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @Cluster = cluster_name FROM sys.dm_hadr_cluster END ---------------------------------------------------------------------------------------------------- --// Execute commands //-- ---------------------------------------------------------------------------------------------------- WHILE EXISTS (SELECT * FROM @tmpDatabases WHERE Selected = 1 AND Completed = 0) BEGIN SELECT TOP 1 @CurrentDBID = ID, @CurrentDatabaseName = DatabaseName FROM @tmpDatabases WHERE Selected = 1 AND Completed = 0 ORDER BY ID ASC SET @CurrentDatabaseID = DB_ID(@CurrentDatabaseName) IF DATABASEPROPERTYEX(@CurrentDatabaseName,'Status') = 'ONLINE' AND SERVERPROPERTY('EngineEdition') <> 5 BEGIN IF EXISTS (SELECT * FROM sys.database_recovery_status WHERE database_id = @CurrentDatabaseID AND database_guid IS NOT NULL) BEGIN SET @CurrentIsDatabaseAccessible = 1 END ELSE BEGIN SET @CurrentIsDatabaseAccessible = 0 END END IF @Version >= 11 AND @Cluster IS NOT NULL BEGIN SELECT @CurrentAvailabilityGroup = availability_groups.name, @CurrentAvailabilityGroupRole = dm_hadr_availability_replica_states.role_desc FROM sys.databases databases INNER JOIN sys.availability_databases_cluster availability_databases_cluster ON databases.group_database_id = availability_databases_cluster.group_database_id INNER JOIN sys.availability_groups availability_groups ON availability_databases_cluster.group_id = availability_groups.group_id INNER JOIN sys.dm_hadr_availability_replica_states dm_hadr_availability_replica_states ON availability_groups.group_id = dm_hadr_availability_replica_states.group_id AND databases.replica_id = dm_hadr_availability_replica_states.replica_id WHERE databases.name = @CurrentDatabaseName END IF SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) FROM sys.database_mirroring WHERE database_id = @CurrentDatabaseID END -- Set database message SET @DatabaseMessage = 'Date and time: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Database: ' + QUOTENAME(@CurrentDatabaseName) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Status: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'Status') AS nvarchar) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Standby: ' + CASE WHEN DATABASEPROPERTYEX(@CurrentDatabaseName,'IsInStandBy') = 1 THEN 'Yes' ELSE 'No' END + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Updateability: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'Updateability') AS nvarchar) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'User access: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'UserAccess') AS nvarchar) + CHAR(13) + CHAR(10) IF @CurrentIsDatabaseAccessible IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Is accessible: ' + CASE WHEN @CurrentIsDatabaseAccessible = 1 THEN 'Yes' ELSE 'No' END + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Recovery model: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'Recovery') AS nvarchar) + CHAR(13) + CHAR(10) IF @CurrentAvailabilityGroup IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Availability group: ' + @CurrentAvailabilityGroup + CHAR(13) + CHAR(10) IF @CurrentAvailabilityGroup IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Availability group role: ' + @CurrentAvailabilityGroupRole + CHAR(13) + CHAR(10) IF @CurrentDatabaseMirroringRole IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Database mirroring role: ' + @CurrentDatabaseMirroringRole + CHAR(13) + CHAR(10) SET @DatabaseMessage = REPLACE(@DatabaseMessage,'%','%%') + ' ' RAISERROR(@DatabaseMessage,10,1) WITH NOWAIT IF DATABASEPROPERTYEX(@CurrentDatabaseName,'Status') = 'ONLINE' AND (@CurrentIsDatabaseAccessible = 1 OR @CurrentIsDatabaseAccessible IS NULL) AND DATABASEPROPERTYEX(@CurrentDatabaseName,'Updateability') = 'READ_WRITE' BEGIN -- Select indexes in the current database IF (EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IS NOT NULL) AND (GETDATE() < DATEADD(ss,@TimeLimit,@StartTime) OR @TimeLimit IS NULL) BEGIN SET @CurrentCommand01 = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, StatisticsID, StatisticsName, PartitionID, PartitionNumber, PartitionCount, Selected, Completed FROM (' IF EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IN('ALL','INDEX') BEGIN SET @CurrentCommand01 = @CurrentCommand01 + 'SELECT schemas.[schema_id] AS SchemaID, schemas.[name] AS SchemaName, objects.[object_id] AS ObjectID, objects.[name] AS ObjectName, RTRIM(objects.[type]) AS ObjectType, ' + CASE WHEN @Version >= 12 THEN 'tables.is_memory_optimized' ELSE 'NULL' END + ' AS IsMemoryOptimized, indexes.index_id AS IndexID, indexes.[name] AS IndexName, indexes.[type] AS IndexType, stats.stats_id AS StatisticsID, stats.name AS StatisticsName' IF @PartitionLevel = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ', partitions.partition_id AS PartitionID, partitions.partition_number AS PartitionNumber, IndexPartitions.partition_count AS PartitionCount' IF @PartitionLevel = 'N' SET @CurrentCommand01 = @CurrentCommand01 + ', NULL AS PartitionID, NULL AS PartitionNumber, NULL AS PartitionCount' SET @CurrentCommand01 = @CurrentCommand01 + ', 0 AS Selected, 0 AS Completed FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects ON indexes.[object_id] = objects.[object_id] INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.tables tables ON objects.[object_id] = tables.[object_id] LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.stats stats ON indexes.[object_id] = stats.[object_id] AND indexes.[index_id] = stats.[stats_id]' IF @PartitionLevel = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ' LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.partitions partitions ON indexes.[object_id] = partitions.[object_id] AND indexes.index_id = partitions.index_id LEFT OUTER JOIN (SELECT partitions.[object_id], partitions.index_id, COUNT(*) AS partition_count FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.partitions partitions GROUP BY partitions.[object_id], partitions.index_id) IndexPartitions ON partitions.[object_id] = IndexPartitions.[object_id] AND partitions.[index_id] = IndexPartitions.[index_id]' IF @PartitionLevel = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ' LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.dm_db_partition_stats dm_db_partition_stats ON indexes.[object_id] = dm_db_partition_stats.[object_id] AND indexes.[index_id] = dm_db_partition_stats.[index_id] AND partitions.partition_id = dm_db_partition_stats.partition_id' IF @PartitionLevel = 'N' SET @CurrentCommand01 = @CurrentCommand01 + ' LEFT OUTER JOIN (SELECT dm_db_partition_stats.[object_id], dm_db_partition_stats.[index_id], SUM(dm_db_partition_stats.in_row_data_page_count) AS in_row_data_page_count FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.dm_db_partition_stats dm_db_partition_stats GROUP BY dm_db_partition_stats.[object_id], dm_db_partition_stats.[index_id]) dm_db_partition_stats ON indexes.[object_id] = dm_db_partition_stats.[object_id] AND indexes.[index_id] = dm_db_partition_stats.[index_id]' SET @CurrentCommand01 = @CurrentCommand01 + ' WHERE objects.[type] IN(''U'',''V'')' + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND indexes.[type] IN(1,2,3,4,5,6,7) AND indexes.is_disabled = 0 AND indexes.is_hypothetical = 0' IF (@UpdateStatistics NOT IN('ALL','INDEX') OR @UpdateStatistics IS NULL) AND @PageCountLevel > 0 SET @CurrentCommand01 = @CurrentCommand01 + ' AND (dm_db_partition_stats.in_row_data_page_count >= @ParamPageCountLevel OR dm_db_partition_stats.in_row_data_page_count IS NULL)' IF NOT EXISTS(SELECT * FROM @ActionsPreferred) SET @CurrentCommand01 = @CurrentCommand01 + ' AND stats.stats_id IS NOT NULL' END IF (EXISTS(SELECT * FROM @ActionsPreferred) AND @UpdateStatistics = 'COLUMNS') OR @UpdateStatistics = 'ALL' SET @CurrentCommand01 = @CurrentCommand01 + ' UNION ' IF @UpdateStatistics IN('ALL','COLUMNS') SET @CurrentCommand01 = @CurrentCommand01 + 'SELECT schemas.[schema_id] AS SchemaID, schemas.[name] AS SchemaName, objects.[object_id] AS ObjectID, objects.[name] AS ObjectName, RTRIM(objects.[type]) AS ObjectType, ' + CASE WHEN @Version >= 12 THEN 'tables.is_memory_optimized' ELSE 'NULL' END + ' AS IsMemoryOptimized, NULL AS IndexID, NULL AS IndexName, NULL AS IndexType, stats.stats_id AS StatisticsID, stats.name AS StatisticsName, NULL AS PartitionID, NULL AS PartitionNumber, NULL AS PartitionCount, 0 AS Selected, 0 AS Completed FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.stats stats INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects ON stats.[object_id] = objects.[object_id] INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.tables tables ON objects.[object_id] = tables.[object_id] WHERE objects.[type] IN(''U'',''V'')' + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND NOT EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes WHERE indexes.[object_id] = stats.[object_id] AND indexes.index_id = stats.stats_id)' SET @CurrentCommand01 = @CurrentCommand01 + ') IndexesStatistics ORDER BY SchemaName ASC, ObjectName ASC' IF (EXISTS(SELECT * FROM @ActionsPreferred) AND @UpdateStatistics = 'COLUMNS') OR @UpdateStatistics = 'ALL' SET @CurrentCommand01 = @CurrentCommand01 + ', CASE WHEN IndexType IS NULL THEN 1 ELSE 0 END ASC' IF EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IN('ALL','INDEX') SET @CurrentCommand01 = @CurrentCommand01 + ', IndexType ASC, IndexName ASC' IF @UpdateStatistics IN('ALL','COLUMNS') SET @CurrentCommand01 = @CurrentCommand01 + ', StatisticsName ASC' IF @PartitionLevel = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ', PartitionNumber ASC' INSERT INTO @tmpIndexesStatistics (SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, StatisticsID, StatisticsName, PartitionID, PartitionNumber, PartitionCount, Selected, Completed) EXECUTE sp_executesql @statement = @CurrentCommand01, @params = N'@ParamPageCountLevel int', @ParamPageCountLevel = @PageCountLevel SET @Error = @@Error IF @Error <> 0 BEGIN SET @ReturnCode = @Error END END IF @Indexes IS NULL BEGIN UPDATE tmpIndexesStatistics SET tmpIndexesStatistics.Selected = 1 FROM @tmpIndexesStatistics tmpIndexesStatistics END ELSE BEGIN UPDATE tmpIndexesStatistics SET tmpIndexesStatistics.Selected = SelectedIndexes.Selected FROM @tmpIndexesStatistics tmpIndexesStatistics INNER JOIN @SelectedIndexes SelectedIndexes ON @CurrentDatabaseName LIKE REPLACE(SelectedIndexes.DatabaseName,'_','[_]') AND tmpIndexesStatistics.SchemaName LIKE REPLACE(SelectedIndexes.SchemaName,'_','[_]') AND tmpIndexesStatistics.ObjectName LIKE REPLACE(SelectedIndexes.ObjectName,'_','[_]') AND COALESCE(tmpIndexesStatistics.IndexName,tmpIndexesStatistics.StatisticsName) LIKE REPLACE(SelectedIndexes.IndexName,'_','[_]') WHERE SelectedIndexes.Selected = 1 UPDATE tmpIndexesStatistics SET tmpIndexesStatistics.Selected = SelectedIndexes.Selected FROM @tmpIndexesStatistics tmpIndexesStatistics INNER JOIN @SelectedIndexes SelectedIndexes ON @CurrentDatabaseName LIKE REPLACE(SelectedIndexes.DatabaseName,'_','[_]') AND tmpIndexesStatistics.SchemaName LIKE REPLACE(SelectedIndexes.SchemaName,'_','[_]') AND tmpIndexesStatistics.ObjectName LIKE REPLACE(SelectedIndexes.ObjectName,'_','[_]') AND COALESCE(tmpIndexesStatistics.IndexName,tmpIndexesStatistics.StatisticsName) LIKE REPLACE(SelectedIndexes.IndexName,'_','[_]') WHERE SelectedIndexes.Selected = 0 END WHILE EXISTS (SELECT * FROM @tmpIndexesStatistics WHERE Selected = 1 AND Completed = 0 AND (GETDATE() < DATEADD(ss,@TimeLimit,@StartTime) OR @TimeLimit IS NULL)) BEGIN SELECT TOP 1 @CurrentIxID = ID, @CurrentSchemaID = SchemaID, @CurrentSchemaName = SchemaName, @CurrentObjectID = ObjectID, @CurrentObjectName = ObjectName, @CurrentObjectType = ObjectType, @CurrentIsMemoryOptimized = IsMemoryOptimized, @CurrentIndexID = IndexID, @CurrentIndexName = IndexName, @CurrentIndexType = IndexType, @CurrentStatisticsID = StatisticsID, @CurrentStatisticsName = StatisticsName, @CurrentPartitionID = PartitionID, @CurrentPartitionNumber = PartitionNumber, @CurrentPartitionCount = PartitionCount FROM @tmpIndexesStatistics WHERE Selected = 1 AND Completed = 0 ORDER BY ID ASC -- Is the index a partition? IF @CurrentPartitionNumber IS NULL OR @CurrentPartitionCount = 1 BEGIN SET @CurrentIsPartition = 0 END ELSE BEGIN SET @CurrentIsPartition = 1 END -- Does the index exist? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentCommand02 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand02 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' IF @CurrentIsPartition = 0 SET @CurrentCommand02 = @CurrentCommand02 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects ON indexes.[object_id] = objects.[object_id] INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] IN(''U'',''V'')' + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND indexes.[type] IN(1,2,3,4,5,6,7) AND indexes.is_disabled = 0 AND indexes.is_hypothetical = 0 AND schemas.[schema_id] = @ParamSchemaID AND schemas.[name] = @ParamSchemaName AND objects.[object_id] = @ParamObjectID AND objects.[name] = @ParamObjectName AND objects.[type] = @ParamObjectType AND indexes.index_id = @ParamIndexID AND indexes.[name] = @ParamIndexName AND indexes.[type] = @ParamIndexType) BEGIN SET @ParamIndexExists = 1 END' IF @CurrentIsPartition = 1 SET @CurrentCommand02 = @CurrentCommand02 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects ON indexes.[object_id] = objects.[object_id] INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.partitions partitions ON indexes.[object_id] = partitions.[object_id] AND indexes.index_id = partitions.index_id WHERE objects.[type] IN(''U'',''V'')' + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND indexes.[type] IN(1,2,3,4,5,6,7) AND indexes.is_disabled = 0 AND indexes.is_hypothetical = 0 AND schemas.[schema_id] = @ParamSchemaID AND schemas.[name] = @ParamSchemaName AND objects.[object_id] = @ParamObjectID AND objects.[name] = @ParamObjectName AND objects.[type] = @ParamObjectType AND indexes.index_id = @ParamIndexID AND indexes.[name] = @ParamIndexName AND indexes.[type] = @ParamIndexType AND partitions.partition_id = @ParamPartitionID AND partitions.partition_number = @ParamPartitionNumber) BEGIN SET @ParamIndexExists = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand02, @params = N'@ParamSchemaID int, @ParamSchemaName sysname, @ParamObjectID int, @ParamObjectName sysname, @ParamObjectType sysname, @ParamIndexID int, @ParamIndexName sysname, @ParamIndexType int, @ParamPartitionID bigint, @ParamPartitionNumber int, @ParamIndexExists bit OUTPUT', @ParamSchemaID = @CurrentSchemaID, @ParamSchemaName = @CurrentSchemaName, @ParamObjectID = @CurrentObjectID, @ParamObjectName = @CurrentObjectName, @ParamObjectType = @CurrentObjectType, @ParamIndexID = @CurrentIndexID, @ParamIndexName = @CurrentIndexName, @ParamIndexType = @CurrentIndexType, @ParamPartitionID = @CurrentPartitionID, @ParamPartitionNumber = @CurrentPartitionNumber, @ParamIndexExists = @CurrentIndexExists OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentIndexExists IS NULL SET @CurrentIndexExists = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the index exists.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END IF @CurrentIndexExists = 0 GOTO NoAction END -- Does the statistics exist? IF @CurrentStatisticsID IS NOT NULL AND @UpdateStatistics IS NOT NULL BEGIN SET @CurrentCommand03 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand03 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand03 = @CurrentCommand03 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.stats stats INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects ON stats.[object_id] = objects.[object_id] INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] IN(''U'',''V'')' + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND schemas.[schema_id] = @ParamSchemaID AND schemas.[name] = @ParamSchemaName AND objects.[object_id] = @ParamObjectID AND objects.[name] = @ParamObjectName AND objects.[type] = @ParamObjectType AND stats.stats_id = @ParamStatisticsID AND stats.[name] = @ParamStatisticsName) BEGIN SET @ParamStatisticsExists = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand03, @params = N'@ParamSchemaID int, @ParamSchemaName sysname, @ParamObjectID int, @ParamObjectName sysname, @ParamObjectType sysname, @ParamStatisticsID int, @ParamStatisticsName sysname, @ParamStatisticsExists bit OUTPUT', @ParamSchemaID = @CurrentSchemaID, @ParamSchemaName = @CurrentSchemaName, @ParamObjectID = @CurrentObjectID, @ParamObjectName = @CurrentObjectName, @ParamObjectType = @CurrentObjectType, @ParamStatisticsID = @CurrentStatisticsID, @ParamStatisticsName = @CurrentStatisticsName, @ParamStatisticsExists = @CurrentStatisticsExists OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentStatisticsExists IS NULL SET @CurrentStatisticsExists = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The statistics ' + QUOTENAME(@CurrentStatisticsName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the statistics exists.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END IF @CurrentStatisticsExists = 0 GOTO NoAction END -- Is one of the columns in the index an image, text or ntext data type? IF @CurrentIndexID IS NOT NULL AND @CurrentIndexType = 1 AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentCommand04 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand04 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand04 = @CurrentCommand04 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.columns columns INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.types types ON columns.system_type_id = types.user_type_id WHERE columns.[object_id] = @ParamObjectID AND types.name IN(''image'',''text'',''ntext'')) BEGIN SET @ParamIsImageText = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand04, @params = N'@ParamObjectID int, @ParamIndexID int, @ParamIsImageText bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamIndexID = @CurrentIndexID, @ParamIsImageText = @CurrentIsImageText OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentIsImageText IS NULL SET @CurrentIsImageText = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the index contains any image, text, or ntext data types.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is one of the columns in the index an xml, varchar(max), nvarchar(max), varbinary(max) or large CLR data type? IF @CurrentIndexID IS NOT NULL AND @CurrentIndexType IN(1,2) AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentCommand05 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand05 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' IF @CurrentIndexType = 1 SET @CurrentCommand05 = @CurrentCommand05 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.columns columns INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.types types ON columns.system_type_id = types.user_type_id OR (columns.user_type_id = types.user_type_id AND types.is_assembly_type = 1) WHERE columns.[object_id] = @ParamObjectID AND (types.name IN(''xml'') OR (types.name IN(''varchar'',''nvarchar'',''varbinary'') AND columns.max_length = -1) OR (types.is_assembly_type = 1 AND columns.max_length = -1))) BEGIN SET @ParamIsNewLOB = 1 END' IF @CurrentIndexType = 2 SET @CurrentCommand05 = @CurrentCommand05 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.index_columns index_columns INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.columns columns ON index_columns.[object_id] = columns.[object_id] AND index_columns.column_id = columns.column_id INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.types types ON columns.system_type_id = types.user_type_id OR (columns.user_type_id = types.user_type_id AND types.is_assembly_type = 1) WHERE index_columns.[object_id] = @ParamObjectID AND index_columns.index_id = @ParamIndexID AND (types.[name] IN(''xml'') OR (types.[name] IN(''varchar'',''nvarchar'',''varbinary'') AND columns.max_length = -1) OR (types.is_assembly_type = 1 AND columns.max_length = -1))) BEGIN SET @ParamIsNewLOB = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand05, @params = N'@ParamObjectID int, @ParamIndexID int, @ParamIsNewLOB bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamIndexID = @CurrentIndexID, @ParamIsNewLOB = @CurrentIsNewLOB OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentIsNewLOB IS NULL SET @CurrentIsNewLOB = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the index contains any xml, varchar(max), nvarchar(max), varbinary(max), or large CLR data types.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is one of the columns in the index a file stream column? IF @CurrentIndexID IS NOT NULL AND @CurrentIndexType = 1 AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentCommand06 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand06 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand06 = @CurrentCommand06 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.columns columns WHERE columns.[object_id] = @ParamObjectID AND columns.is_filestream = 1) BEGIN SET @ParamIsFileStream = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand06, @params = N'@ParamObjectID int, @ParamIndexID int, @ParamIsFileStream bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamIndexID = @CurrentIndexID, @ParamIsFileStream = @CurrentIsFileStream OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentIsFileStream IS NULL SET @CurrentIsFileStream = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the index contains any file stream columns.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is there a columnstore index on the table? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) AND @Version >= 11 BEGIN SET @CurrentCommand07 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand07 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand07 = @CurrentCommand07 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes WHERE indexes.[object_id] = @ParamObjectID AND [type] IN(5,6)) BEGIN SET @ParamIsColumnStore = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand07, @params = N'@ParamObjectID int, @ParamIsColumnStore bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamIsColumnStore = @CurrentIsColumnStore OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentIsColumnStore IS NULL SET @CurrentIsColumnStore = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if there is a columnstore index on the table.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is Allow_Page_Locks set to On? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentCommand08 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand08 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand08 = @CurrentCommand08 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes WHERE indexes.[object_id] = @ParamObjectID AND indexes.[index_id] = @ParamIndexID AND indexes.[allow_page_locks] = 1) BEGIN SET @ParamAllowPageLocks = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand08, @params = N'@ParamObjectID int, @ParamIndexID int, @ParamAllowPageLocks bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamIndexID = @CurrentIndexID, @ParamAllowPageLocks = @CurrentAllowPageLocks OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentAllowPageLocks IS NULL SET @CurrentAllowPageLocks = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if page locking is enabled on the index.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is No_Recompute set to On? IF @CurrentStatisticsID IS NOT NULL AND @UpdateStatistics IS NOT NULL BEGIN SET @CurrentCommand09 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand09 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand09 = @CurrentCommand09 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.stats stats WHERE stats.[object_id] = @ParamObjectID AND stats.[stats_id] = @ParamStatisticsID AND stats.[no_recompute] = 1) BEGIN SET @ParamNoRecompute = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand09, @params = N'@ParamObjectID int, @ParamStatisticsID int, @ParamNoRecompute bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamStatisticsID = @CurrentStatisticsID, @ParamNoRecompute = @CurrentNoRecompute OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentNoRecompute IS NULL SET @CurrentNoRecompute = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The statistics ' + QUOTENAME(@CurrentStatisticsName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if automatic statistics update is enabled.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Has the data in the statistics been modified since the statistics was last updated? IF @CurrentStatisticsID IS NOT NULL AND @UpdateStatistics IS NOT NULL AND @OnlyModifiedStatistics = 'Y' BEGIN SET @CurrentCommand10 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand10 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' IF (@Version >= 10.504000 AND @Version < 11) OR @Version >= 11.03000 BEGIN SET @CurrentCommand10 = @CurrentCommand10 + 'USE ' + QUOTENAME(@CurrentDatabaseName) + '; IF EXISTS(SELECT * FROM sys.dm_db_stats_properties (@ParamObjectID, @ParamStatisticsID) WHERE modification_counter > 0) BEGIN SET @ParamStatisticsModified = 1 END' END ELSE BEGIN SET @CurrentCommand10 = @CurrentCommand10 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.sysindexes sysindexes WHERE sysindexes.[id] = @ParamObjectID AND sysindexes.[indid] = @ParamStatisticsID AND sysindexes.[rowmodctr] <> 0) BEGIN SET @ParamStatisticsModified = 1 END' END EXECUTE sp_executesql @statement = @CurrentCommand10, @params = N'@ParamObjectID int, @ParamStatisticsID int, @ParamStatisticsModified bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamStatisticsID = @CurrentStatisticsID, @ParamStatisticsModified = @CurrentStatisticsModified OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentStatisticsModified IS NULL SET @CurrentStatisticsModified = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The statistics ' + QUOTENAME(@CurrentStatisticsName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if any rows has been modified since the most recent statistics update.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is the index on a read-only filegroup? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentCommand11 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand11 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand11 = @CurrentCommand11 + 'IF EXISTS(SELECT * FROM (SELECT filegroups.data_space_id FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.destination_data_spaces destination_data_spaces ON indexes.data_space_id = destination_data_spaces.partition_scheme_id INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.filegroups filegroups ON destination_data_spaces.data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND indexes.[object_id] = @ParamObjectID AND indexes.[index_id] = @ParamIndexID' IF @CurrentIsPartition = 1 SET @CurrentCommand11 = @CurrentCommand11 + ' AND destination_data_spaces.destination_id = @ParamPartitionNumber' SET @CurrentCommand11 = @CurrentCommand11 + ' UNION SELECT filegroups.data_space_id FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.filegroups filegroups ON indexes.data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND indexes.[object_id] = @ParamObjectID AND indexes.[index_id] = @ParamIndexID' IF @CurrentIndexType = 1 SET @CurrentCommand11 = @CurrentCommand11 + ' UNION SELECT filegroups.data_space_id FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.tables tables INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.filegroups filegroups ON tables.lob_data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND tables.[object_id] = @ParamObjectID' SET @CurrentCommand11 = @CurrentCommand11 + ') ReadOnlyFileGroups) BEGIN SET @ParamOnReadOnlyFileGroup = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand11, @params = N'@ParamObjectID int, @ParamIndexID int, @ParamPartitionNumber int, @ParamOnReadOnlyFileGroup bit OUTPUT', @ParamObjectID = @CurrentObjectID, @ParamIndexID = @CurrentIndexID, @ParamPartitionNumber = @CurrentPartitionNumber, @ParamOnReadOnlyFileGroup = @CurrentOnReadOnlyFileGroup OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentOnReadOnlyFileGroup IS NULL SET @CurrentOnReadOnlyFileGroup = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the index is on a read-only filegroup.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Is the index fragmented? IF @CurrentIndexID IS NOT NULL AND @CurrentOnReadOnlyFileGroup = 0 AND EXISTS(SELECT * FROM @ActionsPreferred) AND (EXISTS(SELECT [Priority], [Action], COUNT(*) FROM @ActionsPreferred GROUP BY [Priority], [Action] HAVING COUNT(*) <> 3) OR @PageCountLevel > 0) BEGIN SET @CurrentCommand12 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand12 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand12 = @CurrentCommand12 + 'SELECT @ParamFragmentationLevel = MAX(avg_fragmentation_in_percent), @ParamPageCount = SUM(page_count) FROM sys.dm_db_index_physical_stats(@ParamDatabaseID, @ParamObjectID, @ParamIndexID, @ParamPartitionNumber, ''LIMITED'') WHERE alloc_unit_type_desc = ''IN_ROW_DATA'' AND index_level = 0' EXECUTE sp_executesql @statement = @CurrentCommand12, @params = N'@ParamDatabaseID int, @ParamObjectID int, @ParamIndexID int, @ParamPartitionNumber int, @ParamFragmentationLevel float OUTPUT, @ParamPageCount bigint OUTPUT', @ParamDatabaseID = @CurrentDatabaseID, @ParamObjectID = @CurrentObjectID, @ParamIndexID = @CurrentIndexID, @ParamPartitionNumber = @CurrentPartitionNumber, @ParamFragmentationLevel = @CurrentFragmentationLevel OUTPUT, @ParamPageCount = @CurrentPageCount OUTPUT SET @Error = @@Error IF @Error = 1222 BEGIN SET @ErrorMessage = 'The index ' + QUOTENAME(@CurrentIndexName) + ' on the object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. The size and fragmentation of the index could not be checked.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO NoAction END END -- Select fragmentation group IF @CurrentIndexID IS NOT NULL AND @CurrentOnReadOnlyFileGroup = 0 AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN SET @CurrentFragmentationGroup = CASE WHEN @CurrentFragmentationLevel >= @FragmentationLevel2 THEN 'High' WHEN @CurrentFragmentationLevel >= @FragmentationLevel1 AND @CurrentFragmentationLevel < @FragmentationLevel2 THEN 'Medium' WHEN @CurrentFragmentationLevel < @FragmentationLevel1 THEN 'Low' END END -- Which actions are allowed? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN IF @CurrentOnReadOnlyFileGroup = 0 AND @CurrentIndexType IN (1,2,3,4,5) AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) AND (@CurrentAllowPageLocks = 1 OR @CurrentIndexType = 5) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REORGANIZE') END IF @CurrentOnReadOnlyFileGroup = 0 AND @CurrentIndexType IN (1,2,3,4,5) AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REBUILD_OFFLINE') END IF @CurrentOnReadOnlyFileGroup = 0 AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) AND (@CurrentIsPartition = 0 OR @Version >= 12) AND ((@CurrentIndexType = 1 AND @CurrentIsImageText = 0 AND @CurrentIsNewLOB = 0) OR (@CurrentIndexType = 2 AND @CurrentIsNewLOB = 0) OR (@CurrentIndexType = 1 AND @CurrentIsImageText = 0 AND @CurrentIsFileStream = 0 AND @Version >= 11) OR (@CurrentIndexType = 2 AND @Version >= 11)) AND (@CurrentIsColumnStore = 0 OR @Version < 11) AND SERVERPROPERTY('EngineEdition') IN (3,5) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REBUILD_ONLINE') END END -- Decide action IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) AND (@CurrentPageCount >= @PageCountLevel OR @PageCountLevel = 0) BEGIN IF EXISTS(SELECT [Priority], [Action], COUNT(*) FROM @ActionsPreferred GROUP BY [Priority], [Action] HAVING COUNT(*) <> 3) BEGIN SELECT @CurrentAction = [Action] FROM @ActionsPreferred WHERE FragmentationGroup = @CurrentFragmentationGroup AND [Priority] = (SELECT MIN([Priority]) FROM @ActionsPreferred WHERE FragmentationGroup = @CurrentFragmentationGroup AND [Action] IN (SELECT [Action] FROM @CurrentActionsAllowed)) END ELSE BEGIN SELECT @CurrentAction = [Action] FROM @ActionsPreferred WHERE [Priority] = (SELECT MIN([Priority]) FROM @ActionsPreferred WHERE [Action] IN (SELECT [Action] FROM @CurrentActionsAllowed)) END END -- Workaround for limitation in SQL Server, http://support.microsoft.com/kb/2292737 IF @CurrentIndexID IS NOT NULL BEGIN SET @CurrentMaxDOP = @MaxDOP IF @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @CurrentAllowPageLocks = 0 BEGIN SET @CurrentMaxDOP = 1 END END -- Update statistics? IF @CurrentStatisticsID IS NOT NULL AND ((@UpdateStatistics = 'ALL' AND (@CurrentIndexType IN (1,2,3,4,7) OR @CurrentIndexID IS NULL)) OR (@UpdateStatistics = 'INDEX' AND @CurrentIndexID IS NOT NULL AND @CurrentIndexType IN (1,2,3,4,7)) OR (@UpdateStatistics = 'COLUMNS' AND @CurrentIndexID IS NULL)) AND (@CurrentStatisticsModified = 1 OR @OnlyModifiedStatistics = 'N' OR @CurrentIsMemoryOptimized = 1) AND ((@CurrentIsPartition = 0 AND (@CurrentAction NOT IN('INDEX_REBUILD_ONLINE','INDEX_REBUILD_OFFLINE') OR @CurrentAction IS NULL)) OR (@CurrentIsPartition = 1 AND @CurrentPartitionNumber = @CurrentPartitionCount)) BEGIN SET @CurrentUpdateStatistics = 'Y' END ELSE BEGIN SET @CurrentUpdateStatistics = 'N' END -- Create comment IF @CurrentIndexID IS NOT NULL BEGIN SET @CurrentComment = 'ObjectType: ' + CASE WHEN @CurrentObjectType = 'U' THEN 'Table' WHEN @CurrentObjectType = 'V' THEN 'View' ELSE 'N/A' END + ', ' SET @CurrentComment = @CurrentComment + 'IndexType: ' + CASE WHEN @CurrentIndexType = 1 THEN 'Clustered' WHEN @CurrentIndexType = 2 THEN 'NonClustered' WHEN @CurrentIndexType = 3 THEN 'XML' WHEN @CurrentIndexType = 4 THEN 'Spatial' WHEN @CurrentIndexType = 5 THEN 'Clustered Columnstore' WHEN @CurrentIndexType = 6 THEN 'NonClustered Columnstore' WHEN @CurrentIndexType = 7 THEN 'NonClustered Hash' ELSE 'N/A' END + ', ' SET @CurrentComment = @CurrentComment + 'ImageText: ' + CASE WHEN @CurrentIsImageText = 1 THEN 'Yes' WHEN @CurrentIsImageText = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment = @CurrentComment + 'NewLOB: ' + CASE WHEN @CurrentIsNewLOB = 1 THEN 'Yes' WHEN @CurrentIsNewLOB = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment = @CurrentComment + 'FileStream: ' + CASE WHEN @CurrentIsFileStream = 1 THEN 'Yes' WHEN @CurrentIsFileStream = 0 THEN 'No' ELSE 'N/A' END + ', ' IF @Version >= 11 SET @CurrentComment = @CurrentComment + 'ColumnStore: ' + CASE WHEN @CurrentIsColumnStore = 1 THEN 'Yes' WHEN @CurrentIsColumnStore = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment = @CurrentComment + 'AllowPageLocks: ' + CASE WHEN @CurrentAllowPageLocks = 1 THEN 'Yes' WHEN @CurrentAllowPageLocks = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment = @CurrentComment + 'PageCount: ' + ISNULL(CAST(@CurrentPageCount AS nvarchar),'N/A') + ', ' SET @CurrentComment = @CurrentComment + 'Fragmentation: ' + ISNULL(CAST(@CurrentFragmentationLevel AS nvarchar),'N/A') END IF @CurrentIndexID IS NOT NULL AND (@CurrentPageCount IS NOT NULL OR @CurrentFragmentationLevel IS NOT NULL) BEGIN SET @CurrentExtendedInfo = (SELECT * FROM (SELECT CAST(@CurrentPageCount AS nvarchar) AS [PageCount], CAST(@CurrentFragmentationLevel AS nvarchar) AS Fragmentation ) ExtendedInfo FOR XML AUTO, ELEMENTS) END IF @CurrentIndexID IS NOT NULL AND @CurrentAction IS NOT NULL AND (GETDATE() < DATEADD(ss,@TimeLimit,@StartTime) OR @TimeLimit IS NULL) BEGIN SET @CurrentCommandType13 = 'ALTER_INDEX' SET @CurrentCommand13 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand13 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand13 = @CurrentCommand13 + 'ALTER INDEX ' + QUOTENAME(@CurrentIndexName) + ' ON ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) IF @CurrentAction IN('INDEX_REBUILD_ONLINE','INDEX_REBUILD_OFFLINE') BEGIN SET @CurrentCommand13 = @CurrentCommand13 + ' REBUILD' IF @CurrentIsPartition = 1 SET @CurrentCommand13 = @CurrentCommand13 + ' PARTITION = ' + CAST(@CurrentPartitionNumber AS nvarchar) SET @CurrentCommand13 = @CurrentCommand13 + ' WITH (' IF @SortInTempdb = 'Y' AND @CurrentIndexType IN(1,2,3,4) SET @CurrentCommand13 = @CurrentCommand13 + 'SORT_IN_TEMPDB = ON' IF @SortInTempdb = 'N' AND @CurrentIndexType IN(1,2,3,4) SET @CurrentCommand13 = @CurrentCommand13 + 'SORT_IN_TEMPDB = OFF' IF @CurrentIndexType IN(1,2,3,4) AND (@CurrentIsPartition = 0 OR @Version >= 12) SET @CurrentCommand13 = @CurrentCommand13 + ', ' IF @CurrentAction = 'INDEX_REBUILD_ONLINE' AND (@CurrentIsPartition = 0 OR @Version >= 12) SET @CurrentCommand13 = @CurrentCommand13 + 'ONLINE = ON' IF @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @WaitAtLowPriorityMaxDuration IS NOT NULL SET @CurrentCommand13 = @CurrentCommand13 + ' (WAIT_AT_LOW_PRIORITY (MAX_DURATION = ' + CAST(@WaitAtLowPriorityMaxDuration AS nvarchar) + ', ABORT_AFTER_WAIT = ' + UPPER(@WaitAtLowPriorityAbortAfterWait) + '))' IF @CurrentAction = 'INDEX_REBUILD_OFFLINE' AND (@CurrentIsPartition = 0 OR @Version >= 12) SET @CurrentCommand13 = @CurrentCommand13 + 'ONLINE = OFF' IF @CurrentMaxDOP IS NOT NULL SET @CurrentCommand13 = @CurrentCommand13 + ', MAXDOP = ' + CAST(@CurrentMaxDOP AS nvarchar) IF @FillFactor IS NOT NULL AND @CurrentIsPartition = 0 AND @CurrentIndexType IN(1,2,3,4) SET @CurrentCommand13 = @CurrentCommand13 + ', FILLFACTOR = ' + CAST(@FillFactor AS nvarchar) IF @PadIndex = 'Y' AND @CurrentIsPartition = 0 AND @CurrentIndexType IN(1,2,3,4) SET @CurrentCommand13 = @CurrentCommand13 + ', PAD_INDEX = ON' IF @PadIndex = 'N' AND @CurrentIsPartition = 0 AND @CurrentIndexType IN(1,2,3,4) SET @CurrentCommand13 = @CurrentCommand13 + ', PAD_INDEX = OFF' SET @CurrentCommand13 = @CurrentCommand13 + ')' END IF @CurrentAction IN('INDEX_REORGANIZE') BEGIN SET @CurrentCommand13 = @CurrentCommand13 + ' REORGANIZE' IF @CurrentIsPartition = 1 SET @CurrentCommand13 = @CurrentCommand13 + ' PARTITION = ' + CAST(@CurrentPartitionNumber AS nvarchar) SET @CurrentCommand13 = @CurrentCommand13 + ' WITH (' IF @LOBCompaction = 'Y' SET @CurrentCommand13 = @CurrentCommand13 + 'LOB_COMPACTION = ON' IF @LOBCompaction = 'N' SET @CurrentCommand13 = @CurrentCommand13 + 'LOB_COMPACTION = OFF' SET @CurrentCommand13 = @CurrentCommand13 + ')' END EXECUTE @CurrentCommandOutput13 = [dbo].[DPCommandExecute] @Command = @CurrentCommand13, @CommandType = @CurrentCommandType13, @Mode = 2, @Comment = @CurrentComment, @DatabaseName = @CurrentDatabaseName, @SchemaName = @CurrentSchemaName, @ObjectName = @CurrentObjectName, @ObjectType = @CurrentObjectType, @IndexName = @CurrentIndexName, @IndexType = @CurrentIndexType, @PartitionNumber = @CurrentPartitionNumber, @ExtendedInfo = @CurrentExtendedInfo, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput13 = @Error IF @CurrentCommandOutput13 <> 0 SET @ReturnCode = @CurrentCommandOutput13 IF @Delay > 0 BEGIN SET @CurrentDelay = DATEADD(ss,@Delay,'1900-01-01') WAITFOR DELAY @CurrentDelay END END IF @CurrentStatisticsID IS NOT NULL AND @CurrentUpdateStatistics = 'Y' AND (GETDATE() < DATEADD(ss,@TimeLimit,@StartTime) OR @TimeLimit IS NULL) BEGIN SET @CurrentCommandType14 = 'UPDATE_STATISTICS' SET @CurrentCommand14 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand14 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand14 = @CurrentCommand14 + 'UPDATE STATISTICS ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' ' + QUOTENAME(@CurrentStatisticsName) IF @StatisticsSample IS NOT NULL OR @StatisticsResample = 'Y' OR @CurrentNoRecompute = 1 SET @CurrentCommand14 = @CurrentCommand14 + ' WITH' IF @StatisticsSample = 100 SET @CurrentCommand14 = @CurrentCommand14 + ' FULLSCAN' IF @StatisticsSample IS NOT NULL AND @StatisticsSample <> 100 AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) SET @CurrentCommand14 = @CurrentCommand14 + ' SAMPLE ' + CAST(@StatisticsSample AS nvarchar) + ' PERCENT' IF @StatisticsResample = 'Y' OR (@CurrentIsMemoryOptimized = 1 AND (@StatisticsSample <> 100 OR @StatisticsSample IS NULL)) SET @CurrentCommand14 = @CurrentCommand14 + ' RESAMPLE' IF (@StatisticsSample IS NOT NULL OR @StatisticsResample = 'Y' OR @CurrentIsMemoryOptimized = 1) AND @CurrentNoRecompute = 1 SET @CurrentCommand14 = @CurrentCommand14 + ',' IF @CurrentNoRecompute = 1 SET @CurrentCommand14 = @CurrentCommand14 + ' NORECOMPUTE' EXECUTE @CurrentCommandOutput14 = [dbo].[DPCommandExecute] @Command = @CurrentCommand14, @CommandType = @CurrentCommandType14, @Mode = 2, @DatabaseName = @CurrentDatabaseName, @SchemaName = @CurrentSchemaName, @ObjectName = @CurrentObjectName, @ObjectType = @CurrentObjectType, @IndexName = @CurrentIndexName, @IndexType = @CurrentIndexType, @StatisticsName = @CurrentStatisticsName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput14 = @Error IF @CurrentCommandOutput14 <> 0 SET @ReturnCode = @CurrentCommandOutput14 END NoAction: -- Update that the index is completed UPDATE @tmpIndexesStatistics SET Completed = 1 WHERE Selected = 1 AND Completed = 0 AND ID = @CurrentIxID -- Clear variables SET @CurrentCommand02 = NULL SET @CurrentCommand03 = NULL SET @CurrentCommand04 = NULL SET @CurrentCommand05 = NULL SET @CurrentCommand06 = NULL SET @CurrentCommand07 = NULL SET @CurrentCommand08 = NULL SET @CurrentCommand09 = NULL SET @CurrentCommand10 = NULL SET @CurrentCommand11 = NULL SET @CurrentCommand12 = NULL SET @CurrentCommand13 = NULL SET @CurrentCommand14 = NULL SET @CurrentCommandOutput13 = NULL SET @CurrentCommandOutput14 = NULL SET @CurrentCommandType13 = NULL SET @CurrentCommandType14 = NULL SET @CurrentIxID = NULL SET @CurrentSchemaID = NULL SET @CurrentSchemaName = NULL SET @CurrentObjectID = NULL SET @CurrentObjectName = NULL SET @CurrentObjectType = NULL SET @CurrentIsMemoryOptimized = NULL SET @CurrentIndexID = NULL SET @CurrentIndexName = NULL SET @CurrentIndexType = NULL SET @CurrentStatisticsID = NULL SET @CurrentStatisticsName = NULL SET @CurrentPartitionID = NULL SET @CurrentPartitionNumber = NULL SET @CurrentPartitionCount = NULL SET @CurrentIsPartition = NULL SET @CurrentIndexExists = NULL SET @CurrentStatisticsExists = NULL SET @CurrentIsImageText = NULL SET @CurrentIsNewLOB = NULL SET @CurrentIsFileStream = NULL SET @CurrentIsColumnStore = NULL SET @CurrentAllowPageLocks = NULL SET @CurrentNoRecompute = NULL SET @CurrentStatisticsModified = NULL SET @CurrentOnReadOnlyFileGroup = NULL SET @CurrentFragmentationLevel = NULL SET @CurrentPageCount = NULL SET @CurrentFragmentationGroup = NULL SET @CurrentAction = NULL SET @CurrentMaxDOP = NULL SET @CurrentUpdateStatistics = NULL SET @CurrentComment = NULL SET @CurrentExtendedInfo = NULL DELETE FROM @CurrentActionsAllowed END END -- Update that the database is completed UPDATE @tmpDatabases SET Completed = 1 WHERE Selected = 1 AND Completed = 0 AND ID = @CurrentDBID -- Clear variables SET @CurrentDBID = NULL SET @CurrentDatabaseID = NULL SET @CurrentDatabaseName = NULL SET @CurrentIsDatabaseAccessible = NULL SET @CurrentAvailabilityGroup = NULL SET @CurrentAvailabilityGroupRole = NULL SET @CurrentDatabaseMirroringRole = NULL SET @CurrentCommand01 = NULL DELETE FROM @tmpIndexesStatistics END ---------------------------------------------------------------------------------------------------- --// Log completing information //-- ---------------------------------------------------------------------------------------------------- Logging: SET @EndMessage = 'Date and time: ' + CONVERT(nvarchar,GETDATE(),120) SET @EndMessage = REPLACE(@EndMessage,'%','%%') RAISERROR(@EndMessage,10,1) WITH NOWAIT IF @ReturnCode <> 0 BEGIN RETURN @ReturnCode END ---------------------------------------------------------------------------------------------------- END GO $JobCreateBase SET @JobDescription = 'Reorganize indexes with fragmentation between 5-30%, and rebuild indexes with greater than 30% fragmentation. Also updates statistics on all tables that have changed.' SET @Job01Command01 = 'sqlcmd -E -S ' + @TokenServer + ' -d $($InfrastructureDatabase) -Q "EXECUTE [dbo].[DPIndexOptimize] @Databases = ''ALL_DATABASES'', @UpdateStatistics = ''ALL'', @OnlyModifiedStatistics = ''Y'', @LogToTable = ''$($LogToTable)'', @MSShippedObjects = ''Y''" -b' EXECUTE msdb.dbo.sp_add_job @job_name = @JobName, @description = @JobDescription, @category_name = @JobCategory, @owner_login_name = '$($JobOwner)' EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = @JobName, @subsystem = 'CMDEXEC', @command = @Job01Command01, @output_file_name = @OutputFile01 EXECUTE msdb.dbo.sp_add_jobserver @job_name = @JobName EXECUTE msdb.dbo.sp_update_job @job_name = @JobName, @enabled = $(if ($Disabled){0}else { 1 }); "@ #DPDatabaseIntegrityCheck procedure $DPDatabaseIntegrityCheck = @" USE [$InfrastructureDatabase]; GO IF OBJECT_ID('dbo.DPDatabaseIntegrityCheck', 'P') IS NOT NULL DROP PROCEDURE dbo.DPDatabaseIntegrityCheck; GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[DPDatabaseIntegrityCheck] @Databases nvarchar(max), @CheckCommands nvarchar(max) = 'CHECKDB', @PhysicalOnly nvarchar(max) = 'N', @NoIndex nvarchar(max) = 'N', @ExtendedLogicalChecks nvarchar(max) = 'N', @TabLock nvarchar(max) = 'N', @FileGroups nvarchar(max) = NULL, @Objects nvarchar(max) = NULL, @LockTimeout int = NULL, @LogToTable nvarchar(max) = 'N', @Execute nvarchar(max) = 'Y' AS BEGIN ---------------------------------------------------------------------------------------------------- --// Source: https://ola.hallengren.com Date: 1/28/2015 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON DECLARE @StartMessage nvarchar(max) DECLARE @EndMessage nvarchar(max) DECLARE @DatabaseMessage nvarchar(max) DECLARE @ErrorMessage nvarchar(max) DECLARE @Version numeric(18,10) DECLARE @AmazonRDS bit DECLARE @Cluster nvarchar(max) DECLARE @CurrentDBID int DECLARE @CurrentDatabaseID int DECLARE @CurrentDatabaseName nvarchar(max) DECLARE @CurrentIsDatabaseAccessible bit DECLARE @CurrentAvailabilityGroup nvarchar(max) DECLARE @CurrentAvailabilityGroupRole nvarchar(max) DECLARE @CurrentDatabaseMirroringRole nvarchar(max) DECLARE @CurrentFGID int DECLARE @CurrentFileGroupID int DECLARE @CurrentFileGroupName nvarchar(max) DECLARE @CurrentFileGroupExists bit DECLARE @CurrentOID int DECLARE @CurrentSchemaID int DECLARE @CurrentSchemaName nvarchar(max) DECLARE @CurrentObjectID int DECLARE @CurrentObjectName nvarchar(max) DECLARE @CurrentObjectType nvarchar(max) DECLARE @CurrentObjectExists bit DECLARE @CurrentCommand01 nvarchar(max) DECLARE @CurrentCommand02 nvarchar(max) DECLARE @CurrentCommand03 nvarchar(max) DECLARE @CurrentCommand04 nvarchar(max) DECLARE @CurrentCommand05 nvarchar(max) DECLARE @CurrentCommand06 nvarchar(max) DECLARE @CurrentCommand07 nvarchar(max) DECLARE @CurrentCommand08 nvarchar(max) DECLARE @CurrentCommand09 nvarchar(max) DECLARE @CurrentCommandOutput01 int DECLARE @CurrentCommandOutput04 int DECLARE @CurrentCommandOutput05 int DECLARE @CurrentCommandOutput08 int DECLARE @CurrentCommandOutput09 int DECLARE @CurrentCommandType01 nvarchar(max) DECLARE @CurrentCommandType04 nvarchar(max) DECLARE @CurrentCommandType05 nvarchar(max) DECLARE @CurrentCommandType08 nvarchar(max) DECLARE @CurrentCommandType09 nvarchar(max) DECLARE @tmpDatabases TABLE (ID int IDENTITY, DatabaseName nvarchar(max), DatabaseType nvarchar(max), [Snapshot] bit, Selected bit, Completed bit, PRIMARY KEY(Selected, Completed, ID)) DECLARE @tmpFileGroups TABLE (ID int IDENTITY, FileGroupID int, FileGroupName nvarchar(max), Selected bit, Completed bit, PRIMARY KEY(Selected, Completed, ID)) DECLARE @tmpObjects TABLE (ID int IDENTITY, SchemaID int, SchemaName nvarchar(max), ObjectID int, ObjectName nvarchar(max), ObjectType nvarchar(max), Selected bit, Completed bit, PRIMARY KEY(Selected, Completed, ID)) DECLARE @SelectedDatabases TABLE (DatabaseName nvarchar(max), DatabaseType nvarchar(max), Selected bit) DECLARE @SelectedFileGroups TABLE (DatabaseName nvarchar(max), FileGroupName nvarchar(max), Selected bit) DECLARE @SelectedObjects TABLE (DatabaseName nvarchar(max), SchemaName nvarchar(max), ObjectName nvarchar(max), Selected bit) DECLARE @SelectedCheckCommands TABLE (CheckCommand nvarchar(max)) DECLARE @Error int DECLARE @ReturnCode int SET @Error = 0 SET @ReturnCode = 0 SET @Version = CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - 1) + '.' + REPLACE(RIGHT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)), LEN(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)))),'.','') AS numeric(18,10)) SET @AmazonRDS = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- ---------------------------------------------------------------------------------------------------- SET @StartMessage = 'Date and time: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Server: ' + CAST(SERVERPROPERTY('ServerName') AS nvarchar) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Version: ' + CAST(SERVERPROPERTY('ProductVersion') AS nvarchar) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Edition: ' + CAST(SERVERPROPERTY('Edition') AS nvarchar) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + (SELECT QUOTENAME(schemas.name) FROM sys.schemas schemas INNER JOIN sys.objects objects ON schemas.[schema_id] = objects.[schema_id] WHERE [object_id] = @@PROCID) + '.' + QUOTENAME(OBJECT_NAME(@@PROCID)) + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Parameters: @Databases = ' + ISNULL('''' + REPLACE(@Databases,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @CheckCommands = ' + ISNULL('''' + REPLACE(@CheckCommands,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @PhysicalOnly = ' + ISNULL('''' + REPLACE(@PhysicalOnly,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @NoIndex = ' + ISNULL('''' + REPLACE(@NoIndex,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @ExtendedLogicalChecks = ' + ISNULL('''' + REPLACE(@ExtendedLogicalChecks,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @TabLock = ' + ISNULL('''' + REPLACE(@TabLock,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @FileGroups = ' + ISNULL('''' + REPLACE(@FileGroups,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @Objects = ' + ISNULL('''' + REPLACE(@Objects,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @LockTimeout = ' + ISNULL(CAST(@LockTimeout AS nvarchar),'NULL') SET @StartMessage = @StartMessage + ', @LogToTable = ' + ISNULL('''' + REPLACE(@LogToTable,'''','''''') + '''','NULL') SET @StartMessage = @StartMessage + ', @Execute = ' + ISNULL('''' + REPLACE(@Execute,'''','''''') + '''','NULL') + CHAR(13) + CHAR(10) SET @StartMessage = @StartMessage + 'Source: https://ola.hallengren.com' + CHAR(13) + CHAR(10) SET @StartMessage = REPLACE(@StartMessage,'%','%%') + ' ' RAISERROR(@StartMessage,10,1) WITH NOWAIT ---------------------------------------------------------------------------------------------------- --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- IF NOT EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'P' AND schemas.[name] = 'dbo' AND objects.[name] = 'DPCommandExecute') BEGIN SET @ErrorMessage = 'The stored procedure DPCommandExecute is missing. Download https://ola.hallengren.com/scripts/CommandExecute.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'P' AND schemas.[name] = 'dbo' AND objects.[name] = 'DPCommandExecute' AND (OBJECT_DEFINITION(objects.[object_id]) NOT LIKE '%@LogToTable%' OR OBJECT_DEFINITION(objects.[object_id]) LIKE '%LOCK_TIMEOUT%')) BEGIN SET @ErrorMessage = 'The stored procedure DPCommandExecute needs to be updated. Download https://ola.hallengren.com/scripts/CommandExecute.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LogToTable = 'Y' AND NOT EXISTS (SELECT * FROM sys.objects objects INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id] WHERE objects.[type] = 'U' AND schemas.[name] = 'dbo' AND objects.[name] = 'CommandLog') BEGIN SET @ErrorMessage = 'The table CommandLog is missing. Download https://ola.hallengren.com/scripts/CommandLog.sql.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF SERVERPROPERTY('EngineEdition') = 5 AND @Version < 12 BEGIN SET @ErrorMessage = 'The stored procedure DPDatabaseIntegrityCheck is not supported on this version of Azure SQL Database.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Error <> 0 BEGIN SET @ReturnCode = @Error GOTO Logging END ---------------------------------------------------------------------------------------------------- --// Select databases //-- ---------------------------------------------------------------------------------------------------- SET @Databases = REPLACE(@Databases, ', ', ','); WITH Databases1 (StartPosition, EndPosition, DatabaseItem) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Databases, 1), 0), LEN(@Databases) + 1) AS EndPosition, SUBSTRING(@Databases, 1, ISNULL(NULLIF(CHARINDEX(',', @Databases, 1), 0), LEN(@Databases) + 1) - 1) AS DatabaseItem WHERE @Databases IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Databases, EndPosition + 1), 0), LEN(@Databases) + 1) AS EndPosition, SUBSTRING(@Databases, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @Databases, EndPosition + 1), 0), LEN(@Databases) + 1) - EndPosition - 1) AS DatabaseItem FROM Databases1 WHERE EndPosition < LEN(@Databases) + 1 ), Databases2 (DatabaseItem, Selected) AS ( SELECT CASE WHEN DatabaseItem LIKE '-%' THEN RIGHT(DatabaseItem,LEN(DatabaseItem) - 1) ELSE DatabaseItem END AS DatabaseItem, CASE WHEN DatabaseItem LIKE '-%' THEN 0 ELSE 1 END AS Selected FROM Databases1 ), Databases3 (DatabaseItem, DatabaseType, Selected) AS ( SELECT CASE WHEN DatabaseItem IN('ALL_DATABASES','SYSTEM_DATABASES','USER_DATABASES') THEN '%' ELSE DatabaseItem END AS DatabaseItem, CASE WHEN DatabaseItem = 'SYSTEM_DATABASES' THEN 'S' WHEN DatabaseItem = 'USER_DATABASES' THEN 'U' ELSE NULL END AS DatabaseType, Selected FROM Databases2 ), Databases4 (DatabaseName, DatabaseType, Selected) AS ( SELECT CASE WHEN LEFT(DatabaseItem,1) = '[' AND RIGHT(DatabaseItem,1) = ']' THEN PARSENAME(DatabaseItem,1) ELSE DatabaseItem END AS DatabaseItem, DatabaseType, Selected FROM Databases3 ) INSERT INTO @SelectedDatabases (DatabaseName, DatabaseType, Selected) SELECT DatabaseName, DatabaseType, Selected FROM Databases4 OPTION (MAXRECURSION 0) INSERT INTO @tmpDatabases (DatabaseName, DatabaseType, [Snapshot], Selected, Completed) SELECT [name] AS DatabaseName, CASE WHEN name IN('master','msdb','model') THEN 'S' ELSE 'U' END AS DatabaseType, CASE WHEN source_database_id IS NOT NULL THEN 1 ELSE 0 END AS [Snapshot], 0 AS Selected, 0 AS Completed FROM sys.databases ORDER BY [name] ASC UPDATE tmpDatabases SET tmpDatabases.Selected = SelectedDatabases.Selected FROM @tmpDatabases tmpDatabases INNER JOIN @SelectedDatabases SelectedDatabases ON tmpDatabases.DatabaseName LIKE REPLACE(SelectedDatabases.DatabaseName,'_','[_]') AND (tmpDatabases.DatabaseType = SelectedDatabases.DatabaseType OR SelectedDatabases.DatabaseType IS NULL) AND NOT ((tmpDatabases.DatabaseName = 'tempdb' OR tmpDatabases.[Snapshot] = 1) AND tmpDatabases.DatabaseName <> SelectedDatabases.DatabaseName) WHERE SelectedDatabases.Selected = 1 UPDATE tmpDatabases SET tmpDatabases.Selected = SelectedDatabases.Selected FROM @tmpDatabases tmpDatabases INNER JOIN @SelectedDatabases SelectedDatabases ON tmpDatabases.DatabaseName LIKE REPLACE(SelectedDatabases.DatabaseName,'_','[_]') AND (tmpDatabases.DatabaseType = SelectedDatabases.DatabaseType OR SelectedDatabases.DatabaseType IS NULL) AND NOT ((tmpDatabases.DatabaseName = 'tempdb' OR tmpDatabases.[Snapshot] = 1) AND tmpDatabases.DatabaseName <> SelectedDatabases.DatabaseName) WHERE SelectedDatabases.Selected = 0 IF @Databases IS NULL OR NOT EXISTS(SELECT * FROM @SelectedDatabases) OR EXISTS(SELECT * FROM @SelectedDatabases WHERE DatabaseName IS NULL OR DatabaseName = '') BEGIN SET @ErrorMessage = 'The value for the parameter @Databases is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END ---------------------------------------------------------------------------------------------------- --// Select filegroups //-- ---------------------------------------------------------------------------------------------------- SET @FileGroups = REPLACE(@FileGroups, ', ', ','); WITH FileGroups1 (StartPosition, EndPosition, FileGroupItem) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FileGroups, 1), 0), LEN(@FileGroups) + 1) AS EndPosition, SUBSTRING(@FileGroups, 1, ISNULL(NULLIF(CHARINDEX(',', @FileGroups, 1), 0), LEN(@FileGroups) + 1) - 1) AS FileGroupItem WHERE @FileGroups IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @FileGroups, EndPosition + 1), 0), LEN(@FileGroups) + 1) AS EndPosition, SUBSTRING(@FileGroups, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @FileGroups, EndPosition + 1), 0), LEN(@FileGroups) + 1) - EndPosition - 1) AS FileGroupItem FROM FileGroups1 WHERE EndPosition < LEN(@FileGroups) + 1 ), FileGroups2 (FileGroupItem, Selected) AS ( SELECT CASE WHEN FileGroupItem LIKE '-%' THEN RIGHT(FileGroupItem,LEN(FileGroupItem) - 1) ELSE FileGroupItem END AS FileGroupItem, CASE WHEN FileGroupItem LIKE '-%' THEN 0 ELSE 1 END AS Selected FROM FileGroups1 ), FileGroups3 (FileGroupItem, Selected) AS ( SELECT CASE WHEN FileGroupItem = 'ALL_FILEGROUPS' THEN '%.%' ELSE FileGroupItem END AS FileGroupItem, Selected FROM FileGroups2 ), FileGroups4 (DatabaseName, FileGroupName, Selected) AS ( SELECT CASE WHEN PARSENAME(FileGroupItem,4) IS NULL AND PARSENAME(FileGroupItem,3) IS NULL THEN PARSENAME(FileGroupItem,2) ELSE NULL END AS DatabaseName, CASE WHEN PARSENAME(FileGroupItem,4) IS NULL AND PARSENAME(FileGroupItem,3) IS NULL THEN PARSENAME(FileGroupItem,1) ELSE NULL END AS FileGroupName, Selected FROM FileGroups3 ) INSERT INTO @SelectedFileGroups (DatabaseName, FileGroupName, Selected) SELECT DatabaseName, FileGroupName, Selected FROM FileGroups4 OPTION (MAXRECURSION 0) ---------------------------------------------------------------------------------------------------- --// Select objects //-- ---------------------------------------------------------------------------------------------------- SET @Objects = REPLACE(@Objects, ', ', ','); WITH Objects1 (StartPosition, EndPosition, ObjectItem) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Objects, 1), 0), LEN(@Objects) + 1) AS EndPosition, SUBSTRING(@Objects, 1, ISNULL(NULLIF(CHARINDEX(',', @Objects, 1), 0), LEN(@Objects) + 1) - 1) AS ObjectItem WHERE @Objects IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @Objects, EndPosition + 1), 0), LEN(@Objects) + 1) AS EndPosition, SUBSTRING(@Objects, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @Objects, EndPosition + 1), 0), LEN(@Objects) + 1) - EndPosition - 1) AS ObjectItem FROM Objects1 WHERE EndPosition < LEN(@Objects) + 1 ), Objects2 (ObjectItem, Selected) AS ( SELECT CASE WHEN ObjectItem LIKE '-%' THEN RIGHT(ObjectItem,LEN(ObjectItem) - 1) ELSE ObjectItem END AS ObjectItem, CASE WHEN ObjectItem LIKE '-%' THEN 0 ELSE 1 END AS Selected FROM Objects1 ), Objects3 (ObjectItem, Selected) AS ( SELECT CASE WHEN ObjectItem = 'ALL_OBJECTS' THEN '%.%.%' ELSE ObjectItem END AS ObjectItem, Selected FROM Objects2 ), Objects4 (DatabaseName, SchemaName, ObjectName, Selected) AS ( SELECT CASE WHEN PARSENAME(ObjectItem,4) IS NULL THEN PARSENAME(ObjectItem,3) ELSE NULL END AS DatabaseName, CASE WHEN PARSENAME(ObjectItem,4) IS NULL THEN PARSENAME(ObjectItem,2) ELSE NULL END AS SchemaName, CASE WHEN PARSENAME(ObjectItem,4) IS NULL THEN PARSENAME(ObjectItem,1) ELSE NULL END AS ObjectName, Selected FROM Objects3 ) INSERT INTO @SelectedObjects (DatabaseName, SchemaName, ObjectName, Selected) SELECT DatabaseName, SchemaName, ObjectName, Selected FROM Objects4 OPTION (MAXRECURSION 0); ---------------------------------------------------------------------------------------------------- --// Select check commands //-- ---------------------------------------------------------------------------------------------------- WITH CheckCommands (StartPosition, EndPosition, CheckCommand) AS ( SELECT 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @CheckCommands, 1), 0), LEN(@CheckCommands) + 1) AS EndPosition, SUBSTRING(@CheckCommands, 1, ISNULL(NULLIF(CHARINDEX(',', @CheckCommands, 1), 0), LEN(@CheckCommands) + 1) - 1) AS CheckCommand WHERE @CheckCommands IS NOT NULL UNION ALL SELECT CAST(EndPosition AS int) + 1 AS StartPosition, ISNULL(NULLIF(CHARINDEX(',', @CheckCommands, EndPosition + 1), 0), LEN(@CheckCommands) + 1) AS EndPosition, SUBSTRING(@CheckCommands, EndPosition + 1, ISNULL(NULLIF(CHARINDEX(',', @CheckCommands, EndPosition + 1), 0), LEN(@CheckCommands) + 1) - EndPosition - 1) AS CheckCommand FROM CheckCommands WHERE EndPosition < LEN(@CheckCommands) + 1 ) INSERT INTO @SelectedCheckCommands (CheckCommand) SELECT CheckCommand FROM CheckCommands OPTION (MAXRECURSION 0) ---------------------------------------------------------------------------------------------------- --// Check input parameters //-- ---------------------------------------------------------------------------------------------------- IF EXISTS (SELECT * FROM @SelectedCheckCommands WHERE CheckCommand NOT IN('CHECKDB','CHECKFILEGROUP','CHECKALLOC','CHECKTABLE','CHECKCATALOG')) OR EXISTS (SELECT * FROM @SelectedCheckCommands GROUP BY CheckCommand HAVING COUNT(*) > 1) OR NOT EXISTS (SELECT * FROM @SelectedCheckCommands) OR (EXISTS (SELECT * FROM @SelectedCheckCommands WHERE CheckCommand IN('CHECKDB')) AND EXISTS (SELECT CheckCommand FROM @SelectedCheckCommands WHERE CheckCommand IN('CHECKFILEGROUP','CHECKALLOC','CHECKTABLE','CHECKCATALOG'))) OR (EXISTS (SELECT * FROM @SelectedCheckCommands WHERE CheckCommand IN('CHECKFILEGROUP')) AND EXISTS (SELECT CheckCommand FROM @SelectedCheckCommands WHERE CheckCommand IN('CHECKALLOC','CHECKTABLE'))) BEGIN SET @ErrorMessage = 'The value for the parameter @CheckCommands is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @PhysicalOnly NOT IN ('Y','N') OR @PhysicalOnly IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @PhysicalOnly is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @NoIndex NOT IN ('Y','N') OR @NoIndex IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @NoIndex is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @ExtendedLogicalChecks NOT IN ('Y','N') OR @ExtendedLogicalChecks IS NULL OR (@ExtendedLogicalChecks = 'Y' AND NOT @Version >= 10) OR (@PhysicalOnly = 'Y' AND @ExtendedLogicalChecks = 'Y') BEGIN SET @ErrorMessage = 'The value for the parameter @ExtendedLogicalChecks is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @TabLock NOT IN ('Y','N') OR @TabLock IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @TabLock is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS(SELECT * FROM @SelectedFileGroups WHERE DatabaseName IS NULL OR FileGroupName IS NULL) OR (@FileGroups IS NOT NULL AND NOT EXISTS(SELECT * FROM @SelectedFileGroups)) OR (@FileGroups IS NOT NULL AND NOT EXISTS (SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKFILEGROUP')) BEGIN SET @ErrorMessage = 'The value for the parameter @FileGroups is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF EXISTS(SELECT * FROM @SelectedObjects WHERE DatabaseName IS NULL OR SchemaName IS NULL OR ObjectName IS NULL) OR (@Objects IS NOT NULL AND NOT EXISTS(SELECT * FROM @SelectedObjects)) OR (@Objects IS NOT NULL AND NOT EXISTS (SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKTABLE')) BEGIN SET @ErrorMessage = 'The value for the parameter @Objects is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LockTimeout < 0 BEGIN SET @ErrorMessage = 'The value for the parameter @LockTimeout is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @LogToTable NOT IN('Y','N') OR @LogToTable IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @LogToTable is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Execute NOT IN('Y','N') OR @Execute IS NULL BEGIN SET @ErrorMessage = 'The value for the parameter @Execute is not supported.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@Error END IF @Error <> 0 BEGIN SET @ErrorMessage = 'The documentation is available at https://ola.hallengren.com/sql-server-integrity-check.html.' + CHAR(13) + CHAR(10) + ' ' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @ReturnCode = @Error GOTO Logging END ---------------------------------------------------------------------------------------------------- --// Check Availability Group cluster name //-- ---------------------------------------------------------------------------------------------------- IF @Version >= 11 AND SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @Cluster = cluster_name FROM sys.dm_hadr_cluster END ---------------------------------------------------------------------------------------------------- --// Execute commands //-- ---------------------------------------------------------------------------------------------------- WHILE EXISTS (SELECT * FROM @tmpDatabases WHERE Selected = 1 AND Completed = 0) BEGIN SELECT TOP 1 @CurrentDBID = ID, @CurrentDatabaseName = DatabaseName FROM @tmpDatabases WHERE Selected = 1 AND Completed = 0 ORDER BY ID ASC SET @CurrentDatabaseID = DB_ID(@CurrentDatabaseName) IF DATABASEPROPERTYEX(@CurrentDatabaseName,'Status') = 'ONLINE' AND SERVERPROPERTY('EngineEdition') <> 5 BEGIN IF EXISTS (SELECT * FROM sys.database_recovery_status WHERE database_id = @CurrentDatabaseID AND database_guid IS NOT NULL) BEGIN SET @CurrentIsDatabaseAccessible = 1 END ELSE BEGIN SET @CurrentIsDatabaseAccessible = 0 END END IF @Version >= 11 AND @Cluster IS NOT NULL BEGIN SELECT @CurrentAvailabilityGroup = availability_groups.name, @CurrentAvailabilityGroupRole = dm_hadr_availability_replica_states.role_desc FROM sys.databases databases INNER JOIN sys.availability_databases_cluster availability_databases_cluster ON databases.group_database_id = availability_databases_cluster.group_database_id INNER JOIN sys.availability_groups availability_groups ON availability_databases_cluster.group_id = availability_groups.group_id INNER JOIN sys.dm_hadr_availability_replica_states dm_hadr_availability_replica_states ON availability_groups.group_id = dm_hadr_availability_replica_states.group_id AND databases.replica_id = dm_hadr_availability_replica_states.replica_id WHERE databases.name = @CurrentDatabaseName END IF SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) FROM sys.database_mirroring WHERE database_id = @CurrentDatabaseID END -- Set database message SET @DatabaseMessage = 'Date and time: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Database: ' + QUOTENAME(@CurrentDatabaseName) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Status: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'Status') AS nvarchar) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Standby: ' + CASE WHEN DATABASEPROPERTYEX(@CurrentDatabaseName,'IsInStandBy') = 1 THEN 'Yes' ELSE 'No' END + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Updateability: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'Updateability') AS nvarchar) + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'User access: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'UserAccess') AS nvarchar) + CHAR(13) + CHAR(10) IF @CurrentIsDatabaseAccessible IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Is accessible: ' + CASE WHEN @CurrentIsDatabaseAccessible = 1 THEN 'Yes' ELSE 'No' END + CHAR(13) + CHAR(10) SET @DatabaseMessage = @DatabaseMessage + 'Recovery model: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabaseName,'Recovery') AS nvarchar) + CHAR(13) + CHAR(10) IF @CurrentAvailabilityGroup IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Availability group: ' + @CurrentAvailabilityGroup + CHAR(13) + CHAR(10) IF @CurrentAvailabilityGroup IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Availability group role: ' + @CurrentAvailabilityGroupRole + CHAR(13) + CHAR(10) IF @CurrentDatabaseMirroringRole IS NOT NULL SET @DatabaseMessage = @DatabaseMessage + 'Database mirroring role: ' + @CurrentDatabaseMirroringRole + CHAR(13) + CHAR(10) SET @DatabaseMessage = REPLACE(@DatabaseMessage,'%','%%') + ' ' RAISERROR(@DatabaseMessage,10,1) WITH NOWAIT IF DATABASEPROPERTYEX(@CurrentDatabaseName,'Status') = 'ONLINE' AND (@CurrentIsDatabaseAccessible = 1 OR @CurrentIsDatabaseAccessible IS NULL) BEGIN -- Check database IF EXISTS(SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKDB') BEGIN SET @CurrentCommandType01 = 'DBCC_CHECKDB' SET @CurrentCommand01 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand01 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand01 = @CurrentCommand01 + 'DBCC CHECKDB (' + QUOTENAME(@CurrentDatabaseName) IF @NoIndex = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ', NOINDEX' SET @CurrentCommand01 = @CurrentCommand01 + ') WITH NO_INFOMSGS, ALL_ERRORMSGS' IF @PhysicalOnly = 'N' SET @CurrentCommand01 = @CurrentCommand01 + ', DATA_PURITY' IF @PhysicalOnly = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ', PHYSICAL_ONLY' IF @ExtendedLogicalChecks = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ', EXTENDED_LOGICAL_CHECKS' IF @TabLock = 'Y' SET @CurrentCommand01 = @CurrentCommand01 + ', TABLOCK' EXECUTE @CurrentCommandOutput01 = [dbo].[DPCommandExecute] @Command = @CurrentCommand01, @CommandType = @CurrentCommandType01, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput01 = @Error IF @CurrentCommandOutput01 <> 0 SET @ReturnCode = @CurrentCommandOutput01 END -- Check filegroups IF EXISTS(SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKFILEGROUP') BEGIN SET @CurrentCommand02 = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT data_space_id AS FileGroupID, name AS FileGroupName, 0 AS Selected, 0 AS Completed FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.filegroups filegroups WHERE [type] <> ''FX'' ORDER BY CASE WHEN filegroups.name = ''PRIMARY'' THEN 1 ELSE 0 END DESC, filegroups.name ASC' INSERT INTO @tmpFileGroups (FileGroupID, FileGroupName, Selected, Completed) EXECUTE sp_executesql @statement = @CurrentCommand02 SET @Error = @@Error IF @Error <> 0 SET @ReturnCode = @Error IF @FileGroups IS NULL BEGIN UPDATE tmpFileGroups SET tmpFileGroups.Selected = 1 FROM @tmpFileGroups tmpFileGroups END ELSE BEGIN UPDATE tmpFileGroups SET tmpFileGroups.Selected = SelectedFileGroups.Selected FROM @tmpFileGroups tmpFileGroups INNER JOIN @SelectedFileGroups SelectedFileGroups ON @CurrentDatabaseName LIKE REPLACE(SelectedFileGroups.DatabaseName,'_','[_]') AND tmpFileGroups.FileGroupName LIKE REPLACE(SelectedFileGroups.FileGroupName,'_','[_]') WHERE SelectedFileGroups.Selected = 1 UPDATE tmpFileGroups SET tmpFileGroups.Selected = SelectedFileGroups.Selected FROM @tmpFileGroups tmpFileGroups INNER JOIN @SelectedFileGroups SelectedFileGroups ON @CurrentDatabaseName LIKE REPLACE(SelectedFileGroups.DatabaseName,'_','[_]') AND tmpFileGroups.FileGroupName LIKE REPLACE(SelectedFileGroups.FileGroupName,'_','[_]') WHERE SelectedFileGroups.Selected = 0 END WHILE EXISTS (SELECT * FROM @tmpFileGroups WHERE Selected = 1 AND Completed = 0) BEGIN SELECT TOP 1 @CurrentFGID = ID, @CurrentFileGroupID = FileGroupID, @CurrentFileGroupName = FileGroupName FROM @tmpFileGroups WHERE Selected = 1 AND Completed = 0 ORDER BY ID ASC -- Does the filegroup exist? SET @CurrentCommand03 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand03 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand03 = @CurrentCommand03 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.filegroups filegroups WHERE [type] <> ''FX'' AND filegroups.data_space_id = @ParamFileGroupID AND filegroups.[name] = @ParamFileGroupName) BEGIN SET @ParamFileGroupExists = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand03, @params = N'@ParamFileGroupID int, @ParamFileGroupName sysname, @ParamFileGroupExists bit OUTPUT', @ParamFileGroupID = @CurrentFileGroupID, @ParamFileGroupName = @CurrentFileGroupName, @ParamFileGroupExists = @CurrentFileGroupExists OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentFileGroupExists IS NULL SET @CurrentFileGroupExists = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The file group ' + QUOTENAME(@CurrentFileGroupName) + ' in the database ' + QUOTENAME(@CurrentDatabaseName) + ' is locked. It could not be checked if the filegroup exists.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error END IF @CurrentFileGroupExists = 1 BEGIN SET @CurrentCommandType04 = 'DBCC_CHECKFILEGROUP' SET @CurrentCommand04 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand04 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand04 = @CurrentCommand04 + 'USE ' + QUOTENAME(@CurrentDatabaseName) + '; DBCC CHECKFILEGROUP (' + QUOTENAME(@CurrentFileGroupName) IF @NoIndex = 'Y' SET @CurrentCommand04 = @CurrentCommand04 + ', NOINDEX' SET @CurrentCommand04 = @CurrentCommand04 + ') WITH NO_INFOMSGS, ALL_ERRORMSGS' IF @PhysicalOnly = 'Y' SET @CurrentCommand04 = @CurrentCommand04 + ', PHYSICAL_ONLY' IF @TabLock = 'Y' SET @CurrentCommand04 = @CurrentCommand04 + ', TABLOCK' EXECUTE @CurrentCommandOutput04 = [dbo].[DPCommandExecute] @Command = @CurrentCommand04, @CommandType = @CurrentCommandType04, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput04 = @Error IF @CurrentCommandOutput04 <> 0 SET @ReturnCode = @CurrentCommandOutput04 END UPDATE @tmpFileGroups SET Completed = 1 WHERE Selected = 1 AND Completed = 0 AND ID = @CurrentFGID SET @CurrentFGID = NULL SET @CurrentFileGroupID = NULL SET @CurrentFileGroupName = NULL SET @CurrentFileGroupExists = NULL SET @CurrentCommand03 = NULL SET @CurrentCommand04 = NULL SET @CurrentCommandOutput04 = NULL SET @CurrentCommandType04 = NULL END END -- Check disk space allocation structures IF EXISTS(SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKALLOC') BEGIN SET @CurrentCommandType05 = 'DBCC_CHECKALLOC' SET @CurrentCommand05 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand05 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand05 = @CurrentCommand05 + 'DBCC CHECKALLOC (' + QUOTENAME(@CurrentDatabaseName) SET @CurrentCommand05 = @CurrentCommand05 + ') WITH NO_INFOMSGS, ALL_ERRORMSGS' IF @TabLock = 'Y' SET @CurrentCommand05 = @CurrentCommand05 + ', TABLOCK' EXECUTE @CurrentCommandOutput05 = [dbo].[DPCommandExecute] @Command = @CurrentCommand05, @CommandType = @CurrentCommandType05, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput05 = @Error IF @CurrentCommandOutput05 <> 0 SET @ReturnCode = @CurrentCommandOutput05 END -- Check objects IF EXISTS(SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKTABLE') BEGIN SET @CurrentCommand06 = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT schemas.[schema_id] AS SchemaID, schemas.[name] AS SchemaName, objects.[object_id] AS ObjectID, objects.[name] AS ObjectName, RTRIM(objects.[type]) AS ObjectType, 0 AS Selected, 0 AS Completed FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.schema_id = schemas.schema_id LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.tables tables ON objects.object_id = tables.object_id WHERE objects.[type] IN(''U'',''V'') AND EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes WHERE indexes.object_id = objects.object_id)' + CASE WHEN @Version >= 12 THEN ' AND (tables.is_memory_optimized = 0 OR is_memory_optimized IS NULL)' ELSE '' END + ' ORDER BY schemas.name ASC, objects.name ASC' INSERT INTO @tmpObjects (SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, Selected, Completed) EXECUTE sp_executesql @statement = @CurrentCommand06 SET @Error = @@Error IF @Error <> 0 SET @ReturnCode = @Error IF @Objects IS NULL BEGIN UPDATE tmpObjects SET tmpObjects.Selected = 1 FROM @tmpObjects tmpObjects END ELSE BEGIN UPDATE tmpObjects SET tmpObjects.Selected = SelectedObjects.Selected FROM @tmpObjects tmpObjects INNER JOIN @SelectedObjects SelectedObjects ON @CurrentDatabaseName LIKE REPLACE(SelectedObjects.DatabaseName,'_','[_]') AND tmpObjects.SchemaName LIKE REPLACE(SelectedObjects.SchemaName,'_','[_]') AND tmpObjects.ObjectName LIKE REPLACE(SelectedObjects.ObjectName,'_','[_]') WHERE SelectedObjects.Selected = 1 UPDATE tmpObjects SET tmpObjects.Selected = SelectedObjects.Selected FROM @tmpObjects tmpObjects INNER JOIN @SelectedObjects SelectedObjects ON @CurrentDatabaseName LIKE REPLACE(SelectedObjects.DatabaseName,'_','[_]') AND tmpObjects.SchemaName LIKE REPLACE(SelectedObjects.SchemaName,'_','[_]') AND tmpObjects.ObjectName LIKE REPLACE(SelectedObjects.ObjectName,'_','[_]') WHERE SelectedObjects.Selected = 0 END WHILE EXISTS (SELECT * FROM @tmpObjects WHERE Selected = 1 AND Completed = 0) BEGIN SELECT TOP 1 @CurrentOID = ID, @CurrentSchemaID = SchemaID, @CurrentSchemaName = SchemaName, @CurrentObjectID = ObjectID, @CurrentObjectName = ObjectName, @CurrentObjectType = ObjectType FROM @tmpObjects WHERE Selected = 1 AND Completed = 0 ORDER BY ID ASC -- Does the object exist? SET @CurrentCommand07 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand07 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand07 = @CurrentCommand07 + 'IF EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.objects objects INNER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.schemas schemas ON objects.schema_id = schemas.schema_id LEFT OUTER JOIN ' + QUOTENAME(@CurrentDatabaseName) + '.sys.tables tables ON objects.object_id = tables.object_id WHERE objects.[type] IN(''U'',''V'') AND EXISTS(SELECT * FROM ' + QUOTENAME(@CurrentDatabaseName) + '.sys.indexes indexes WHERE indexes.object_id = objects.object_id)' + CASE WHEN @Version >= 12 THEN ' AND (tables.is_memory_optimized = 0 OR is_memory_optimized IS NULL)' ELSE '' END + ' AND schemas.[schema_id] = @ParamSchemaID AND schemas.[name] = @ParamSchemaName AND objects.[object_id] = @ParamObjectID AND objects.[name] = @ParamObjectName AND objects.[type] = @ParamObjectType) BEGIN SET @ParamObjectExists = 1 END' EXECUTE sp_executesql @statement = @CurrentCommand07, @params = N'@ParamSchemaID int, @ParamSchemaName sysname, @ParamObjectID int, @ParamObjectName sysname, @ParamObjectType sysname, @ParamObjectExists bit OUTPUT', @ParamSchemaID = @CurrentSchemaID, @ParamSchemaName = @CurrentSchemaName, @ParamObjectID = @CurrentObjectID, @ParamObjectName = @CurrentObjectName, @ParamObjectType = @CurrentObjectType, @ParamObjectExists = @CurrentObjectExists OUTPUT SET @Error = @@Error IF @Error = 0 AND @CurrentObjectExists IS NULL SET @CurrentObjectExists = 0 IF @Error = 1222 BEGIN SET @ErrorMessage = 'The object ' + QUOTENAME(@CurrentDatabaseName) + '.' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + ' is locked. It could not be checked if the object exists.' + CHAR(13) + CHAR(10) + ' ' SET @ErrorMessage = REPLACE(@ErrorMessage,'%','%%') RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END IF @Error <> 0 BEGIN SET @ReturnCode = @Error END IF @CurrentObjectExists = 1 BEGIN SET @CurrentCommandType08 = 'DBCC_CHECKTABLE' SET @CurrentCommand08 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand08 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand08 = @CurrentCommand08 + 'USE ' + QUOTENAME(@CurrentDatabaseName) + '; DBCC CHECKTABLE (''' + QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName) + '''' IF @NoIndex = 'Y' SET @CurrentCommand08 = @CurrentCommand08 + ', NOINDEX' SET @CurrentCommand08 = @CurrentCommand08 + ') WITH NO_INFOMSGS, ALL_ERRORMSGS' IF @PhysicalOnly = 'N' SET @CurrentCommand08 = @CurrentCommand08 + ', DATA_PURITY' IF @PhysicalOnly = 'Y' SET @CurrentCommand08 = @CurrentCommand08 + ', PHYSICAL_ONLY' IF @ExtendedLogicalChecks = 'Y' SET @CurrentCommand08 = @CurrentCommand08 + ', EXTENDED_LOGICAL_CHECKS' IF @TabLock = 'Y' SET @CurrentCommand08 = @CurrentCommand08 + ', TABLOCK' EXECUTE @CurrentCommandOutput08 = [dbo].[DPCommandExecute] @Command = @CurrentCommand08, @CommandType = @CurrentCommandType08, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @SchemaName = @CurrentSchemaName, @ObjectName = @CurrentObjectName, @ObjectType = @CurrentObjectType, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput08 = @Error IF @CurrentCommandOutput08 <> 0 SET @ReturnCode = @CurrentCommandOutput08 END UPDATE @tmpObjects SET Completed = 1 WHERE Selected = 1 AND Completed = 0 AND ID = @CurrentOID SET @CurrentOID = NULL SET @CurrentSchemaID = NULL SET @CurrentSchemaName = NULL SET @CurrentObjectID = NULL SET @CurrentObjectName = NULL SET @CurrentObjectType = NULL SET @CurrentObjectExists = NULL SET @CurrentCommand07 = NULL SET @CurrentCommand08 = NULL SET @CurrentCommandOutput08 = NULL SET @CurrentCommandType08 = NULL END END -- Check catalog IF EXISTS(SELECT * FROM @SelectedCheckCommands WHERE CheckCommand = 'CHECKCATALOG') BEGIN SET @CurrentCommandType09 = 'DBCC_CHECKCATALOG' SET @CurrentCommand09 = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand09 = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand09 = @CurrentCommand09 + 'DBCC CHECKCATALOG (' + QUOTENAME(@CurrentDatabaseName) SET @CurrentCommand09 = @CurrentCommand09 + ') WITH NO_INFOMSGS' EXECUTE @CurrentCommandOutput09 = [dbo].[DPCommandExecute] @Command = @CurrentCommand09, @CommandType = @CurrentCommandType09, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@Error IF @Error <> 0 SET @CurrentCommandOutput09 = @Error IF @CurrentCommandOutput09 <> 0 SET @ReturnCode = @CurrentCommandOutput09 END END -- Update that the database is completed UPDATE @tmpDatabases SET Completed = 1 WHERE Selected = 1 AND Completed = 0 AND ID = @CurrentDBID -- Clear variables SET @CurrentDBID = NULL SET @CurrentDatabaseID = NULL SET @CurrentDatabaseName = NULL SET @CurrentIsDatabaseAccessible = NULL SET @CurrentAvailabilityGroup = NULL SET @CurrentAvailabilityGroupRole = NULL SET @CurrentDatabaseMirroringRole = NULL SET @CurrentCommand01 = NULL SET @CurrentCommand02 = NULL SET @CurrentCommand05 = NULL SET @CurrentCommand06 = NULL SET @CurrentCommand09 = NULL SET @CurrentCommandOutput01 = NULL SET @CurrentCommandOutput05 = NULL SET @CurrentCommandOutput09 = NULL SET @CurrentCommandType01 = NULL SET @CurrentCommandType05 = NULL SET @CurrentCommandType09 = NULL DELETE FROM @tmpFileGroups DELETE FROM @tmpObjects END ---------------------------------------------------------------------------------------------------- --// Log completing information //-- ---------------------------------------------------------------------------------------------------- Logging: SET @EndMessage = 'Date and time: ' + CONVERT(nvarchar,GETDATE(),120) SET @EndMessage = REPLACE(@EndMessage,'%','%%') RAISERROR(@EndMessage,10,1) WITH NOWAIT IF @ReturnCode <> 0 BEGIN RETURN @ReturnCode END ---------------------------------------------------------------------------------------------------- END GO $JobCreateBase SET @JobDescription = 'Check integrity of all databases.' SET @Job01Command01 = 'sqlcmd -E -S ' + @TokenServer + ' -d $($InfrastructureDatabase) -Q "EXECUTE [dbo].[DPDatabaseIntegrityCheck] @Databases = ''ALL_DATABASES''" -b' -- Create Jobs EXECUTE msdb.dbo.sp_add_job @job_name = @JobName, @description = @JobDescription, @category_name = @JobCategory, @owner_login_name = $($JobOwner) EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = @JobName, @subsystem = 'CMDEXEC', @command = @Job01Command01, @output_file_name = @OutputFile01 EXECUTE msdb.dbo.sp_add_jobserver @job_name = @JobName EXECUTE msdb.dbo.sp_update_job @job_name = @JobName, @enabled = $(if ($Disabled){0}else { 1 }); "@ #Job DP_HistoryCleanup Create $DPHistoryCleanup = @" /*********** --START History Cleanup Setup-- ***********/ -- Set job properties SET @JobDescription = 'Clean up job log files, backup history, and job history older than 90 days.' SET @Job01Command01 = 'cmd /q /c "For /F "tokens=1 delims=" %v In (''ForFiles /P "' + @OutputFileDirectory + '" /m *_*_*.txt /d -90 2^>^&1'') do IF EXIST "' + @OutputFileDirectory + '"\%v echo del "' + @OutputFileDirectory + '"\%v& del "' + @OutputFileDirectory + '"\%v"' SET @Job01Command02 = 'sqlcmd -E -S ' + @TokenServer + ' -d ' + 'msdb' + ' -Q "DECLARE @CleanupDate datetime SET @CleanupDate = DATEADD(dd,-90,GETDATE()) EXECUTE dbo.sp_delete_backuphistory @oldest_date = @CleanupDate" -b' SET @Job01Command03 = 'sqlcmd -E -S ' + @TokenServer + ' -d ' + 'msdb' + ' -Q "DECLARE @CleanupDate datetime SET @CleanupDate = DATEADD(dd,-90,GETDATE()) EXECUTE dbo.sp_purge_jobhistory @oldest_date = @CleanupDate" -b' SET @Job01Command04 = N'-- Delete backup history FROM SQL Backup Pro''s SQL Server Compact database ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON DECLARE @backup_id INT , @command NVARCHAR(4000) , @retain_date NVARCHAR(64) , @IDList VARCHAR(2000) IF exists(SELECT * FROM sys.objects WHERE name like ''sqbdata'') BEGIN -- number of days of history that you want to retain (currently 30 days) SET @retain_date = GETDATE() - 30 -- temp table for ids we''re deleting. IF OBJECT_ID(''tempdb..#DeleteTheseIDs'') IS NOT NULL DROP TABLE #DeleteTheseIDs CREATE TABLE #DeleteTheseIDs ( id INT ) -- get total FROM the SQL Server Compact database (this will also show an error IF its corrupted) EXEC [master]..sqbdata N''SELECT COUNT(*) AS TotalBackupRows FROM backuphistory'' EXEC [master]..sqbdata N''SELECT COUNT(*) AS TotalRestoreRows FROM restorehistory '' ---------------------------------------------------------------------------------------------------- -- Delete backup history FROM SQL Backup Pro GUI activity cache ---------------------------------------------------------------------------------------------------- --get all of the ids that we want to delete SET @command = ''SELECT id FROM backuphistory WHERE backup_end < '''''' + @retain_date + '''''''' TRUNCATE TABLE #DeleteTheseIDs INSERT INTO #DeleteTheseIDs EXEC [master]..sqbdata @command SELECT ''Deleteing # Backup ids '' = COUNT(*) FROM #DeleteTheseIDs --loop until they''re all deleted WHILE EXISTS ( SELECT 1 FROM #DeleteTheseIDs ) BEGIN --get next set of ids (do not get too many at a time, otherwise the list will be truncated) SET @IDList = '''' SELECT TOP 150 @IDList = @IDList + CASE WHEN @IDList = '''' THEN '''' ELSE '','' END + CONVERT(VARCHAR(10), id) FROM #DeleteTheseIDs ORDER BY id --delete history SET @command = ''delete FROM backupfiles WHERE backup_id IN ('' + @IDList + '')'' EXEC [master]..sqbdata @command SET @command = ''delete FROM backuplog WHERE backup_id IN ('' + @IDList + '')'' EXEC [master]..sqbdata @command SET @command = ''delete FROM backuphistory WHERE id IN ('' + @IDList + '')'' EXEC [master]..sqbdata @command --delete FROM temp file SET @command = ''DELETE FROM #DeleteTheseIDs WHERE id IN ('' + @IDList + '')'' EXEC (@command) END ---------------------------------------------------------------------------------------------------- -- Delete restore history FROM SQL Backup Pro GUI activity cache ---------------------------------------------------------------------------------------------------- --get all of the ids that we want to delete SET @command = ''SELECT id FROM restorehistory WHERE restore_end < '''''' + @retain_date + '''''''' TRUNCATE TABLE #DeleteTheseIDs INSERT INTO #DeleteTheseIDs EXEC [master]..sqbdata @command SELECT ''Deleting # Restore ids '' = COUNT(*) FROM #DeleteTheseIDs --loop until they''re all deleted WHILE EXISTS ( SELECT 1 FROM #DeleteTheseIDs ) BEGIN -- get next set of ids SET @IDList = '''' SELECT TOP 200 @IDList = @IDList + CASE WHEN @IDList = '''' THEN '''' ELSE '','' END + CONVERT(VARCHAR(10), id) FROM #DeleteTheseIDs ORDER BY id --delete history SET @command = ''delete FROM restorefiles WHERE restore_id IN ('' + @IDList + '')'' EXEC [master]..sqbdata @command SET @command = ''delete FROM restorelog WHERE restore_id IN ('' + @IDList + '')'' EXEC [master]..sqbdata @command SET @command = ''delete FROM restorehistory WHERE id IN ('' + @IDList + '')'' EXEC [master]..sqbdata @command --delete FROM temp file SET @command = ''DELETE FROM #DeleteTheseIDs WHERE id IN ('' + @IDList + '')'' EXEC (@command) END SELECT ''Done.'' END ELSE BEGIN PRINT ''RedGate not installed'' END' SET @Job01Command05 = 'sqlcmd -E -S ' + @TokenServer + ' -d ' + 'msdb' + ' -Q "DECLARE @CleanupDate datetime SET @CleanupDate = DATEADD(dd,-90,GETDATE()) EXEC msdb..sp_maintplan_delete_log null,null,@CleanupDate" -b'; -- Create Job EXECUTE msdb.dbo.sp_add_job @job_name = @JobName, @description = @JobDescription, @category_name = @JobCategory, @owner_login_name = @JobOwner, @enabled = $(if ($Disabled){0}else {1}) EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = N'Output File Cleanup', @subsystem = 'CMDEXEC', @command = @Job01Command01, @on_success_action=3 EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = N'Delete Backup History', @subsystem = 'CMDEXEC', @command = @Job01Command02, @on_success_action=3 EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = N'Purge Job History', @subsystem = 'CMDEXEC', @command = @Job01Command03, @on_success_action=3 EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = N'Cycle SQL Error Log', @subsystem=N'TSQL', @command=N'EXEC master..sp_cycle_errorlog', @on_success_action=3 EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = N'Cleanup RedGate History', @subsystem=N'TSQL' , @command=@Job01Command04, @database_name=N'master', @on_success_action=3; EXECUTE msdb.dbo.sp_add_jobstep @job_name = @JobName, @step_name = N'Cleanup Maintenance Plan History', @subsystem = 'CMDEXEC', @command = @Job01Command05 EXECUTE msdb.dbo.sp_add_jobserver @job_name = @JobName; "@ if ($DefaultBackupDirectory.length -eq 0){ $DefaultBackupDirectory = ($Global:folders | where value -eq backupDirectory | select data).data } $BackupCommand = @" Declare @BackupCommand nvarchar(max) = '' SET @BackupCommand = N'DECLARE @exitcode INT , @sqlerrorcode INT; EXECUTE master..sqlbackup ''-SQL "BACKUP $(if ($PSCmdlet.ParameterSetName -eq "DP_RedGateFullBackup"){ " DATABASES "} ELSEIF ( $PSCmdlet.ParameterSetName -eq "DP_RedGateLogBackup"){ " LOGS " })[*] TO DISK = ''''$($DefaultBackupDirectory)\$($BackupFileName)'''' WITH NAME = '''''''' , DESCRIPTION = '''''''' , DISKRETRYINTERVAL = 10 , DISKRETRYCOUNT = 3 , CHECK_PREFERRED_AG_REPLICA , COMPRESSION = $($Compression) , ERASEFILES = $(if ($PSCmdlet.ParameterSetName -eq 'DP_RedGateFullBackup'){ " $FullRetention " } ELSEIF ( $PSCmdlet.ParameterSetName -eq "DP_RedGateLogBackup"){ " $LogRetention "}) $(if ($FileCount -gt 1) {"`r`n, FILECOUNT = $FileCount"}) , CHECKSUM , VERIFY"'', @exitcode OUTPUT, @sqlerrorcode OUTPUT IF (@exitcode <>0) OR (@sqlerrorcode <> 0) BEGIN RAISERROR (''SQL Backup job failed with exitcode: %d SQL error code: %d'' , 16, 1, @exitcode, @sqlerrorcode) END'; "@ $FullBackupCreate = @" SET @JobDescription = 'Using RedGate SQLBackup to perform Full backup of applicable databases.' EXEC msdb.dbo.sp_add_job @job_name=@JobName, @description=@JobDescription, @category_name=N'Database Maintenance', @owner_login_name=N'$($JobOwner)', @enabled = $(if ($Disabled){0}else {1}); EXEC msdb.dbo.sp_add_jobstep @job_name=@JobName, @step_name=N'Step 1: Full Backup of All Databases', @on_success_action=1,@subsystem=N'TSQL', @command= @BackupCommand, @database_name=N'master'; EXEC msdb.dbo.sp_add_jobserver @job_name=@JobName; "@ $LogBackupCreate = @" SET @JobDescription = 'Using RedGate SQLBackup to perform Log backup of applicable databases.' EXEC msdb.dbo.sp_add_job @job_name=@JobName, @description=@JobDescription, @category_name=N'Database Maintenance', @owner_login_name=N'$($JobOwner)', @enabled = $(if ($Disabled){0}else {1}); EXEC msdb.dbo.sp_add_jobstep @job_name=@JobName, @step_name=N'Step 1: Log Backup of All Databases', @on_success_action=1,@subsystem=N'TSQL', @command = @BackupCommand, @database_name=N'master'; EXEC msdb.dbo.sp_add_jobserver @job_name=@JobName; "@ } PROCESS { if ($PSCmdlet.ParameterSetName -eq 'DP_IndexOptimize') { $JobCreateBase += $CommandExecute $JobCreateBase += $CommandLog $JobCreateBase += $DPIndexOptimize try { Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -query $JobCreateBase -ConnectionTimeout 120 -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Job: $($PSCmdlet.ParameterSetName) has been created with Disabled = $Disabled" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } if ($PSCmdlet.ParameterSetName -eq 'DP_DatabaseIntegrityCheck') { $JobCreateBase += $CommandExecute $JobCreateBase += $CommandLog $JobCreateBase += $DPDatabaseIntegrityCheck try { Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -query $JobCreateBase -ConnectionTimeout 120 -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Job: $($PSCmdlet.ParameterSetName) has been created with Disabled = $Disabled" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } if ($PSCmdlet.ParameterSetName -eq 'DP_HistoryCleanup') { $JobCreateBase += $DPHistoryCleanup try { Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -query $JobCreateBase -ConnectionTimeout 120 -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Job: $($PSCmdlet.ParameterSetName) has been created with Disabled = $Disabled" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } if ($PSCmdlet.ParameterSetName -eq 'DP_RedGateFullBackup') { $JobCreateBase += $BackupCommand $JobCreateBase += $FullBackupCreate try { Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -query $JobCreateBase -ConnectionTimeout 120 -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Job: $($PSCmdlet.ParameterSetName) has been created" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - BackupDirectory: $DefaultBackupDirectory " DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - Retention : $FullRetention" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - Compression : $Compression" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - Filecount : $FileCount" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } if ($PSCmdlet.ParameterSetName -eq 'DP_RedGateLogBackup') { $JobCreateBase += $BackupCommand $JobCreateBase += $LogBackupCreate try { Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -query $JobCreateBase -ConnectionTimeout 120 -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Job: $($PSCmdlet.ParameterSetName) has been created" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - BackupDirectory: $DefaultBackupDirectory " DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - Retention : $LogRetention" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - Compression : $Compression" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message " - Filecount : $FileCount" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } } END { $jobname = $($PSCmdlet.ParameterSetName) return $jobname } } Function DPSQLCreateJobSchedule { <# .SYNOPSIS Creates a Job schedule for an Agent Job .DESCRIPTION Creates a Job schedule for an Agent Job .EXAMPLE DPSQLCreateJobSchedule -Daily -StartTime 00:15:00 -FrequencyMinutes 60 -JobName DP_RedGateLogBackup Creates a daily schedule at 12:15AM that runs every 60 minutes for job DP_RedGateLogBackup .EXAMPLE DPSQLCreateJobSchedule -Daily -StartTime 22:00:00 -JobName DP_RedGateFullBackup Creates a daily schedule at 10:00PM for job DP_RedGateFullBackup .EXAMPLE DPSQLCreateJobSchedule -Weekly -DayOfWeek Sunday -StartTime 01:00:00 -JobName DP_RedGateIndexOptimize Creates a weekly schedule for Sunday at 1AM for job DP_RedGateIndexOptimize #> [CmdletBinding(DefaultParameterSetName="All")] param( [parameter(mandatory=$false,ParameterSetName='Weekly', ValueFromPipelineByPropertyName=$true)] [parameter(mandatory=$false,ParameterSetName='Daily', ValueFromPipelineByPropertyName=$true)] $TargetInstance , [parameter(mandatory=$true,ParameterSetName='Weekly')] [switch]$Weekly , [parameter(mandatory=$true,ParameterSetName='Daily')] [switch]$Daily , [parameter(mandatory=$true,ParameterSetName='Weekly')] [Validateset("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday")] [String]$DayOfWeek , [parameter(mandatory=$true,ParameterSetName='Weekly')] [parameter(mandatory=$true,ParameterSetName='Daily')] [Validateset('00:00:00','00:15:00','00:30:00','00:45:00','01:00:00','01:15:00','01:30:00','01:45:00','02:00:00','02:15:00','02:30:00','02:45:00','03:00:00','03:15:00','03:30:00','03:45:00','04:00:00','04:15:00','04:30:00','04:45:00','05:00:00','05:15:00','05:30:00','05:45:00','06:00:00','06:15:00','06:30:00','06:45:00','07:00:00','07:15:00','07:30:00','07:45:00','08:00:00','08:15:00','08:30:00','08:45:00','09:00:00','09:15:00','09:30:00','09:45:00','10:00:00','10:15:00','10:30:00','10:45:00','11:00:00','11:15:00','11:30:00','11:45:00','12:00:00','12:15:00','12:30:00','12:45:00','13:00:00','13:15:00','13:30:00','13:45:00','14:00:00','14:15:00','14:30:00','14:45:00','15:00:00','15:15:00','15:30:00','15:45:00','16:00:00','16:15:00','16:30:00','16:45:00','17:00:00','17:15:00','17:30:00','17:45:00','18:00:00','18:15:00','18:30:00','18:45:00','19:00:00','19:15:00','19:30:00','19:45:00','20:00:00','20:15:00','20:30:00','20:45:00','21:00:00','21:15:00','21:30:00','21:45:00','22:00:00','22:15:00','22:30:00','22:45:00','23:00:00','23:15:00','23:30:00')] [String]$StartTime , [parameter(mandatory=$false,ParameterSetName='Daily')] [Validateset('5','10','15','20','25','30','35','40','45','50','55','60')] [String]$FrequencyMinutes , [parameter(mandatory=$true,ParameterSetName='Daily', ValueFromPipeline=$true)] [parameter(mandatory=$true,ParameterSetName='Weekly', ValueFromPipeline=$true)] [String]$JobName ,[parameter(mandatory=$false,ParameterSetName='Weekly', ValueFromPipelineByPropertyName=$true)] [parameter(mandatory=$false,ParameterSetName='Daily', ValueFromPipelineByPropertyName=$true)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if ((!$TargetInstance ) -and ($Implement)) { DPSelectTargetInstance | Out-Null } } PROCESS { $Schedule_TSQL = @" EXEC msdb.dbo.sp_add_jobschedule @job_name=N'$($JobName)' , @enabled=1 , @active_start_date=$(Get-Date -Format 'yyyyMMdd') , @active_end_date=99991231 , @active_start_time=$($StartTime.Replace(':','')) "@ $ClearExistingSchedule = @" Declare @sqlstring nvarchar(1000) = ''; select @sqlstring += 'exec msdb.dbo.sp_delete_schedule @schedule_id = ' + cast(schedule_id as nvarchar(100)) + ' , @force_delete = 1; ' from msdb.dbo.sysjobschedules sjs join msdb.dbo.sysjobs sj on sjs.job_id = sj.job_id where name = '$($JobName)' if (len(@sqlstring) > 0) exec (@sqlstring);`r`n "@ if ($PSCmdlet.ParameterSetName -eq "Daily") { $Schedule_TSQL += @" , @freq_type=4 , @freq_interval=1 "@ if (!$FrequencyMinutes) { $name = "$($PSCmdlet.ParameterSetName): $($StartTime)" $Schedule_TSQL += @" , @name=N'$($name)'; "@ } else { $name = "$($PSCmdlet.ParameterSetName): $($StartTime) every $($FrequencyMinutes) minutes" $Schedule_TSQL += @" , @freq_relative_interval=0 , @freq_recurrence_factor=1 , @freq_subday_type=4 , @freq_subday_interval=$($FrequencyMinutes) , @name=N'$($name)'; "@ } } else { $name = "$($PSCmdlet.ParameterSetName): $($DayOfWeek) at $($StartTime)" switch($DayOfWeek) { 'Sunday' {$DayOfWeekNumeric = '1'} 'Monday' {$DayOfWeekNumeric = '2'} 'Tuesday' {$DayOfWeekNumeric = '4'} 'Wednesday' {$DayOfWeekNumeric = '8'} 'Thursday' {$DayOfWeekNumeric = '16'} 'Friday' {$DayOfWeekNumeric = '32'} 'Saturday' {$DayOfWeekNumeric = '64'} } $Schedule_TSQL += @" , @freq_type=8 , @freq_interval=$($DayOfWeekNumeric) , @freq_subday_type=1 , @freq_recurrence_factor=1 , @name=N'$($name)'; "@ } $Schedule_TSQL = $ClearExistingSchedule + $Schedule_TSQL; #build custom message for success if ($PSCmdlet.ParameterSetName -eq 'weekly') { $message = "$($PSCmdlet.ParameterSetName) on $DayOfWeek at $StartTime" } else { $message = "$($PSCmdlet.ParameterSetName) at $StartTime $(if ($FrequencyMinutes){"every $FrequencyMinutes minutes"})" } try { Invoke-Sqlcmd -Query $Schedule_TSQL -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -ConnectionTimeout 30 -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "$jobname schedule has been set to $message " } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } END { } } Function DPSQLGetFiles { [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Get tempdb current configuration .DESCRIPTION Returns the quantity of database files in Tempdb .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLGetFiles -TargetInstance $selection #> BEGIN { if (!$TargetInstance ) { DPSelectTargetInstance | Out-Null } } PROCESS { try { $Global:SQLFileConfiguration = Invoke-Sqlcmd -ServerInstance $selection.fullname -Query "SELECT '$($selection.fullname)' [Server], db_name(database_id) [DBName], name, physical_name, file_id, type, type_desc, (size * 8 /1024) [SizeMB], growth from sys.master_files" -QueryTimeout $Global:QueryTimeout -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Created `$Global:SQLFileConfiguration" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } } END { #DPAddConfigurationObject -Instance $selection.Fullname -Function $MyInvocation.MyCommand.Name -Configuration '$Global:SQLFileConfiguration' -CurrentValue '' -NewValue '$Global:SQLFileConfiguration' -Action $action } } Function DPSQLSetTempdb { [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance , [parameter(mandatory=$false,Position=1)] [int]$TempdbCount = ([System.Environment]::ProcessorCount) , [parameter(mandatory=$false,Position=2)] [ValidateSet (64,128,256,512)] [int]$TempdbAutoGrowth = 512 , [parameter(mandatory=$false,Position=3)] [ValidateSet (1024,2048,4096,8192)] [int]$TempdbSize = 2048 ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Sets up tempdb database with proper file count .DESCRIPTION This function will create tempdb database files per core up to 8. .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .PARAMETER TempdbCount Amount of Tempdb File the instance should have .PARAMETER TempdbSize Initial size of tempdb files in MB .PARAMETER TempdbAutoGrowth Amount the tempdb files should auto grow in MB .EXAMPLE DPSQLSetTempdb -TargetInstance $selection #> BEGIN { if (!$TargetInstance) { DPSelectTargetInstance | Out-Null } else { if (!$Global:SQLFileConfiguration) { DPSelectTargetInstance | Out-Null } DPSQLGetFiles -TargetInstance $selection | Out-Null } $TempdbDataFileCount = (($Global:SQLFileConfiguration | select DBname, type, physical_name | where dbname -eq 'tempdb' | where type -eq 0) | Measure-Object).Count if ($TempdbCount -gt 8) { $TempDBFilesToCreate = (8 - $TempdbDataFileCount) } else { $TempDBFilesToCreate = ($TempdbCount - $TempdbDataFileCount) } #Fix up the default data and log file. $TempdbDefaultFiles = ($Global:SQLFileConfiguration | where dbname -eq 'tempdb' | where SizeMB -lt $TempdbSize) #Generate change statement $Statement = @" USE [master] GO "@ foreach ($file in $TempdbDefaultFiles) { $Statement += "ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'$($file.name)', SIZE = $($TempdbSize)MB , FILEGROWTH = $($TempdbAutoGrowth)MB );`r`n" $worktodo = 1 } $TempdbFolder = ([regex]::Match(($Global:SQLFileConfiguration | where dbname -eq 'tempdb' | where file_id -eq 1).physical_name, '^(.+)\\')).captures.value #$TempDBFilesToCreate $cnter = 1 if ($TempDBFilesToCreate -gt 0) { while ($cnter -le $TempDBFilesToCreate) { $Statement += "ALTER DATABASE [tempdb] ADD FILE ( NAME = N'tempdb$($TempdbDataFileCount+$cnter)', FILENAME = N'$($TempdbFolder)tempdb_$($TempdbDataFileCount+$cnter).ndf' , SIZE = $($TempdbSize)MB , FILEGROWTH = $($TempdbAutoGrowth)MB );`r`n" $worktodo = 1; $cnter +=1; } } } PROCESS { if ($worktodo -eq 1) { TRY { Invoke-Sqlcmd -ServerInstance $selection.fullname -Query $Statement -QueryTimeout $Global:QueryTimeout -ErrorAction Stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Tempdb created without error." } catch { # Handle the error $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.message)" }; } } else { $action = 'No Action' } } END { #refresh count DPSQLGetFiles -TargetInstance $selection | Out-Null #DPAddConfigurationObject -Instance $selection.Fullname -Function $MyInvocation.MyCommand.Name -Configuration 'Tempdb' -CurrentValue "$($TempdbDataFileCount)" -NewValue $TempDBFilesToCreate -Action $action } } Function DPSQLGetSystemConfiguration { [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Get System configurations from sys.configurations .DESCRIPTION This command will return the existing system configuration. .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLGetSystemConfiguration -TargetInstance $selection #> BEGIN { if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } } PROCESS { try { $Global:SystemConfigurations = Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -ErrorAction Stop -Database msdb -Query "select '$($selection.fullname)' [Server], name,value,minimum,maximum,value_in_use,description,is_dynamic,is_advanced from sys.configurations" $action = 'Created $Global:SystemConfigurations' } catch { # Handle the error $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.message)" }; } } END { #DPAddConfigurationObject -Instance $selection.Fullname -Function $MyInvocation.MyCommand.Name -Configuration 'Created $Global:SystemConfigurations' -CurrentValue '' -NewValue '$Global:SystemConfigurations' -Action $action if ($Global:SystemConfigurations) { return $Global:SystemConfigurations } } } Function DPSQLSetAdvancedOptions { [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } } PROCESS { $AdvancedOptions = Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -ErrorAction Stop -Query "execute sp_configure 'show advanced options'" if ($AdvancedOptions.config_value -eq 1 -and $AdvancedOptions.run_value -eq 1) { #DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "DPSQLSetAdvancedOptions: Show Advanced options already enabled, no action taken" } else { try { #Set show advanced options to 1 Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -ErrorAction Stop -Query "execute sp_configure 'show advanced options',1; GO RECONFIGURE; GO" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "Enabled advanced options Successfully" } catch { # Handle the error $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.message)" }; } } } END { #Write-Verbose "DPSQLSetAdvancedOptions: Refreshing the configuration" DPSQLGetSystemConfiguration -TargetInstance $selection | Out-Null } } Function DPSQLSetSysConfig { [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance, [parameter(mandatory=$True,Position=1)] [Validatescript({ if ($SystemConfigurations.name -contains $_) {$true} else { throw "Select from one of the options in variable `$SystemConfigurations.name"}})] [string]$SQLConfiguration, [parameter(mandatory=$True,Position=2)] [int]$Value ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Sets a System configurations .DESCRIPTION This command will modify the sys.configurations value. .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .PARAMETER SysConfiguration Sets the configuration provided in SQL. .EXAMPLE DPSQLGetSystemConfiguration -TargetInstance $selection #> BEGIN { $result = '' if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } } PROCESS { #show advanced options DPSQLSetAdvancedOptions -TargetInstance $selection #confirm if the global variable matches the existing instance. (It should) if ($selection.fullname -eq $SystemConfigurations[0].server) { #get full detail of that option $SQLConfigurationFull = $SystemConfigurations | where name -eq $SQLConfiguration #Confirm if the $Value variable is between the min and max). If it is then set the new value if ($Value -ge $SQLConfigurationFull.minimum -and $Value -le $SQLConfigurationFull.maximum) { if ($value -eq $SQLConfigurationFull.value -or $value -eq $SQLConfigurationFull.value_in_use) { $action = "$($SQLConfiguration): is already $($SQLConfigurationFull.value_in_use)" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message $action } else { try { (Invoke-Sqlcmd -ServerInstance $selection.fullname -QueryTimeout $Global:QueryTimeout -ErrorAction Stop -Query "execute sp_configure '$($SQLConfigurationFull.name)',$value; GO RECONFIGURE; GO") DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "$($SQLConfiguration): $Value was $($SQLConfigurationFull.value_in_use)" } catch { # Handle the error $err = $_.Exception while( $err.InnerException ) { $err = $err.InnerException DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($err.message)" }; } } } } } END { } } Function DPSQLGetMaxDop { [CmdletBinding()] param( [parameter(mandatory=$false,Position=0)] $TargetInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Get MaxdegreeofParallelism bases off core count / numa node .DESCRIPTION It will return the recommended MaxDop setting base off best practice .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLGetMaxDop -TargetInstance $selection #> BEGIN { $MaxDopQuery = @" /*********** --Start Max DOP Cores Per Numa Node-- ***********/ DECLARE @CoreCount smallint, @NumaNodes smallint, @MaxDop smallint, @Error nvarchar(max); SET @CoreCount = (SELECT i.cpu_count FROM sys.dm_os_sys_info i); SET @NumaNodes = ( SELECT MAX(c.memory_node_id) + 1 FROM sys.dm_os_memory_clerks c WHERE memory_node_id < 64 ); SET @MaxDop = @CoreCount / @NumaNodes SELECT @MaxDop [MaxDop]; "@ if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } } PROCESS { $maxdopSetting = Invoke-Sqlcmd -ServerInstance $selection.fullname -Query $MaxDopQuery -QueryTimeout $Global:QueryTimeout -ErrorAction Stop; } END { Return $MaxDopSetting.MaxDop } } Function DPSQLGetMaxMemory { [CmdletBinding()] param ( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Get 'max server memory (MB)' property based off equation MaxServerMemory MB = ((Total Server Memory - 4096) * .9) .DESCRIPTION It will return the recommended MaxServerMemory MB setting base off best practice .PARAMETER TargetInstance Works with DPSelectTargetInstance command. If not supplied you will be prompted .EXAMPLE DPSQLGetMaxMemory -TargetInstance $selection #> BEGIN { [int]$ServerMemory = ((Get-WmiObject -Class Win32_PhysicalMemory | Measure-Object -Sum capacity).sum / 1024 / 1024) } PROCESS { if ($ServerMemory -le 4096) { $ServerMemory = ($ServerMemory - 1023) } else { $ServerMemory = (($ServerMemory - 4096) * .9) } #Round to nearest GB $ServerMemory = [math]::round($ServerMemory / 1024,0) * 1024 } END { return $ServerMemory } } Function DPSQLNameChange { [CmdletBinding(DefaultParametersetName="Work")] param( [parameter(mandatory=$false,Position=0,parametersetname="Work")] [parameter(mandatory=$false,Position=0,parametersetname="Check")] $TargetInstance , [parameter(mandatory=$false,Position=1,ParametersetName="Work")] [switch]$Restart = $false , [parameter(mandatory=$false,Position=1,ParametersetName="Check")] [switch]$Check = $false ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Renames SQL server instance to match the servername .DESCRIPTION After executing this command it will modify the SQL server name to the hostname on the machine .PARAMETER TargetInstance Works with DPSelectTargetInstance command. Run that first to select your instance. .EXAMPLE DPSQLNameChange -TargetInstance $selection #> BEGIN { if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } #Local instances only If (!$TargetInstance.clustername) { #Get the current SQL name $CurrentSQLName = (Invoke-Sqlcmd -ServerInstance $TargetInstance.fullname -Query "sp_helpserver" -ConnectionTimeout 5 -ErrorAction Stop) #Check if named instance so we can get the root name If ($TargetInstance.InstanceName -ne "MSSQLSERVER") { $CurrentSQLName = $CurrentSQLName.name $NewSQLname = "$($env:COMPUTERNAME)\$($TargetInstance.instancename)" } else { $CurrentSQLName = $CurrentSQLName.name $NewSQLName = "$($env:COMPUTERNAME)" } } else { DPLOG -WriteToHost $WriteToHost -Type WARNING -Message "No action to take its a cluster" } } PROCESS { #Only do work if Check flag wasn't set If ($PsCmdlet.ParameterSetName -eq "Work"){ try { #Now lets see if there is actually any work to be done. If ($NewSQLname -ne $CurrentSQLName) { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "SQL name change starting" #Let us setup the statement $NameChangeScript = @" use [master]; go sp_dropserver '$($CurrentSQLName)' go sp_addserver '$($NewSQLName)','LOCAL' go "@ Invoke-Sqlcmd -Query $NameChangeScript -ServerInstance $TargetInstance.fullname -ConnectionTimeout 0 -ErrorAction Stop; "SQL name change complete" If ($Restart){ DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Option to restart detected" DPSQLRestart -TargetInstance $TargetInstance } else { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "A SQL restart is required to effect the change from $($CurrentSQLName) to $($NewSQLname)" } } else { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "The SQL name already matches the servername: $($NewSQLname) = $($CurrentSQLName)" break; } } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message ("An error had occurred: " + $_.exception.message) } } else { If ($NewSQLname -ne $CurrentSQLName) { DPLOG -WriteToHost $WriteToHost -Type ERROR "The $($CurrentSQLName) is not equal to $($NewSQLname)" } } } END {} } Function DPSQLRestart { param( [parameter(mandatory=$true,Position=0)] $TargetInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Restarts the selected SQL instance via Restart-Service .DESCRIPTION Takes the $targetinstance parameter and will restart if it is a stand-alone instance only .PARAMETER TargetInstance Works with DPSelectTargetInstance command. Run that first to select your instance. .EXAMPLE DPSQLRestart -TargetInstance $selection #> BEGIN{ #Validate its not a cluster otherwise exit if (!$selection.isClustered){ $Service = Get-Service -DisplayName "SQL Server ($($targetinstance.instancename))" } else { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "Traditional SQL cluster detected, please restart that manually" } } PROCESS{ #Stop dependent services try { if ($Service.DependentServices.Status -eq 'running') { $Dependents = $Service | ?{$_.dependentservices.status -eq 'running'} $Dependents.DependentServices | %{Stop-Service -Name $_.name -Verbose;} } } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message ("An error occurred: " + $_) } try { Restart-Service $Service -Verbose } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message ($_) } try { #Start the dependent services $Service.DependentServices | %{Start-Service -Name $_.name -Verbose} } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message ($_) } } END { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Service $($TargetInstance.fullname) has been restarted, please verify" } } Function DPGetSQLInstances { [CMDLETBINDING()] param( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { } PROCESS { $InstanceDetail = @() $registryLocation = 'hklm:SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL' $Instances = Get-Item -Path $registryLocation | select -ExpandProperty property Foreach ($instance in $Instances) { $obj = New-Object System.Object $obj | Add-Member -MemberType NoteProperty -Name InstanceName -Value $instance $script = "(Get-ItemProperty -Path ""$registryLocation"" -Name ${instance}).${instance}" $InstanceIdentifier = (Invoke-Expression $script) $obj | add-member -MemberType NoteProperty -name Identifier -value $InstanceIdentifier $registryLoc2 = "hklm:\SOFTWARE\Microsoft\Microsoft SQL Server\${instanceidentifier}\Cluster" if ((test-path -Path $registryLoc2)) { $script = "(Get-ItemProperty -Path ""$registryLoc2"" -Name ClusterName).clustername" $clustername = Invoke-Expression $script $obj | add-member -MemberType NoteProperty -name isClustered -value $true $obj | add-member -MemberType NoteProperty -name ClusterName -value $clustername if ($instance -eq 'MSSQLSERVER'){ $obj | add-member -MemberType NoteProperty -name Fullname -value $clustername } else{ $obj | Add-Member -MemberType NoteProperty -Name Fullname -Value "$($clustername)\$($instance)" } } else { $obj | add-member -MemberType NoteProperty -name isClustered -value $false $obj | add-member -MemberType NoteProperty -name ClusterName -value "" if ($instance -eq 'MSSQLSERVER'){ $obj | add-member -MemberType NoteProperty -name Fullname -value $env:COMPUTERNAME } else{ $obj | Add-Member -MemberType NoteProperty -Name Fullname -Value "$($env:COMPUTERNAME)\$($instance)" } } $obj | Add-Member -MemberType NoteProperty -Name Status -Value (Get-Service -DisplayName "sql server ($($instance))").Status $InstanceDetail += $obj } DPLOG -WriteToHost $WriteToHost -Message "Instance detail gathered without error" -Type INFO } END { return $InstanceDetail } } Function DPSelectTargetInstance { [CMDLETBINDING()] param( [Parameter(Mandatory=$false)] [switch]$Default = $false , [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { DPLOG -WriteToHost $WriteToHost -Type START -Message " " } PROCESS{ $Instances = (DPGetSQLInstances -WriteToHost N) if ($Default) { $Global:selection = $Instances | where instancename -like "mssqlserver" } else { DPLOG -WriteToHost Y -Type INFO -Message "Please select a SQL instance to be worked on" do{ $ref = "" $cnt = 1; $Instances | %{ Write-Host "$cnt. $($Instances[$cnt-1].fullname) ($($instances[$cnt-1].status))" $cnt+=1; } $ans = Read-Host 'Enter selection' $__TryParseOutput = [int]::TryParse($ans,[ref]$ref) if ($__TryParseOutput) { if ([int]$ans -gt 0 -and [int]$ans -le $Instances.count -and $instances[$ans-1].status -eq 'Running'){ $Global:selection = $Instances[$ans-1] DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "You've selected $($selection.fullname)" } else { if ($instances[$ans-1].status -ne 'Running'){ DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "Invalid selection, please select a running instance from the list." } else{ DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "Invalid selection, please select an item from the list." } } } else{ DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "Invalid selection, please select an item from the list." } }until ($__TryParseOutput -eq $true -and [int]$ans -le $Instances.count -and [int]$ans -gt 0 -and $instances[$ans-1].status -eq 'Running' ) } } END { #Get the configurations while we are at it. DPSQLGetSystemConfiguration -TargetInstance $selection -WriteToHost N | Out-Null DPSQLGetFiles -TargetInstance $selection -WriteToHost N| Out-Null DPSQLGetDefaultFolders -TargetInstance $selection -WriteToHost N| Out-Null #Create the SMO object for the instance we are working on $global:ServerInstanceSMO = New-Object ('Microsoft.SQLServer.Management.SMO.Server') $selection.fullname return $selection DPLOG -WriteToHost $WriteToHost -Type FINISH -Message " " } } Function DPSetSqlStartupParam{ param( ## The parameter you wish to add [parameter(mandatory=$false,Position=0)] $TargetInstance , [parameter(Mandatory = $true)] [string]$StartupParameter ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { $__Retval = [string]::Empty if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } $FunctionSQLServerConfiguration = @(); } PROCESS { $hklmRootNode = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server" $targetinstance = $selection.instancename $props = Get-ItemProperty "$hklmRootNode\Instance Names\SQL" $instances = $props.psobject.properties | ?{$_.value -Match "\.$targetinstance$"} | select Value $regKey = "$hklmRootNode\$($instances.value)\MSSQLServer\Parameters" $props = Get-ItemProperty $regKey $params = $props.psobject.properties | ?{$_.Name -like 'SQLArg*'} | select Name, Value $hasFlag = $false foreach ($param in $params) { if($param.Value -eq $StartupParameter) { $hasFlag = $true break; } } $newRegProp = "SQLArg"+($params.Count) if (-not $hasFlag) { TRY { Set-ItemProperty -Path $regKey -Name $newRegProp -Value $StartupParameter; $Action = "Add $($StartupParameter) to registry" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "$Action" } CATCH { $Action = $_.Exception.Message DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$Action" } } else { $Action = "Trace flag $($StartupParameter) exists already" DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "$Action" } } END { } } Function DPCheckVolumeBlocksize { [CMDLETBINDING()] param( [parameter(mandatory=$false)] [ValidateSet(512,1024,2048,4096,8192,16384,32768,65536)] $blocksize = 65536 ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN{ #$__Retval = @() $DiskInfo = gwmi win32_volume | ?{$_.drivetype -eq 3 -and $_.caption -ne "c:\" -and $_.label -ne 'System Reserved'} | select caption, label, blocksize } PROCESS{ $DiskinfoCObject = $DiskInfo | ForEach-Object { [pscustomobject]@{ caption = $_.caption; ` label = $_.label; ` blocksize = $_.blocksize; } } $DiskinfoCObject | ForEach-Object { if ($_.blocksize -ne $blocksize){ DPLOG -WriteToHost $WriteToHost -Message "Volume: $($_.caption) : Label: $($_.label) has a blocksize of $($_.blocksize)" -Type ERROR } } } END { } } Function DPSQLPostInstall{ [CMDLETBINDING()] param( [parameter(mandatory=$false,Position=0)] $Targetinstance , [parameter(mandatory=$false,Position=1)] [int]$MaxServerMemory = (DPSQLGetMaxMemory) , [parameter(mandatory=$false,Position=2)] [int]$MinServerMemory = 0 , [parameter(mandatory=$false,Position=3)] [int]$FullBackupRetention = 3 , [parameter(mandatory=$false,ParameterSetName='DP_RedGateFullBackup')] [ValidateSet(1,2,4,6,8,10,12)] [int]$FileCount = 1 , [parameter(mandatory=$false,Position=4)] [int]$LogBackupRetention = 4 , [parameter(mandatory=$false,Position=5)] [string]$DefaultBackupDirectory , [parameter(mandatory=$false,Position=6)] [string]$BackupFileName , [parameter(mandatory=$false,Position=7)] [validaterange(0,1)] [int]$IsPci = 0 , [parameter(mandatory=$false,Position=8)] [ValidateSet (2,4,6,8)] [int]$TempdbCount , [parameter(mandatory=$false,Position=9)] [ValidateSet (64,128,256,512)] [int]$TempdbAutoGrowth = 512 , [parameter(mandatory=$false,Position=10)] [ValidateSet (1024,2048,4096,8192)] [int]$TempdbSize = 2048 , [parameter(mandatory=$false,Position=11)] [int]$MaxDop , [parameter(mandatory=$false,Position=12)] [int]$CostThresholdForParallelism = 50 , [parameter(mandatory=$false,Position=13)] [int]$DefaultFillFactor = 90 , [parameter(mandatory=$false,Position=14)] [string[]]$Traceflags = @('-T3226','-T2371') , [parameter(mandatory=$false,Position=15)] [ValidateSet(1,2,3,4)] [int]$Compression = 4 , [parameter(mandatory=$false,Position=15)] [int]$MaximumJobHistoryRows = 10000 , [parameter(mandatory=$false,Position=16)] [int]$MaximumHistoryRows = 900000 ) BEGIN { Push-Location if (!$Targetinstance){ (DPSelectTargetInstance -WriteToHost N| Out-Null) } DPLOG -WriteToHost $WriteToHost -Message "Starting SQL Post Install on the $($selection.fullname) SQL instance" -Type START $Date = get-date -Uformat '%m%d%y_%H%M%S' #$BuildFolder = "$($PSScriptRoot)\SQLPostInstall_$($selection.Fullname -replace "\\","_")_$($date)" #$Outfile = "$($BuildFolder)\SQLPostInstall.txt" #New-Item -Path $BuildFolder -ItemType directory -Force -ErrorAction SilentlyContinue | Out-Null DPLOG -WriteToHost $WriteToHost -Type INFO -Message "/* ----------------------------- Datapipe SQL Post-install $($Global:Version) Configuration Report ----------------------------- */" $OSDetail = @() $OSDetail = get-wmiobject win32_computersystem | select-object DNSHostName,Manufacturer,Model DPLOG -WriteToHost $WriteToHost -Type INFO -Message "HostName: $($OSDetail.DNSHostName)" DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Server Type: $($OSDetail.Manufacturer) $($OSDetail.Model)" DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Is Clustered: $($selection.isClustered)"; $OSDetail = get-wmiobject win32_processor | select-object numberofcores,numberoflogicalprocessors,maxclockspeed,currentclockspeed DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Physical Processors: $(($OSDetail | Measure-Object).count)" #hyperthreading check if ($OSDetail[0].numberofcores -ne $OSDetail[0].numberoflogicalprocessors) { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Hyperthreading is enabled: Physical Cores: $($OSDetail[0].numberofcores) != Virtual Cores: $($OSDetail[0].numberoflogicalprocessors)" } else { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Hyperthreading is disabled: Physical Cores: $($OSDetail[0].numberofcores) == Virtual Cores: $($OSDetail[0].numberoflogicalprocessors)" } #Power option check if ($OSDetail[0].maxclockspeed -ne $OSDetail[0].currentclockspeed) { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Power options aren't max: Max Clock Speed: $($OSDetail[0].maxclockspeed) != Current Clock Speed: $($OSDetail[0].currentclockspeed)" } else { DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Power options set to max: Max Clock Speed: $($OSDetail[0].maxclockspeed) == Current Clock Speed: $($OSDetail[0].currentclockspeed)" } DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Physical Server Memory: $([math]::round((gwmi win32_computersystem).totalphysicalmemory / 1024 /1024))" $VersionEdition = Invoke-Sqlcmd -ErrorAction Stop -ServerInstance $selection.Fullname -Query "select serverproperty('ProductVersion') [Version], serverproperty('Edition')[Edition], serverproperty('collation') [collation]" DPLOG -WriteToHost $WriteToHost -Type INFO -Message "ProductVersion: $($VersionEdition.Version)" DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Edition: $($VersionEdition.Edition)" DPLOG -WriteToHost $WriteToHost -Type INFO -Message "Collation: $($VersionEdition.collation)" } PROCESS { #Setting Auditlevel if ($IsPci -eq 1) {$setting = "ALL"}else{$setting = "Failure"} DPSQLSetSystemProperty -TargetInstance $selection -AuditLevel $setting if (!$MaxDop) { $MaxDop = DPSQLGetMaxDop -TargetInstance $selection; } #Setting Max degree of parallelism DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'max degree of parallelism' -Value $MaxDop #Set Cost Threshold for Parallelism DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'cost threshold for parallelism' -Value $CostThresholdForParallelism #Set Default Fill Factor DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'fill factor (%)' -Value $DefaultFillFactor #Set 'max server memory (MB)' DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'max server memory (MB)' -Value $MaxServerMemory #Set 'min server memory (MB)' DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'min server memory (MB)' -Value $MinServerMemory #Add Trace flags to registry #DPLOG -WriteToHost $WriteToHost -Message "Setting 'StartupParameters' $($Traceflags | %{"$_"})" -Type INFO $Traceflags | %{DPSetSqlStartupParam -TargetInstance $selection -StartupParameter $_} if ($VersionEdition.Version -match '^10' -and -$VersionEdition.Edition -ne 'Enterprise') { DPSetSqlStartupParam -TargetInstance $selection -StartupParameter '-T845' #DPLOG -WriteToHost $WriteToHost -Message "Setting 'StartupParameters' to T845" -Type SUCCESS } #Setup system databases DPSQLSetSizeAndGrowth -TargetInstance $selection -Database master -InitialSizeMB 64 -GrowthMB 64 DPSQLSetSizeAndGrowth -TargetInstance $selection -Database model -InitialSizeMB 64 -GrowthMB 64 DPSQLSetSizeAndGrowth -TargetInstance $selection -Database msdb -InitialSizeMB 512 -GrowthMB 512 #InstallRedgate DPSQLInstallRedGate8 #Setup TEMPDB if (!$TempdbCount) { DPSQLSetSizeAndGrowth -TargetInstance $selection -Database tempdb -GrowthMB $TempdbAutoGrowth -InitialSizeMB $TempdbSize } else { DPSQLSetTempdb -TargetInstance $selection -TempdbCount $TempdbCount -TempdbAutoGrowth $TempdbAutoGrowth -TempdbSize 2048 } if ($VersionEdition.Edition -like "Express*") { DPLOG -Type INFO -Message "Edition like $($VersionEdition.Edition) not deploying SQL Agent changes" } else { #DP_IndexOptimize DPSQLCreateAgentJob -TargetInstance $selection -DP_IndexOptimize -Disabled | Out-Null; #DP_DatabaseIntegrityCheck DPSQLCreateAgentJob -TargetInstance $selection -DP_DatabaseIntegrityCheck -Disabled | Out-Null; #DP_HistoryCleanup DPSQLCreateAgentJob -TargetInstance $selection -DP_HistoryCleanup | DPSQLCreateJobSchedule -Daily -StartTime 00:00:00 if (!$BackupFileName) { $BackupFileName = '\\' } if (!$DefaultBackupDirectory) { #DP_RedGateFullBackup DPSQLCreateAgentJob -TargetInstance $selection -DP_RedGateFullBackup ` -BackupFileName $BackupFileName -FullRetention $FullBackupRetention -Compression $Compression -FileCount $FileCount | DPSQLCreateJobSchedule -Daily -StartTime 22:00:00 #DP_RedGateLogBackup DPSQLCreateAgentJob -TargetInstance $selection -DP_RedGateLogBackup ` -BackupFileName $BackupFileName -Compression $Compression -LogRetention $LogBackupRetention -FileCount $FileCount | DPSQLCreateJobSchedule -Daily -StartTime 00:30:00 -FrequencyMinutes 60 } else { #DP_RedGateFullBackup DPSQLCreateAgentJob -TargetInstance $selection -DP_RedGateFullBackup ` -BackupFileName $BackupFileName -DefaultBackupDirectory $DefaultBackupDirectory -FullRetention $FullBackupRetention -Compression $Compression -FileCount $FileCount | DPSQLCreateJobSchedule -Daily -StartTime 22:00:00 #DP_RedGateLogBackup DPSQLCreateAgentJob -TargetInstance $selection -DP_RedGateLogBackup ` -BackupFileName $BackupFileName -DefaultBackupDirectory $DefaultBackupDirectory -Compression $Compression -LogRetention $LogBackupRetention -FileCount $FileCount | DPSQLCreateJobSchedule -Daily -StartTime 00:15:00 -FrequencyMinutes 60 } #SQL Agent Alerts DPSQLAddAgentAlerts -TargetInstance $selection -Severity 19,20,21,22,23,24,25 -WriteToHost N DPSQLAddAgentAlerts -TargetInstance $selection -MessageID 823,824,825 -WriteToHost N #Agent log setup. DPSQLSetSystemProperty -TargetInstance $selection -MaximumHistoryRows $MaximumHistoryRows -WriteToHost N DPSQLSetSystemProperty -TargetInstance $selection -MaximumJobHistoryRows $MaximumJobHistoryRows -WriteToHost N } #backup compression if ($VersionEdition.version -eq 10 -and $VersionEdition.edition -eq 3) { DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'backup compression default' -Value 1; } if ($VersionEdition.version -gt 10 -and $VersionEdition.Edition -notlike "Express*") { DPSQLSetSysConfig -TargetInstance $selection -SQLConfiguration 'backup compression default' -Value 1; } #ModifyXEvent DPSQLModifyXEvent -TargetInstance $selection #dp_mon create DPSQLCreate_dp_mon -TargetInstance $selection; DPSetMonitoringScript -WriteToHost N #Disabling SA $SQL = "if ((select is_disabled from sys.server_principals where name = 'sa') = 0) BEGIN ALTER LOGIN [sa] DISABLE; END" try { Invoke-Sqlcmd -ServerInstance $selection.fullname -Query $SQL -ConnectionTimeout 10 -ErrorAction stop DPLOG -WriteToHost $WriteToHost -Type SUCCESS -Message "SA disabled" } catch { DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.exception.message)" } DPSQLSetSystemProperty -TargetInstance $selection -NumberOfLogFiles 99 (DPCheckVolumeBlocksize -blocksize 65536) | where isCorrect -eq $false | %{ DPLOG -WriteToHost $WriteToHost -Type ERROR -Message "$($_.caption) blocksize is not 65536, Currently $($_.blocksize)`n" } if ((DPGetSQLInstances -WriteToHost N).count -gt 1){ DPLOG -WriteToHost $WriteToHost -Type WARNING -Message 'Multiple SQL instances Detected: Please verify memory allocation is not over subscribed' } if ($OSDetail[0].currentclockspeed -ne $OSDetail[0].maxclockspeed){ DPLOG -WriteToHost $WriteToHost -Type WARNING -Message 'Check High performance mode in the OS is set for Power options. CPU speeds are not maxed' } DPSQLNameChange -TargetInstance $selection -Check DPLOG -WriteToHost $WriteToHost -Type INFO -Message '/* ----------------------------- Datapipe Post-install Configuration Report ----------------------------- */' } END { Pop-Location DPLOG -WriteToHost Y -Type FINISH -Message "Log file located C:\Windows\Temp\DPAutomation.log" } } Function DPSQLSetDefaultFolders { <# .SYNOPSIS .PARAMETER ... .EXAMPLE -Param1 [CmdletBinding()] param( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { #$Global:folders } PROCESS { New-Item -ItemType directory -Path $DefaultData -Force | out-null New-Item -ItemType directory -Path $DefaultLog -Force | out-null New-Item -ItemType directory -Path $DefaultBackup -Force | out-null Set-Acl -AclObject $DataFolderACL -Path $DefaultData; Set-Acl -AclObject $DataFolderACL -Path $DefaultLog; Set-Acl -AclObject $DataFolderACL -Path $DefaultBackup; $query = "EXEC master..xp_instance_regwrite N'HKEY_LOCAL_MACHINE', @key='SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer', @value_name='BackupDirectory', @type='REG_SZ', @value='$DefaultBackup'; EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE' , N'Software\Microsoft\MSSQLServer\MSSQLServer' , N'DefaultData' , REG_SZ , N'$DefaultData'; EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE' , N'Software\Microsoft\MSSQLServer\MSSQLServer' , N'DefaultLog' , REG_SZ , N'$DefaultLog';" } END { } } Function DPGetNetVersion { [CMDLETBINDING()] param( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Returns object for all .net versions installed from registry. Author: Justin Procacci .DESCRIPTION Returns $Global:NetVersion object with a RegistryPath and Version. .EXAMPLE DPGetNetVersion #> begin { $NetPaths = @() $NetPaths += [string[]]((Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\') -match "v[2-3]").name.Replace("HKEY_LOCAL_MACHINE","HKLM:") #Net Versions 1-3 $NetPaths += 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full\1033' #4.0 $NetPaths += 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full' #4.5+ $Net1To3 = ((Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\') -match "v[2-3]")# | select -ExpandProperty property $Global:NetVersions = @() } process { Foreach($NetVersionName in $NetPaths) { switch -Wildcard ($NetVersionName) { '*\v2*' {$NetVersion = '2.0'} '*\v3.0*' {$NetVersion = '3.0'} '*\v3.5*' {$NetVersion = '3.5'} '*\full\1033' {$NetVersion = '4.0'} '*v4\full' {$NetVersion = '4.5'} } $RegistryObject = New-Object System.Object try { if (Test-Path $NetVersionName) { $RegistryObject | Add-Member -MemberType noteproperty -Name "RegistryPath" -Value $NetVersionName $RegistryObject | Add-Member -MemberType noteproperty -Name "Version" -Value (Get-ItemProperty -Path $NetVersionName -Name "Version").version $RegistryObject | Add-Member -MemberType noteproperty -Name "NetVersion" -Value $NetVersion $Global:NetVersions += $RegistryObject } } catch { $isError = $_.exception.message } } } end { if ($isError) { Write-Error -Message "Error - $isError" } else { return $Global:NetVersions } } } Function DPZipDirectory { [CMDLETBINDING(DefaultParameterSetName='Create')] param( [parameter(mandatory=$false,parametersetname='Create')] $Directory ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Creates a zip file from a directory Author: Justin Procacci .DESCRIPTION Creates a zip file from a directory .EXAMPLE DPZipFile -directory C:\test #> begin { #Check if .net 4.5 is installed if ((DPGetNetVersion).netversion -match "4.5"){ Add-Type -AssemblyName "system.io.compression.filesystem" } else { Write-Error "Error = .Net 4.5 required" } } process { switch ($PSCmdlet.ParameterSetName) { 'Create' { $ZipFileName = $Directory + ([regex]::Match($Directory,"^:\\[^\]]+").Groups[0].Value) + ".zip" #If it doesn't exist then create it if (!(Get-Item -Path $ZipFileName -ErrorAction SilentlyContinue)) { try { Write-Output "Creating: $($ZipFileName) from directory $($Directory)" [System.IO.Compression.ZipFile]::CreateFromDirectory($Directory,$ZipFileName) $action = "Created $($ZipFileName)" } catch { $action = "Error: $($_.exception.message)" } } else { $action = "$($ZipFileName) exists already" } } } } end { #DPAddConfigurationObject -Instance $env:COMPUTERNAME -Function $MyInvocation.MyCommand.Name -Configuration $Directory -CurrentValue '' -NewValue '' -Action $action } } Function DPUnZipFile { [CMDLETBINDING(DefaultParameterSetName='Create')] param( [parameter(mandatory=$false,parametersetname='Create')] $File ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) <# .SYNOPSIS Creates a zip file from a directory Author: Justin Procacci .DESCRIPTION Creates a zip file from a directory .EXAMPLE DPZipFile -File C:\test.zip #> begin { #Check if .net 4.5 is installed if ((DPGetNetVersion).netversion -match "4.5"){ Add-Type -AssemblyName "system.io.compression.filesystem" } else { Write-Error "Error = .Net 4.5 required" } } process { switch ($PSCmdlet.ParameterSetName) { 'Create' { $directory = ([regex]::Match($File,"^.*[^\.zip]").Groups[0].Value) #If it doesn't exist then create it if (!(Get-Item -Path $directory -ErrorAction SilentlyContinue)) { try { Write-Output "Creating: $($directory) from zip $($File)" [System.IO.Compression.ZipFile]::ExtractToDirectory($File,$directory) $action = "Created $($directory)" } catch { $action = "Error: $($_.exception.message)" } } else { $action = "$($directory) exists already" } } } } end { #DPAddConfigurationObject -Instance $env:COMPUTERNAME -Function $MyInvocation.MyCommand.Name -Configuration $File -CurrentValue '' -NewValue '' -Action $action } } Function DPSQLGetRestoreFiles { <# .SYNOPSIS Gets a list of .bak files from a directory and sub directories .DESCRIPTION Retrieves a list of database files from a directory and groups them by the database .PARAMETER Directory Directory to be scanned .EXAMPLE DPSQLGetRestoreFiles -Directory d:\Backupfiles\ #> [CmdletBinding()] param( [parameter(mandatory=$True)] [ValidateScript({Test-Path "filesystem::$_" -PathType Container})] [string]$Directory ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { #Get all bak files from directory and group by database $FileCollection = gci -Recurse "filesystem::$directory" | where Extension -in ('.bak','.trn') | select fullname, LastWriteTime, basename #| select @{expression={[regex]::Match($_.BaseName,"^(.*?)(_[0-9]{16,}.*)").Groups[1].Value;};label="DBName"},fullname | Group-Object -Property DBName } PROCESS { } END { return $FileCollection; } } Function DPSQLBackupFileInformation { <# .SYNOPSIS Get a SQL Header from a backup. .DESCRIPTION Provide it a database backup file and the instance you want to restore it to .PARAMETER Instance Instance the RESTORE HeaderOnly will be executed against .PARAMETER File SQL BAK to get the HeaderOnly info .EXAMPLE DPSQLBackupFileInformation -Instance Name1 -File c:\backup.bak #> [CmdletBinding()] param( [parameter(mandatory=$False,position=0)] $TargetInstance ,[parameter(mandatory=$True,position=1)] [ValidateScript({Test-Path "filesystem::$_" -PathType Any})] [string]$File ,[parameter(mandatory=$False,position=2)] [switch]$ReadBackupHeader ,[parameter(mandatory=$False,position=3)] [switch]$ReadFileList ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } else { $selection = $TargetInstance; } $BackupFileInformation = New-Object System.Object; $BackupInformation = @() } PROCESS { Write-Host "$file" $srv = New-Object ('Microsoft.SQLServer.Management.SMO.Server') $TargetInstance.fullname $rs = new-object('Microsoft.SqlServer.Management.Smo.Restore') $bdi = new-object ('Microsoft.SqlServer.Management.Smo.BackupDeviceItem') ($File, 'File') $rs.Devices.Add($bdi) #Header Only $bh = $rs.ReadBackupHeader($srv) $bh | %{ #File List $fl = $rs.ReadFileList($srv) $DatabaseName = $_.DatabaseName $FirstLSN = $_.FirstLSN $LastLSN = $_.LastLSN $CheckpointLSN = $_.CheckpointLSN $DatabaseBackupLSN = $_.DatabaseBackupLSN $BackupStartDate = $_.BackupStartDate $BackupFinishDate = $_.BackupFinishDate $fl | %{ $BackupFileInformation = New-Object System.Object; $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'DatabaseName' -Value $DatabaseName $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'FirstLSN' -Value $FirstLSN $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'LastLSN' -Value $LastLSN $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'CheckpointLSN' -Value $CheckpointLSN $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'DatabaseBackupLSN' -Value $DatabaseBackupLSN $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'BackupStartDate' -Value $BackupStartDate $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'BackupFinishDate' -Value $BackupFinishDate $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'LogicalName' -Value $_.LogicalName $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'fileid' -Value $_.fileid $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'Type' -Value $_.Type $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'SizeMB' -Value ($_.Size / 1MB) $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'Drive' -Value (Split-Path $_.PhysicalName -Qualifier) $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'Folder' -Value (Split-Path $_.PhysicalName -Parent) $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'File' -Value (Split-Path $_.PhysicalName -Leaf) $BackupFileInformation | Add-Member -MemberType noteproperty -Name 'FileExt' -Value ([regex]::Match($_.physicalname,"...$").captures.value) #I'm assuming the file extension will be 3 letters :) $BackupInformation += $BackupFileInformation } } } END { return $BackupInformation } } Function DPSQLRestoreFileList { <# .SYNOPSIS Get a SQL File list from a FULL backup .DESCRIPTION Provide it a database backup file and the instance you want to restore it to .PARAMETER Instance Instance the RESTORE FileList will be executed against .PARAMETER File SQL BAK to get the file listing .EXAMPLE DPSQLGetRestoreFileList -Instance Name1 -File #> [CmdletBinding()] param( [parameter(mandatory=$False)] $TargetInstance ,[parameter(mandatory=$True)] [ValidateScript({Test-Path $_ -PathType Any})] [string]$File ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } $selection = $TargetInstance; $selection } PROCESS { $srv = New-Object ('Microsoft.SQLServer.Management.SMO.Server') $selection.fullname $rs = new-object('Microsoft.SqlServer.Management.Smo.Restore') $bdi = new-object ('Microsoft.SqlServer.Management.Smo.BackupDeviceItem') ($File, 'File') $rs.Devices.Add($bdi) $fl = $rs.ReadFileList($srv) } END { return $fl | select LogicalName, fileid, Type, @{Name='SizeMB';Expression={$_.Size / 1MB}}, @{Name='Drive';Expression={Split-Path $_.PhysicalName -Qualifier}}, @{Name='Folder';Expression={Split-Path $_.PhysicalName -Parent}}, @{Name='File';Expression={Split-Path $_.PhysicalName -Leaf}} } } Function DPSQLGenerateRestoreTSQL { <# .SYNOPSIS Restore a database from a collection of .BAK files .DESCRIPTION Provide it 1 or more .bak files for restore. Expecting the files have _FULL and _DIFF in them. .PARAMETER Instance .PARAMETER File SQL BAK to get the file listing .EXAMPLE DPSQLGenerateRestoreTSQL -File #> [CmdletBinding()] param( [parameter(mandatory=$False)] $TargetInstance, [parameter(mandatory=$True)] $Directory, [parameter(mandatory=$false)] [ValidateScript({Test-Path $_ -PathType Any})] $NewDatabaseNameMapCSV, [parameter(mandatory=$True)] $DataFileLocation, [parameter(mandatory=$False)] $SecondaryDataFileLocation, [parameter(mandatory=$True)] $LogFileLocation, [parameter(mandatory=$False)] [validateset("RECOVERY","NORECOVERY")] $RecoveryType = 'NORECOVERY', [parameter(mandatory=$False)] [switch]$Replace ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { if (!$Targetinstance){ (DPSelectTargetInstance | Out-Null) } #Get Files from directory $Files = DPSQLGetRestoreFiles -Directory $Directory #clean folders if ($DataFileLocation -notmatch "\\$"){ $DataFileLocation += "\"} if ($SecondaryDataFileLocation) { if ($SecondaryDataFileLocation -notmatch "\\$") { $SecondaryDataFileLocation += "\" } } else { $SecondaryDataFileLocation = $DataFileLocation } if ($LogFileLocation -notmatch "\\$"){ $LogFileLocation += "\"} } PROCESS { $importedNames = import-csv $NewDatabaseNameMapCSV -Delimiter "," $importedNames $AllInfo = $Files | Where-Object fullname -match "FULL_1.*$" | %{DPSQLBackupFileInformation -TargetInstance $selection -File $_.fullname} $DatabasesToBeRestored = $AllInfo | Select-Object -Property DatabaseName -Unique $RestoreTSQL = '' $DatabasesToBeRestored foreach ($database in $DatabasesToBeRestored) { $CurrentDatabase = $AllInfo | where databasename -eq $database.databasename #gets all the files for that database $DatabaseFiles = $files | where basename -match "$($database.databasename)_[0-9]{16,}"#[regex]::Match($_.BaseName,"$($database.databasename)_[0-9]{16,}_[F]").Groups[0].Value;} #Just get each type of file $fulls = $DatabaseFiles | where basename -Like "*FULL*" $Differentials = $DatabaseFiles | where basename -Like "*DIFF*" Write-Host "starting $($database.databasename)" $newName = $importedNames | where original -eq $database.databasename | select new $newName if ($newName){ $RestoreTSQL += "`r`nPRINT 'Restoring $($newName.new) originally ($($database.databasename)) - ' + (cast((getdate()) as nvarchar(100)))`r`n USE [master];`r`nGO`r`n" $RestoreTSQL += "RESTORE DATABASE [$($newName.new)] `r`n FROM " $RestoreTSQL += $Fulls | %{"DISK = N'$($_.fullname)' `r`n,"} #Restore file ending comma $RestoreTSQL = $RestoreTSQL -replace ".$" $RestoreTSQL += " WITH FILE = 1, NOUNLOAD, STATS = 5, $(if ($Replace) { "REPLACE ,"}) $(if (!$Differentials){$RecoveryType + "`r`n,"} else{"NORECOVERY `r`n,"}) " $dcnt = 1; $lcnt = 1; $RestoreTSQL += $CurrentDatabase | %{ "MOVE N'$($_.LogicalName)' TO N'$( if ($_.fileid -eq 1) {$DataFileLocation + $($newName.new) + "." + $($_.fileExt)} elseif ($_.fileid -eq 2 -and $_.type -eq 'L') {$LogFileLocation + $($newName.new) + "." + $($_.fileExt)} elseif ($_.fileid -gt 2 -and $_.type -eq 'L') {$LogFileLocation + $($newName.new) + "_" + $($lcnt) + "." + $($_.fileExt)} elseif ($_.fileid -gt 2 -and $_.type -eq "D" ) {$SecondaryDataFileLocation + $($newName.new) + "_" + $($dcnt) + "." + $($_.fileExt)})'`r`n," if ($_.type -eq 'D'){ $dcnt++;} if ($_.type -eq 'l'){ $lcnt++;} } #Restore destination ending comma $RestoreTSQL = $RestoreTSQL -replace ".$" #Add Diff Restore restring $RestoreTSQL += "`r`nGO`r`nRESTORE DATABASE [$($newName.new)] `r`n FROM " $RestoreTSQL += $Differentials | %{"DISK = N'$($_.fullname)' `r`n,"} #Restore destination ending comma $RestoreTSQL = $RestoreTSQL -replace ".$" $RestoreTSQL += " WITH FILE = 1, NOUNLOAD, STATS = 5, $($RecoveryType)`r`n," $RestoreTSQL = $RestoreTSQL -replace ".$" $RestoreTSQL += "`r`nGO" } else { Write-Host -BackgroundColor Black -ForegroundColor Red "Warning: Original database: $($database.databasename) has no correlating new database name...skipping." $newName } } } END { $Date = get-date -Uformat '%m%d%y_%H%M%S' Set-Content -Value $RestoreTSQL -Path "$($PSScriptRoot)\ScriptGen_$($Date).sql" #Out-File -FilePath "$($PSScriptRoot)\ScriptGen_$($Date).sql" -InputObject $restoreTSQL Write-Host "Script file located: $($PSScriptRoot)\ScriptGen_$($Date).sql" -ForegroundColor Green Write-Host "Opening Script file located: $($PSScriptRoot)\ScriptGen_$($Date).sql" -ForegroundColor Green notepad "$($PSScriptRoot)\ScriptGen_$($Date).sql" } } Function DPGetLastFullBackup { [CmdletBinding()] param( [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Instance , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $DatabaseName , [parameter(mandatory=$false, ValueFromPipelineByPropertyName=$true)] [switch]$Latest , [parameter(mandatory=$false, ValueFromPipelineByPropertyName=$true)] [datetime]$PointInTime ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN{ Write-Host "Getting full backup for $($DatabaseName) before $PointInTime" -ForegroundColor green -BackgroundColor Black if ($latest) { $Query = @" SELECT top 1 "@ } else { $Query = @" SELECT "@ } $query += @" bf.physical_device_name, bs.backup_start_date, bs.checkpoint_lsn, bs.position, type FROM msdb.dbo.backupmediafamily bf INNER JOIN msdb.dbo.backupset bs ON bf.media_set_id = bs.media_set_id WHERE bs.database_name = '$($DatabaseName)' and bs.type='D' and is_copy_only = 0 and is_snapshot = 0 and bs.backup_start_date < '$($PointInTime)' ORDER BY bs.backup_start_date desc "@ } PROCESS{ $Results = Invoke-Sqlcmd -ServerInstance $Instance -Database $DatabaseName -Query $Query -ConnectionTimeout 5 -QueryTimeout 30 } END{ $results | select @{expression={"$Instance"};Label='Instance'},@{expression={"$DatabaseName"};Label='DatabaseName'}, physical_device_name, backup_start_date,checkpoint_lsn, position, type } } Function DPGetDifferentialForFull { [CmdletBinding()] param( [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Instance , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $DatabaseName , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Physical_device_name , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $backup_start_date , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $checkpoint_lsn , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $position ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN{ Write-Host "Getting Differentials" -ForegroundColor green -BackgroundColor Black $Query = @" SELECT bs.database_name, bf.physical_device_name, bs.backup_start_date, bs.checkpoint_lsn, bs.position, type FROM msdb.dbo.backupmediafamily BF INNER JOIN msdb.dbo.backupset BS ON bf.media_set_id = bs.media_set_id WHERE bs.type='I' and is_copy_only = 0 and is_snapshot = 0 "@ } PROCESS{ $PerDBQuery = $query + @" AND bs.database_name = '$($DatabaseName)' AND bs.database_backup_lsn = '$($checkpoint_lsn)' "@ $results += @(Invoke-Sqlcmd -ServerInstance $Instance -Database $DatabaseName -Query $PerDBQuery | ` select @{expression={"$Instance"};Label='Instance'}, @{expression={"$DatabaseName"};Label='DatabaseName'}, @{expression={"$physical_device_name"};Label='FullBackup'}, @{expression={"$position"};Label='FullBackup_position'},` backup_start_date,checkpoint_lsn, physical_device_name, position,type) } END{ $results } } Function DPGetLogsAfterFull { [CmdletBinding()] param( [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Instance , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $DatabaseName , [parameter(mandatory=$false, ValueFromPipelineByPropertyName=$true)] $Physical_device_name , [parameter(mandatory=$false, ValueFromPipelineByPropertyName=$true)] $backup_start_date , [parameter(mandatory=$false, ValueFromPipelineByPropertyName=$true)] $checkpoint_lsn , [parameter(mandatory=$false, ValueFromPipelineByPropertyName=$true)] $position ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN{ $Query = @" SELECT bf.physical_device_name, bs.type, backup_start_date, bs.checkpoint_lsn, bs.position FROM msdb.dbo.backupmediafamily bf INNER JOIN msdb.dbo.backupset BS ON bf.media_set_id = bs.media_set_id WHERE bs.type='L' and is_copy_only = 0 and is_snapshot = 0 "@ } PROCESS{ Write-Host "DPGetLogsAfterFull - Start - Get log files for $($DatabaseName)" -ForegroundColor green -BackgroundColor Black $PerDBQuery = $query + @" AND bs.database_name = '$($DatabaseName)' ORDER BY bs.backup_start_date asc; "@ #AND bs.backup_start_date >= '$($backup_start_date)' $results += @(Invoke-Sqlcmd -ServerInstance $Instance -Database $DatabaseName -Query $PerDBQuery | ` select @{expression={"$Instance"};Label='Instance'}, @{expression={"$DatabaseName"};Label='DatabaseName'}, @{expression={"$physical_device_name"};Label='FullBackup'}, @{expression={"$position"};Label='FullBackup_position'},` backup_start_date, physical_device_name, type, position) } END{ Write-Host "DPGetLogsAfterFull - FINISH - Get log files for $($DatabaseName)" -ForegroundColor green -BackgroundColor Black $results } } function DPRestoreToPointInTime { [CmdletBinding()] param( [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Instance , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $DatabaseName , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] [Validatescript({$_ -match "^\d{2}:\d{2}:\d{2}$"})] $RestoreTime , [parameter(mandatory=$false)] [switch]$UseDifferential ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN{ Write-Host "DPRestoreToPointInTime - Start" -ForegroundColor green -BackgroundColor Black [datetime]$RestoreDateTime = Get-Date "$($RestoreTime)" } PROCESS{ #Get Latest Full $Full = DPGetLastFullBackup -Instance $Instance -DatabaseName $DatabaseName -Latest -PointInTime $RestoreDateTime if ($Full) { Write-Host "DPRestoreToPointInTime - Found $(($Full | Measure-Object).Count) for the latest full backup" -BackgroundColor Black -ForegroundColor Green } else { Write-Host "DPRestoreToPointInTime - Found $(($Full | Measure-Object).Count) for the latest full backup..exiting" -BackgroundColor Black -ForegroundColor Green return; } $FinalFiles = @($full | select instance,databasename,backup_start_date,position,Physical_device_name,type) if ($UseDifferential) { #Will attempt to use diff and after Write-Host "DPRestoreToPointInTime - Attempt restore $DatabaseName using differential backup" -ForegroundColor green -BackgroundColor Black #Get Diffs for the latest full backup $diffs = DPGetLastFullBackup -Instance $Instance -DatabaseName $DatabaseName -Latest -PointInTime $RestoreDateTime | DPGetDifferentialForFull if ($Diffs) { #There are differentials to use Write-Host "DPRestoreToPointInTime - Found $(($diffs | Measure-Object).Count) for the latest full backup" -ForegroundColor Green -BackgroundColor Black } } #Get All logs after the FULL Write-Host "DPRestoreToPointInTime - getting log files" -ForegroundColor green -BackgroundColor Black $logs = DPGetLogsAfterFull -Instance $Instance -DatabaseName $DatabaseName #trim logs after the full $BetweenFullandRestoreTime = $logs | where backup_start_date -gt $full.backup_start_date | where backup_start_date -lt $RestoreDateTime if ($logs) { Write-Host "DPRestoreToPointInTime - Found $(($BetweenFullandRestoreTime | Measure-Object).Count) logs for the latest full backup" -ForegroundColor Green -BackgroundColor Black } Write-Host "DPRestoreToPointInTime - Generate files to restore to $($RestoreDateTime)" -ForegroundColor green -BackgroundColor Black #$Full | where backup_start_date -lt $RestoreDateTime | select physical_device_name, backup_start_date $LatestDiff = ($diffs | where backup_start_date -lt $RestoreDateTime | select instance,databasename,backup_start_date,position,PHysical_device_name,type) | Select-Object -Last 1 if ($UseDifferential){ #Differentials $FinalFiles += @($LatestDiff | select instance,databasename,backup_start_date,position,physical_device_name,type) #Transaction Logs $FinalFiles += @($BetweenFullandRestoreTime | where backup_start_date -gt $LatestDiff.backup_start_Date | select instance,databasename,backup_start_date,position,PHysical_device_name,type) } else { $FinalFiles += @($BetweenFullandRestoreTime | select instance,databasename,backup_start_date,position,PHysical_device_name,type) } #Log file that contains the point in time. $PointInTimeLog = $logs | where backup_start_date -gt ([datetime]$RestoreDateTime) | select -First 1 $FinalFiles += @($PointInTimeLog | select instance,databasename,backup_start_date,position,physical_device_name,type, @{expression={"$RestoreTime"};Label="RestoreTime"}) } END{ Write-Host "DPRestoreToPointInTime - Finish" -ForegroundColor green -BackgroundColor Black $FinalFiles } } Function DPGenerateRestoreTSQL { param( [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Instance , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $DatabaseName , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] [Validatescript({$_ -match "^\d{2}:\d{2}:\d{2}$"})] $RestoreTime , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $NewName , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] [switch]$Replace , [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] [validateset("RECOVERY","NORECOVERY")] $RecoveryType = 'NORECOVERY' ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { } PROCESS { $Files = DPRestoreToPointInTime -Instance $Instance -DatabaseName $DatabaseName -RestoreTime $RestoreTime -UseDifferential $full = $Files | where type -eq 'D' | %{ DPSQLBackupFileInformation -instance $Instance -File $_.physical_device_name} $Diff = $Files | where type -eq 'I' | %{ DPSQLBackupFileInformation -instance $Instance -File $_.physical_device_name} $Logs = $Files | where type -eq 'L' | %{ DPSQLBackupFileInformation -instance $Instance -File $_.physical_device_name} Write-Host "Restoring full backup with start date of $($full[0].BackupStartDate)" -BackgroundColor Black -ForegroundColor Green if ($newName){ $RestoreTSQL += "`r`nPRINT 'Restoring $($newName) originally ($($DatabaseName)) - ' + (cast((getdate()) as nvarchar(100)))`r`n USE [master];`r`nGO`r`n" $RestoreTSQL += "RESTORE DATABASE [$($newName)] `r`n FROM " $RestoreTSQL += $Files | where type -eq 'D' | %{"DISK = N'$($_.physical_device_name)' `r`n,"} #Restore file ending comma $RestoreTSQL = $RestoreTSQL -replace ".$" $RestoreTSQL += " WITH FILE = $(($Files | where type -eq 'D')[0].position), NOUNLOAD, STATS = 5, $(if ($Replace) { "REPLACE ,"}) $("$RecoveryType`r`n,")" $dcnt = 1; $lcnt = 1; $RestoreTSQL += $full | %{ " MOVE N'$($_.LogicalName)' TO N'$( $_.folder + "\" + $_.file -replace $databasename , $newName)'`r`n," } #Restore destination ending comma $RestoreTSQL = $RestoreTSQL -replace ".$" Write-Host "Restoring diff with backup with start date of $($diff[0].BackupStartDate)" -BackgroundColor Black -ForegroundColor Green #Add Diff Restore restring $RestoreTSQL += "`r`nGO`r`nRESTORE DATABASE [$($newName)] `r`n FROM " $RestoreTSQL += $Files | where type -eq 'I' | %{"DISK = N'$($_.physical_device_name)' `r`n,"} #Restore destination ending comma $RestoreTSQL = $RestoreTSQL -replace ".$" $RestoreTSQL += " WITH FILE = 1, NOUNLOAD, STATS = 5, $($RecoveryType)`r`n," $RestoreTSQL = $RestoreTSQL -replace ".$" $RestoreTSQL += "`r`nGO" $StopAt = ((get-date -Uformat '%Y-%m-%d') + "T" + $RestoreTime) $Logs | %{ Write-Host "Restoring log with backup with start date of $($_.BackupStartDate)" -BackgroundColor Black -ForegroundColor Green } #Add Log Restore $RestoreTSQL += $Files | where type -eq 'L' | %{ "`r`nRESTORE DATABASE [$($newName)] `r`n FROM " + "DISK = N'$($_.physical_device_name)' `r`n" + " WITH FILE = 1, NOUNLOAD, STATS = 5, $($RecoveryType), Stopat = '$StopAt'" } $RestoreTSQL += "`r`nGO" } else { write-host "No files found" -BackgroundColor Black -ForegroundColor Red return; } } END { $Date = get-date -Uformat '%m%d%y_%H%M%S' <#Set-Content -Value $RestoreTSQL -Path "$($PSScriptRoot)\ScriptGen_$($Date).sql" #Out-File -FilePath "$($PSScriptRoot)\ScriptGen_$($Date).sql" -InputObject $restoreTSQL Write-Host "Script file located: $($PSScriptRoot)\ScriptGen_$($Date).sql" -ForegroundColor Green Write-Host "Opening Script file located: $($PSScriptRoot)\ScriptGen_$($Date).sql" -ForegroundColor Green notepad "$($PSScriptRoot)\ScriptGen_$($Date).sql" #> return $RestoreTSQL } } Function DPGetAGReplicaConfig { param( [parameter(mandatory=$true, ValueFromPipelineByPropertyName=$true)] $Instance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { $Query = 'select ag.name, ar.replica_server_name [secondary_replica] , ags.primary_replica from sys.availability_groups ag join sys.availability_replicas ar on ag.group_id = ar.group_id join sys.dm_hadr_availability_group_states ags on ar.group_id = ags.group_id where ar.replica_server_name <> ags.primary_replica' } PROCESS { Invoke-Sqlcmd -ServerInstance $Instance -Database master -Query $Query -ConnectionTimeout 5 -QueryTimeout 30 } END { } } Function DPAddDatabaseToAgSecondary { param( [parameter(mandatory=$true)] $Instance , [parameter(mandatory=$true)] $Database , [parameter(mandatory=$true)] $AGName ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { $addSecondary = @" begin try declare @conn bit declare @count int declare @replica_id uniqueidentifier declare @group_id uniqueidentifier set @conn = 0 set @count = 30 -- wait for 5 minutes if (serverproperty('IsHadrEnabled') = 1) and (isnull((select member_state from master.sys.dm_hadr_cluster_members where upper(member_name COLLATE Latin1_General_CI_AS) = upper(cast(serverproperty('ComputerNamePhysicalNetBIOS') as nvarchar(256)) COLLATE Latin1_General_CI_AS)), 0) <> 0) and (isnull((select state from master.sys.database_mirroring_endpoints), 1) = 0) begin select @group_id = ags.group_id from master.sys.availability_groups as ags where name = N'$($AGConfig.name)' select @replica_id = replicas.replica_id from master.sys.availability_replicas as replicas where upper(replicas.replica_server_name COLLATE Latin1_General_CI_AS) = upper(@@SERVERNAME COLLATE Latin1_General_CI_AS) and group_id = @group_id while @conn <> 1 and @count > 0 begin set @conn = isnull((select connected_state from master.sys.dm_hadr_availability_replica_states as states where states.replica_id = @replica_id), 1) if @conn = 1 begin -- exit loop when the replica is connected, or if the query cannot find the replica status break end waitfor delay '00:00:10' set @count = @count - 1 end end end try begin catch -- If the wait loop fails, do not stop execution of the alter database statement end catch ALTER DATABASE [$($NewDB)] SET HADR AVAILABILITY GROUP = [$($AGConfig.name)]; GO GO "@ } PROCESS { Invoke-Sqlcmd -ServerInstance $Instance -Database master -Query $addSecondary -ConnectionTimeout 5 -QueryTimeout 30 -Verbose } END { } } Function GetSQLDataDiskUsage { [CMDLETBINDING()] param( [parameter(mandatory=$true)] [string]$ServerInstance ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { DPLOG -WriteToHost $WriteToHost -Message "$($MyInvocation.InvocationName) - BEGIN" -Level INFO [string]$query = "select volume_mount_point, total_bytes, Available_bytes, a.usage, left(f.physical_name,len(f.physical_name)-charindex('\',reverse(f.physical_name)))[directory] from (select left(mf2.physical_name,3) [disk] , stuff((select ',' + type_desc as [text()] from sys.master_files mf where left(mf.physical_name,3) = left(mf2.physical_name,3) group by left(mf.physical_name,3), type_desc for xml path('')),1,1,'') [usage] from sys.master_files mf2) a join sys.master_files AS f ON a.disk = left(f.physical_name,3) CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.file_id) WHERE f.database_id > 4 GROUP BY volume_mount_point, total_bytes, Available_bytes, a.usage, left(f.physical_name,len(f.physical_name)-charindex('\',reverse(f.physical_name))) ORDER BY 1 asc;" } PROCESS { #Connect to Instance and get summary stats try { $SummaryResults = Invoke-Sqlcmd -ServerInstance $ServerInstance -Database master -Query $query -ErrorAction Stop -ConnectionTimeout 10 -Verbose $SummaryResults = $SummaryResults | select volume_mount_point, usage,directory, @{expression={[math]::Round((($_.available_bytes / $_.total_bytes) * 100),1)};label='PercentFree'}, @{expression={[int]($_.available_bytes / 1024/1024.00/1024)};label='AvailableGB'} #Convert data row to custom object $SummaryResults = $SummaryResults | ForEach-Object { [pscustomobject]@{ Volume = $_.volume_mount_point; ` Usage = $_.usage; ` directory = $_.directory; ` PercentFree = $_.PercentFree;` AvailableGB = $_.AvailableGB; } } } catch { DPLOG -Level ERROR -Message "$($_.exception.message)" } } END{ $SummaryResults; DPLOG -WriteToHost $WriteToHost -Message "$($MyInvocation.InvocationName) - END" -Level INFO } } Function CreateDatabase { [CMDLETBINDING()] param( [parameter(mandatory=$true)] [string]$ServerInstance , [parameter(mandatory=$true)] [string]$DatabaseName , [parameter(mandatory=$false)] [int]$FileCount = 4 , [parameter(mandatory=$false)] [int]$FileSizeGB = 5 ,[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [ValidateSet('Y','N')] [string]$WriteToHost = "Y" ) BEGIN { DPLOG -WriteToHost $WriteToHost -Message "$($MyInvocation.InvocationName) - BEGIN" -Level INFO #Get drive usage $diskUsage = GetSQLDataDiskUsage -ServerInstance $ServerInstance #| where usage -eq 'rows' | Sort-Object -Descending availableGB | Select-Object -First $FileCount $dataUsage = $diskUsage | where usage -eq 'ROWS' | Sort-Object -Descending availableGB | Select-Object -First $FileCount $LogUsage = $diskUsage | where usage -eq 'LOG' | Sort-Object -Descending availableGB | Select-Object -First 1 } PROCESS { #Database exists check $DBExists = Invoke-Sqlcmd -ServerInstance $ServerInstance -Database master -ConnectionTimeout 10 -Query "select * from sys.databases where name = '$($DatabaseName)';" if ($DBExists) { DPLOG -WriteToHost $WriteToHost -Message "Database $($DatabaseName) exists exiting" -Level WARNING } else { #Generate TSQL Statement for a new database DPLOG -WriteToHost $WriteToHost -Message "Generating TSQL for creating $($DatabaseName) on $($FileCount) least used volumes with size of $($FileSizeGB) GB." -Level INFO try { $CreateTSQL += "CREATE DATABASE [$($DatabaseName)] `r`n CONTAINMENT = NONE`r`n ON PRIMARY `r`n " $CreateTSQL += 1..$FileCount | %{"( NAME = N'$($DatabaseName)', FileName = N'$($dataUsage[$_-1].directory)\$($DatabaseName)$(if ($_ -eq 1) {".mdf"}else {"_$_.ndf"})' , SIZE = $($FileSizeGB)GB)`r`n,"} #Restore destination ending comma $CreateTSQL = $CreateTSQL -replace ".$" $CreateTSQL += "LOG ON `r`n " $CreateTSQL += "( NAME = N'$($DatabaseName)_log', FILENAME = N'$($LogUsage.directory)\$($DatabaseName)_log.ldf' , SIZE = $($FileSizeGB)GB )`r`nGO" DPLOG -WriteToHost $WriteToHost -Message "Create TSQL ran without error" -Level SUCCESS $CreateTSQL } catch { DPLOG -WriteToHost $WriteToHost -Message "$($_.exception.message)" -Level ERROR } } } END { DPLOG -WriteToHost $WriteToHost -Message "$($MyInvocation.InvocationName) - END" -Level INFO } }