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.
}
Related
I need to run a stored procedure that return 2 result sets with PowerShell. I use dbatools to do so but I could use .NET to get there. I just don't know how.
For this example, I use exec sp_spaceused that will return the space used in the actual database. Here's the result in SSMS:
As you can see here, there are 2 result sets. Now when I run the same command in PowerShell, I can't figure how to get the next result set.
Here is the code I've come up with:
$conn = Connect-DbaInstance -SqlInstance . -MultipleActiveResultSets
$query = 'exec sp_spaceused'
Invoke-DbaQuery -SqlInstance $conn -Query $query
I'm not even sure if I used MultipleActiveResultSets in the right way. I can't find any good example anywhere.
Wow, I just found the answer by testing all the different -As options. Here's the code:
$conn = Connect-DbaInstance -SqlInstance . -Database 'StackOverFlow'
$query = 'exec sp_spaceused'
$ds = Invoke-DbaQuery -SqlInstance $conn -Query $query -As DataSet
foreach ($table in $ds.Tables) {
$table | Out-String
}
I use Out-String to avoid joining objet but you could use Out-GridView. I also realize that I don't need to use -MultipleActiveResultSets.
I've done some research and I found the command "Invoke-Sqlcmd". I believe this is the command I want to use, but not which arguments. I've tried multiple things, but keep getting "invoke-sqlcmd : Login failed for user 'Hello'". Here is some practice data:
"Forehead" is the name of the server I am executing the PowerShell query from
"Elbow" is the name of the server that is running the SQL database
"Kitten" is the name of the database on "Elbow"
"Fluid" is the name of the table I wish to query
"Hello" is the username to log into "Elbow"
"World" is the password to log into "Elbow"
"Timmy" is the username to log into "Kitten"
"Sticky" is the password to log into "Kitten"
"SELECT * FROM Fluid" is the query I wish to run
With this information, from "Forehead" how can I execute the above query on Kitten? Is there more information I need?
Thank you for any help!
You need to pass the username, password, sql server and database to Invoke-Sqlcmd. Then your query (nice namings... :-)) should work.
$ServerInstance = 'Elbow'
$Database = 'Kitten'
$Username = 'Timmy'
$Password = 'Sticky'
$Query = 'SELECT * FROM Fluid'
Invoke-Sqlcmd -ServerInstance $ServerInstance -Database $Database -Username $Username -Password $Password -Query $Query
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.
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!
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.