powershell: invoke-sqlcmd catching errors when using -InputFile instead of -Query - sql

I have an powershell script which is executing sql scripts from a given folder. This is working, but in case of error I don't see the reason of the error. In some cases the error is displayed, when the powershell itself throws the error. But when it's a more simple failure such as a primary key conflict, no error is shown.
I've tried it the following way, but this does not work when using the "-InputFile" parameter. Replacing this by the "-Query" Parameter and the error will be shown.
try
{
sqlps Invoke-Sqlcmd -ServerInstance "$dbInstance" -Database "$dbName" -InputFile "$updateScriptsFolder\$updateSql" -username $username -password $password -ErrorAction 'Stop' -Verbose -OutputSqlErrors 1
}
catch
{
Write-Host "Error while executing $updateScriptsFolder\$updateSql" -foregroundcolor red
Write-Host $error -foregroundcolor red
}
The only solution for now is to add the error handling to every sql script. But it's very likely that developers forget to add the errorhandling to their script. I want a more general error handling. Can anybody help?
Thanks,
Michael

As per the comments above, read the file into a string variable and use that variable as the value for the -query parameter.

Related

Powershell process wait for SQL query to complete

I have a Powershell script that runs daily. The script is supposed to run a SQL query and create a file with the results.
Import-Module SqlPs
Invoke-Sqlcmd -InputFile "C:\SQL Queries\dailyexport1pm.sql" | Out-File -filepath "I:\HTPN Training and Workflow\Daily Epic Completion\$(get-date -f yyyy-MM-dd)dailyexport1pm.txt"
This used to work, however we recently added a large amount of data that causes the query to take up to 3.5 minutes. I do not have a strong understanding of powershell and need to have the out-file process run once the SQL query is complete. Any assistance would be appreciated.
The script outputs a blank txt file. When I check the task scheduler last run result, that the powershell script is the only action of, it says "The operation completed successfully. (0x0)"
I think there might be some error in the sql-file. Requesting you to try this once:
$Error.Clear()
try {
Import-Module SqlPs
Invoke-Sqlcmd -InputFile "C:\SQL Queries\dailyexport1pm.sql" -WarningAction SilentlyContinue -OutputSqlErrors $false
}
catch {
$Error | out-file -filepath "C:\temp\SqlLog.txt"
}
Note: Later if you see no error and the output is coming properly then you can pipe it to 'Out-File -filepath "I:\HTPN Training and Workflow\Daily Epic Completion\$(get-date -f yyyy-MM-dd)dailyexport1pm.txt" '
Hope it helps.

Invoke multiple sql using powershell in sequence with runtime arguments

I'm trying to run sql queries in sequence. If any one of the sql query fails, then the windows powershell script should exit and send email. The log should be written to the log directory. where data= < this will passed in the run time>
Example code below:
Invoke-Sqlcmd -Query "SELECT data from emp where data=<run time argument>;" -ServerInstance "MyComputer\MyInstance"
Invoke-Sqlcmd -Query "SELECT data from class where data=<run time argument>;" -ServerInstance "MyComputer\MyInstance"
Invoke-Sqlcmd -Query "SELECT data from stud where data=<run time argument>;" -ServerInstance "MyComputer\MyInstance"
Invoke-Sqlcmd -Query "SELECT data from cust where data=<run time argument>;" -ServerInstance "MyComputer\MyInstance"
Invoke-Sqlcmd -Query "SELECT data from new where data=<run time argument>;" -ServerInstance "MyComputer\MyInstance"
Any help would be appreciated.
Regards,
What does it look like when "sql query fails"? You could rely on the Invoke-SqlCmd function's return, or have an expected "fail" message (or multiple messages).
I'm not familiar with Invoke-SqlCmd. Check out the MSDN page; -AbortOnError looks like it would be helpful to you, as would -ErrorLevel.
Here is an outline for a single expected error, with comment on how to extend. it's worth storing your queries in an array so that you can loop over then and break out of a loop instead of having linear code (where you have to copy and paste the check part after each invoke-sqlcmd
# string with a single error. you could use an array and add
# a foreach ($error in $errors) on the line marked #here
$expectedError = "Failed"
# Functions have to appear above where they are used
Function Check-SQLResults($result){
# a try-catch statement will execute the code in the try part, going
# to the catach part on a TERMINATING error
try{
# check each line for your expected error
foreach($line in $result){
#here
if($line -like "*$expectedError*"){
Write-Error "Something went wrong: $line" -ErrorAction Stop
}
}
# true is only returned if none of the result lines are like your error
return $true
}catch{
# false is returned if any lines contain error
return $false
}
}
# store the sql outcome in a variable so you can check it
$result = Invoke-Sqlcmd -Query "SELECT data from emp where data=;" -ServerInstance "MyComputer\MyInstance"
# using a function that tells you if the results contain an error or not is neater.
# again, this is manually dealing with errors and invoke-sqlcmd provides other options.
$resultIsErrorFree = Check-SQLResults -result $result
If(resultIsErrorFree -eq $true){
# execute next invoke-sqlcmd
}else{
# Send e-mail. $results can be added to body.
}

Capture the Error returned within sql result data set using power shell script

