5

I have a 3rd party app that up to now talked to quickbooks using a plug-in. That plug-in no longer works with the latest versions of the windows OS, so I am replacing it using PowerShell scripts. The plug-in would instanstiate the QBXMLRP.RequestProcessor com object then open a connection and begin a session with QuickBooks, process various requests from my app then close and disconnect the connection with quickbooks. While the connection is open, a ticket provided by QuickBooks is used to process any number of requests from my app.

Using PowerShell, I execute a command line prompt to "launch" PowerShell with a PowerShell .ps1 script file to run. As the plug-in did, the PS script instantiates the com object, opens a qb connection, begins a qb session, sends a qb Request, ends the qb session, closes the qb connection.

This works fine except that unlike with the plug-in I cannot send multiple requests from my app during a single open session with QuickBooks. Once I issue the command line prompt the PS script does it's thing and PS quits and the com object is lost. Is their anyway to preserve the live instance of the qb com object and reuse it in subsequent PowerShell sessions...

My app issues a command line prompt to run PowerShell that begins a qb session...

(.ps1 script)    
$myqbxmrlp = New-Object -com QBXMLRP.RequestProcessor
$myqbxmrlp.OpenConnection(...)
$ticket = $myqbxmrlp.BeginSession(....) 
$ticket | Export-CliXml $ticket (or set-content)
?? preserve the live $myqbxmrlp com object ??

My app issuse a command line call to open PS Session 2 send a request to qb...

(.ps1 script)    
$myqbxmrlp = ?? get the live com object back ??
$ticket = Import-CliXml $ticket (or get-content)
$myqbxmrlp.ProcessRequest($ticket,....)      

Command line call to open PS Session 3 with another request...

Command line call to open PS Session 4 with another request...

Command line call to open PS Session 5 and end the qb session and close the qb connection...

(.ps1 script)    
$myqbxmrlp = ?? get the com object back ??
$ticket = Import-CliXml $ticket (or get-content)
myqbxmrlp.EndSession($ticket,....)
$myqbxmrlp.CloseConnection

Is there another way to approach this using powershell?

user278859
  • 10,379
  • 12
  • 51
  • 74

1 Answers1

3

I can't verify that this will work for QuickBooks, but it's possible for Excel and other COM-Objects. You have to use Marshal.GetActiveObject method:

# Name of the QuickBooks COM object
$QbComObject = 'QBXMLRP.RequestProcessor'

# Try to get active instance of the QuickBooks COM object
if(-not ($myqbxmrlp = [Runtime.InteropServices.Marshal]::GetActiveObject($QbComObject)))
{
    # If we can't, then create new instance
    $myqbxmrlp = New-Object -ComObject $QbComObject
    $myqbxmrlp.OpenConnection(<#...your code...#>)
}

# Some code to process tickets...
$ticket = $myqbxmrlp.BeginSession(<#...your code...#>) 
$ticket | Export-CliXml $ticket

Realated question: How to connect to existing instance of Excel from PowerShell?

UPDATE #1:

How do I make Marshal.GetActiveObject available. I am getting the following error...Exception calling "GetActiveObject" with "1" argument(s): "Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))"

Probably this means that the 3rd party app is not registered as an automation server. It is not possible to get a reference to the running instance.. You could try to register file which exposes QBXMLRP.RequestProcessor (it could be dll\tlb\ocx\exe) with regsvr32.exe, but given my zero knowledge of QuickBooks I can't give you any concrete instructions. Try searching QuickBooks installation directory for files containing string RequestProcessor.

UPDATE: #2

While it seems that you can't get a live instance of the QuickBooks object, this could be mitigated via interprocess communication (IPC):

  1. One script should create a QuickBooks object and then wait for input
  2. All QuickBooks interaction is done via subsequent calls to another script, that will just pass requests to the first script via IPC.

IPC could be done via Named Pipes, here is some examples:

Community
  • 1
  • 1
beatcracker
  • 6,714
  • 1
  • 18
  • 41
  • How do I make Marshal.GetActiveObject available. I am getting the following error...Exception calling "GetActiveObject" with "1" argument(s): "Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))" – user278859 Apr 26 '15 at 16:46
  • @user278859 See update, not sure if it helps, but it's the best I can do. – beatcracker Apr 26 '15 at 20:32
  • Thanks for your help on this. I think it is time to move on and just accept that I am going to have to open and close the connection for each query. It will work, it is just that it can seem a bit slow if I have multipble requests to make. I wonder what I should to with this question. Mark it as answered, levave it unanswered, or delete it? – user278859 Apr 27 '15 at 00:11
  • 1
    @user278859 Definitely not delete it. Mark as answered if you're 100% sure that I'm right it can't be done or just leave it unanswered and give a chance for someone else to answer it. Even if there would be no answers the question itself could save some other QuickBooks user from futile attempts to make it work. Btw, see update, maybe this workaround will work for you. – beatcracker Apr 27 '15 at 11:24
  • IPC does look like it will work, but I have already moved on. Just running out of time to warrant pursuing this any further. Thanks again for your suggestions. I will be leaving this unanswered for now. If someone else is able to show that IPC will work, I will then mark it as answered. Thanks again. – user278859 Apr 27 '15 at 16:46