MSSQL List Active DBFiles

Met behulp van de volgende query kun je een overzicht opvragen van alle actieve bestanden eventueel kun je een WHERE clause opnemen (WHERE type_desc = ‘LOG|ROWS’) om alleen de logbestanden of alleen de data bestanden weer te geven.

SELECT smf.physical_name, sdb.name as database_name
FROM sys.master_files smf
LEFT JOIN sys.databases sdb on sdb.database_id = smf.database_id
--WHERE type_desc = 'LOG'
ORDER BY smf.physical_name

PowerShell Check Database-backup

This next script can be used to check if Full and Transaction Log backups are made within the last two days. Databases are read from a CSV file. I use a slightly modified version which reads databases from a registration database.

# ********************************************************************
# Scriptnaam: CHECKBACKUP.PS1
# Geschreven_door: Tim van Kooten Niekerk
# Versie: 20110811A
# Info: Check if backup is made within last two days...
# ********************************************************************

# Global config settings...
[string]$sServerInstanceFile = ".ServerInstance.csv"
[string]$sSMTPServer1 = "smtp-server-name"
[string]$sToAddress1 = "email-adsress"

# Global objects...
$oNETIP = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()

# Register Snapins...
$oPSSnapinRegResult = PSSnapin SqlServerCmdletSnapin* -registered
if ($oPSSnapinRegResult) {
  $oPSSnapinResult = PSSnapin $oPSSnapinRegResult.Name
  if (-not $oPSSnapinResult) { 
    Add-PSSnapin $oPSSnapinRegResult.Name
  }
} else {
  break
}
  
# Functions and Procedures...
function fSendMail([string]$sSMTPSrvrName, [string]$sFrom, [string]$sTo, [string]$sSubject, [string]$sBody, [string]$sAttFileName) {
  if (($sSMTPSrvrName) -and ($sFrom) -and ($sTo) -and $sSubject) {
  
    # Declare mail objects...
    $oMessage = new-object Net.Mail.MailMessage
    $oSMTP = new-object Net.Mail.SmtpClient($sSMTPSrvrName)

    # Pass values to object...
    $oMessage.From = $sFrom
    $oMessage.To.Add($sTo)
    $oMessage.Subject = $sSubject
    if ($sBody) { $oMessage.Body = $sBody }

    # Add attachment...
    if ($sAttFileName) {
      $oAttachment = new-object Net.Mail.Attachment($sAttFileName)
      $oMessage.Attachments.Add($oAttachment)
    }

    $oSMTP.Send($oMessage)
    if ($? -eq "True") {
      return "INFO: Email has been sent."
    } else {
      return "ERROR: Error sending e-mail."
    }

  } else {
    return "ERROR: Argument(s) missing. [fSendMail `"SMTPServerName`" `"From`" `"To`" `"Subject`" (`"Body`") (`"AttachFileName`")]"
  }
}

function fSQLCmd([string]$sInstance, [string]$sQuery, [string]$sDatabase) {
  if ($sDatabase) {
    [string]$sQuery = "Invoke-SqlCmd -ServerInstance " + $sInstance + " -Database " + $sDatabase + " -QueryTimeout 30 -Query `"" `
                               + $sQuery + "`" ; if (`$? -eq `$false) { @{`"ERROR0`" = `$error[0]}; @{`"ERROR1`" = `$error[1]} }" 
  } else {
    [string]$sQuery = "Invoke-SqlCmd -ServerInstance " + $sInstance + " -QueryTimeout 30 -Query `"" + $sQuery + "`" ; `
                               if (`$? -eq `$false) { @{`"ERROR0`" = `$error[0]}; @{`"ERROR1`" = `$error[1]} }" 
  }
  return Invoke-Expression $sQuery
}

