Handling SQLite Blob with Powershell - powershell

I am trying to copy Data from a SQLite DB via Powershell to another SQLite DB, but i have Problems handling a binary Blob from the Database.
The columns of the DB look like this:
ID (int), Alive (int), UID (string), Data (Blob)
In the DB, the Blob is Hexadecimal but when i have in Powershell it is decimal.
This is how i geht the Data:
$conSource = New-Object -TypeName System.Data.SQLite.SQLiteConnection
$conSource.ConnectionString = "Data Source=" + $db_source
$conSource.Open()
$sqlSource = $conSource.CreateCommand()
$sqlSource.CommandText = "SELECT * FROM Players WHERE UID = '" + $player_uid + "'"
$adapterSource = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter $sqlSource
$dataSource = New-Object System.Data.DataSet
[void]$adapterSource.Fill($dataSource)
$dataSource
$sqlSource.Dispose()
$conSource.Close()
I was able to convert it, but then it becomes a string and I have no idea how to get the hexadecimal string as a blob into the other database (via UPDATE).
Output of $dataSource.Tables.Data.GetType():
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array

Related

PowerShell - select number with decimal separator (DB2 SQL)

Cannot figure out how to contain decimal separator when selecting DB2 data with PowerShell.
DB2 table contains column with item price:
+------+---------+
| Item | Price |
+------+---------+
| A | 99,104 |
| B | 27,05 |
| C | 320,001 |
+------+---------+
This is part from Powershell script which gets this data:
$SQL = "SELECT Item, Price FROM Inventory"
$connection = New-Object System.Data.Odbc.OdbcConnection
$connection.ConnectionString = "DSN=$DNS;UID=$USERNAME;password=$PASSWORD"
$connection.open() | Get-Item -ErrorAction Stop
$cmd = New-object System.Data.Odbc.OdbcCommand($SQL,$connection)
$result = New-Object system.Data.DataSet
(New-Object system.Data.odbc.odbcDataAdapter($cmd)).fill($result) # here comma gets removed from Price
$connection.close()
$result.Tables[0] | Export-Csv -NoTypeInformation -Delimiter -Encoding UTF8 $OutputFile
This somehow selects data without decimals which is incorrect - prices are now enourmously high:
99104
2705
320001
I though that comma is removed during Export-Csv so added -UseCulture, but result is the same. It appears that comma is removed when data is selected:
New-Object system.Data.odbc.odbcDataAdapter($cmd)
My question is how can I fix this? Is there additional parameter or something is missing here?
I cant place a comment yet.
As others asked, what is the datatype for you price column at the database? Per your output it's left justified, so it does not seems to be a numeric type.
Making a simple test here with PRODUCT table from db2sample database:
And, also, you may try to use IBM.Data.Db2 .Net provider instead of using ODBC.
$dbFactory = [System.Data.Common.DbProviderFactories]::GetFactory('IBM.Data.DB2')
$connection = $dbFactory.CreateConnection()
$connection.ConnectionString = "Database=SAMPLE"
$connection.Open()
$da = $dbFactory.CreateDataAdapter()
$ds = new-object "System.Data.DataSet"
$cmd = $dbFactory.CreateCommand()
$cmd.Connection = $connection
$cmd.CommandText = "SELECT PID, PRICE FROM PRODUCT"
$da.SelectCommand = $cmd
$da.Fill($ds)
$ds.Tables[0]
Produces the expected decimal format.
PID PRICE
--- -----
100-100-01 9,99
100-101-01 19,99
100-103-01 49,99
100-201-01 3,99
$ds.Tables[0].Columns[1].DataType
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Decimal System.ValueType

Merge 2 PowerShell variables

