Timeout issue in Backup-SQLDatabase cmdlet - sql-server

I’m trying to take back-up of a large database using “Backup-SQLDatabase” cmdlet using following statement, but I’m getting time-out error after 10 minutes.
{Backup-SqlDatabase -ServerInstance $Server -Database $DatabaseName -BackupFile $BackUpFile -CompressionOption On -ConnectionTimeout 0 -Initialize -Verbose -ea Stop}
Here’s the error exactly after 600 seconds of execution :
VERBOSE: 60 percent processed.
VERBOSE: The backup or restore was aborted.
The wait operation timed out
+ CategoryInfo : InvalidOperation: (:) [Backup-SqlDatabase], Win3
2Exception
+ FullyQualifiedErrorId : ExecutionFailed,Microsoft.SqlServer.Management.P
owerShell.BackupSqlDatabaseCommand
+ PSComputerName : localhost
I looked up at internet and found a bug filled here.
However, the issue still exists in SQL Server 2012 (11.0.339).
I’ve also tried reconfiguring “remote query timeout” to 0 as given here, but the issue persists.
This is actually very weird issue. PowerShell is for automation and scripts do take more than 10 minutes to run. “Backup-SQLDatabase” should have considered this.
Please suggest a workaround by which I can fix this while using this cmdlet.
Else , I’ve to re-write the code using SMO classes or basic T-SQL.

I did some research on this and came around the following workaround :
$serverConn = new-object ("Microsoft.SqlServer.Management.Smo.Server") $server
$serverConn.ConnectionContext.StatementTimeout = 0
Backup-SqlDatabase -InputObject $serverConn -Database abc -BackupFile "L:\123\abc.bak"
When we pass Server name as a string, it tries to create it's own connection and we don't have the option to change QueryTimeout from 600 to 0.
However, we can create a SMO.Server object and use it after setting desired properties.
Hope it helps!

Related

powershell try-catch doesn't capture invoke-sqlcmd error [duplicate]

This question already has answers here:
Powershell Try Catch invoke-sqlcmd
(3 answers)
Error detection from Powershell Invoke-Sqlcmd not always working?
(3 answers)
Closed 4 years ago.
I have a function that I pass a server name to, then select some data from that server and insert it into a table on a centralized server. The list of servers is generated from a centralized server that isn't always up to date, and I would like for it to keep processing and log any errors that occur. However, my try-catch block doesn't seem to capture any errors.
I saw this question and tried that, and I still can't capture the errors. Here's a generic version of my function:
function Get-QueryData
{
[CmdletBinding()]
param
(
[string] $server
)
$QuerySelect = "select * from dbo.Table"
try
{
$results = Invoke-Sqlcmd -ServerInstance $server `
-Database TheDatabase `
-Query $QuerySelect `
-QueryTimeout 20 `
-OutputSqlErrors $True `
-ConnectionTimeout 5 `
-ErrorAction Stop
}
catch
{
#to-do: log error
Write Host " An error occurred trying to get query info"
}
# remaining function inserts into central server, this part doesn't fail
# unless the first part fails
}
The error I get:
Invoke-Sqlcmd: A network-related or instance-specific error occurred
while establishing a connection to SQL Server... CategoryInfo:
InvalidOperations (:) [Invoke-SqlCmd] SqlException
FullQualifiedErrorId :
SqlExecutionError,Microsoft.SqlServer.Management.Powershell.GetScriptCommand
The reason I'm getting this error is that the server was stood up, and then had to be rebuilt, but it was already added to our central management server. I can't rely on this being cleaned up right away so I need the powershell to log the error and keep moving.
Output from $PsVersionTable.PSVersion
Major - 5
Minor - 1
Build - 14409
Revision - 1012
In the Try{} set $flag=$True
In the Try{} remove the $results variable from the get-sqlcmd
In the Catch{} set $flag=$false
Add a finally{} that checks for the flag
In the Finally{} add an if(!x){y}else{z}
In the Finally{if(!x){y}else{z}}
if $flag is $false write to log and exit
if $flag is $true do your work and then write to log
I've provided [sting]$message >> $targetFile for simple logging. There are way better ways to do logging and I've used this example only as an simple example and not a suggestion.
function Get-QueryData
{
[CmdletBinding()]
param(
[string] $server
)
$QuerySelect = "select * from dbo.Table"
try
{
$flag = $true
Invoke-Sqlcmd -ServerInstance $server `
-Database TheDatabase `
-Query $QuerySelect `
-QueryTimeout 20 `
-OutputSqlErrors $True `
-ConnectionTimeout 5 `
-ErrorAction Stop
}
catch
{
$flag = $false
#to-do: log error with $_ which contains the error object
Write-Host "An error occurred trying to get query info"
$errorMessage = $_.Exception.Message
}
finaly
{
# log errors if flag false
if (!$flag){
"[$(get-date)] - $errorMessage" >> `
$(some target accessible path to a writable file)
#Stop the function and return an exit code of 1
Return 1
} else {
# remaining function inserts into central server
"[$(get-date)] - Short Meaningful Success Message" >> `
$(some target accessible path to a writable file)
}
}
}
So I'm an idiot and I was copying from an outdated copy. My NEW version that reflects the changes made per the link in my question works perfectly.