# Start Main script...
[int]$iCounter = 0
Import-Csv $($sServerInstanceFile) -header ("instance", "checkfull", "checktl") | foreach {
  # Skip header...
  if (($iCounter -ne 0) -and ($_.instance)) {
    $oResult1 = $null
    $oResult2 = $null
    # Run Queries on servers...
    if ($_.checkfull -eq 1) {
      [string]$sQuery1 = "/* ##### Begin T-SQL Query... ##### */ `
      SELECT sys.databases.name AS NoRecentFullBackup `
      FROM sys.databases `
      WHERE sys.databases.name NOT IN `
      (SELECT DISTINCT sys.databases.name from sys.databases `
      INNER JOIN msdb..backupset ON sys.databases.name = msdb..backupset.database_name `
      WHERE ((msdb..backupset.type = 'D' OR msdb..backupset.type = 'I') `
      AND msdb..backupset.is_copy_only = 0 `
      AND msdb..backupset.backup_start_date > (GetDate() -2))) `
      AND sys.databases.state = 0 `
      AND sys.databases.name  'tempdb' `
      /* ##### Einde T-SQL Query... ##### */"
      # Forceer in een object zodat we altijd kunnen tellen...
      [Object[]]($oResult1) = fSQLCmd $($_.instance) $sQuery1 "master"
    }


    if ($_.checktl -eq 1) {
      [string]$sQuery2 = "/* ##### Begin T-SQL Query... ##### */ `
      SELECT sys.databases.name AS NoRecentTLBackup `
      FROM sys.databases `
      WHERE sys.databases.name NOT IN `
      (SELECT DISTINCT sys.databases.name from sys.databases `
      INNER JOIN msdb..backupset ON sys.databases.name = msdb..backupset.database_name `
      WHERE (msdb..backupset.type = 'L' AND msdb..backupset.backup_start_date > (GetDate() -2))) `
      AND sys.databases.recovery_model != 3 and sys.databases.state = 0 `
      /* ##### Einde T-SQL Query... ##### */"
      # Forceer in een object zodat we altijd kunnen tellen...
      [Object[]]($oResult2) = fSQLCmd $($_.instance) $sQuery2 "master"
    }

    # Zodra er rows worden geteld een e-mail samenstellen...
    if (($oResult1.Count -gt 0) -or ($oResult2.Count -gt 0)) {
      $oResult1 = $oResult1 | Out-String
      $oResult2 = $oResult2 | Out-String
      [string]$sFromAddress1 = "noreply@" + $oNETIP.HostName + "." + $oNETIP.DomainName
      [string]$sBody1 = $oResult1 + $oResult2
      [string]$sSubject1 = $($_.instance.Replace("", "_")) + ":Database backup older than 2 days..."
      fSendMail $sSMTPServer1 $sFromAddress1 $sToAddress1 $sSubject1 $sBody1
    }
  }
  $iCounter++
}
# ********************************************************************

CSV File format:

instance,checkfull,checktl
SERVERA,1,1
SERVERBINS1,1,1
SERVERC,1,1

PowerShell E-mail Function

Met behulp van onderstaande functie kun je vanuit een script een e-mail verzenden. De procedure is in een functie gegoten waardoor deze gemakkelijk kan worden hergebruikt. Deze functie werkt zowel in PowerShell V1 als PowerShell V2. Deze functie maakt gebruik van een andere functie fnWriteEventLog t.b.v. schrijfacties naar het Windows EventLog.

function fnSendMail()
{
  param (
    [string]$sSMTPSrvrName, 
    [string]$sFrom, 
    [string]$sTo, 
    [string]$sSubject, 
    [string]$sBody, 
    [string]$sAttFileName, 
    [switch]$swIsBodyHTML = $false
    )

  if (($sSMTPSrvrName) -and ($sFrom) -and ($sTo) -and $sSubject) {
  
    # Declare mail objects...
    $oMessage = new-object Net.Mail.MailMessage
    $oSMTP = new-object Net.Mail.SmtpClient($sSMTPSrvrName)

    # Pass values to object...
    $oMessage.From = $sFrom
    $oMessage.To.Add($sTo)
    $oMessage.Subject = $sSubject
    $oMessage.IsBodyHtml = $swIsBodyHTML
    $oMessage.BodyEncoding = ([System.Text.Encoding]::UTF8)
    if ($sBody) { $oMessage.Body = $sBody }

    # Add attachment...
    if ($sAttFileName) {
      $oAttachment = new-object Net.Mail.Attachment($sAttFileName)
      $oMessage.Attachments.Add($oAttachment)
    }

    $oSMTP.Send($oMessage)
    if ($? -eq "True") {
      #fnWriteEventLog -sNode (fnGetFQDN) -sMessage "Email has been sent..." -iEventID 1 -sType "Information"
      return "INFO: Email has been sent..." 
    } else {
      fnWriteEventLog -sNode (fnGetFQDN) -sMessage "Error sending mail..." -iEventID 501
      return "ERROR: Error sending e-mail..."
    }

  } else {
    fnWriteEventLog -sNode (fnGetFQDN) -sMessage "fSendMail argument missing..." -iEventID 501
    return "ERROR: Argument(s) missing. [fnSendMail `"SMTPServerName`" `"From`" `"To`" `"Subject`" `"Body`" (`"AttachFileName`" `"isBodyHTML`")]"
  }
}

