How can I use Invoke-SqlCmd with variables to output the SQL command only or some similar method?
-
02-01-2021 - |
Question
I have a big *.sql
file that I run with Invoke-Sqlcmd
and variables to do some tasks, and when I have an issue, it's a pain to debug because of the variables and I want to do logging of the SQL script about to be run.
Is there a reasonably native way to produce the final SQL
about to be executed with variable substitution without actually running?
Here's a sample I run to restore a *.bak to various environments for example:
Invoke-Sqlcmd -InputFile $sqlFile -QueryTimeout 0 -ServerInstance 'SQLServer' -Database 'Master' -Variable @("DatabaseBAK=$TransactDB", "Database=$TargetDatabase") -Verbose
SQL File:
USE [master]
print 'Killing connections to database $(Database)'
DECLARE @kill varchar(8000) = '';
SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), session_id) + ';'
FROM sys.dm_exec_sessions
WHERE database_id = db_id('$(Database)')
and session_id <> @@SPID
EXEC(@kill);
GO
USE [master]
print '[Info] RESTORE DATABASE [$(Database)]'
print '[Info] FROM DISK = N''$(DatabaseBAK)'''
print 'Starting restore-------------------->'
RESTORE DATABASE [$(Database)]
FROM DISK = N'$(DatabaseBAK)'
WITH FILE = 1
,NOUNLOAD
,REPLACE
,STATS = 5
GO
print '<--------------------End restore'
I would like to somehow just output the above with variable substitution the way Invoke-SqlCmd does it.
Solution 3
I figured out a clever way with set quoted_identifier off
PowerShell
$sqlFile = "C:\Users\user\Desktop\TestOutput.sql"
$begin = 'set quoted_identifier off print "'
$end = '" set quoted_identifier on'
Invoke-Sqlcmd -InputFile $sqlFile -QueryTimeout 0 -ServerInstance 'Server' -Database 'Database' -Variable @("begin=$begin", "end=$end") -Verbose
$begin = '--Begin'
$end = '--End'
Invoke-Sqlcmd -InputFile $sqlFile -QueryTimeout 0 -ServerInstance 'Server' -Database 'Database' -Variable @("begin=$begin", "end=$end") -Verbose
TSQL
/*
$(begin) is either
set quoted_identifier off print "
or
--Begin
*/
$(begin)
select SALESID from SALESTABLE where SALESID = 'SO-000003'
select SALESID from SALESTABLE where SALESID = 'SO-000004'
$(end)
/*
$(end) is either
" set quoted_identifier on
or
--End
*/
OTHER TIPS
I don't think invoke-sqlcmd can do thi. Regular sqlcmd.exe has the -e parameter to output the batches, although it will not output the "GO" . EG
sqlcmd -e -i restore.sql -v database="foo" databaseBak="bk" > Restore.final.sql
You can put SET NOEXEC ON at the top, or just point it at an dummy instance to generate the script.
Or something like:
sqlcmd -e -Q "set noexec on;`n:r restore.sql" -v database="foo" databaseBak="bk"
Instead of reinventing the wheel, just use dbatools - restore-dbadatabase
it has extensive coverage of all the scenarios that you might ever need.
Note: dbatools also has a better version of invoke-sqlcmd --> invoke-sqlcmd2 with a -ParseGO
to parse scripts with GO
batch seperators and is more optimized version.