1

I am trying to execute some asynchronous JavaScript code from PowerShell and get the result. However, when using the node command in PowerShell, it seems to only return synchronous results.

My PowerShell script is as follows:

$hubspot_api_key = 'xxx'

$result = $(node hubspot.js $($hubspot_api_key) 'ci')

Write-Output 'Results:' $result

The main part of my hubspot.js file is as follows:

(async () => { return await getContacts(); })()

How can I get the results to return immediately? When I run this the PowerShell script continues to process before the hubspot.js results are returned.

I tried using the code below but this does not work either.

$someFunc = $(node hubspot.js $($hubspot_api_key) 'ci') $results = Start-Job -ScriptBlock $someFunc | wait-job | receive-job

Additional code from hubspot.js:

getContacts = async () => {
    const emailFilter = `*bstdev${environment}*`
    console.log('emailFilter', emailFilter);
    const filter = { propertyName: 'email', operator: 'EQ', value: emailFilter }
    const filterGroup = { filters: [filter] }
    const sort = JSON.stringify({ propertyName: 'createdate', direction: 'DESCENDING' })
    const query = 'test'
    const properties = ['createdate', 'firstname', 'lastname']
    const limit = 100
    const after = 0

    const contacts = [];

    const publicObjectSearchRequest = {
        filterGroups: [filterGroup],
        sorts: [sort],
        query,
        properties,
        limit,
        after,
    }

    let result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest);

    if(result.results){
        result.results.forEach((publicObject) => {
            contacts.push(publicObject.properties);            
        })

        while(result.paging){
            publicObjectSearchRequest.after = result.paging.next.after;

            await setAsyncTimeout(async() => {
                result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest);
                if(result.results){
                    result.results.forEach((publicObject) => {
                        contacts.push(publicObject.properties);                
                    })
                }
            }, 1000);
        }
    }    

    console.log('count', contacts.length);
    
    return contacts;
    
}
Brian Rice
  • 11
  • 3
  • If I don't add the async part to the hubspot.js file, I get the error " await is only valid in async functions and the top level bodies of modules". However, adding the async in my hubspot.js creates a promise that does not get resolved in PowerShell. – Brian Rice Jun 09 '23 at 18:55
  • I see. Is `getContacts()` itself asynchronous, i.e. do you need `await` at all? PowerShell definitely can _not_ resolve Node.js promises for you. – mklement0 Jun 09 '23 at 19:00
  • 1
    Yes, unfortunately, I am calling a third party method from getContacts that requires the async calls. I have provided additional code from hubspot.js if it helps. – Brian Rice Jun 09 '23 at 19:02
  • 1
    [In this answer](https://stackoverflow.com/a/46515787/2412846) you find options for making the call to getContacts() synchronous. The third option seems to be the one from the answer of @mklement0 – davidhigh Jun 11 '23 at 06:34

1 Answers1

0

Since you seemingly cannot use await in the top-level scope of a .js file, you can use the Thenable interface that an async function implements: It provides a .then() method with callbacks, whose completion a Node.js CLI call waits for:

getContacts().then(
  result => { // success: output to stdout
    console.log(result)
  },
  err => { // failure: output to stderr
    console.error(err.toString())
  }
)

This answer provides a comprehensive discussion of solution options.


As an aside: you can simplify your node call from PowerShell as follows:

$result = node hubspot.js $hubspot_api_key ci
mklement0
  • 382,024
  • 64
  • 607
  • 775