PowerShell Create MSSQL Agent Job

M.b.v. onderstaande PowerShell script voorbeeld kun je, door gebruik te maken van SQL PowerShell Modules, een SQL Agent Job aanmaken t.b.v. MS SQL Server.

$oSRV=Get-Item SQLSERVER:\SQLSERVERNAAM\INSTANCENAAM

# Maak een SQL Agent Job...
$oJOB=New-Object Microsoft.SqlServer.Management.Smo.Agent.Job
$oJOB.parent=$oSRV.Jobserver
$oJOB.Name="Backup System Database Job"
$oJOB.Create()

# Maak een JobStep t.b.v. backup master database in de nieuwe Job...
$oStep1=New-Object Microsoft.SqlServer.Management.Smo.Agent.JobStep
$oStep1.parent=$oJOB
$oStep1.Name="Master Backup"
$oStep1.SubSystem="TransactSQL"
$oStep1.Command="BACKUP DATABASE [master] TO DISK='X:\Path\To\File.bak'"
$oStep1.OnSuccessAction = "GotoNextStep"
$oStep1.Create()

# Maak een JobStep t.b.v. backup master database in de nieuwe Job...
$oStep2=New-Object Microsoft.SqlServer.Management.Smo.Agent.JobStep
$oStep2.parent=$oJOB
$oStep2.Name="Model Backup"
$oStep2.SubSystem="TransactSQL"
$oStep2.Command="BACKUP DATABASE [model] TO DISK='X:\Path\To\File.bak'"
$oStep2.OnSuccessAction = "GotoNextStep"
$oStep2.Create()

MSSQL Query Linked Server

Voor uitvoer van Stored Procedures op een linked server moet de optie RPC onder Server Options op True worden gezet. Hieronder een tweetal methodes m.b.t. uitvoeren SP’s op een linked server. Het eerste voorbeeld maakt gebruik van de four-part name. Het tweede voorbeeld gebruikt OPENQUERY.

EXEC [LINKEDSERVERNAME].[master].sys.sp_who2
SELECT * FROM OPENQUERY([LINKEDSERVERNAME],'EXEC master.sys.sp_who')

Hieronder een tweetal methodes om een query uit te voeren op een tabel in een linked server.

SELECT * FROM [LINKEDSERVERNAME].[master].sys.databases
SELECT * FROM OPENQUERY([LINKEDSERVERNAME], 'SELECT * FROM sys.databases')

Met de onderstaande opdracht maak je een linked server aan die terugvalt op de actuele security context.

sp_addlinkedserver 'SERVERNAME', 'SQL Server'
sp_addlinkedsrvlogin 'SERVERNAME', 'True', NULL

MSSQL Read output SP in temptable

