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

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.

Related

while exporting data from SQL Server using Export-Csv (PowerShell) command double quotes are converted into question mark (?)

Here is my Table having column "Value"-
Value
This "data"). has consists of "information"
("Party A") and ("Party B")
Invoke-Sqlcmd -ServerInstance 'SQLSERVER' -Database "SQL" -Query "select * from Table" | Export-Csv -Path "C:\Users\Desktop\Outquery.csv" -NoTypeInformation
this code works fine but while exporting the data into CSV file doublequotes are converted into unexpected value with question mark (?)
CSV OUTPUT:-
VALUE
-------
This ?data?). has consists of ?information?
(?Party A?) and (?Party B?)
After further research adding "-Encoding UTF8" at the end of the code it is now exporting as expected.

Invoke-Sqlcmd ran SQL script capture verbose output

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.

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

create table with records in sql server with powershell: what's best?

I need to create and populate a table on sql server db starting from a powershell array of objects coming from select-object. I need to create the table with the correct datatypes and fields.
One way that I well know is export-csv and then invoke-sqlcmd with BULK INSERT, but I prefer to skip csv export.
How invoke-sqlcmd is normally used to create/populate a table starting from array of hash tables?
Do you know other ways doing the same job without using invoke-sqlcmd? Do I need to use System.Data? How to?
Thanks
EDIT 1: Another possible way is New-Object System.Data.SqlClient.SqlConnection by which I could ExecuteNonQuery() for each array element.
EDIT 2: Another option, always based on System.Data, is update a SqlDataAdapter instance.
I wrote an blog post for the Scripting Guy that covers just such a scenario
http://blogs.technet.com/b/heyscriptingguy/archive/2010/11/01/use-powershell-to-collect-server-data-and-write-to-sql.aspx
Using the code demonstrated in the blog post you can take any PowerShell command create a System.DataTable, then create a SQL Server Table and finally insert the DataTable into the newly created table. Here's an example
$dt = get-psdrive | out-datatable
Add-SqlTable -ServerInstance "Z003\R2" -Database dbutility -TableName psdrive -DataTable $dt
Write-DataTable -ServerInstance "Z003\R2" -Database "dbutility" -psdrive"diskspace" -Data $dt

Resources