White marks in string printed in PowerShell - sql-server

I have PowerShell command that's executing the SQL Query and it is returning this query as XML.
$query = #(Invoke-Sqlcmd -Query "select * from LS.dbo.live_Holdbacks FOR XML PATH('test');" -ServerInstance 'localhost')
$query | FORMAT-TABLE -Wrap
The problem is I have to print this result on the screen and then something strange happens. There are white marks in random places. You can see it marked on red. Word "Number" is literally split in the middle for no reason. What may cause it and how should I deal with it?

Apparently I dealt with it. Script below returns whole XML without those white marks.
$query = #(Invoke-Sqlcmd -Query "select top 100 * from LS.dbo.live_Holdbacks FOR XML PATH('test');" -MaxCharLength 100000 -ServerInstance 'localhost' )
$count = $query.Count
$out_string = ''
for($i=0; $i -lt $count; $i++){
$r = $query[$i].ItemArray[0].Trim()
$out_string += $r
}
$out_string

Related

Split values using Powershell

I have a file with multiple expressions like "$REGX('CareMedic.2_0','CustomerInformation','Customer Information')". The file can be a xml file, text file or any other type. If the file contains 9 of those expressions, I'm trying to pull all nine and send the values to a database.
I've tried my code as below:
$input_path = ‘C:\Users\Administrator\Desktop\test2.xml’
$SQLServer = "WIN-17V7QT0IJVK"
$SQLDBName = "Test"
$uid ="WIN-17V7QT0IJVK\Administrator"
$pwd = "letmebackinplease"
$SqlQuery = "SELECT * from product_schema;"
$ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True;"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection $ConnectionString
$SqlConnection.open()
if($SqlConnection.state -eq "Open"){
Write-Host "Test connection successful"
}
$regex = '()\(.*?\)'
$output = select-string -Path $input_path -Pattern $regex -AllMatches | % { $.Matches } | % { $.Value } |
ForEach-Object {
($_ -split "\(|\)")[1]
}
foreach ($line in $output){
$line = $line -replace "\(",""
$line = $line -replace "\)",""
$line = $line -replace "\'",""
$col1,$col2,$col3 = $line -split ","
[PSCustomObject]#{
col1 = $col1
col2 = $col2
col3 = $col3
} | select col1,col2,col3
$insert_query = "INSERT INTO [$SQLDBName].[dbo].[product_schema]
([version]
,[field]
,[value])
VALUES
($col1, $col2, $col3);"
$execute_query = New-Object System.Data.SqlClient.SqlCommand
$execute_query.connection = $SQLConnection
$execute_query.commandtext = $insert_query
$execute_query.ExecuteNonQuery()
}
$SqlConnection.close()
If the file has two of the below:
('Medic.2_0','AgeInformation','Age Information')
('Medic.2_0','TransactionID','Transaction ID')
My actual output should be:
'Medic.2_0' stored in Version Column
'AgeInformation' stored in the Field Column
'Age Information' stored in the value column
'Medic.2_0' stored in Version Column
'TransactionID' stored in the Field Column
'Transaction ID' stored in the value column
I have to take each of the values and store it in a column in a temp table setup on MySQL server like below:
**Version** **Field** **Value**
Medic.2_0 AgeInformation Age Information
Medic.2_0 TransactionID Transaction ID
Error Encountered:
Exception calling "ExecuteNonQuery" with "0" argument(s): "Incorrect syntax near '.2'."
At C:\Users\Administrator\Desktop\test.ps1:47 char:10
+ $execute_query.ExecuteNonQuery()
+ ~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
Can someone please recommend how shall I change my code to solve this?
In answer to your original question before editing: Assuming your output looks like this and is saved in a variable named $output
('Medic.2_0','AgeInformation','Age Information')
('Medic.2_0','TransactionID','Transaction ID')
Try this:
foreach ($line in $output){
$line = $line -replace "\(",""
$line = $line -replace "\)",""
$line = $line -replace "\'",""
$col1,$col2,$col3 = $line -split ","
[PSCustomObject]#{
col1 = $col1
col2 = $col2
col3 = $col3
} | select col1,col2,col3 | export-csv d:\test.csv -append -NoTypeInformation
}
We are looping through the $output line by line removing the brackets and the single quotes, splitting the remaining text on the comma, then assigning each of the three entries into the relevant variables. Once they are in variables we can then easily create a PSObject and use it to select our requirements for our export-csv
Try to add this code:
$info=#() #for store your values
foreach($item in $output){
$z=$item.split(',') #for split to 3 strings
$info+=[PSCustomObject]#{ #create custom object which have named columns and store our values
Version = $z[0]
Field = $z[1]
Value = $z[2]
}
}
Write-Output $info #variable that store all columns
Then you must run foreach loop to each object in $info .
you can run it like this:
foreach($data in $info){
$data.Version #to access Version field
$data.Field #to access Field field
$data.Value #to access Value field
.......your SQL query......
}