De onderstaande gegevens plaatst de gegevens uit een stored procedure in een tijdelijke tabel. Deze specifieke uitwerking plaatst de output van sp_who2 in een tijdelijke tabel met de naam #tWho2. Nu kun je de gegevens filteren d.m.v. queries op de tijdelijke tabel.

-- Oude tijdelijke tabel verwijderen...
DROP TABLE #tWho2
GO

-- Nieuwe tijdelijke tabel aanmaken met alle velden...
CREATE TABLE #tWho2 (
SPID char(5),
[Status] nvarchar(max),
[Login] nvarchar(max),
HostName nvarchar(max),
BlkBy char(5),
DBName nvarchar(max),
Command nvarchar(max),
CPUTime nvarchar(max),
DiskIO nvarchar(max),
LastBatch nvarchar(max),
ProgramName nvarchar(max),
SPID2 char(5),
REQUESTID char(5)
)
GO

-- Gegevens uit stored procedure inlezen in tijdelijk tabel...
INSERT INTO #tWho2 EXEC sp_who2
GO

MSSQL Query Execution Plan running query

Met onderstaande query kun je het Query Execution Plan bekijken voor een lopende (probleem)query op basis van de session_id.

USE [master]
SELECT * FROM sys.dm_exec_query_plan (
  (SELECT plan_handle
   FROM sys.dm_exec_requests
   WHERE session_id = 53)
)
GO

Ook handig is om performance gegevens te tonen in het messages scherm m.b.t. de query. Met onderstaande query kun je deze opties aanzetten binnen een sessie.

SET STATISTICS [TIME|IO] [ON|OFF];

MSSQL update value dependent on original

Query to change the format of a postal code string for specific postal codes. This specific script changes all values in the postcode column from format  ‘1234AB’ to ‘1234 AB’.

UPDATE tablename
SET postcode = LEFT(LTRIM(postcode),4) + ' ' + RIGHT(RTRIM(postcode),2)
WHERE
  LEN(LTRIM(postcode)) = 6 AND
  LEN(REPLACE(postcode, ' ', '')) = 6 AND
  ((land = 'Nederland') OR (land = 'Nederland (NL)'))

Other example to replace values. This time replacing a value with a string from another table.

UPDATE   a
SET      ColumnX = b.ColumnY
FROM     Table1 a
JOIN     Table2 b ON b.ID=a.ID

PowerShell Check File LastWriteTime

PowerShell script to start a specific routine when a file is older than two days (LastWriteTime). This specific example writes an error in the application event log.

# *****************************************************************************
# Scriptnaam: CHKMODTIME.PS1
# Geschreven_door: Tim van Kooten Niekerk
# Versie: 2010.10.29.01
# Info: PowerShell script t.b.v. uitvoeren actie als de wijzigingsdatum
# Info: van het opgegeven bestand ouder is dan ingestelde waarde.
# *****************************************************************************

function fGetFileModTime([string]$sFileName) {
  $vFileInfo = get-childitem $sFileName
  return $vFileInfo.lastwritetime 
}

# Opvragen van wijzigingsdatum bestand...
[datetime]$dFileModTime = fGetFileModTime("D:PadNaarBestand.bak")
# Voer een actie uit als de wijzigingsdatum van het bestand ouder is dan 2 dagen...
if ((Get-date).AddDays(-2) -gt $dFileModTime) {
  # Schrijf Error melding weg naar eventlog of voer een andere actie uit...  
  $oEventLog = new-object System.Diagnostics.EventLog('Application')
  $oEventLog.MachineName = "."
  $oEventLog.Source = "WSH"
  $oEventLog.WriteEntry("Back-up is to old...", "Error")
}

 

PowerShell Edit Multiple Files

PowerShell example to edit multiple files. This specific example remove the first 15 chars from every XML file in a directory.

get-childitem D:TEMPMessages *.xml |
  % { 
         [string]$sFileContent = cat $_.fullname
         $sFileContent = $sFileContent.substring(15,$sFileContent.length-15) | Out-File -Filepath $_.fullname
         echo $_.fullname
  }