Convert JSON array to single JSON object in Powershell - arrays

I am trying to convert JSON array into single JSON Object.
Below is the output screenshot
I want the output as
I am using the below powershell script
$getdb_Conn=Invoke-Sqlcmd -ServerInstance $ServerName -Database 'master' -Username $UserName -Password $Password -Query $getdb
$deadlockDB=$getdb_Conn.Database_Name
$deadlockSP=$getdb_Conn.SP_Name
$deadlockTable_Name=$getdb_Conn.Table_Name
$deadlockTIMESTAMP=$getdb_Conn.TIMESTAMP
$Obj = [PSCustomObject]#{
Database = $deadlockDB
SP = $deadlockSP
Table = $deadlockTable_Name
TIMESTAMP = $deadlockTIMESTAMP
}
Write-Output ( $obj | ConvertTo-Json)
Please someone help me, on how to the get required output. I do not want the JSON in an array.

The issue is you have one single non-array object that contains properties, which all contain arrays of values. To achieve the desired results, you need an array of objects that each contain one set of property values. You can choose to do this at the source when you are building $Obj or build a new set of objects to be sent to ConvertTo-Json.
For building a new set of objects using your current $Obj:
for ($i = 0; $i -lt $obj.TIMESTAMP.Count; $i++) {
[pscustomobject]#{
Database = $obj.Database[$i]
SP = $obj.SP[$i]
Table = $obj.Table[$i]
TIMESTAMP = $obj.TIMESTAMP[$i]
} | ConvertTo-Json
}
Building the objects from the source data:
$getdb_Conn=Invoke-Sqlcmd -ServerInstance $ServerName -Database 'master' -Username $UserName -Password $Password -Query $getdb
foreach ($conn in $getdb_Conn) {
[PSCustomObject]#{
Database = $conn.Database_Name
SP = $conn.SP_Name
Table = $conn.Table_Name
TIMESTAMP = $conn.TIMESTAMP
} | ConvertTo-Json
}

Related

Powershell - Ingesting API json results into SQL Server table

Looking for some help with ingesting data retrieved from an API endpoint and inserting it into SQL Server. This endpoint returns json.
I'm trimming the script to make this more readable. The script gets the data I'm requesting, the issues is the insert into the SQL table.
# Pass the `Authorization` header value with the payload we calculate from the id + secret
$Time = Invoke-RestMethod -Uri $TimeCardURL -Method Get -Header #{ Authorization = "Bearer ${AuthorizationValue}" } -Body $Body -Certificate $Cert -ContentType 'application/json'
$Time.teamTimeCards | Select-Object associateOID,timeCards
#SQL authentication and insert $Result data
$serverName = "sql-server"
$databaseName = "database"
$tableName = "table"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$serverName';database='$databaseName';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
foreach($ID in $associateOID){
$insertquery="
INSERT INTO $tableName
([associateOID],[timeCards])
VALUES
('$associateOID','$timeCards')"
$Command.CommandText = $insertquery
$Command.ExecuteNonQuery()
}
$Connection.Close();
It's trying to load the entire object $associateOID into the column, which is resulting in a "String or binary data would be truncated in table 'database.table', column 'associateOID'. Truncated value: '1 2 3 4 5 6 7 8'. The statement has been terminated."
I'm guessing there is an issue with this section of the script
$Time.teamTimeCards | Select-Object associateOID,timeCards
I rewrote your code to use another source of data, but you probably get the idea:
$output = Get-Process | Select-Object Handles, Id, ProcessName
echo($output)
foreach($value in $output){
$id = $value.Id
$name = $value.ProcessName
$insertquery="
INSERT INTO $tableName
([ID],[Name])
VALUES
('$id','$name')"
echo($insertquery)
}

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......
}

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.

How to create only specific delete statements using Scripter