Restore-SqlDatabase Wait operation timeout

I have setup a process for Restoring Databases using the Restore-SqlDatabase cmdlet and scheduled this into a SQl Agent job. It's been working fine until I tried to restore a 160GB database. It basically fails after 600s with the error "The wait operation timed out". I've tried adding in a StatementTimeout of 0 to see if it would get round this and also change the Remote query Timeout on the SQL Server but it still bobmbs out after 10 minutes. Does anyone know if there is another setting I can change to increase the timeout? The Code I'm running is:
# Load Module path! its not loading by default in calls from powershell
$env:PSModulePath=$env:PSModulePath + ";" + "C:\Program Files\Microsoft SQL Server\110\Tools\PowerShell\Modules\SQLPS\"
## Load module and run functions now
#Import SQL Server PowerShell Provider.
Import-Module "sqlps" -DisableNameChecking
#GEt Around Wait Timeout Error with Remote Connection via PoSh
$server = "THESERVER"
$serverConn = new-object ("Microsoft.SqlServer.Management.Smo.Server") $server
$serverConn.ConnectionContext.StatementTimeout = 0
#Restore Latest Copy of Test Database that was copied over
Restore-SqlDatabase -ServerInstance $server -Database "Test" -BackupFile "H:\SQLBACKUP\DATABASE_Refresh\Test_Latest.BAK" -ReplaceDatabase
Error That Appears is:
Restore-SqlDatabase : The wait operation timed out
At H:\SQLBACKUP\_AutoScripts\5_Test_DBRESTORE.ps1:16 char:1
+ Restore-SqlDatabase -ServerInstance $server -Database "Test ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Restore-SqlDatabase], Win32Exception
+ FullyQualifiedErrorId : ExecutionFailed,Microsoft.SqlServer.Management.PowerShell.RestoreSqlDatabaseCommand
It looks like Restore-SqlDatabase has a -ConnectionTimeout parameter:
Specifies the number of seconds to wait for a server connection before a timeout failure. The timeout value must be an integer between 0 and 65534. If 0 is specified, connection attempts do not timeout.
So your command can become:
Restore-SqlDatabase `
-ServerInstance $server `
-Database "Test" `
-BackupFile "H:\SQLBACKUP\DATABASE_Refresh\Test_Latest.BAK" `
-ReplaceDatabase `
-ConnectionTimeout 0

Powershell - Output SQL Messages to file

I have a Powershell script that invokes a saved SQL Query file and runs it on a specific Server & Database. That part is working well, the issue is that I would like to save the SQL Messages that it generates to a log file (see picture).
SQL Output from after Query is run
This is not working with my current code, and I believe that's because since it's technically not Query output but instead reindexing and updating tables, not fetching data.
My current relevant code is:
{
Import-Module SQLPS
$Data = Invoke-Sqlcmd -InputFile $SQLQuery -ServerInstance $Server -Database $Database -QueryTimeout 0
$Data | out-file "$Output$Database$date.txt"
}
But that just generates an empty text file. I'm looking to get the info on rebuilding indexes and the updates it's doing saved off into a different file through Powershell. You can do this through SSMS by right clicking in the Messages window and clicking "Save Results As..." but looking to include this in my automation since it's running as a Scheduled Task and no one is on SSMS.
Powershell v3/Windows Server 2012/SQL SSMS 2014
Any help would be appreciated!! This is my first post so sorry for odd formatting.
It looks like the following link explains exactly this problem:
https://sqlnotesfromtheunderground.wordpress.com/2015/09/09/powershell-outputting-a-sql-server-query-result-from-the-message-tab/
Essentially, what you are seeing in the 'Messages' tab are not results from the query, but rather just PRINT statements (essentially the same as Write-Host or Console.WriteLine). If you use Invoke-SqlCommand2, its -Verbose option will capture these PRINT statements to the Verbose PowerShell stream. To then write this stream to a text file, you have to specify the specific stream (in this case, 4):
Invoke-Sqlcmd2 -ServerInstance . -Database master -Query "PRINT 'Export This result'" -Verbose 4> Out-File C:\Temp\Test.txt
I had the same issue but instead in powershell script i use it in a command and i used -verbose.
like this
Invoke-Sqlcmd -ServerInstance '.\Your_server_instance' -Database 'DATABASE_Name' -InputFile "D:\Your_script.sql" verbose 4> "C:\sql\YOUR_OUTPUT_FILE.txt"
so i think this code should work for you
{
Import-Module SQLPS
$Data = Invoke-Sqlcmd -InputFile $SQLQuery -ServerInstance $Server -Database $Database -QueryTimeout 0
$Data -verbose *> "$Output$Database$date.txt"
}
for -verbose *> it streams All output you can redirect specific streams :
1 Success output
2 Errors
3 Warning messages
4 Verbose output
5 Debug messages

Powershell sql insert error data will be truncated removed data and still get error

I have a powershell script that I am trying to use to write data from a source .txt to an SQL table
Import-Csv $_.fullname -Header Z_AP_EXNUM,Z_AP_ID | ForEach-Object {Invoke-Sqlcmd `
-Database $database -ServerInstance $server -Username $uid -Password $pwd `
-Query "insert into $table VALUES ('$_.Z_AP_EXNUM','$_.Z_AP_ID')"
My actual code has about 293 headers/columns to insert. The error I receiving is that String or binary data will be truncated. The statement has been terminated. I went into one of my test files and removed all the data but a few standard fields and still receive these errors. I am not sure what could be causing the insert to fail.
Error:
Invoke-Sqlcmd : String or binary data would be truncated.
The statement has been terminated.
At C:\Users***\Desktop\script\scripy.ps1:79 char:111
+ Z_AP_STR_CSEM5_9,Z_AP_STR_NAME5_10,Z_AP_STR_SCOR5_10,Z_AP_STR_CSEM5_10 | ForEach-Object {Invoke-Sqlcmd <<<< `
+ CategoryInfo : InvalidOperation: (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Check the table schema, this error usually shows due to the difference of column definition type in the table and the powershell data type you want to store in it.

powershell set database IndexOutOfRangeException

I'm trying to set a database name in powershell using Microsoft.SqlServer.SMO. When I execute my script it runs in error with the following error text:
format-default : Index was outside the bounds of the array.
+ CategoryInfo : NotSpecified: (:) [format-default], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException,Microsoft.PowerShell.Commands.FormatDefaultCommand
The server is set as follows
$srv = New-Object "Microsoft.SqlServer.Management.SMO.Server" $server
$srv.ConnectionContext.LoginSecure=$false;
$srv.ConnectionContext.set_Login("login");
$srv.ConnectionContext.set_Password("password")
$srv.Databases | Select name,
shows me the proper databases, but when setting the database,
$db = $srv.Databases[$database]
the error is thrown.
This scrip does work in other sqlservers.
Any solutions for this issue?
It looks like the database "CRD_DEV" does not exist on the server where the script throws the error.
That or the user does not have access to that database.
The IndexOutOfRangeException is thrown because there is no item in $srv.Databases that matches "CRD_DEV"

Resources