Public/ConvertTo-SqliteDataTable.ps1

function ConvertTo-SqliteDataTable
{
<#
.SYNOPSIS
    Creates a DataTable for an object

.DESCRIPTION
    Creates a DataTable based on an object's properties.

.PARAMETER InputObject
    One or more objects to convert into a DataTable

.PARAMETER NonNullable
    A list of columns to set disable AllowDBNull on

.INPUTS
    Object
        Any object can be piped to ConvertTo-SqliteDataTable

.OUTPUTS
   System.Data.DataTable

.EXAMPLE
    $dt = Get-psdrive | ConvertTo-SqliteDataTable

    Creates a DataTable from the properties returned by Get-PSDrive and assigns it to $dt.

.EXAMPLE
    $dataTable = Get-Process | Select-Object Name, CPU | ConvertTo-SqliteDataTable
    Invoke-SQLiteBulkCopy -DataTable $dataTable -DataSource C:\Processes.sqlite -Table Processes -Force

    Converts selected process properties to a DataTable and inserts the rows into SQLite.

.NOTES
    Adapted from script by Marc van Orsouw and function from Chad Miller
    Version History
    v1.0 - Chad Miller - Initial Release
    v1.1 - Chad Miller - Fixed Issue with Properties
    v1.2 - Chad Miller - Added setting column datatype by property as suggested by emp0
    v1.3 - Chad Miller - Corrected issue with setting datatype on empty properties
    v1.4 - Chad Miller - Corrected issue with DBNull
    v1.5 - Chad Miller - Updated example
    v1.6 - Chad Miller - Added column datatype logic with default to string
    v1.7 - Chad Miller - Fixed issue with IsArray
    v1.8 - ramblingcookiemonster - Removed if($Value) logic. This would not catch empty strings, zero, $false and other non-null items
                                  - Added perhaps pointless error handling

.LINK
    https://github.com/pwshdevs/devsetup.core.sqlite

.FUNCTIONALITY
    SQL
#>

    [CmdletBinding()]
    [OutputType([System.Data.DataTable])]
    param(
        [Parameter( Position=0,
                    Mandatory=$true,
                    ValueFromPipeline = $true)]
        [PSObject[]]$InputObject,

        [string[]]$NonNullable = @()
    )

    Begin
    {
        $dt = New-Object Data.datatable
        $First = $true
    }
    Process
    {
        foreach ($Object in $InputObject)
        {
            $DR = $DT.NewRow()
            foreach ($Property in $Object.PsObject.Properties)
            {
                $Name = $Property.Name
                $Value = $Property.Value

                #RCM: what if the first property is not reflective of all the properties? Unlikely, but...
                if ($First)
                {
                    $Col = New-Object Data.DataColumn
                    $Col.ColumnName = $Name

                    #If it's not DBNull or Null, get the type
                    if ($Value -isnot [System.DBNull] -and $Value -ne $null)
                    {
                        $Col.DataType = [System.Type]::GetType( $(Get-SqliteDataColumnType $property.TypeNameOfValue) )
                    }

                    #Set it to nonnullable if specified
                    if ($NonNullable -contains $Name )
                    {
                        $col.AllowDBNull = $false
                    }

                    try
                    {
                        $DT.Columns.Add($Col)
                    }
                    catch
                    {
                        Write-Error "Could not add column $($Col | Out-String) for property '$Name' with value '$Value' and type '$($Value.GetType().FullName)':`n$_"
                    }
                }

                Try
                {
                    #Handle arrays and nulls
                    if ($property.GetType().IsArray)
                    {
                        $DR.Item($Name) = $Value | ConvertTo-XML -As String -NoTypeInformation -Depth 1
                    }
                    elseif($Value -eq $null)
                    {
                        $DR.Item($Name) = [DBNull]::Value
                    }
                    else
                    {
                        $DR.Item($Name) = $Value
                    }
                }
                Catch
                {
                    Write-Error "Could not add property '$Name' with value '$Value' and type '$($Value.GetType().FullName)'"
                    continue
                }

                #Did we get a null or dbnull for a non-nullable item? let the user know.
                if($NonNullable -contains $Name -and ($Value -is [System.DBNull] -or $Value -eq $null))
                {
                    write-verbose "NonNullable property '$Name' with null value found: $($object | out-string)"
                }

            }

            Try
            {
                $DT.Rows.Add($DR)
            }
            Catch
            {
                Write-Error "Failed to add row '$($DR | Out-String)':`n$_"
            }

            $First = $false
        }
    }

    End
    {
        Write-Output @(,$dt)
    }

} #ConvertTo-SqliteDataTable