Private/duckdb/New-DuckDBConnection.ps1

function New-DuckDBConnection {
    <#
    .SYNOPSIS
        Opens a DuckDB connection to the specified database file or in-memory database.
    .PARAMETER DbPath
        Path to the .db file (created if it does not exist). Use ':memory:' for an in-memory database.
    .PARAMETER EncryptionKey
        Optional encryption key (AES-256, requires DuckDB 1.4.0 or later).
        When provided the database is attached via ATTACH ... (ENCRYPTION_KEY '...') and
        set as the default catalog with USE, so all subsequent queries are transparent.
    .PARAMETER EncryptionCipher
        Cipher to use when EncryptionKey is set. 'GCM' (default, authenticated) or 'CTR' (faster, no integrity check).
    .EXAMPLE
        $conn = New-DuckDBConnection -DbPath '.\pipeline.db'
    .EXAMPLE
        $conn = New-DuckDBConnection -DbPath '.\pipeline.db' -EncryptionKey 'mysecretkey'
    #>

    [CmdletBinding()]
    [OutputType([DuckDB.NET.Data.DuckDBConnection])]
    param(
        [Parameter(Mandatory)]
        [string]$DbPath,

        [string]$EncryptionKey,

        [ValidateSet('GCM', 'CTR')]
        [string]$EncryptionCipher = 'GCM'
    )

    If ( -not $Script:isDuckDBLoaded ) {
        throw "DuckDB.NET is not loaded. Please ensure it is installed and available in the lib folder."
    }

    if ($EncryptionKey -and $DbPath -ne ':memory:') {
        # DuckDB encryption is configured via ATTACH, not via connection string.
        # Open a plain in-memory bootstrap connection, attach the encrypted file,
        # then make it the default catalog so all subsequent queries are transparent.
        $conn = [DuckDB.NET.Data.DuckDBConnection]::new('DataSource=:memory:')
        $conn.Open()

        # Escape single quotes in path and key to prevent SQL injection
        $escapedPath = $DbPath    -replace "'", "''"
        $escapedKey  = $EncryptionKey -replace "'", "''"

        $cmd = $conn.CreateCommand()
        try {
            # DuckDB 1.4.1+ requires OpenSSL (via httpfs) for writes to encrypted databases.
            $cmd.CommandText = 'INSTALL httpfs'
            $null = $cmd.ExecuteNonQuery()
            $cmd.CommandText = 'LOAD httpfs'
            $null = $cmd.ExecuteNonQuery()

            $cmd.CommandText = "ATTACH '$escapedPath' AS encrypted_db (ENCRYPTION_KEY '$escapedKey', ENCRYPTION_CIPHER '$EncryptionCipher')"
            $null = $cmd.ExecuteNonQuery()

            $cmd.CommandText = 'USE encrypted_db'
            $null = $cmd.ExecuteNonQuery()
        } finally {
            $cmd.Dispose()
        }

        Write-Verbose "Encrypted connection opened: $DbPath"
    } else {
        $conn = [DuckDB.NET.Data.DuckDBConnection]::new("DataSource=$DbPath")
        $conn.Open()
        Write-Verbose "Connection opened: $DbPath"
    }

    $conn

}