Invoke-Sqlcmd ran SQL script capture verbose output - sql-server

I need to do health check on various servers on daily basis. I have SQL script which includes missing indexes, duplicate indexes, CPU and memory, recovery, failed job, last backup etc in one script.
I am running this script manually on sever and changing result to text (I have made script which use print statement so I can directly copy and paste result).
Now I want to run this script with PowerShell but I am not getting result to text format with row-column format.
Code:
$RESULT = (Invoke-Sqlcmd -InputFile $sqlscript -ServerInstance $server -Database $databse -Verbose 4>&1) |
Out-File $outfile
I am getting all the print statement but not the result in text file.

A more appropriate way to do this is as follows.
[string]$SqlsSript = '..\path\'
[string]$ConnectionString = '...'
$DataSet = Invoke-SqlCmd -ConnectionString $Connectionstring -InputFile $SqlScript -As DataSet
You can then explore the $DataSet collection, i.e
$DataSet.Tables[0].Rows
Which you can then transform / output to a file if you like.
Do ensure that your SqlScript returns a table, e.g. a table variable.

Related

Powershell invoke-sqlcmd sees hash as System.Byte[]

Currently i am trying to retrieve a query hash from a database. The plan is to query slow queries from the query store and write them to a csv file. To retrieve the data fro the database I am using the following command:
$queryResult = Invoke-Sqlcmd -ServerInstance $SQLServer -Database $SQLDatabase -InputFile $SQLQueryPath -Username $SQLUser -Password $SQLPassword -ConnectionTimeout 60 | Export-Csv $ResultPath -Delimiter "," -NoTypeInformation
The query used retrieves queries that are running slow with their query hash (stored in the query_hash field). This query is tested on the same database using SMSS and then it returns the hash field shown as a hash. This hash is stored in the sql database, it is not generated by the query or script.
But whenever I try to retrieve the query hash using Invoke-Sqlcmd it returns the query_hash field as a byte array (System.Byte[]). All other fields are shown as in SMSS. Tried printing the result in the powershell terminal but there it also shows me an array of bytes.
How can I get the script to return the hash?
Tried to use [System.Text.Encoding]::ASCII.GetString($.query_hash) and [System.Text.Encoding]::UTF8.GetString($.query_hash) but they expect a single byte where this script gives an array.

SQL Unclosed quotation error in PowerShell

I have a small PowerShell Script that uploads CSV files to my SQL Server database using the Invoke-Sqlcmd command. It's working fine if the CSV file is small but I'm getting this error if the file has over 10,000 records.
Unclosed quotation mark after the character string.
I though the error is something else but it weird that it's working fine if I test with smaller size csv file.
$CSVImport = Import-CSV $PNP_CSV
ForEach ($CSVLine in $CSVImport) {
$CSVItemID = $CSVLine.ItemId
$CSVItemPath = $CSVLine.Path
$query = "USE $Global:Database
INSERT INTO PNP_Main (ItemId, ItemPath)
VALUES('$CSVItemID', '$CSVItemPath');"
Invoke-Sqlcmd -Query $query -ServerInstance $Global:Server -Database $Global:Database
}
Any help or suggestion would be really appreciated.

How to delete record from database if no longer existed

