9

I have a Power-shell script that calls a SQL script. This is currently working, but inside my sql script I have some hard coded parameters that I would like to pass to the SQL script via the powershell.

So this is the snip-it from the Power-shell script

function ExecSqlScript([string] $scriptName)
{
$scriptFile = $script:currentDir + $scriptName
$sqlLog = $script:logFileDir + $scriptName + "_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date)
$result = sqlcmd -S uk-ldn-dt270 -U sa -P passwordhere3! -i $scriptFile -b | Tee-Object -             filepath $sqlLog

 if ($result -like "*Msg *, Level *, State *" -Or $result -like "*Sqlcmd: Error:*") 
    {
    throw "SQL script " + $scriptFile + " failed: " + $result
    }   
}

try
{
    ExecSqlScript "restoreDatabase.sql"
}
catch
{
 //Some Error handling here
}

And this is from the SQL

USE MASTER
GO
DECLARE @dbName varchar(255)
SET @dbName = 'HardCodedDatabaseName'

So I want to pass the value for dbName, any ideas?

5 Answers 5

15

You could take advantage of sqlcmd's scripting variables. Those can be used in script file and are marked with $(). Like so,

-- Sql script file
use $(db);
select someting from somewhere;

When calling sqlcmd, use the -v parameter to assign variables. Like so,

sqlcmd -S server\instance -E -v db ="MyDatabase" -i s.sql

Edit

Mind the Sql syntax when setting variables. Consider the following script:

DECLARE @dbName varchar(255)
SET @dbName = $(db)
select 'val' = @dbName

As passed to the Sql Server, it looks like so (Profiler helps here):

use master;

DECLARE @dbName varchar(255)
SET @dbName = foo
select 'val' = @dbName

This is, obviously invalid a syntax, as SET @dbName = foo won't make much sense. The value ought to be within single quotes like so,

sqlcmd -S server\instance -E -v db ="'foo'" -i s.sql
Sign up to request clarification or add additional context in comments.

3 Comments

Ok this is what my sql looks like now >> SET @dbName = $(db) and the Powershell script > $result = sqlcmd -S uk-ldn-dt270 -U sa -P jjj88J! -v db ="LiveV5_V2_Integration_Ayo" -i $scriptFile -b | Tee-Object -filepath $sqlLog and now I am getting an invalid column error and it saying the invalid column is the value I am trying to pass in..hmmm
@user2537315 You are missing single quotes. See updated post.
@vonPrzy its working now... thanks. Marking as correct! Surprised I have not been voted up... ;-)
4

Just in case someone else needs to do this... here is a working example.

Power Shell Script:

sqlcmd -S uk-ldn-dt270 -U sa -P 1NetNasdf£! -v db = "'DatabaseNameHere'" -i $scriptFile -b | Tee-Object -filepath $sqlLog

Note the -v switch to assign the variables

And here is the MS SQL:

USE MASTER
GO

if db_id($(db)) is null

BEGIN
    EXEC('
    RESTORE DATABASE ' + $(db) + '
    FROM DISK = ''D:\DB Backup\EmptyLiveV5.bak''
    WITH MOVE ''LiveV5_Data'' TO ''C:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\LiveV5_' + $(db) + '.MDF'',
    MOVE ''LiveV5_Log'' To ''C:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\LiveV5_' + $(db) + '_log.LDF'', REPLACE,
    STATS =10')
END

Note: You do not have to assign the scripting varible to a normal sql varible like this.

SET @dbName = $(db)

you can just use it in your sql code. - Happy coding.

1 Comment

It's better to use the sql variable since that helps to prevent against sql injection
1

Here's a full example using a different PowerShell approach. Here I'm using a specific script to reset local databases for a clean development environment.

## Reset the Database
$resetScript= "C:\ResetSite\resetDatabases.sql"
Write-Host "Resetting the DB - Running $($resetScript)"
$connectionString = "Server = localhost; Database = 'master'; UID = myusername; PWD = mypassword"

# Create variables & params
$sqlCmdVariables = @(
    "Database=$($siteConfig.db_name)",
    "UserName=$($siteConfig.db_username)",
    "UserPassword=$($siteConfig.db_user_password)"
)
$sqlCmdParameters = @{
    InputFile = $resetScript
    QueryTimeout = 1800
    ConnectionString = $connectionString
    Variable = $sqlCmdVariables
}
# Invoke
Invoke-SqlCmd @sqlCmdParameters

The .sql file then uses the parameters passed in, the same way @nmbell mentions.

-- Declare the vars
DECLARE @Database nvarchar(100), @UserName nvarchar(100), @UserPassword nvarchar(100)

-- Set the vars
SET @Database = '$(Database)' -- database name
SET @UserName = '$(UserName)' -- SQL login and database username
SET @UserPassword = '$(UserPassword)' -- login password

... more stuff here.. use the vars like normal

This is partly derived from this blog post but modified slightly to use a file rather than an inline query.

1 Comment

I think this answer is more in the spirit of using PowerShell more than a command interpreter. The SqlServer module is very powerful and flexible, but people get bogged down in TSQL and creating kludges with sqlcmd. You also get the results in a more useful format than an executed application.
0

Adjusting vonPryz's answer to use:

SET @dbName = '$(db)'

means you can pass in the parameter from the command line in a more natural form as

sqlcmd -S server\instance -E -v db ="foo" -i s.sql

The SqlCmd variable still substitutes correctly.

Comments

0

I know this is an old answer but I do have a better way that is much easier if you only need a small amount of data from Powershell (or even a large amount as long as all you want is text), and you work mainly in SQL for your scripting like I do:

1: Start the PowerShell from SQL using xp_cmdshell, and insert the results to a one-column table which allows NULLs e.g:

DECLARE @Results (Line varchar(1000) NULL)
INSERT @Results
EXEC master.dbo.xp_cmdshell '"powershell.exe C:\PowershellScripts\MyScript.ps1 MyParams"'

2: During your PowerShell script, for anything you want to pass back to SQL, simply use "Write-Output", e.g:

Write-Output $returned_data

You can do this as many times as you want. If you have 10,000 values to pass back to SQL, then you could use write-output 10,000 times.

So in the above example once the "MyScript.ps1" PowerShell script finishes running, all of the output will be in the @Results table variable, ready to be used, queried, imported into individual variables, whatever you want really.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.