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:
- It can yield false positives.
- It is limited to use case where a text-based format is the desired output format.
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:
- For a more sophisticated function wrapper for the above functionality,
Convert-BitColumsToInt, which outputs DataRow instances rather than [pscustomobject] instances, see the bottom section of this answer.