How I can avoid System databases while taking backups using SMO object in Powershell
I am trying to take the all available databases excluding system databases.
param(
$serverName,
$backupDirectory,
$daysToStoreBackups
)
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") $serverName
$dbs = $server.Databases
foreach ($database in $dbs)
{
$dbName = $database.Name
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $dbName + "_" + $timestamp + ".bak"
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.SqlBackup($server)
"backed up $dbName ($serverName) to $targetPath"
}
Reference for the script is SMO Object Backup Script Link for PS
Change this
foreach ($database in $dbs)
To
foreach ($database in $dbs | where { $_.IsSystemObject -eq $False })
This should do the trick.
Related
I have 2 PowerShell scripts I wanna combine I have this one for doing data dumps
$query = "use [ISTABLocalDB]
SELECT
Item.[ID] as PartIdDB
,Item.[ItemNumber] as Varenummer
,ImageFile.[ResourceFile_ID] as ImageID
,ImageFile.[Description] as ImageName
, CASE WHEN ImageFile.[ResourceFile_ID] is null
THEN ''
ELSE
CONCAT('F:\App\ISTAB.Data\pictures_global\P\',
SUBSTRING(CONVERT(varchar, Item.[ID]), 1, 3), '\',
SUBSTRING(CONVERT(varchar, Item.[ID]), 4, 3), '\',
SUBSTRING(CONVERT(varchar, Item.[ID]), 7, 3), '\',
ImageFile.[ResourceFile_ID],'-g')
END as PathOnDrive
,Item.[ItemType_ID]"
$extractFile = "$path $date.csv"
$connectionTemplate = "Data Source={0};Integrated Security=SSPI;Initial Catalog={1};"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$command = New-Object System.Data.SqlClient.SqlCommand
$command.CommandText = $query
$command.Connection = $connection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $command
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$connection.Close()
$DataSet.Tables[0] | Export-Csv $extractFile -NoTypeInformation
and this one for copy pictures where I manually pasting in the path which I get from PathOnDrive in the query into the $imagesList
$targetFolderName = "C:\test"
$sourceFolderName = "F:\App\ISTAB.Data\pictures_global\P"
$imagesList = (
"F:\App\ISTAB.Data\pictures\P\122\338\7\1326647",
"F:\App\ISTAB.Data\pictures\P\179\924\0\1678117"
)
foreach ($itemToCopy in $imagesList)
{
$targetPathAndFile = $itemToCopy.Replace( $sourceFolderName , $targetFolderName )
$targetfolder = Split-Path $targetPathAndFile -Parent
if (!(Test-Path $targetfolder -PathType Container)) {
New-Item -Path $targetfolder -ItemType Directory -Force
}
Copy-Item -Path $itemToCopy -Destination $targetPathAndFile
}
so my question is how do I get the all the records from the PathOnDrive column into my $imagesList automatically
i figured it out
foreach ($Columns in $DataSet.Tables[0].Rows) {
$imagesList = "$($Columns.PathOnDrive)"
write-Output "$($imagesList)"
$targetFolderName = "D:\DataFeed\Pictures\Parts"
$sourceFolderName = "F:\App\ISTAB.Data\pictures_global\P"
foreach ($itemToCopy in $imagesList)
{
$targetPathAndFile = $itemToCopy.Replace( $sourceFolderName , $targetFolderName )
$targetfolder = Split-Path $targetPathAndFile -Parent
if (!(Test-Path $targetfolder -PathType Container)) {
New-Item -Path $targetfolder -ItemType Directory -Force
}
Copy-Item -Path $itemToCopy -Destination $targetPathAndFile
}
}
I have several queries that I use for identifying issues in a SQL database but I'm trying to create at powershell script that I can use to do this automatically. The trouble I am having is that when I invoke my SQL scripts there are multiple result sets and my script only seems to capture the first set. I'm wondering what I need to do to cycle through all the results. This is the code with just some simple selects
$dataSource = 'Server'
$database = "DB"
$sqlcommand = #"
Select TOP 1000 * from tblA;
Select TOP 1000 * from tblB
"#
Function Convert-Dataset
{
Param
(
[Parameter(Mandatory=$true)]
$dataset
)
Begin
{
$return=#()
For($r = 0; $r -lt $dataset.tables[0].rows.Count; $r++)
{
$table= new-object psobject
If($dataset.tables[0].columns.ColumnName.Count -le 1)
{
$colName = [String]$dataset.tables[0].columns.ColumnName
If($dataset.tables[0].rows.Count -eq 1)
{
$colValue = [string]$dataset.tables[0].rows.$colName
}
Else
{
$colValue = [string]$dataset.tables[0].rows[$r].$colName
}
$table | Add-Member -memberType noteproperty -Name $colName -Value $colValue
}
Else{
For($c = 0; $c -lt $dataset.tables[0].columns.ColumnName.Count; $c++)
{
$colName = [String]$dataset.tables[0].columns.ColumnName[$c]
$colValue = [string]$dataset.tables[0].rows[$r][$c]
$table | Add-Member -memberType noteproperty -Name $colName -Value $colValue
}
}
$return +=$table
}
}
End
{
Return $return
}
}
$connectionString = "Data Source=$dataSource; " +
"Integrated Security=True; " +
"Initial Catalog=$database"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
$connection.Open()
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
$connection.Close()
$return=Convert-Dataset -dataset $dataset
$return | Out-GridView
I figured it out
$connectionString = "Data Source=$dataSource; " +
"Integrated Security=True; " +
"Initial Catalog=$database"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
$connection.Open()
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
$connection.Close()
ForEach($table in $dataset.Tables)
{
$table |Out-GridView -PassThru
}
So i have the following code that should backup every database daily, weekly and monthly. The daily backup works fine but it doesnt seem to create a weekly or a monthly backup.
The database connection part of the script looks like:
$serverName = "."
$backupDirectory = "\\SERVER\BACKUP"
$daysToStoreDailyBackups = 7
$daysToStoreWeeklyBackups = 28
$monthsToStoreMonthlyBackups = 3
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
$mySrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$mySrvConn.ServerInstance=$serverName
$mySrvConn.LoginSecure = $false
$mySrvConn.Login = "sa"
$mySrvConn.Password = "myPAssword"
$server = new-object Microsoft.SqlServer.Management.SMO.Server($mySrvConn)
$dbs = $server.Databases
$startDate = (Get-Date)
"$startDate"
The daily and weekly part of the script looks like:
foreach ($database in $dbs | where {$_.IsSystemObject -eq $False})
{
$dbName = $database.Name
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $dbName + "_" + $timestamp + "_daily.bak"
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.SqlBackup($server)
"backed up $dbName ($serverName) to $targetPath"
}
else
{
"$dbName backup skipped"
}
}
if([Int] (Get-Date).DayOfWeek -eq 0)
{
Get-ChildItem "$backupDirectory\*_weekly.bak" |? { $_.lastwritetime -le (Get-Date).AddDays(-$daysToStoreWeeklyBackups)} |% {Remove-Item $_ -force }
"removed all previous daily backups older than $daysToStoreWeeklyBackups days"
foreach ($database in $dbs | where { $_.IsSystemObject -eq $False})
{
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
$dbName = $database.Name
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $dbName + "_" + $timestamp + "_weekly.bak"
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.SqlBackup($server)
"backed up $dbName ($serverName) to $targetPath"
}
else
{
"$dbName backup skipped"
}
}
}
I assumed it would create the weekly backup on Sunday, but that didn't happen.
In the daily block you have
$dbName = $database.Name
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
but in the weekly block, you have
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
$dbName = $database.Name
dbName is checked before it is set. If it fails the check, it's never set for any database.
If your code comes out of the daily block value left as "ReportServerTempDB", it will never pass the if test in the weekly block, and dbName will not change, so nothing will be backed up.
a) Move the $dbName = $database.Name assignment above the if
b) Or use $database.Name directly
c) Or don't have big chunks of copy-paste code which have to be the same, but can somehow end up different. Instead move that duplicate chunk to one function and call it from both places.
I have the following script to backup all databases from an SQL instance
This works perfectly from my local PC but when I run it on an external server it fails with the following:
master backup failed.
Exception calling "SqlBackup" with "1" argument(s): "Backup failed for Server 'SERVER2016'."
$SQLInstance = "Localhost"
$BackupFolder = "D:\Backups\"
$timeStamp = Get-Date -Format yyyy_MM_dd_HHmmss
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
$srv = New-Object ("Microsoft.SqlServer.Management.Smo.Server") $SQLInstance
$dbs = New-Object Microsoft.SqlServer.Management.Smo.Database
$dbs = $srv.Databases
foreach ($Database in $dbs) {
$Database.Name
$bk = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$bk.Action = [Microsoft.SqlServer.Management.Smo.BackupActionType]::Database
$bk.BackupSetName = $Database.Name + "_backup_" + $timeStamp
$bk.Database = $Database.Name
$bk.CompressionOption = 1
$bk.MediaDescription = "Disk"
$bk.Devices.AddDevice($BackupFolder + "\" + $Database.Name + "_" + $timeStamp + ".bak", "File")
try {
$bk.SqlBackup($srv)
} catch {
$Database.Name + " backup failed."
$_.Exception.Message
}
}
# Load SMO extension
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;
# Servers to check
#$sqlservers = #("$svr", "$svr\$inst");
$sqlservers = Get-Content 'servers.txt'
foreach ($server in $sqlservers) {
$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $server;
# Get mirrored databases
$databases = $srv.Databases | Where-Object {$_.IsMirroringEnabled -eq $true};
#Write-Host $databases;
Write-Host "==================================";
# $test= $databases | Select-Object -Property Name, MirroringStatus | Format-Table -AutoSize;
$databases | Select-Object -Property MirroringStatus | Format-Table -AutoSize;
foreach ($status in $databases) {
switch ($databases.MirroringPartnerInstance) {
1 { $status. + "Disconnected" }
2 { $status. + "Suspended" }
2 { $status. + "Synchronizing" }
3 { $status. + "Not Synchronized" }
}
}
I want code like this.
Below is my code if you do this way you will not get issue
function mirroring (
[string] $svr,
[string]$inst,
[string] $datastore
)
{
Set-StrictMode -Version 2
[Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo")
[Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
[Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended")
$Conn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$SqlConnection = "Server=$svr\$inst;Database=master;Integrated Security=True;"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = " SELECT db_name(sd.[database_id])AS [Database Name]
,sd.mirroring_state AS [Mirror State]
,sd.mirroring_state_desc AS [Mirror State]
,sd.mirroring_partner_name AS [Partner Name]
,sd.mirroring_role_desc AS [Mirror Role]
,sd.mirroring_safety_level_desc AS [Safety Level]
,sd.mirroring_witness_name AS [Witness]
,sd.mirroring_connection_timeout AS [Timeout(sec)]
FROM sys.database_mirroring AS sd
WHERE mirroring_guid IS NOT null
ORDER BY [Database Name];"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0]
$datastore = $DataSet.Tables[0].Rows[0][2]
write-host $datastore
if( $datastore -eq "Disconnected")
{
# test
DisconnectedREMEDIATION
}
elseif($datastore -eq "SYNCHRONIZED")
{
SYNCHRONIZEDREMEDIATION
}
}