I have 2 PowerShell variables that include data in the following format. For the first table:
UserName Department
-------- ----------
X#Y.com IT
and data in the following format in the second table:
Country MobileNumber
------- ------------
Singapore +65 8xxxxxxx
and the other variable is the same with different column names and different content. I want to merge the 2 variables to have them in one single variable in that would be in the following format:
UserName Department Country MobileNumber
-------- ---------- ------- ------------
Update:
The result of Ansgar commnet, generate it in the following format:
UserName Department Country MobileNumber
-------- ---------- ------- ------------
{x#y.com, z#y.com} {IT, Sales} {Singapore, Singapore} the same here
Assuming that you have individual objects in your two variables you could construct new objects from them like this:
$obj = New-Object -Type PSObject -Property #{
'UserName' = $obj1.UserName
'Department' = $obj1.Department
'Country' = $obj2.Country
'MobileNumber' = $obj2.MobileNumber
}
If you have arrays of objects (which, judging from your updated question, is the case) you need to build the objects in a loop. Note that this assumes an equal number of objects in both variables. Note also that you MUST ensure that both arrays are in the correct order, unless you have some criteria by which you can match objects from one array to the corresponding object from the other array.
$obj = for ($i=0; $i -lt $obj1.Count; $i++) {
New-Object -Type PSObject -Property #{
'UserName' = $obj1[$i].UserName
'Department' = $obj1[$i].Department
'Country' = $obj2[$i].Country
'MobileNumber' = $obj2[$i].MobileNumber
}
}
I would create a new object and map the properties in a hashtable like this:
First, you have your variables with the data, in this example it is
$Variable1
$Variable2
Then we want to make a Hashtable, this will map the data in each of these two variables to a property in our new object, so we map the two properties Username and Department from the first variable and the Country and the MobileNumber from the second variable.
$properties = #{
'Username'=$Variable1.UserName;
'Department'=$Variable1.Department;
'Country'=$Variable2.Country;
'MobileNumber'=$Variable2.MobileNumber;}
Lastly we create a new object, in this example I call the object $User. We tell this object to contain the properties for our Hashtable:
$User = New-Object -TypeName psobject -Property $properties

Convert sql Collection to String in Powershell

I've been trying to pull data from a sql query and get it converted to HTML to finally embed the results in an email body.
My code is as follows;
$SQLCommand = New-Object System.Data.SqlClient.SqlCommand
$SQLCommand.CommandText = "SELECT DISTINCT SYS.Name,LDISK.DeviceID0,LDISK.Size0 AS DiskSizeMB,LDISK.FreeSpace0 AS FreeSpaceMB,SCCM.dbo.v_GS_WORKSTATION_STATUS.LastHWScan,SCCM.dbo.v_GS_LastSoftwareScan.LastScanDate
FROM v_FullCollectionMembership_Valid SYS
JOIN v_GS_LOGICAL_DISK LDISK ON SYS.ResourceID = LDISK.ResourceID
INNER JOIN SCCM.dbo.v_GS_WORKSTATION_STATUS
ON LDISK.ResourceID = SCCM.dbo.v_GS_WORKSTATION_STATUS.ResourceID
INNER JOIN SCCM.dbo.v_GS_LastSoftwareScan
ON SCCM.dbo.v_GS_LastSoftwareScan.ResourceID =
SCCM.dbo.v_GS_WORKSTATION_STATUS.ResourceID
WHERE
LDISK.DeviceID0 = 'C:' AND
LDISK.DriveType0 = 3 AND
((LDISK.FreeSpace0 <= ((LDISK.Size0 * 10) / 100)) OR
(LDISK.FreeSpace0 <= 1024)) AND
SYS.CollectionID = 'SMS00001'
ORDER BY
SYS.Name"
$SQLCommand.Connection = $SQLConnection
$SQLAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SQLCommand
$SQLDataset = New-Object System.Data.DataSet
$SqlAdapter.fill($SQLDataset) | out-null
$FileInfo = $SQLDataset.tables | FT -AutoSize
The resulting format of the data stored in $FileInfo looks good;
Name DeviceID0 DiskSizeMB FreeSpaceMB LastHWScan LastScanDate
---- --------- ---------- ----------- ---------- ------------
Server01 C: 53244 2010 7/28/2017 3:18:01 PM 7/28/2017 5:25:51 AM
...however when I pipe this to ConvertTo-HTML ($FileInfo | ConvertTo-HTML) the resulting format comes out like this;
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML TABLE</title>
</head><body>
<table>
<colgroup><col/><col/><col/><col/><col/><col/></colgroup>
<tr><th>ClassId2e4f51ef21dd47e99d3c952918aff9cd</th><th>pageHeaderEntry</th><th>pageFooterEntry</th><th>autosizeInfo</th><th>shapeInfo</th><th>groupingEntry</th></tr>
<tr><td>033ecb2bc07a4d43b5ef94ed5a35d280</td><td></td><td></td><td>Microsoft.PowerShell.Commands.Internal.Format.AutosizeInfo</td><td>Microsoft.PowerShell.Commands.Internal.Format.TableHeaderInfo</td><td></td></tr>
<tr><td>9e210fe47d09416682b841769c78b8a3</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>27c87ef9bbda4f709f6b4002fa4af63c</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>27c87ef9bbda4f709f6b4002fa4af63c</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>27c87ef9bbda4f709f6b4002fa4af63c</td><td></td><td></td><td></td><td></td><td></td></tr>
When I look at the type of my $FileInfo I get this;
$FileInfo.GetType();
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
...so I suspect that the ConvertTo-HTML module is looking for input in string format however I can't seem to get this to work properly - even after trying options like $FileInfo | Out-String -Stream
I want to believe that this can be done easily - I just can't find the right approach. Thanks in advance!
Remove format-table, use select with exlude not necessary option with first table, try this
$SQLDataset.tables[0] |
select * -ExcludeProperty RowError, RowState, HasErrors, Name, Table, ItemArray |
ConvertTo-Html

