Remote Microsoft SQL Server Database Restore with Powershell and Script Block - sql-server

Long time lurker, first time poster. I'm hoping somebody here can give me a hand trying to figure out an issue that's got me stumped. Essentially I am trying to write a Powershell script that will restore a multi-part SQL Server database to a remote server. I have messed around with the invoke-command and script-block features to a point where I understand how to use variables and parameters... However I am noticing some very interesting behaviour.
Here is my code right now:
cls
$strbaktest = "S:\Landing\testdb1.bak,S:\Landing\testdb2.bak"
echo "The backup files are $strbaktest"
write-host
$StrScrBlk = {param($StrBaktest); &Restore-SqlDatabase -ServerInstance "mydbserver" -Database testdb -BackupFile $strbaktest -ReplaceDatabase}
invoke-command -ComputerName mydbserver -ScriptBlock $StrScrBlk -argumentlist $strbaktest
This yields an error like this:
System.Data.SqlClient.SqlError: Cannot open backup device 'S:\Landing\testdb1.bak,S:\Landing\testdb2.bak'. Operating system error 123(The filename, directory name, or volume label syntax is incorrect.).
However, if I hardcode the same path into my script block, it works:
cls
$StrScrBlk = {Restore-SqlDatabase -ServerInstance "mydbserver" -Database testdb -BackupFile S:\Landing\testdb1.bak,S:\Landing\testdb2.bak -ReplaceDatabase}
invoke-command -ComputerName mydbserver -ScriptBlock $StrScrBlk
The other interesting thing I noticed was that if I only have a single file to restore, using the first method with a variable works:
cls
$strbaktest = "S:\Landing\testdb.bak"
echo "The backup files are $strbaktest"
write-host
$StrScrBlk = {param($StrBaktest); &Restore-SqlDatabase -ServerInstance "mydbserver" -Database testdb -BackupFile $strbaktest -ReplaceDatabase}
invoke-command -ComputerName mydbserver -ScriptBlock $StrScrBlk -argumentlist $strbaktest
Hopefully this makes sense to somebody. I've spent a couple hours trying a bunch of different ways to get this to work - however I can't seem to figure it out. Any help or advice is appreciated.
Thanks!

The comma is an operator or identifier that separates elements of an array. Compare:
PS C:\> 1,2
1
2
PS C:\> "1,2"
1,2
PS C:\>
Try this:
$strbaktest = "S:\Landing\testdb1.bak","S:\Landing\testdb2.bak"
It's working with "x","c" . The comma is not required, as it is waiting for an array.

Related

Capture messages output from SQL Server

I have below PS script which creates a table. I would like to capture messages output (Command(s) completed successfully.) from sql server. Is there a way to achieve that?
I tried -Verbose switch but that didn't helped.
PS File:
$CreateTableFile = "C:\DBScripts\CreateTable.sql"
Invoke-Sqlcmd -ServerInstance xyz -InputFile $CreateTableFile -Database "PSLearning" -Verbose
CreateTable.sql:
CREATE TABLE abc (
column_1 int,
)
You don't say what you want to capture. Everything or just errors.
Errors, you can use try/catch, everything you can use Start-Transcript, or write your own log code, or stuff like print script.
Example:
Invoke-Sqlcmd -Query "update your database set column_name ={expression} where <search_condition>; PRINT 'update successfully';" –Verbose
As documented in the Bulit-In Help files …
# get function / cmdlet details
(Get-Command -Name Invoke-SqlCmd).Parameters
Get-help -Name Invoke-SqlCmd -Full
Get-help -Name Invoke-SqlCmd -Online
Get-help -Name Invoke-SqlCmd -Examples
Get-help -Name Invoke-SqlCmd -Examples
# -------------------------- EXAMPLE 5 --------------------------
C:\PS>Invoke-Sqlcmd -Query "PRINT N'abc'" -Verbose
VERBOSE: abc
# Description
# -----------
# This example uses the PowerShell -Verbose parameter to return the message output of the PRINT command.
... or the online ones.
Invoke-Sqlcmd
You can display SQL Server message output, such as those that result
from the SQL PRINT statement, by specifying the Verbose parameter
Example 5: Run a query and display verbose output
PSet-Location "SQLSERVER:\SQL\MyComputer\MainInstance"
Invoke-SqlCmd -Query "PRINT N'abc'" -Verbose
VERBOSE: abc