I am new to power shell and trying to execute multiple SQL scripts in a single PS script file. Below is my code,
Function ExecuteQuery($scriptname, $variableExe, $Databasename, $folder, $Optional)
{
invoke-sqlcmd -inputfile $ScriptLocation\$folder\$scriptname -Variable $variableExe -database $Databasename
-username $UsernameExecuteDBScript -password $PasswordExecuteDBScript -serverinstance $ServerName -querytimeout 65535
}
Then I am checking for any errors that may occur using the following code,
if($Error[0].Exception.Message -Match "Error")
{
Write-Host '------------------------------------------------'
Write-Host 'An Error has occured'
Write-Host
Write-Host $scriptname "execution Failed"
I am logging this SQL result, as well as the error messages generated in the command prompt using Start-Transcript
start-transcript $file
ExecuteQuery script1.SQL $null $dbname xy 0
ExecuteQuery script2.SQL $xyz $dbname xy 0
ExecuteQuery script3.SQL $null $dbname xy 0
I execute my PS script using a .bat file.
But I have an issue with this, if any SQL query completed it's execution successfully , but the table returned has columns saying "Error 547, FK violation" or some other similar error messages, my powershell script or Start Transcript do not capture it. It just goes on and runs the script and next scripts in the list.
Below is a sample data returned by the sql execution. The query completes it's execution and goes on to the next script. But the actual execution of the delete did not happen due to the FK violation. Data is returned in the table with 3 columns
ERR_NUMBER : 547
ERR_MESSAGE : The DELETE statement conflicted with the REFERENCE constraint "FK
_abc_sample". The conflict occurred in database "sample", table "dbo.sample_LOOKUP", column 'CONFIG_ID'.
ERR_LINE : 201
I want the Powershell script execution to be stopped/terminated and log the information into my log file when this happens.
Can anyone please help me out with this

Powershell Job within SQL Server Agent

I am having trouble with a powershell job returning a result set when it runs, it runs successfully but no results. I am running it against a list of servers. If I run the script against a specific server that I know I can connect to, it runs fine and gives results.
This is a script within the sql server agent running powershell. Am I using the SMO object right? Ive tried to use a try/catch (job fails), ive tried to add -ErrorAction "Continue" to the script (job fails), using smo to resolve a server name in order to use the if statement (job succeeds) but no results. Here is the script:
$ErrorActionPreference = "Continue";
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
$instanceNameList = Get-Content "c:\Scripts\InPutFiles\servers.txt";
$results = #()
foreach($instanceName in $instanceNameList)
{
$serverObject = New-Object Microsoft.SqlServer.Management.Smo.Server($instanceName)
$serverName = $serverObject.ComputerNamePhysicalNetBIOS;
if($serverName -ne $null) {
$results += Invoke-Sqlcmd -Query "
(My Query is in here!)
" -ServerInstance $instanceName.Name}
$instanceName| Where-Object {$_} | Export-csv 'C:\scripts\HungJobs_UnabletoConnect.csv' -NoTypeInformation
}
$results| Where-Object {$_} | Export-csv 'C:\scripts\HungJobs.csv' -NoTypeInformation
Mid-way through your script, is the $scripts variable being populated properly by the Invoke-Sqlcmd?
If so, I'm thinking that you should be able to do away with Where-Object {$_} on your last two commands. Where-Object is used as a filter, and in these two cases it doesn't seem to be filtering anything. You should just be able to directly export the $instanceName and $results directly to csv.

Using the results of a stored procedure in a loop with a condition

I have the following code that I am hoping to use to determine whether there is an active query on the server, and this logic will be used to prevent or allow something else to happen. I'm doing this in Powershell.
$Active = invoke-sqlcmd "sp_whoisactive" -database $DATABASE -serverinstance $SQLSERVER -verbose
Foreach($item in $Active){
If ($item -eq $null) {
"There is nothing active on the database server."
}
Else {
"There is something active on the database server."
}
}
Regardless of whether something runs or not it gives me the following warning:
VERBOSE: Warning: Null value is eliminated by an aggregate or other SET operation.
Which I'm assuming is coming from the internals of sp_whoisactive.
The other problem is that if nothing is active on the server it doesn't display the message, so I'm not sure that logic is actually firing.
Why would it be showing that information and how could I use the results of that SP in that sort of a test?
Note that I'm open to doing this in other ways, the problem is that I just need some logic that could fire to see if there is an active transaction on the server. I'd use something like seeing if there are connections, but there are always background connections. I'm only concerned about actual active transactions that are affecting tables.
EDIT: So I just gave another idea a shot and it seems to have the same problem, I think it's choking on what to do when nothing is returned except for the headers (when nothing is running).
$Active = invoke-sqlcmd "sp_whoisactive" -database $DATABASE -serverinstance $SQLSERVER -verbose | Out-String
select-string -InputObject $Active -Pattern "query" -quiet
It will return True if something is running (so I could use that in a conditional check) but doesn't return False if nothing is running.
It looks like I needed to just understand how Powershell handles null values berrer, which I found using this link.
Basically if I just leave the $Active variable alone and have Powershell test that, it works. So the end code looks like this:
$Active = invoke-sqlcmd "sp_whoisactive" -database $DATABASE -serverinstance $SQLSERVER -verbose
If ($Active) {
"There is something active on the database server. Stopping."
}
Else {
"There is nothing active on the database server." }
And it looks like it works!