Answered by:
Running SQL via powershell

Question
-
I am just trying to run stored procedures and general SQL using power shell, but I am having difficulties running a stored procedure runs SQL backups, what i noticed is that there is some kind of timeout period with the powershell. So running the query and having it take more than 30 seconds or so causes a timeout.
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection $SqlConnection.ConnectionString = "Server=localhost;Database=master;Integrated Security=True" $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $SqlCmd.CommandText = " waitfor delay '00:00:50'" $SqlCmd.Connection = $SqlConnection $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter $SqlAdapter.SelectCommand = $SqlCmd $DataSet = New-Object System.Data.DataSet $SqlAdapter.Fill($DataSet) $SqlConnection.Close() $DataSet.Tables[0]
Even the example above does timeout with a simple query as specified above, also I am going to be running the powershell from SQL Agent, if i want to pipe the output of the query to a txt file, what is the best way to do this, as I note that if i do this from the SQL agent job, it doesnt output print commands within the stored procedure, how can i capture everything for debugging purposes etc ?
Thanks.
Tuesday, August 10, 2010 3:56 PM
Answers
-
MrFlinstone,
to change the timeout you can set CommandTimeout property like this:
$SqlCmd.CommandTimeout = 0
So that your example become this:
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=localhost;Database=master;Integrated Security=True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = " sp_helpdb"
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandTimeout = 0
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
The above will work.
To capture info messages (result of print statements) you need to subscribe to a .net event (SqlConnection.InfoMessage). You can download this project: http://powershell4sql.codeplex.com/ for an example of how to do this. If you don't need ado.net datasets you might even be able to *use* powershell4sql unchanged for your needs.
Also this project could be of interest to you: http://sqlpsx.codeplex.com/
Andrew- Marked as answer by Mervyn Zhang Friday, August 13, 2010 9:52 AM
Wednesday, August 11, 2010 10:53 AM
All replies
-
This is what I use for returning SQL queries:
$sqlsvr = 'server' $database = 'database' $sqlserver = New-Object Microsoft.SqlServer.Management.Smo.Server($sqlsvr) $db = $sqlserver.databases[$database] $db.ExecuteWithResults("Select * FROM BaselineSoftware").tables
Tuesday, August 10, 2010 4:43 PM -
Yes, the default timeout is 30 seconds. You should be able to set the timeout to infinite by changing it to zero, but there seems to be a bug there (I have a Connect item open). Instead, one possibility is to set it to the max value, 65535. Another option was proposed by Chad Miller, to create your own Invoke-Sqlcmd:
function Invoke-Sqlcmd2
{
param(
[string]$ServerInstance,
[string]$Database,
[string]$Query,
[Int32]$QueryTimeout=30
)$conn=new-object System.Data.SqlClient.SQLConnection
$conn.ConnectionString=”Server={0};Database={1};Integrated Security=True” -f $ServerInstance,$Database
$conn.Open()
$cmd=new-object system.Data.SqlClient.SqlCommand($Query,$conn)
$cmd.CommandTimeout=$QueryTimeout
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[void]$da.fill($ds)
$ds.Tables[0]
$conn.Close()
}- Proposed as answer by Marco Shaw Wednesday, August 11, 2010 12:45 AM
Tuesday, August 10, 2010 5:57 PM -
Thanks for the answer, do you have an example of the powershell script in action. lets assume we want to run sp_helpdb
Wednesday, August 11, 2010 9:30 AM -
Grant,
I think that the bug and the Connect item are irrelevant here because they are only applicable to Invoke-SqlCmd, and the OP is not using Invoke-SqlCmd. I'm just clarifying it here for the OP. However your Invoke-Sqlcmd2 function should be able to address OP's needs.
Wednesday, August 11, 2010 10:38 AM -
MrFlinstone,
to change the timeout you can set CommandTimeout property like this:
$SqlCmd.CommandTimeout = 0
So that your example become this:
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=localhost;Database=master;Integrated Security=True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = " sp_helpdb"
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandTimeout = 0
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
The above will work.
To capture info messages (result of print statements) you need to subscribe to a .net event (SqlConnection.InfoMessage). You can download this project: http://powershell4sql.codeplex.com/ for an example of how to do this. If you don't need ado.net datasets you might even be able to *use* powershell4sql unchanged for your needs.
Also this project could be of interest to you: http://sqlpsx.codeplex.com/
Andrew- Marked as answer by Mervyn Zhang Friday, August 13, 2010 9:52 AM
Wednesday, August 11, 2010 10:53 AM -
Probably true. I can't help but mention it. It's a pain that you can't set the timeout.
I think the OP's issue was simply the timeout, but we'll see.
Wednesday, August 11, 2010 11:30 AM -
ok thanks guys, the issue was indeed related to timeout. I have set this to 0 i.e unlimited.
As for the ability to get print messages written to a text file. I already tried to do this, but what i find is that i am not getting the full message, in my stored procedure proc1 calls proc 2, i notice that i am getting print messages from just proc 1 but not proc2.
As for using a method to pipe out the results, i am looking for a solution that will not invlve any form of binary isntallation. is this possible ?
Wednesday, August 11, 2010 12:26 PM -
Hello, I'm not sure why you are talking about binary installation, I don't think I suggested that. Anyway here is and example that runs a query and captures the messages. I create two stored procedures sp1 and sp2 each outputs a message and one is called from the other. I can see both messages in the resulting file.
Here is the code:
function WriteConnectionEvents($currentEventID) {
Get-Event | % {
if ($_.SourceIdentifier -eq $currentEventID) {
$CurrentEventIdentifier = $_.EventIdentifier;
$info = $_.SourceEventArgs
Remove-Event -EventIdentifier $CurrentEventIdentifier
$info.Message
}
}
}
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=localhost;Database=master;Integrated Security=True"
$eventID = "Connection.Messages."+[datetime]::Now.Ticks;
Register-ObjectEvent -inputObject $SqlConnection -eventName InfoMessage -sourceIdentifier $eventID
$sp2 = @"
CREATE PROCEDURE dbo.sp2
AS
BEGIN
print 'Hello from sp2'
SELECT * from sys.tables
END
"@
$sp1 = @"
CREATE PROCEDURE dbo.sp1
AS
BEGIN
print 'Hello from sp1'
Exec dbo.sp2
END
"@
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandTimeout = 0
$SqlCmd.Connection.Open()
$SqlCmd.CommandText = $sp2
$SqlCmd.ExecuteNonQuery()
$SqlCmd.CommandText = $sp1
$SqlCmd.ExecuteNonQuery()
$SqlCmd.CommandText = "exec dbo.sp1"
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0] > c:\result.txt
WriteConnectionEvents $eventID >> c:\result.txt
$SqlCmd.CommandText = "drop procedure dbo.sp1"
$SqlCmd.ExecuteNonQuery()
$SqlCmd.CommandText = "drop procedure dbo.sp2"
$SqlCmd.ExecuteNonQuery()
$SqlConnection.Close()
Wednesday, August 11, 2010 8:14 PM -
thanks,
the Timeout = 0 worked great.
Tuesday, February 9, 2016 2:00 PM