Server Agent PowerShell job step - Difference between calling a file and calling a command

I have some simple PowerShell code to insert a value into a table:
Invoke-SqlCmd -ServerInstance myserver -Query 'insert into Database.dbo.tbl values (1)'
and if I save it as a file, I can call it in a CmdExec job step. However, can anyone tell me why I can't run the command, especially as it is only one line:
powershell.exe -ExecutionPolicy Bypass -Command 'Invoke-Sqlcmd -ServerInstance myserver -Query ''insert into DBADatabase.dbo.tbl values (1)'''
Can anyone tell me why running as a command will not work, yet the same code as a file can work. Any help appreciated.
Thanks
Your powershell.exe ... command is executed from outside PowerShell, possibly via cmd.exe.
In that case, '...'-enclosed strings have no syntactical function and are passed straight through to PowerShell, causing it to interpret them as enclosing a string literal, which is simply output as-is (in other words: your command is printed rather than executed).
Instead, you must use "..." to enclose the command to pass to PowerShell; inside that string, you're free to use '...':
powershell.exe -ExecutionPolicy Bypass -Command "Invoke-Sqlcmd -ServerInstance myserver -Query 'insert into DBADatabase.dbo.tbl values (1)'"
I have create test job on my server with below powershell code and it work. Below image have my job detail.
My Test code
Invoke-Sqlcmd -ServerInstance 'MYSERVER' -Query 'insert into DBA_TOOLS.dbo.tbl values (1)'
your code - you are missing single quotes 'myserver' around sql server.
Invoke-Sqlcmd -ServerInstance 'myserver' -Query ''insert into DBADatabase.dbo.tbl values (1)'
hope this help

How to capture SSMS event log from Powershell into file?

Using a Powershell. I'm calling stored procedure containing batch of insert statements. Now I would like to capture the event log of the insert statements (both success message and error) into file like.
(1 row(s) affected).
Msg 8146, Level 16, State 1, Procedure test, Line 0 [Batch Start Line 0]
Procedure test has no parameters and arguments were supplied.
I'm trying this, but it not work. The execution happens, but file loads empty.
$conn = New-Object System.Data.SqlClient.SqlConnection SqlConnection
$conn.ConnectionString = "Server=$server;Database=$databaseName;User=$userName;password=$password;trusted_connection=true;" # set the connection string
$conn.Open();
$cmd = $conn.CreateCommand();
Invoke-Sqlcmd -ServerInstance $server -Database $databaseName -Query "exec batch_insert_statements" -Verbose
out-file -filepath C:\Logs\Test.txt
I found the answer here: https://www.sqlservercentral.com/Forums/Topic914307-391-1.aspx
$sql = "sqlcmd.exe -S ServerName -E -d DatabaseName -Q ""EXEC YourProc"""
Invoke-Expression $sql | Out-File C:\temp\outfile.txt
I just tried it (ps version 5.1.16299.98) and it wrote (1 rows affected) to outfile.txt
This would of course require SQLCMD.EXE to be installed, but I think that's a given if you are already using Invoke-Sqlcmd
You shouldn't need the first few lines, you also haven't piped the command to Out-File, try this:
$server = "."
$databaseName = "dbName"
Invoke-Sqlcmd -ServerInstance $server -Database $databaseName -Query "exec batch_insert_statements" -Verbose -OutputSqlErrors 1 -IncludeSqlUserErrors | out-file -filepath C:\Logs\Test.txt
I found much similar way, but it is totally powershell.
$Query = 'EXEC tes'
$log = "c:\logs\Lead_Scoring_Log_$(get-date -f dd-MM-yyyy-HH-mm-ss).txt"
$SqlcmdOptions = #"
-S"$ServerInstance" -d "$Database" -v User=$userName Password=$password -Q
"$Query"
"#
Start-Process -FilePath "sqlcmd.exe" -ArgumentList #"
$SqlcmdOptions
"# -Wait -NoNewWindow -RedirectStandardOutput $log -PassThru

