6

Situation

  • I am new to the QuickBooks world.
  • I have a .qbw file -> CompanyName.qbw
  • It's a huge file that contain almost everything about my company.
  • I want to query some data out of that file - NOT all , but some.:)

Let's say, I want to query only the inventory report.

  • Within that inventory report, I only want 3 fields.

    1. product_id
    2. name
    3. availability

I've been looking for a tool out there everywhere, I could not find anything that will does exactly what I want.

Can someone get me start on this ? Can anybody at least point me to the right direction ?

I am not exactly sure, if what I am trying to do is possible.

iori
  • 3,236
  • 12
  • 43
  • 78

3 Answers3

6

Not a direct answer, but some direction as you requested:

The QOBDC driver available here (http://qodbc.com) should allow you to access your qbw file like a SQL database and perform queries against it. There is a free trial, but it looks like you'll need to pay $150-$500 to buy this driver if you find that it works and you want to use it long term.

As for querying a specific report like inventory, I don't know, but there are plenty of tutorials around in the form of blog posts and YouTube videos that should help you figure out how to use QODBC for your purpose.

PeterDNCO
  • 396
  • 1
  • 7
  • I followed your suggestion, and I've installed the QODBC driver. But when I tried to `Test Connection to QuickBooks`, I keep getting error. Can you shed some lights on this ? – iori Jan 28 '15 at 15:40
  • Unfortunately, I'm not a QODBC user myself, but perhaps you could try the info on this link if you haven't already: http://www.qodbc.com/qodbcconnect.htm Failing that, you might try searching Stackoverflow for "QODBC"? – PeterDNCO Jan 29 '15 at 21:44
6

Intuit (the people that make QuickBooks) offers something called the QuickBooks SDK specifically for situations like yours.

It's free to download. Download, install, and you can connect to QuickBooks and extract any data you want or run any reports you want.

There's about 600 pages of documentation available in PDF format:

And you'll probably also want to look at the QuickBooks OSR, which shows all of the XML messages you can send QuickBooks, along with the XML responses you get back and even some auto-generated sample code:

If you post more details (e.g. what language are you developing in?) we could post sample code for you too.

Keith Palmer Jr.
  • 27,666
  • 16
  • 68
  • 105
0

There may be a third option to QODBC and QBSDK that doesn't suck, cost money, or waste a LOT of your time. It can be done with native Windows Server tools alone if you are not terrified of .NET and PowerShell.

Intuit hides it but, Quickbooks Enterprise supports ODBC access natively for custom reporting. Lesser editions might/might not; I have not worked with them. So ...

PLEASE, IF YOU ATTEMPT THIS METHOD, leave a comment with your results and the edition/year of your Quickbooks installation for posterity.

Caveats, Provisos, Disclaimers, and the like.

  • The underlying data engine in Quickbooks is Sybase's SQL Anywhere. So to write your queries you will need to familiarize yourself with Sybase conventions and syntax. See References at the end of this article.

  • This procedure can only be performed on a system that Quickbooks is installed upon. The proprietary Sybase drivers are part of the QB installation. So if you intend to do this "across the net", you must have the same edition/version of Quickbooks installed on both ends.

  • You cannot access a company file that has been left in "single-user" mode using this method. You'll need to log in as admin and change the mode to "multi-user"

  • Pay careful attention to your access method defined in the connection string. It is easy to leave a company file inaccessible until reboot. See ASTOP below.

  • It will always be safest to make copies of your files and access the copies. You will need the .qbw, .qbw.DSN, .qbw.ND, and .qbw.TLG files. This may be impractical if your company file is constantly in use and, like myself, you need to perform dozens of extracts daily.

  • Always have a backup before accessing your data in this (or any other) manner.

  • And finally, if this blows up in your face, I was never here...

Procedure

  1. Using the admin account, establish an ODBC user account. This is separate from your QB logins. Grant the account only those rights it needs for your application. The user name and password will be used in your connection string plain text so any file containing it must be kept secured.

Custom Reports/ODBC ODBC User

  1. Construct a connection string. Most of the required parameters are provided by the QB DSN file that is created in the same folder as your company file. But the data needs to be converted to Sybase convention. And special care needs to be given to the DBF (DatabaseFile), LINKS (CommLinks), ASTOP (AutoStop) parameters; ASTOP needs to be 'NO' for multi-user access via the QB Server (using LINKS=TCP...) and 'YES' for direct file (shared memory) access (using DBF=). If AutoStop is not set appropriately for your access type, you may well lock everyone out of the file until you reboot.

Examples connection strings:

For direct connect (DBF=.../ASTOP=YES):

 connStr = "DRIVER={QB SQL Anywhere}; `
        DBF=<full path to company file>; `
        ENG=<ServerName from QB DSN file>; `
        UID=<ODBC account>;PWD=********; `
        ENP=<DatabaseName from QB DSN file>; `
        LOG='<Path to a debug log file>'; `
        ASTOP=YES;INT=NO;DBG=NO;DMRF=NO;COMP=NO";

For access via the server (LINKS=.../ASTOP=NO):

 connStr = "DRIVER={QB SQL Anywhere}; `
        LINKS=<CommLinks from QB DSN file>; `
        ENG=<ServerName from QB DSN file>; `
        UID=<ODBC account>;PWD=********; `
        ENP=<DatabaseName from QB DSN file>; `
        LOG='<Path to a debug log file>'; `
        ASTOP=NO;INT=NO;DBG=NO;DMRF=NO;COMP=NO";
  1. Write your code. Here's an example:
function Export-QbKe {
    [CmdletBinding()]
    param(
        # Full path to company (.qbw) file
        [Parameter(Mandatory)]
        [string]$QbDataFile,

        # ODBC username as set under Custom Reports in Quickbooks  
        [Parameter(Mandatory)]
        [string[]]$aQueries,

        # ODBC username as set under Custom Reports in Quickbooks  
        [Parameter(Mandatory)]
        [string]$User,

        # ODBC user password as set under Custom Reports in Quickbooks  
        [Parameter(Mandatory)]
        [string]$Pswd,

        # Flag for using TCP (company file has active users) or Shared Memory (company file is inactive)
        [Parameter(Mandatory)]
        [bool]$UseTCP,

        # Full path to output XML file.  
        # The DSN Debug file will be created/appended in the same folder
        [Parameter(Mandatory)]
        [string]$DataSetFile
    )

    # Construct Paths
    $DebugDSNPath = ( Split-Path -Path $DataSetFile -Parent ) + "\DebugDsn.log";
    $QbDsnFile = $QbDataFile + ".dsn"

    # Construct Sybase compliant connection string from QB DSN file
    $connStr = "UID=" + $User + ";PWD=" + $Pswd + ";LOG='" + $DebugDSNPath + "';"
    #$connStr = "UID=" + $User + ";LOG='" + $DebugDSNPath + "';"
    Get-Content $QbDsnFile | ForEach-Object {
      If ($_ -match "=") {
        $line = $_
        $p = ($line -Split "=")[0]
        $v = ($line -Split "=")[1]
        Switch ($p) {
          ("driver") {$connStr += "DRIVER={"  + $v + "};"}
          ("compress") {$connStr += "COMP=" + $v + ";"}
          ("DisableMultiRowFetch") {$connStr += "DMRF=" + $v + ";"}
          ("debug") {$connStr += "DBG=" + $v + ";"}
          ("integrated") {$connStr += "INT=" + $v + ";"}
          ("ServerName") {$connStr += "ENG=" + $v + ";"}
          ("DatabaseName") {$connStr += "ENP=" + $v + ";"}
          ("CommLinks") {
            if ($UseTCP) { $connStr += ($line -replace "commlinks","LINKS")  + ";ASTOP=NO;"}
            else { $connStr += "DBF='" + $QbDataFile + "';ASTOP=YES;"}
          }
        }
      }
    }

    # Instantiate required objects
    $conn = New-Object System.Data.Odbc.OdbcConnection
    $cmd = New-Object System.Data.Odbc.OdbcCommand
    $adapter = New-Object System.Data.Odbc.OdbcDataAdapter
    $ds = New-Object System.Data.DataSet

    # Attempt connecting to Sybase - bail on failure
    "Connecting to " + $QbDataFile + " using:"
    $connStr -replace "=$Pswd","=********"               # Obfuscate the password
    try {
       $conn.ConnectionString = $connStr
       $conn.Open()
       $cmd.Connection = $connStr
       $adapter.SelectCommand = $cmd
    }
    catch {
       $Err = "An error occurred on open.  Extract is terminated."
       #Alert $Err
       $Err
       return $false
    }

<#
   Example array of queries:
   $aQueries =  @(
        "select * from v_cf_custom_field"
        ,"select * from v_cf_customer"
        ,"select * from v_cf_item"
        ,"select * from v_cf_name"
        ,"select * from v_lst_contacts"
        ,"select * from v_lst_customer"
        ,"select * from v_lst_employee"
        ,"select * from v_lst_item"
        ,"select * from v_lst_names"
        ,"select * from v_lst_unit"
    )
#>

    # Perform queries
    try {
        foreach ( $qry in $aQueries )
        {
            $tname = $qry.Split()[-1]
            $ds.Tables.Add($tname)
            $cmd.CommandText = $qry
            $recCount = $adapter.Fill($ds,$tname)
            "$recCount records read from QB table: $tname"
        }
    }
    catch {
       $Err = "An error occurred while querying QB.  The extract is terminated."
       #Alert $Err
       $conn.Close();$conn.Dispose();
       $Err
       return $false  
    }
       $conn.Close();$conn.Dispose();

    # Output DataSet to XML file
    $writer = New-Object System.IO.StreamWriter $DataSetFile
    try {
        $ds.WriteXml($writer, [System.Data.XmlWriteMode]::WriteSchema)
    }
    catch {
       $Err = "An error occurred while querying QB.  The extract is terminated."
       #Alert $Err
       return $false  
    }
    $writer.Close()
    $writer.Dispose()

    # Truncate DebugDSN.log
    Set-Content $DebugDSNPath (Get-Content $DebugDSNPath -Tail 500)
}

Our Environment

As of this writing, we are running Quickbooks Desktop Enterprise 2021 on Windows Server 2012r2 (migrating to 2019 Q1-2023) with Remote Desktop Services. Our users RDP to the server to use Quickbooks. Our field service folk (who do not have access to Quickbooks) are coordinated via a website updated every 20 minutes by a Scheduled Task that utilizes the exact PowerShell function above. The resulting XML file is copied to our MSSQL server and imported into the websites database using the very cool Write-SqlTableData command (but that is a different episode).

References

Sybase Connection Strings

SQL Anywhere Reference

Frobozz
  • 183
  • 8