If I have a new data/record in my CSV file then I'm importing it to my SQL Server database using PowerShell like this.
$CSVImport = Import-CSV $Global:ErrorReport
ForEach ($CSVLine1 in $CSVImport) {
$CSVHold1 = $CSVLine1.Hold
$CSVGSID1 = $CSVLine1.GSID
$CSVSource1 = $CSVLine1.Source
$CSVTYPE1 = $CSVLine1.TYPE
$CSVMessage1 = $CSVLine1.Message
$CSVCreatedDate1 = $CSVLine1.Time
$query = "USE $Global:Database
IF NOT EXISTS (SELECT * FROM Lit_Hold_Err
WHERE GSID = '$CSVGSID1'
AND Source = '$($CSVSource1 -replace "'","''")')
BEGIN
INSERT INTO Lit_Hold_Err (Hold, GSID, Source, Error, Type,Date)
VALUES('$CSVHold1', '$CSVGSID1', '$($CSVSource1 -replace "'","''")','$CSVMessage1','$CSVTYPE1', '$CSVCreatedDate1')
END"
Invoke-Sqlcmd -Query $query -ServerInstance $Global:Server -Database $Global:Database
I'm just wondering how should I write another query that compare my CSV file with my database and delete a particular/s record from my database if it's no longer existed in my CSV file?.
I know I'll need to use DELETE Statement but I'm kinda stuck on WHERE Clause so Any help or suggestion would be really appreciated.
A suggestion would be using DBATool's Import-DbaCsv to read the CSV file and bulk load it to a table on tempdb, then use a merge instruction to make the inserts/updates/deletes.
The import command would be something like:
$Credential = Get-Credential
Import-DbaCsv -Path .\test.csv -AutoCreateTable -SqlInstance my-instance -Database tempdb -SqlCredential $Credential -SupportsMultiline

Powershell script scripts on dbachecks to compare the MaxMemory of server listed in a table

Run checks against servers
Import-Module dbatools
Import-Module dbachecks
$Server = "AMCB123"
$Database = "DBA"
# Create recordset of servers to evaluate
$sconn = new-object System.Data.SqlClient.SqlConnection("server=$Server;Trusted_Connection=true");
$q = "SELECT DISTINCT servername FROM DBA.[dbo].[Server_Group] WHERE ID =1;"
$sconn.Open()
$cmd = new-object System.Data.SqlClient.SqlCommand ($q, $sconn);
$cmd.CommandTimeout = 0;
$dr = $cmd.ExecuteReader();
# Loop through the servers and build an array
while ($dr.Read()) {
Get-DbaMaxMemory -SqlServer $dr.GetValue(0) | Format-Table
}
$dr.Close()
$sconn.Close()
I have Listed the sql server(stage, prod, DR servers in a table as per the groups), Now I want to compare the servers with group id's to check wethere the servers(stage,prod, DR) with same group id is having same MAXMemory cofiguration or not.
For this I'm using the below powershell script can you please help me with this, I have created a table with all the servewith grop id.
Request to please help me with the loop thorugh the servers and build an array, so that I can run the MAXMEMORY powershell command to compare it using the group id for all servers.
I have collected all the servers details into a table dbo.server groups
the powershell script should iterate through the table by using the ID and check whether the servers in the ID group has same MAXMEMORY configuration ID server_name Environment
1 ABC0123 prod
1 ABC5123 stage
1 ABC4123 DR
2 DEF0123 prod
2 DEF5123 stage
2 DEF4123 DR
I'm trying to use a powershell script which will check and compare the MAXMEMORY configuration as per the ID(to check whether stage, prod, DR server of the same group_id have similar setting or not), if not then it will display a warning/message as group_ids servers are not configured similarly.
Please help me with the script
You're making this script longer than it needs to be. Also, you're using Format-Table prematurely - you should only use the Format-* functions for displaying final information to the user; they output strings, not properly typed data/variables that can be used down the line.
Use the tools that PowerShell and dbatools give you to get your server list, and then pass that list to Get-DbaMaxMemory as a collection.
import-module dbatools
$ServerList = Invoke-DbaSqlQuery -ServerInstance $Server -query "select distinct servername from dba.dbo.server_group where group_id = 1" | Select-Object -ExpandProperty servername;
Get-DbaMaxMemory -ServerInstance $ServerList | Select-Object SqlInstance, SqlMaxMB;
This will give you a list of your SQL instances and the memory they're configured to use. What you do after that...it's hard to say as you haven't clearly defined what you're looking for.
But this may not tell the full story. Wouldn't it be better to check the configured values and what you're currently running with? You can do that with Get-DbaSpConfigure.
import-module dbatools
$ServerList = Invoke-DbaSqlQuery -ServerInstance $Server -query "select distinct servername from dba.dbo.server_group where group_id = 1" | Select-Object -ExpandProperty servername;
Get-DbaSpConfigure -ServerInstance $ServerList | Select-Object ServerName,ConfiguredValue,RunningValue;
You can even create a computed column in that final Select-Object to tell you if the configured & running values differ.
If you just wanted to use dbachecks (which uses dbatools in the background) you can use
$ServerList = (Invoke-DbaSqlQuery -ServerInstance $Server -query "select distinct servername from dba.dbo.server_group where group_id = 1").servername
and
Invoke-DbcCheck -SQlInstance $ServerList -Check MaxMemory
Or you can set the configuration item app.computername and app.sqlinstance to your server list using
Set-DbcConfig -Name app.sqlinstance -Value $serverlist
Set-DbcConfig -Name app.computername -Value $serverlist
and then you can run this (or any other checks) using
Invoke-DbcCheck -Check MaxMemory

Powershell - Output SQL Messages to file

I have a Powershell script that invokes a saved SQL Query file and runs it on a specific Server & Database. That part is working well, the issue is that I would like to save the SQL Messages that it generates to a log file (see picture).
SQL Output from after Query is run
This is not working with my current code, and I believe that's because since it's technically not Query output but instead reindexing and updating tables, not fetching data.
My current relevant code is:
{
Import-Module SQLPS
$Data = Invoke-Sqlcmd -InputFile $SQLQuery -ServerInstance $Server -Database $Database -QueryTimeout 0
$Data | out-file "$Output$Database$date.txt"
}
But that just generates an empty text file. I'm looking to get the info on rebuilding indexes and the updates it's doing saved off into a different file through Powershell. You can do this through SSMS by right clicking in the Messages window and clicking "Save Results As..." but looking to include this in my automation since it's running as a Scheduled Task and no one is on SSMS.
Powershell v3/Windows Server 2012/SQL SSMS 2014
Any help would be appreciated!! This is my first post so sorry for odd formatting.
It looks like the following link explains exactly this problem:
https://sqlnotesfromtheunderground.wordpress.com/2015/09/09/powershell-outputting-a-sql-server-query-result-from-the-message-tab/
Essentially, what you are seeing in the 'Messages' tab are not results from the query, but rather just PRINT statements (essentially the same as Write-Host or Console.WriteLine). If you use Invoke-SqlCommand2, its -Verbose option will capture these PRINT statements to the Verbose PowerShell stream. To then write this stream to a text file, you have to specify the specific stream (in this case, 4):
Invoke-Sqlcmd2 -ServerInstance . -Database master -Query "PRINT 'Export This result'" -Verbose 4> Out-File C:\Temp\Test.txt
I had the same issue but instead in powershell script i use it in a command and i used -verbose.
like this
Invoke-Sqlcmd -ServerInstance '.\Your_server_instance' -Database 'DATABASE_Name' -InputFile "D:\Your_script.sql" verbose 4> "C:\sql\YOUR_OUTPUT_FILE.txt"
so i think this code should work for you
{
Import-Module SQLPS
$Data = Invoke-Sqlcmd -InputFile $SQLQuery -ServerInstance $Server -Database $Database -QueryTimeout 0
$Data -verbose *> "$Output$Database$date.txt"
}
for -verbose *> it streams All output you can redirect specific streams :
1 Success output
2 Errors
3 Warning messages
4 Verbose output
5 Debug messages

Resources