Iterate through array of variables passing each one to a function in PowerShell

I have a function that exports the results of a SQL query to a json file:
# Connect to SQL Server
$SqlCommand.CommandText = $Query;
$SqlCommand.Connection = $SqlConnection;
# Execute query and get the result back
$QueryResult = $SqlCommand.ExecuteReader()
# Hold query result in data table
$QueryTable = New-Object "System.Data.DataTable"
$QueryTable.Load($QueryResult)
# Export query results to json
$QueryTable | Select-Object $QueryTable.Columns.ColumnName | ConvertTo-Json | Out-File "$OutputDirectory\$SqlInstance-$QueryName.json"
And I have multiple queries that I want to execute and have created variables for each one:
$q1 = "SELECT blah"
$q2 = "SELECT more blah"
$q3 = "SELECT even more blah"
I call the function by:
ExportQueryResultsToJson -Query $q1 -QueryName "q1"
I have around 80 queries that I want to execute so instead of having 80 lines of ExportQueryResultsToJson ... I want to use ForEach. I've created an array of variables:
$SqlServer2012QueryArray = #(
$q1,
$q2,
$q3
)
I've tried many variations of the following:
foreach ($Query in $SqlServer2012QueryArray) {
$Expression = "ExportQueryResultsToJson -Query '$Query' -QueryName $Query"
Invoke-Expression $Expresion
}
And I've tried using a splat but I can't figure out how to pass all queries in correctly.
What am I doing wrong?
You can approach this in a number of ways. Three possible ways, which are all very algorithmically similar, are below:
Using Your Array:
The solution depends on your array $sqlserver2012QueryArray having a list of sequentially numbered variables in the format q<number>. The first variable name must be q1.
for ($i = 0; $i -lt $sqlserver2012QueryArray.Count; $i++) {
ExportQueryResultsToJson -Query $sqlserver2012QueryArray[$i] -QueryName $((Get-Variable "q$($i+1)").Name)
}
Querying Already Created Variables:
This solution relies on your variables being named in the format q<number>. They do not have to be sequentially named. It could capture unwanted variables if they are named like q<number>abc.
foreach ($var in (Get-Variable -Name q[0-9]*)) {
ExportQueryResultsToJson -Query $var.Value -QueryName $var.Name
}
Using a Hash Table:
You can create a hash table with each key name being your variable name and the associated value being the query string. You can bypass creating the query variables all together with this solution by just inputting the query strings as the values.
$queryhash = #{'q1' = $q1; 'q2' = $q2; 'q3' = $q3; 'q14' = $q14}
foreach ($var in $queryhash.GetEnumerator()) {
ExportQueryResultsToJson -Query $var.Value -QueryName $var.Key
}
Note: In all cases, you should try to avoid Invoke-Expression. It is not generally a safe command to use because it welcomes code injection. I also don't see why it is necessary at all in this case either.

Powershell - proper way to execute SQL query with multiple select statements and result tables

