I've created a sample Azure Automation Powershell Runbook. I'm trying to execute a SQL command and then print the messages from that command into Workbook output.
My code is taken from Capturing InfoMessage Output from SQL Server using PowerShell and it works if I run it locally:
Write-Output "Starting"
$conn = New-Object System.Data.SqlClient.SqlConnection "Data Source=abc.database.windows.net,1433;Initial Catalog=def;Integrated Security=False;User ID=ghj;Password=qwe"
## Attach the InfoMessage Event Handler to the connection to write out the messages
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] {param($sender, $event) Write-Output $event.Message };
$conn.add_InfoMessage($handler);
$conn.FireInfoMessageEventOnUserErrors = $true;
$conn.Open();
$cmd = $conn.CreateCommand();
$cmd.CommandText = "PRINT 'This is the message from the PRINT statement'";
$cmd.ExecuteNonQuery();
$cmd.CommandText = "RAISERROR('This is the message from the RAISERROR statement', 10, 1)";
$cmd.ExecuteNonQuery();
$conn.Close();
Write-Output "Done"
After I run the workbook, I see Starting
, -1
(from ExecuteNotQuery
result) and Done
but not messages from SQL.
Register-ObjectEvent
from this answer doesn't work either:
Register-ObjectEvent : Cannot register for the specified event.
An event with the name 'InfoMessage' does not exist. Parameter name: eventName
What am I doing wrong?
It seems in Azure Automation there is a scope problem calling Write-Output
or Write-Host
inside of the handler. Setting the message to a global variable in the handler and then calling Write-Output
after ExecuteNonQuery
worked for my purposes.
Write-Output "Starting"
$conn = New-Object System.Data.SqlClient.SqlConnection "Data Source=abc.database.windows.net,1433;Initial Catalog=def;Integrated Security=False;User ID=ghj;Password=qwe"
## Attach the InfoMessage Event Handler to the connection to write out the messages
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] {param($sender, $event) $global:message = $event.Message};
$conn.add_InfoMessage($handler);
$conn.FireInfoMessageEventOnUserErrors = $true;
$conn.Open();
$cmd = $conn.CreateCommand();
$cmd.CommandText = "PRINT 'This is the message from the PRINT statement'";
$cmd.ExecuteNonQuery() | Out-Null;
Write-Output $global:message
$cmd.CommandText = "RAISERROR('This is the message from the RAISERROR statement', 10, 1)";
$cmd.ExecuteNonQuery() | Out-Null;
Write-Output $global:message
$conn.Close();
Write-Output "Done"
If you are expecting more than one message you could concatenate them to the variable instead.
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] {param($sender, $event) $global:message += $event.Message + "`n"};
However, in either case, they will not be raised when they are thrown, but after the query has finished.
EDIT: I found a solution that I like even better and wanted to share it. Use an object list in the handler...
$events = new-object System.Collections.Generic.List[Object]
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] { param($sender, $event) $events.Add($event) }
...and after ExecuteNonQuery
loop to write all the messages
ForEach($event in $events)
{
Write-Output $event.Message
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With