Reputation: 41
I have an issue whereby a query called via Invoke-SQLCmd returns a certain set of results. For some columns the value is a 0 or 1 of BIT data type. The results instead come back as False or True in powershell.
Is there anyway to stop this happening?
I have searched far and wide and aside from suggestions to amend the select query and add conversions (which would be too much work considering I am just leveraging the same query but within Powershell in order to generate some logs for monitoring reasons)
Upvotes: 1
Views: 78
Reputation: 439777
sirtao's helpful answer explains why the MSSQL BIT data type of necessity becomes the [bool]
data type in .NET (and therefore in PowerShell), the closest logical equivalent.
Your own answer shows a CSV-based solution that transforms False
and True
string values to 0
and 1
after the fact, using string replacements. However:
The following sample code demonstrates how to generically transform the output objects (data rows, System.Data.DataRow
instances) from an Invoke-SQLCmd
call by replacing their [bool]
property (column) values with their [byte]
equivalents, i.e. by transforming $true
to 1
and $false
to 0
(if you know the columns of interest ahead of time and are willing to hard-code them, the solution would be simpler):
# Create a sample DataTable as a stand-in for Invoke-SqlCmd output,
# with 2 columns:
# * Name (type [string])
# * BitAsBoolean (type [bool])
$dt = [System.Data.DataTable]::new('sample')
$dt.Columns.AddRange([System.Data.DataColumn[]] ( @{ ColumnName = 'Name'; DataType = [string] }, @{ ColumnName = 'BitAsBoolean'; DataType = [bool] } ))
@{ Name = 'John'; BitAsBoolean = $true }, @{ Name = 'Susan'; BitAsBoolean = $false } |
ForEach-Object {
$dt.Rows.Add(($dr = $dt.NewRow()))
foreach ($entry in $_.GetEnumerator()) { $dr[$entry.Key] = $entry.Value }
}
# Process output from a (simulated) Invoke-SqlCmd call and transform
# each data row by converting [bool] column values to [byte] ones.
$propNames = $null
$dt.Rows |
ForEach-Object {
$row = $_
if ($null -eq $propNames) {
$columns = $row.Table.Columns
# Get all property (column) names.
$propNames = $columns.ColumnName
# Determine the names of those properties that are of type Boolean.
$boolPropNames = $columns.Where({ $_.DataType -eq [bool] }).ColumnName
}
# Create a copy of the input row, so that we can modify it.
$rowCopy = $_ | Select-Object $propNames
# Replace the [bool] values with their [byte] equivalents,
# i.e. transform $true to 1 and $false to 0.
$boolPropNames.ForEach({ $rowCopy.$_ = [byte] $rowCopy.$_ })
$rowCopy # Output the modified row copy.
}
The OO (object-oriented) nature of the above operation gives you a choice of what output format you'd like to generate from it; in your case, where CSV is desired, simply append something like the following to the pipeline above:
| Export-Csv -NoTypeInformation -Encoding utf8 output.csv
Outputting $dt.Rows
, i.e. the results of the simulated query, yields:
Name BitAsBoolean
---- ------------
John True
Susan False
Running the transformation code yields:
Name BitAsBoolean
---- ------------
John 1
Susan 0
Note:
Convert-BitColumsToInt
, which outputs DataRow
instances rather than [pscustomobject]
instances, see the bottom section of this answer.Upvotes: 2
Reputation: 41
In the end I generated the csv file by piping the invoke-sqlcmd results that are in a variable using export-csv then i used the below two lines just after the exporting.
(Get-Content -path %pathtoCsv%) -replace 'False', '0' | set-content "%pathtocsv%"
(Get-Content -path %pathtoCsv%) -replace 'True', '1' | set-content "%pathtocsv%"
Upvotes: 0
Reputation: 2880
There is no bit
type in Powershell.
Thus the result gets converted in its closest equivalent: bool
.
...which is just semantic bit anyway.
Details would depend on your specific script, but you can simply use .ToInt16($null)
to convert $true
to 1
and $false
to 0
Upvotes: 2