Why does code like this execute in PowerShell ISE:
$var = 'dog';Invoke-SqlCmd -ServerInstance 'servername' -Query "insert into DB.dbo.tbl values ('$($var)')"
But not in SQL Server Agent as a CmdExec job step? Despite enclosing it as per usual. I believe it is the multiple queries as individual queries work
powershell.exe -ExecutionPolicy Bypass -Command {$var = 'dog';Invoke-SqlCmd -ServerInstance 'servername' -Query "insert into DB.dbo.tbl values ('$($var)')"}
TL;DR;
I have a SQL Server Agent job with a CmdExec step. I wish to assign a variable and then use it in an insert statement.
So far the following insert will work:
powershell.exe -ExecutionPolicy Bypass -Command "Invoke-SqlCmd -ServerInstance 'servername' -Query 'insert into DB.dbo.tbl values (''cat'')'"
This inserts a cat. Now I need a dog, something along the lines of:
powershell.exe -ExecutionPolicy Bypass -Command "$var = 'dog'; Invoke-SqlCmd -ServerInstance 'servername' -Query ""insert into DB.dbo.tbl values (''$($var)'')"""
There are two issues here, the comma terminator which I have used successfully in other jobs to separate commands. The second issue is escaping the double quotes. I understand they are required to process the variable into the string.
I have tried escaping with double quotes as well as one of these `. I've also tried separating the variable declaration into one server agent job step and using the variable in another.
Based on #gvee answer below, I put the code in a script block, which executes perfectly in PowerShell, but not as a SQL Agent CmdExec job step
powershell.exe -ExecutionPolicy Bypass -Command {$var = '''dog'''; Invoke-SqlCmd -ServerInstance 'servername' -Query "insert into DB.dbo.tbl values ($($var))"}
Note I had to escape the variable three times, which inserted into the table as 'dog' with the quotes included. I removed the single quotes from the insert statement, however I cannot get this to run in Server Agent as a CmdExec step
-Command accepts a ScriptBlock, so give this a whirl:
powershell.exe -ExecutionPolicy Bypass -Command {
Invoke-SqlCmd -ServerInstance "servername" -Query "insert into DB.dbo.tbl values ('cat')"
}
Related
I have a Powershell script that calls a stored procedure in SQL server and outputs the resulting XML directly to a file. It works for a smaller test file but falls down with the full size (~1.5gb file).
The stored procedure works fine. I can call it within SQL server - the problem is that I have to open it in the SQL server then manually save it to a file, then edit that file to remove newlines. When I run the script it falls down when it tries to delete the intermediary files at the end. However, when I run it line by line it falls down at the invoke-sql line.
#net use S: "\\processStore\projects"
# Create variables
$SQLquery = "DECLARE #return_value int; EXEC #return_value = [XML].[XMLdata];"
$outpath = "D:\MyDocuments\XML\XML files"
$outfile = "TestOutput"
# Run the SQL command and store the object to a variable. Need to extend the timeout from the default.
$sql = invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinstance 'statdata' -QueryTimeout 100000
cd C:
# Store the SQL output as an interim text file
$sql.{XML_F52E2B61-18A1-11d1-B105-00805F49916B} | out-file -Filepath "$outpath\$outfile.txt"
# Remove Linebreaks
(Get-Content "$outpath\$outfile.txt" -Raw).Replace("`r`n","") | Set-Content "$outpath\${outfile}_del.xml" -Force
format-xml "$outpath\${outfile}_del.xml" | Set-Content "$outpath\$outfile.xml" -Force
# Delete interim text files
del "$outpath\$outfile.txt"
del "$outpath\${outfile}_del.xml"
When running lines one by one the code falls down at the invoke-sqlcmd line with the error:
invoke-sqlcmd : A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote
host.)
At line:1 char:8
+ $sql = invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinst ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Change from
invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinstance 'statdata' -QueryTimeout 100000
to
invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinstance 'statdata' -QueryTimeout 0
Setting QueryTimeout = 0 will prevent the query from timing out
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
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
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;
}
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.