I'm trying to execute an SQL query with few select statements, that returns multiple tables as a result. The problem is that I can't find a way to read and use the tables separately.
Expected results:
Actual results: (it is printed row by row)
Purpose: I've made a script that creates an empty excel file with multiple sheets and each of the sheets will be used to contain each resultset of the query.
The only thing left is to put the needed text into the sheets. Here is my code for that part only:
$ConnectionString = "Data Source=...;Initial Catalog=...;User Id=...;Password=..."
$DBServerName = $ConnectionString.split('=')[1].split(';')[0]
$DBName = $ConnectionString.split('=')[2].split(';')[0]
$DBUser = $ConnectionString.split('=')[3].split(';')[0]
$DBPassword = $ConnectionString.split('=')[4].split(';')[0]
$CurrentFilePath = "C:\SQLqueryWithManyResultsets.sql"
$query = Get-Content -literalPath $CurrentFilePath | Out-String #getting the query string from file
$resultTables = Invoke-Sqlcmd -Query $query -ServerInstance $DBServerName -Database $DBName -DisableVariables -Password $DBPassword -Username $DBUser -ErrorAction Stop
foreach ($result in $resultTables) {
$result | Format-Table #where the magic happens
}
I've made a lot of research, but I cannot find a proper way to store and read the tables the way i need.
Try this:
Clear-Host;
$objConnection = New-Object System.Data.SqlClient.SqlConnection;
$objConnection.ConnectionString = "...";
$ObjCmd = New-Object System.Data.SqlClient.SqlCommand;
$ObjCmd.CommandText = "...";
$ObjCmd.Connection = $objConnection;
$ObjCmd.CommandTimeout = 0;
$objAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$objAdapter.SelectCommand = $ObjCmd;
$objDataSet = New-Object System.Data.DataSet;
$objAdapter.Fill($objDataSet) | Out-Null;
for ($i=0; $i -lt $objDataSet.Tables.Count; $i++) {
Write-Host ($objDataSet.Tables[$i] | Format-Table | Out-String);
}
$query = $null;
$objDataSet = $null;
$objConnection.Close();
$objConnection = $null;

how to get sql minsize property from file header via powershell?

I am interested in some way to grab the smallest size a sql log file can shrink to.
from reading this blog: http://social.technet.microsoft.com/wiki/contents/articles/22661.sql-server-misleading-database-initial-size-label.aspx
I understand I need to grab somehow the minsize (also known as initial size) value out of the file header.
how do I accomplish this?
To get all Databases and their initial size, via PowerShell, on some instance you can use this:
Import-Module SQLPS -DisableNameChecking
$instance = 'SERVER\INSTANCE'
$results = #()
try {
$sqlres = Invoke-SQLcmd -Server $instance -Database master 'SELECT [name],(size * 8 / 1024) InitialSize FROM sys.master_files WHERE [type] = 1'
ForEach($st in $sqlres) {
$dbinfo = #{
Name = $st.Name
InitialSize = $st.InitialSize
}
$results += New-Object PSObject -Property $dbinfo
}
} catch {
"error when running Invoke-SQLcmd "+$instance
Write-Host($error)
}
$results | export-csv -Path D:\sql_db_info.csv -NoTypeInformation
This will write databases names and initial size into D:\sql_db_info.csv file.
NOTE: in query I use [type] = 1 to get info on LOG files, if you need ROWS use [type] = 0, if you need all - remove WHERE statement.

Powershell Invoke-Sqlcmd to DataTable rowcount is incorrect when its 1 record

$sql=("select top 1 * FROM CollectionProfile")
$CollectionProfile = New-Object System.Data.DataTable
$CollectionProfile = Invoke-Sqlcmd -ServerInstance $Instance -Database $db -Query $sql -ErrorAction Stop
$CollectionProfile.Rows.Count
RETURNS :0
But if I change the TOP count to 2 -
$sql=("select top 2 * FROM CollectionProfile")
RETURNS :2
Driving me crazy and yes, I could not find a single reference to this on the "innernets". I must be doing something wrong, but WHAT?
When you use the query with TOP 1, Invoke-SqlCmd returns a DataRow.
When you use the query with TOP 2, Invoke-SqlCmd returns an Array of DataRows. Invoke-SqlCmd does not return a DataTable. You could change your code to force an array to be returned (see here: force array), and then check the Count on it:
$sql = ("select top 1 * FROM CollectionProfile")
$CollectionProfile = #(Invoke-Sqlcmd -ServerInstance $Instance -Database $db -Query $sql -ErrorAction Stop)
$CollectionProfile.Count #Returns 0 with Null, 1 with TOP 1, and 2 with TOP 2
Use one of the column name from select statement in place of Rows, which will give correct result count.
Here in my example I gave name in place of rows which is my first column name in the select statement "Select top 1 * from Sysdatabases". This will give you correct result for top 1 or top 2 ..
$sql=("select top 1 * FROM sysdatabases")
$sysdatabases = New-Object System.Data.DataTable
$sysdatabases = Invoke-Sqlcmd -ServerInstance $Instance -Database $db -Query $sql -ErrorAction Stop
$sysdatabases.name.Count

Resources