I am using the Scripter class to give me a script for the data out of an existing database. I want to script a dataset that can be inserted into a production database. We are doing this to test if an installation of our Software is correct.
Unfortunately the dataset has to be removed later without any entries left behind so that it does not interfere with the data of our customers. So what I need are INSERT and DELTE statements. These are maintained manually at the moment which is too much of a burden.
Very well so I just went and executed the Scripter twice (once for INSERT, once for DELETE)
Problem is that when setting ScriptDrops to true then the output is in the form
DELETE FROM [dbo].[TableName]
What I would like is something of the form:
DELETE FROM [dbo].[TableName] WHERE ID = 'GUID'
Technically this would be possible since there are Primary Keys on all the tables.
The Scripter class must also in some form know of that things since it also gets the order of the DELETE-statements (dependencies) correct via foreign keys.
Any help on this would be appreciated.
Following are the 2 PowerShell-scripts I am using to export the data:
ScriptRepositoryData.ps1
$scriptPath = $MyInvocation.MyCommand.Path
$scriptDirectory = Split-Path $scriptPath -Parent
. $scriptDirectory\DatabaseScripting.ps1
$filepath='c:\data.sql'
$database='ECMS_Repository'
$tablesToExclude = #(
"SomeUnwantedTable"
)
$tablesListFromDatabase = GetTableList $database
$tablesArray = #()
$tablesListFromDatabase |% {
if (-not $tablesToExclude.Contains($_.Name.ToString()))
{
$tablesArray += $_.Name
}
}
ScriptInsert $database $tablesArray $filepath
DatabaseScripting.ps1
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMOExtended") | out-null
Function GetTableList ($database)
{
Invoke-SqlCmd -Database $database -query "SELECT * FROM sys.tables"
}
Function ScriptInsert ($database, $tables, $destination)
{
try {
$serverMO = new-object ("Microsoft.SqlServer.Management.Smo.Server") "localhost"
if ($serverMO.Version -eq $null) {Throw "Can't find the instance localhost"}
$urnsToScript = New-Object Microsoft.SqlServer.Management.Smo.UrnCollection
$databaseMO = $serverMO.Databases.Item("ECMS_Repository")
if ($databaseMO.Name -ne $database) {Throw "Can't find the database $database"}
$tables |% {
$tableListMO = $databaseMO.Tables.Item($_, "dbo")
$tableListMO |% {
$urnsToScript.Add($_.Urn)
}
}
$scripter = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') $serverMO
$scripter.Options.ScriptSchema = $False;
$scripter.Options.ScriptData = $true;
$scripter.Options.ScriptDrops = $true;
$scripter.Options.ScriptAlter = $true;
$scripter.Options.NoCommandTerminator = $true;
$scripter.Options.Filename = $destination;
$scripter.Options.ToFileOnly = $true
$scripter.Options.Encoding = [System.Text.Encoding]::UTF8
$scripter.EnumScript($urnsToScript)
Write-Host -ForegroundColor Green "Done"
}
catch {
Write-Host
Write-Host -ForegroundColor Red "Error occured"
Write-Host
Write-Host $_.Exception.ToString()
Write-Host
}
}
Unfortunately I did not find a way to do this using the Sql Management Objects.
Anyhow I now use the output of the Scripter and select the IDs of each table. I then use the IDs to change every line that looks like
DELETE FROM [dbo].[tableName]
to this:
DELETE FROM [dbo].[tableName] WHERE ID IN ('guid1', 'guid2')
Here is how I did it:
$content = Get-Content $destination
Clear-Content $destination
$content |% {
$line = $_
$table = $line.Replace("DELETE FROM [dbo].[","").Replace("]","")
$query = "SELECT ID, ClassID FROM" + $_
$idsAsQueryResult = Invoke-SqlCmd -Database $database -query $query
$ids = $idsAsQueryResult | Select-Object -Expand ID
if ($ids -ne $null) {
$joinedIDs = [string]::Join("','",$ids)
$newLine = $line + " WHERE ID IN ('" + $joinedIDs + "')"
Add-Content $destination $newLine
}
}
Where $destination is the script that has been generated with the Scripter class and $database is a string containing the database name.
I had to select a second column (ClassID which is there on all tables due to our OR mapper re-store) because of some weird error in Select-Object which I do not fully understand.
This of course only works because all tables have primary keys and all primary keys are named ID and are not combined primary keys or something.
You could of course achieve the same thing for other more complicated database schemas by extracting primary key information via SQL management objects.

Resources