Make Powershell Wait for SQL Script/Query to Finish

So I am trying to write a Powershell script that creates a backup of a databases, compresses the backup, and uploads it to an FTP site. Here is a part of my script
Sample Script/Code:
Write-Host "Backup of Database " $databaseName " is starting"
push-location
Invoke-Sqlcmd -Query "--SQL Script that backs up database--" -ServerInstance "$serverName"
pop-location
Write-Host "Backup of Database " + $databaseName " is complete"
#Create a Zipfile of the database
Write-Host "Compressing Database and creating Zip file...."
sz a -t7z "$zipfile" "$file"
Write-Host "Completed Compressing Database and creating Zip file!"
I am wanting to prevent any code after the "Invoke-Sqlcmd......." part from being executed until the SQL script backing up the database is complete because the compression line is failing to find the backup of the database because the backup takes a fairly long time to complete.
I am extremely new to using Powershell and didn't quite understand what a couple of the other possibly related questions I found were offering as a solution as I call my SQL statement a different way.
Possible Related Questions:
Get Powershell to wait for an SQL command to execute
Powershell run SQL job, delay, then run the next one
Are you sure your ...script that backs up the database isnt just throwing an error and the ps continuing?
This seems to indicate that it does in fact wait on that call:
Write-Host "starting"
push-location
Invoke-Sqlcmd -Query "waitfor delay '00:00:15';" -ServerInstance "$serverName"
pop-location
Write-Host "complete"
In any case, you should guard against the file existing, by either aborting if the file does not exist or polling until it does (i'm not 100% on when the .bak file is written to disk).
# abort
if(!(test-path $file)) {
}
# or, poll
while(!(test-path $file)) {
start-sleep -s 10;
}

execute .sql script using powershell and store the output in .sql file

I’m trying to run the sql script .sql file from powershell and save the result into .sql file. Overview : SQL database restore requires a user and permission backup pre-restore and once the restore is complete we need to execute the output( users permissions backup which we did pre-restore ) on the database.
here’s my script and when i execute i see an empty file.
Add-PSSnapin SqlServerProviderSnapin100;
$server = 'DBA_Test';
$database = 'Test';
$mydata = invoke-sqlcmd -inputfile "C:\users\security.sql" -serverinstance $server -database $database | Format-Table -HideTableHeaders -AutoSize
$mydata | out-file C:\users\output.sql;
Remove-PSSnapin SqlServerCmdletSnapin100;
Can someone help me on this ?
Thanks in advance
invoke-sqlcmd -inputfile "C:\users\security.sql" -serverinstance $server -database $database | Format-Table -HideTableHeaders -AutoSize >> C:\users\output.sql
or
Invoke-sqlcmd -inputfile "C:\users\security.sql" -serverinstance $server -database $database | Format-Table -HideTableHeaders -AutoSize | Out-File –FilePath C:\users\output.sql –Append
should do the trick.
Your problem is that you're only capturing one output stream. Your code would work as expected if your query was running "Select 'Hello World!'".
In order to get all output streams (verbose, error, and output), into a single file, you can do the following:
invoke-sqlcmd -inputfile "C:\users\security.sql" -serverinstance $server -database $database -verbose *>&1 | out-file C:\users\output.sql
The -verbose flag turns on a lot of the messages you'd expect to see. The * indicates you want all output streams (you can look up the definitions if you'd like. The verbose stream itself is 4, so 4>&1 would just redirect that one stream). Then you are just redirecting the output to out-file.

Resources