Unable to set Comobject Value

I have a snippet of code that opens a word template, then attempts to set values of named FormFields.
$options = #{
'foo' ='bar';
'bizz' = 'buzz';
}
$document = 'C:\Form_template.doc'
$word = new-object -ComObject Word.application
$doc = $word.Documents.Open($document)
$word.visible = $true
$fields = $doc.FormFields
$fields.item('foo').Result = $options['foo']
$fields.item('bizz').Result = $options['bizz']
When running this snippet, the form fields are not set properly. However, when I run
$fields.item('foo').Result = 'bar'
$fields.item('bizz').Result = 'buzz'
The values are set as desired.
Edit: Here's an example in Interactive shell
PS C:\>$fields.item('foo').Result = $options['foo']
PS C:\>$fields.item('bizz').Result = $options['bizz']
PS C:\> $doc.FormFields.Item('foo').Result
PS C:\> $doc.FormFields.Item('bizz').Result
PS C:\>#Now let's try setting the values directly with a string.
PS C:\>$fields.item('foo').Result = 'bar'
PS C:\>$fields.item('bizz').Result = 'buzz'
PS C:\> $doc.FormFields.Item('foo').Result
bar
PS C:\> $doc.FormFields.Item('bizz').Result
buzz
Why am I not able to set the FormField values using values from the hash?
Per a suggestion from Ben casting the string with [string]$options['bizz'] resulted in setting the value correctly.
PS C:\>$fields.item('bizz').Result = [string]$options['bizz']
PS C:\> $doc.FormFields.Item('foo').Result
buzz
Upon further investigation I found that casting the hash value to string returned a different type vs using .toString()
PS C:\> $options['bizz'].getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
PS C:\> $options['bizz'].toString().getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
PS C:\> [string]$options['bizz'].getType()
string
I'm interested in why that is, but that would be a topic for another thread. Proper casting resolved my issue.

Instantiate empty csv variable

I'm using methods to pick records from different csv files and I want to know how to create an empty variable that would act like a csv file. For Example...
an empty array would be $array = #()
an empty hash table would be $hashTable = #{}
a non-empty csv object would be $csvFileRecords = Import-Csv $someFileName
an empty csv object would be ????
What would the syntax be?
A "CSV object" is actually just an array (of psobjects).
$csvFileRecords = #()
To add new records to that array, you just need to add psobjects with appropriate attributes corresponding to the desired columns. One way to create a psobject with desired properties is from a hash table.
$obj = new-object psobject -property #{fname="Fiddle";lname="Freak"}
$csvFileRecords += $obj
Well, CSV's can't created from $null, but you could do something like this:
PS C:\> New-Object -TypeName System.Object | ConvertTo-Csv
#TYPE System.Object
But your challenge is that this doesn't work back and forth. For example:
PS U:\> ((New-Object -TypeName System.Int32 ) | ConvertTo-Csv).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
means that the output of ConvertTo-CSV is not null, but this shows where you've lost the pipeline:
PS U:\> ((New-Object -TypeName System.Int32 ) | ConvertTo-Csv | ConvertFrom-csv).GetType()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ ((New-Object -TypeName System.Int32 ) | ConvertTo-Csv | ConvertFrom-c ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
The help says:
Inputs
System.Management.Automation.PSObject
You can pipe any object that has an Extended Type System (ETS) adapter to ConvertTo-CSV.
So I bet your issue is that $null or blank doesn't have an ETS Adapter.
Here's some more reading on this: https://blogs.msdn.microsoft.com/besidethepoint/2011/11/22/psobject-and-the-adapted-and-extended-type-systems-ats-and-ets/