[{"data":1,"prerenderedAt":1738},["ShallowReactive",2],{"post:\u002F2018\u002F12\u002F27\u002Fpowershell-connectwise-rest-api-query-contacts-by-email-address\u002F":3},{"post":4,"newer":1699,"older":1708,"related":1716,"series":1736},{"id":5,"title":6,"body":7,"canonical":1678,"categories":1679,"date":1682,"description":1683,"extension":1684,"featured":1685,"hero":1686,"image":76,"meta":1687,"navigation":395,"path":1688,"readingTime":252,"seo":1689,"series":1686,"seriesOrder":1686,"sites":1690,"source":1692,"stem":1693,"tags":1694,"updated":1696,"url":1697,"__hash__":1698},"blog\u002Fblog\u002F2018\u002F12\u002F27\u002Fpowershell-connectwise-rest-api-query-contacts-by-email-address.md","PowerShell: ConnectWise REST API Query Contacts by Email Address",{"type":8,"value":9,"toc":1666},"minimark",[10,26,29,34,70,81,85,200,204,207,212,215,218,295,298,464,468,471,474,503,519,592,596,599,636,640,643,651,654,675,682,688,697,701,704,1641,1645,1662],[11,12,13,14,20,21,25],"p",{},"I’ve found myself at a new job, recreating many of the processes that I spent the last few years putting together, tweaking, modifying, building a new managed services provider with an exciting new company. One of those challenges lead me to Email parsing and ConnectWise (CW). Previously I had the opportunity to use Autotask and email2ticket, however with the modifications to the API that CW did a few years ago, email2ticket is no longer supported for CW. With my found love of Azure Functions and looking at existing mail based parsing tools (",[15,16,17],"a",{"href":17,"rel":18},"https:\u002F\u002Fmailparser.io\u002F",[19],"nofollow",", ",[15,22,23],{"href":23,"rel":24},"https:\u002F\u002Fwww.thinkautomation.com\u002F",[19],") which have amazing feature sets, they didn’t do quite what I was looking for and to replace the functionality that I once had with email2ticket.",[11,27,28],{},"That is leading me to this PowerShell series for how to utilize the CW REST API and the things that took some understanding and digging in a little to determine how to do simple queries. The CW developer portal has some great resources, and I stumbled upon the forums that ultimately made it possible to finally build a wildcard query via PowerShell to identify whether a contact exists in CW.",[30,31,33],"h2",{"id":32},"requirements","Requirements",[35,36,37,46,49,63],"ul",{},[38,39,40,41,45],"li",{},"PowerShell 5.1 or later, with ",[42,43,44],"code",{},"Invoke-RestMethod",".",[38,47,48],{},"A CW API Access Account (an API member on the Members tab) with its public key, private key and your company identifier. First things first, you have to authenticate to the CW REST API, and you need access to the Admin Setup tables to create the account. The member's security role must be able to read contacts.",[38,50,51,52,55,56,59,60,45],{},"An Azure Functions PowerShell function with an HTTP trigger binding. The script reads the ",[42,53,54],{},"email"," query string parameter from ",[42,57,58],{},"$req_query_email"," and writes its JSON response to the output binding file path in ",[42,61,62],{},"$res",[38,64,65,66,69],{},"Outbound HTTPS from the function to your CW API host (",[42,67,68],{},"api-na.myconnectwise.net"," for the North America cloud).",[11,71,72,77],{},[73,74],"img",{"alt":75,"src":76},"ConnectWise Manage Members screen with the API Members tab highlighted by a red arrow","\u002Fuploads\u002F2018\u002F12\u002Fimage.png",[78,79,80],"em",{},"CW Members Tab – API Members",[30,82,84],{"id":83},"parameters","Parameters",[86,87,88,107],"table",{},[89,90,91],"thead",{},[92,93,94,98,101,104],"tr",{},[95,96,97],"th",{},"Name",[95,99,100],{},"Type",[95,102,103],{},"Required",[95,105,106],{},"Description",[108,109,110,132,149,166,183],"tbody",{},[92,111,112,117,120,123],{},[113,114,115],"td",{},[42,116,54],{},[113,118,119],{},"string",[113,121,122],{},"Yes",[113,124,125,126,129,130,45],{},"Full or partial email address to search for, for example ",[42,127,128],{},"@xyz.corp"," for every contact in a domain. Passed in the query string and read from ",[42,131,58],{},[92,133,134,139,141,143],{},[113,135,136],{},[42,137,138],{},"$global:CWcompany",[113,140,119],{},[113,142,122],{},[113,144,145,146,45],{},"Value to edit: your CW company identifier, ",[42,147,148],{},"\u003Ccompany-id>",[92,150,151,156,158,160],{},[113,152,153],{},[42,154,155],{},"$global:CWprivate",[113,157,119],{},[113,159,122],{},[113,161,162,163,45],{},"Value to edit: the API member's private key, ",[42,164,165],{},"\u003Cprivate-key>",[92,167,168,173,175,177],{},[113,169,170],{},[42,171,172],{},"$global:CWpublic",[113,174,119],{},[113,176,122],{},[113,178,179,180,45],{},"Value to edit: the API member's public key, ",[42,181,182],{},"\u003Cpublic-key>",[92,184,185,190,192,194],{},[113,186,187],{},[42,188,189],{},"$global:CWserver",[113,191,119],{},[113,193,122],{},[113,195,196,197,45],{},"Value to edit: the base URL of your CW API host, for example ",[42,198,199],{},"https:\u002F\u002Fapi-na.myconnectwise.net",[30,201,203],{"id":202},"walkthrough","Walkthrough",[11,205,206],{},"Once you have an integration setup you can proceed with creating a PowerShell script to handle the automation. I build in Azure Functions mostly, so there will be some pieces in here that relate to that, I’ll breakdown each section (and eventually move some of these pieces to linked articles).",[208,209,211],"h3",{"id":210},"authentication","Authentication",[11,213,214],{},"Authentication to the CW rest API is fairly simple. It requires your public and private keys and your company identifier.",[11,216,217],{},"First set your variables for your credentials.",[219,220,225],"pre",{"className":221,"code":222,"language":223,"meta":224,"style":224},"language-powershell shiki shiki-themes github-light","$global:CWcompany    = \"\u003Ccompany-id>\"\n$global:CWprivate    = \"\u003Cprivate-key>\"\n$global:CWpublic     = \"\u003Cpublic-key>\"\n$global:CWserver     = \"https:\u002F\u002Fapi-na.myconnectwise.net\"\n","powershell","",[42,226,227,250,265,280],{"__ignoreMap":224},[228,229,232,236,240,243,246],"span",{"class":230,"line":231},"line",1,[228,233,235],{"class":234},"sgsFI","$",[228,237,239],{"class":238},"sD7c4","global",[228,241,242],{"class":234},":CWcompany    ",[228,244,245],{"class":238},"=",[228,247,249],{"class":248},"sYBdl"," \"\u003Ccompany-id>\"\n",[228,251,253,255,257,260,262],{"class":230,"line":252},2,[228,254,235],{"class":234},[228,256,239],{"class":238},[228,258,259],{"class":234},":CWprivate    ",[228,261,245],{"class":238},[228,263,264],{"class":248}," \"\u003Cprivate-key>\"\n",[228,266,268,270,272,275,277],{"class":230,"line":267},3,[228,269,235],{"class":234},[228,271,239],{"class":238},[228,273,274],{"class":234},":CWpublic     ",[228,276,245],{"class":238},[228,278,279],{"class":248}," \"\u003Cpublic-key>\"\n",[228,281,283,285,287,290,292],{"class":230,"line":282},4,[228,284,235],{"class":234},[228,286,239],{"class":238},[228,288,289],{"class":234},":CWserver     ",[228,291,245],{"class":238},[228,293,294],{"class":248}," \"https:\u002F\u002Fapi-na.myconnectwise.net\"\n",[11,296,297],{},"Second configure the authentication string and setup the standard headers for your GET request.",[219,299,301],{"className":221,"code":300,"language":223,"meta":224,"style":224},"[string]$Accept      = \"application\u002Fvnd.connectwise.com+json; version=3.0\"\n[string]$ContentType = 'application\u002Fjson'\n[string]$Authstring  = $CWcompany + '+' + $CWpublic + ':' + $CWprivate\n$encodedAuth         = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(($Authstring)))\n\n$headers = New-Object \"System.Collections.Generic.Dictionary[[String],[String]]\"\n$headers.Add(\"Authorization\", \"Basic $encodedAuth\")\n$headers.Add(\"Content-Type\", 'application\u002Fjson')\n$headers.Add(\"Accept\", $Accept)\n",[42,302,303,318,332,368,390,397,412,436,451],{"__ignoreMap":224},[228,304,305,308,310,313,315],{"class":230,"line":231},[228,306,307],{"class":234},"[",[228,309,119],{"class":238},[228,311,312],{"class":234},"]$Accept      ",[228,314,245],{"class":238},[228,316,317],{"class":248}," \"application\u002Fvnd.connectwise.com+json; version=3.0\"\n",[228,319,320,322,324,327,329],{"class":230,"line":252},[228,321,307],{"class":234},[228,323,119],{"class":238},[228,325,326],{"class":234},"]$ContentType ",[228,328,245],{"class":238},[228,330,331],{"class":248}," 'application\u002Fjson'\n",[228,333,334,336,338,341,343,346,349,352,355,358,360,363,365],{"class":230,"line":267},[228,335,307],{"class":234},[228,337,119],{"class":238},[228,339,340],{"class":234},"]$Authstring  ",[228,342,245],{"class":238},[228,344,345],{"class":234}," $CWcompany ",[228,347,348],{"class":238},"+",[228,350,351],{"class":248}," '+'",[228,353,354],{"class":238}," +",[228,356,357],{"class":234}," $CWpublic ",[228,359,348],{"class":238},[228,361,362],{"class":248}," ':'",[228,364,354],{"class":238},[228,366,367],{"class":234}," $CWprivate\n",[228,369,370,373,375,378,381,384,387],{"class":230,"line":282},[228,371,372],{"class":234},"$encodedAuth         ",[228,374,245],{"class":238},[228,376,377],{"class":234}," [",[228,379,380],{"class":238},"Convert",[228,382,383],{"class":234},"]::ToBase64String([",[228,385,386],{"class":238},"Text.Encoding",[228,388,389],{"class":234},"]::ASCII.GetBytes(($Authstring)))\n",[228,391,393],{"class":230,"line":392},5,[228,394,396],{"emptyLinePlaceholder":395},true,"\n",[228,398,400,403,405,409],{"class":230,"line":399},6,[228,401,402],{"class":234},"$headers ",[228,404,245],{"class":238},[228,406,408],{"class":407},"sYu0t"," New-Object",[228,410,411],{"class":248}," \"System.Collections.Generic.Dictionary[[String],[String]]\"\n",[228,413,415,418,421,424,427,430,433],{"class":230,"line":414},7,[228,416,417],{"class":234},"$headers.Add(",[228,419,420],{"class":248},"\"Authorization\"",[228,422,423],{"class":238},",",[228,425,426],{"class":248}," \"Basic ",[228,428,429],{"class":234},"$encodedAuth",[228,431,432],{"class":248},"\"",[228,434,435],{"class":234},")\n",[228,437,439,441,444,446,449],{"class":230,"line":438},8,[228,440,417],{"class":234},[228,442,443],{"class":248},"\"Content-Type\"",[228,445,423],{"class":238},[228,447,448],{"class":248}," 'application\u002Fjson'",[228,450,435],{"class":234},[228,452,454,456,459,461],{"class":230,"line":453},9,[228,455,417],{"class":234},[228,457,458],{"class":248},"\"Accept\"",[228,460,423],{"class":238},[228,462,463],{"class":234}," $Accept)\n",[208,465,467],{"id":466},"request-uri","Request URI",[11,469,470],{},"Then for the URI, this consists of a few parts, your base URL, your query parameters, and your target for your request.",[11,472,473],{},"Query String – this is the conditions you’re going to pass to do the lookup. In this case I’m looking for the email address of a contact. This requires the use of CW’s childconditions parameters. Initially the communicationItems is used to determine the value of the email address, then forcing it to only look for the type of email address to speed the query result. The “%” is used as the wildcard for the “like” operator. I spent some time trying to determine what would work best, contains and in both resulted in invalid syntax so using the like operator was the eventual conclusion.",[219,475,477],{"className":221,"code":476,"language":223,"meta":224,"style":224},"[string]$query       = '?childconditions=communicationItems\u002Fvalue like \"%' + $email + '%\" AND communicationItems\u002FcommunicationType=\"Email\"'\n",[42,478,479],{"__ignoreMap":224},[228,480,481,483,485,488,490,493,495,498,500],{"class":230,"line":231},[228,482,307],{"class":234},[228,484,119],{"class":238},[228,486,487],{"class":234},"]$query       ",[228,489,245],{"class":238},[228,491,492],{"class":248}," '?childconditions=communicationItems\u002Fvalue like \"%'",[228,494,354],{"class":238},[228,496,497],{"class":234}," $email ",[228,499,348],{"class":238},[228,501,502],{"class":248}," '%\" AND communicationItems\u002FcommunicationType=\"Email\"'\n",[11,504,505,506,511,512,515,516,518],{},"Putting it all together, you have a target of ",[15,507,510],{"href":508,"rel":509},"https:\u002F\u002Fdeveloper.connectwise.com\u002Fproducts\u002Fmanage\u002Frest?a=Company&e=Contacts&o=GET",[19],"\u002Fcompany\u002Fcontacts"," and use the query string. ",[42,513,514],{},"$email"," is the full or partial email address you’re searching for. Benefits of using a partial, such as ",[42,517,128],{},", would yield all contacts for that domain and you can use some logic there to determine what company they belong to (more to come on that subject).",[219,520,522],{"className":221,"code":521,"language":223,"meta":224,"style":224},"[string]$TargetUri   = '\u002Fcompany\u002Fcontacts'\n[string]$query       = '?childconditions=communicationItems\u002Fvalue like \"%' + $email + '%\" AND communicationItems\u002FcommunicationType=\"Email\"'\n[string]$BaseUri     = \"$CWserver\" + \"\u002Fv4_6_release\u002Fapis\u002F3.0\" + $TargetUri + $query\n",[42,523,524,538,558],{"__ignoreMap":224},[228,525,526,528,530,533,535],{"class":230,"line":231},[228,527,307],{"class":234},[228,529,119],{"class":238},[228,531,532],{"class":234},"]$TargetUri   ",[228,534,245],{"class":238},[228,536,537],{"class":248}," '\u002Fcompany\u002Fcontacts'\n",[228,539,540,542,544,546,548,550,552,554,556],{"class":230,"line":252},[228,541,307],{"class":234},[228,543,119],{"class":238},[228,545,487],{"class":234},[228,547,245],{"class":238},[228,549,492],{"class":248},[228,551,354],{"class":238},[228,553,497],{"class":234},[228,555,348],{"class":238},[228,557,502],{"class":248},[228,559,560,562,564,567,569,572,575,577,579,582,584,587,589],{"class":230,"line":267},[228,561,307],{"class":234},[228,563,119],{"class":238},[228,565,566],{"class":234},"]$BaseUri     ",[228,568,245],{"class":238},[228,570,571],{"class":248}," \"",[228,573,574],{"class":234},"$CWserver",[228,576,432],{"class":248},[228,578,354],{"class":238},[228,580,581],{"class":248}," \"\u002Fv4_6_release\u002Fapis\u002F3.0\"",[228,583,354],{"class":238},[228,585,586],{"class":234}," $TargetUri ",[228,588,348],{"class":238},[228,590,591],{"class":234}," $query\n",[208,593,595],{"id":594},"sending-the-request","Sending the request",[11,597,598],{},"Finally, send the Invoke-RestMethod command to get the results. This returns a JSON table that Invoke-RestMethod converts to a PS Object.",[219,600,602],{"className":221,"code":601,"language":223,"meta":224,"style":224},"$JSONResponse = Invoke-RestMethod -Uri $BaseUri -Headers $headers -ContentType $ContentType -Method Get\n",[42,603,604],{"__ignoreMap":224},[228,605,606,609,611,614,617,620,623,626,628,631,633],{"class":230,"line":231},[228,607,608],{"class":234},"$JSONResponse ",[228,610,245],{"class":238},[228,612,613],{"class":407}," Invoke-RestMethod",[228,615,616],{"class":238}," -",[228,618,619],{"class":234},"Uri $BaseUri ",[228,621,622],{"class":238},"-",[228,624,625],{"class":234},"Headers $headers ",[228,627,622],{"class":238},[228,629,630],{"class":234},"ContentType $ContentType ",[228,632,622],{"class":238},[228,634,635],{"class":234},"Method Get\n",[30,637,639],{"id":638},"usage","Usage",[11,641,642],{},"Once the function is deployed, request it with the full or partial email address in the query string.",[219,644,649],{"className":645,"code":647,"language":648,"meta":224},[646],"language-text","https:\u002F\u002F\u003Cfunction-app>.azurewebsites.net\u002Fapi\u002F\u003Cfunction-name>?email=\u003Cemail>\n","text",[42,650,647],{"__ignoreMap":224},[11,652,653],{},"The same call from PowerShell:",[219,655,657],{"className":221,"code":656,"language":223,"meta":224,"style":224},"Invoke-RestMethod -Uri \"https:\u002F\u002F\u003Cfunction-app>.azurewebsites.net\u002Fapi\u002F\u003Cfunction-name>?email=\u003Cemail>\" -Method Get\n",[42,658,659],{"__ignoreMap":224},[228,660,661,663,665,668,671,673],{"class":230,"line":231},[228,662,44],{"class":407},[228,664,616],{"class":238},[228,666,667],{"class":234},"Uri ",[228,669,670],{"class":248},"\"https:\u002F\u002F\u003Cfunction-app>.azurewebsites.net\u002Fapi\u002F\u003Cfunction-name>?email=\u003Cemail>\"",[228,672,616],{"class":238},[228,674,635],{"class":234},[11,676,677,678,681],{},"If the function's authorization level is not anonymous, add ",[42,679,680],{},"&code=\u003Cfunction-key>"," to the URL. A matching contact comes back in this shape:",[219,683,686],{"className":684,"code":685,"language":648,"meta":224},[646],"{\n    \"id\":  1234,\n    \"firstName\":  \"\u003Cfirst-name>\",\n    \"lastName\":  \"\u003Clast-name>\",\n    \"emails\":  \"\u003Cemail>;\",\n    \"company\":  \"\u003Ccompany-name>\",\n    \"companyid\":  56,\n    \"companyidentifier\":  \"\u003Ccompany-identifier>\"\n}\n",[42,687,685],{"__ignoreMap":224},[11,689,690,691,694,695,45],{},"If nothing matches, the script returns ",[42,692,693],{},"$false"," and writes nothing to ",[42,696,62],{},[30,698,700],{"id":699},"script","Script",[11,702,703],{},"Here’s the full code that I’m using to query for a specific contact’s email address.",[219,705,707],{"className":221,"code":706,"language":223,"meta":224,"style":224},"\u003C#\n.SYNOPSIS\n    Queries ConnectWise for contacts by full or partial email address.\n.DESCRIPTION\n    Runs as an Azure Functions PowerShell HTTP trigger. Reads the email address from the\n    query string ($req_query_email), authenticates to the ConnectWise REST API with an API\n    member's keys, searches \u002Fcompany\u002Fcontacts with a wildcard \"like\" condition on the\n    contact's email communication items, and writes the matching contacts (id, name,\n    emails and company details) as JSON to the output binding file path in $res.\n.PARAMETER email\n    Full or partial email address to search for. Passed in the query string and read from $req_query_email.\n.EXAMPLE\n    Invoke-RestMethod -Uri \"https:\u002F\u002F\u003Cfunction-app>.azurewebsites.net\u002Fapi\u002F\u003Cfunction-name>?email=\u003Cemail>\" -Method Get\n.NOTES\n    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n    Version : 1.1 (2026-09-20)\n    History : 1.0 2018-12-27 Initial version.\n              1.1 2026-09-20 The Accept header value no longer includes an \"Accept: \" prefix.\n    Requires: PowerShell 5.1 or later; Azure Functions HTTP trigger ($req_query_email, $res); ConnectWise API member\n.LINK\n    https:\u002F\u002Fdeveloper.connectwise.com\u002Fproducts\u002Fmanage\u002Frest?a=Company&e=Contacts&o=GET\n#>\n\n# GET method: each querystring parameter is its own variable\nif ($req_query_email) {\n    $email = $req_query_email\n}\n\n# Initializations\n$global:CWcompany    = \"\u003Ccompany-id>\"\n$global:CWprivate    = \"\u003Cprivate-key>\"\n$global:CWpublic     = \"\u003Cpublic-key>\"\n$global:CWserver     = \"https:\u002F\u002Fapi-na.myconnectwise.net\"\n\n# CW auth string\n[string]$Accept      = \"application\u002Fvnd.connectwise.com+json; version=3.0\"\n[string]$Authstring  = $CWcompany + '+' + $CWpublic + ':' + $CWprivate\n[string]$ContentType = 'application\u002Fjson'\n$encodedAuth         = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(($Authstring)))\n\n# CW headers\n$headers = New-Object \"System.Collections.Generic.Dictionary[[String],[String]]\"\n$headers.Add(\"Authorization\", \"Basic $encodedAuth\")\n$headers.Add(\"Content-Type\", 'application\u002Fjson')\n$headers.Add(\"Accept\", $Accept)\n\n# CW query\n[string]$TargetUri   = '\u002Fcompany\u002Fcontacts'\n[string]$query       = '?childconditions=communicationItems\u002Fvalue like \"%' + $email + '%\" AND communicationItems\u002FcommunicationType=\"Email\"'\n[string]$BaseUri     = \"$CWserver\" + \"\u002Fv4_6_release\u002Fapis\u002F3.0\" + $TargetUri + $query\n\n# Get response\n$JSONResponse = Invoke-RestMethod -Uri $BaseUri -Headers $headers -ContentType $ContentType -Method Get\n\n# Parse contact info to usable short table\n$contactInfo = @()\nforeach ($contact in $JSONResponse) {\n    $email = $null\n    $emails = $null\n    $obj = New-Object PSObject\n    $obj | Add-Member -MemberType NoteProperty -Name \"id\" -Value $contact.id\n    $obj | Add-Member -MemberType NoteProperty -Name \"firstName\" -Value $contact.firstName\n    $obj | Add-Member -MemberType NoteProperty -Name \"lastName\" -Value $contact.lastName\n    foreach ($commtype in $contact.communicationItems) {\n        $email = $($commtype | Where-Object { $_.communicationType -eq \"Email\" }).value\n        if ($email.length -gt 2) {\n            $emails += $email + \";\"\n        }\n    }\n    $obj | Add-Member -MemberType NoteProperty -Name \"emails\" -Value $emails\n    $obj | Add-Member -MemberType NoteProperty -Name \"company\" -Value $contact.company.name\n    $obj | Add-Member -MemberType NoteProperty -Name \"companyid\" -Value $contact.company.id\n    $obj | Add-Member -MemberType NoteProperty -Name \"companyidentifier\" -Value $contact.company.identifier\n    $contactInfo += $obj\n}\n\nif ($contactInfo) {\n    Out-File -Encoding Ascii -FilePath $res -InputObject $($contactInfo | ConvertTo-Json)\n} else {\n    return $false\n}\n",[42,708,709,715,722,727,734,739,744,749,754,759,770,776,784,790,798,804,810,816,822,828,836,842,848,853,859,868,879,885,890,896,909,922,935,948,953,959,972,1001,1014,1031,1036,1042,1053,1070,1083,1094,1099,1105,1118,1139,1168,1173,1179,1204,1209,1215,1229,1244,1254,1264,1277,1306,1331,1356,1370,1407,1425,1441,1447,1453,1478,1503,1528,1553,1564,1569,1574,1582,1615,1627,1636],{"__ignoreMap":224},[228,710,711],{"class":230,"line":231},[228,712,714],{"class":713},"sAwPA","\u003C#\n",[228,716,717,719],{"class":230,"line":252},[228,718,45],{"class":407},[228,720,721],{"class":238},"SYNOPSIS\n",[228,723,724],{"class":230,"line":267},[228,725,726],{"class":713},"    Queries ConnectWise for contacts by full or partial email address.\n",[228,728,729,731],{"class":230,"line":282},[228,730,45],{"class":407},[228,732,733],{"class":238},"DESCRIPTION\n",[228,735,736],{"class":230,"line":392},[228,737,738],{"class":713},"    Runs as an Azure Functions PowerShell HTTP trigger. Reads the email address from the\n",[228,740,741],{"class":230,"line":399},[228,742,743],{"class":713},"    query string ($req_query_email), authenticates to the ConnectWise REST API with an API\n",[228,745,746],{"class":230,"line":414},[228,747,748],{"class":713},"    member's keys, searches \u002Fcompany\u002Fcontacts with a wildcard \"like\" condition on the\n",[228,750,751],{"class":230,"line":438},[228,752,753],{"class":713},"    contact's email communication items, and writes the matching contacts (id, name,\n",[228,755,756],{"class":230,"line":453},[228,757,758],{"class":713},"    emails and company details) as JSON to the output binding file path in $res.\n",[228,760,762,764,767],{"class":230,"line":761},10,[228,763,45],{"class":407},[228,765,766],{"class":238},"PARAMETER",[228,768,769],{"class":238}," email\n",[228,771,773],{"class":230,"line":772},11,[228,774,775],{"class":713},"    Full or partial email address to search for. Passed in the query string and read from $req_query_email.\n",[228,777,779,781],{"class":230,"line":778},12,[228,780,45],{"class":407},[228,782,783],{"class":238},"EXAMPLE\n",[228,785,787],{"class":230,"line":786},13,[228,788,789],{"class":713},"    Invoke-RestMethod -Uri \"https:\u002F\u002F\u003Cfunction-app>.azurewebsites.net\u002Fapi\u002F\u003Cfunction-name>?email=\u003Cemail>\" -Method Get\n",[228,791,793,795],{"class":230,"line":792},14,[228,794,45],{"class":407},[228,796,797],{"class":238},"NOTES\n",[228,799,801],{"class":230,"line":800},15,[228,802,803],{"class":713},"    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n",[228,805,807],{"class":230,"line":806},16,[228,808,809],{"class":713},"    Version : 1.1 (2026-09-20)\n",[228,811,813],{"class":230,"line":812},17,[228,814,815],{"class":713},"    History : 1.0 2018-12-27 Initial version.\n",[228,817,819],{"class":230,"line":818},18,[228,820,821],{"class":713},"              1.1 2026-09-20 The Accept header value no longer includes an \"Accept: \" prefix.\n",[228,823,825],{"class":230,"line":824},19,[228,826,827],{"class":713},"    Requires: PowerShell 5.1 or later; Azure Functions HTTP trigger ($req_query_email, $res); ConnectWise API member\n",[228,829,831,833],{"class":230,"line":830},20,[228,832,45],{"class":407},[228,834,835],{"class":238},"LINK\n",[228,837,839],{"class":230,"line":838},21,[228,840,841],{"class":713},"    https:\u002F\u002Fdeveloper.connectwise.com\u002Fproducts\u002Fmanage\u002Frest?a=Company&e=Contacts&o=GET\n",[228,843,845],{"class":230,"line":844},22,[228,846,847],{"class":713},"#>\n",[228,849,851],{"class":230,"line":850},23,[228,852,396],{"emptyLinePlaceholder":395},[228,854,856],{"class":230,"line":855},24,[228,857,858],{"class":713},"# GET method: each querystring parameter is its own variable\n",[228,860,862,865],{"class":230,"line":861},25,[228,863,864],{"class":238},"if",[228,866,867],{"class":234}," ($req_query_email) {\n",[228,869,871,874,876],{"class":230,"line":870},26,[228,872,873],{"class":234},"    $email ",[228,875,245],{"class":238},[228,877,878],{"class":234}," $req_query_email\n",[228,880,882],{"class":230,"line":881},27,[228,883,884],{"class":234},"}\n",[228,886,888],{"class":230,"line":887},28,[228,889,396],{"emptyLinePlaceholder":395},[228,891,893],{"class":230,"line":892},29,[228,894,895],{"class":713},"# Initializations\n",[228,897,899,901,903,905,907],{"class":230,"line":898},30,[228,900,235],{"class":234},[228,902,239],{"class":238},[228,904,242],{"class":234},[228,906,245],{"class":238},[228,908,249],{"class":248},[228,910,912,914,916,918,920],{"class":230,"line":911},31,[228,913,235],{"class":234},[228,915,239],{"class":238},[228,917,259],{"class":234},[228,919,245],{"class":238},[228,921,264],{"class":248},[228,923,925,927,929,931,933],{"class":230,"line":924},32,[228,926,235],{"class":234},[228,928,239],{"class":238},[228,930,274],{"class":234},[228,932,245],{"class":238},[228,934,279],{"class":248},[228,936,938,940,942,944,946],{"class":230,"line":937},33,[228,939,235],{"class":234},[228,941,239],{"class":238},[228,943,289],{"class":234},[228,945,245],{"class":238},[228,947,294],{"class":248},[228,949,951],{"class":230,"line":950},34,[228,952,396],{"emptyLinePlaceholder":395},[228,954,956],{"class":230,"line":955},35,[228,957,958],{"class":713},"# CW auth string\n",[228,960,962,964,966,968,970],{"class":230,"line":961},36,[228,963,307],{"class":234},[228,965,119],{"class":238},[228,967,312],{"class":234},[228,969,245],{"class":238},[228,971,317],{"class":248},[228,973,975,977,979,981,983,985,987,989,991,993,995,997,999],{"class":230,"line":974},37,[228,976,307],{"class":234},[228,978,119],{"class":238},[228,980,340],{"class":234},[228,982,245],{"class":238},[228,984,345],{"class":234},[228,986,348],{"class":238},[228,988,351],{"class":248},[228,990,354],{"class":238},[228,992,357],{"class":234},[228,994,348],{"class":238},[228,996,362],{"class":248},[228,998,354],{"class":238},[228,1000,367],{"class":234},[228,1002,1004,1006,1008,1010,1012],{"class":230,"line":1003},38,[228,1005,307],{"class":234},[228,1007,119],{"class":238},[228,1009,326],{"class":234},[228,1011,245],{"class":238},[228,1013,331],{"class":248},[228,1015,1017,1019,1021,1023,1025,1027,1029],{"class":230,"line":1016},39,[228,1018,372],{"class":234},[228,1020,245],{"class":238},[228,1022,377],{"class":234},[228,1024,380],{"class":238},[228,1026,383],{"class":234},[228,1028,386],{"class":238},[228,1030,389],{"class":234},[228,1032,1034],{"class":230,"line":1033},40,[228,1035,396],{"emptyLinePlaceholder":395},[228,1037,1039],{"class":230,"line":1038},41,[228,1040,1041],{"class":713},"# CW headers\n",[228,1043,1045,1047,1049,1051],{"class":230,"line":1044},42,[228,1046,402],{"class":234},[228,1048,245],{"class":238},[228,1050,408],{"class":407},[228,1052,411],{"class":248},[228,1054,1056,1058,1060,1062,1064,1066,1068],{"class":230,"line":1055},43,[228,1057,417],{"class":234},[228,1059,420],{"class":248},[228,1061,423],{"class":238},[228,1063,426],{"class":248},[228,1065,429],{"class":234},[228,1067,432],{"class":248},[228,1069,435],{"class":234},[228,1071,1073,1075,1077,1079,1081],{"class":230,"line":1072},44,[228,1074,417],{"class":234},[228,1076,443],{"class":248},[228,1078,423],{"class":238},[228,1080,448],{"class":248},[228,1082,435],{"class":234},[228,1084,1086,1088,1090,1092],{"class":230,"line":1085},45,[228,1087,417],{"class":234},[228,1089,458],{"class":248},[228,1091,423],{"class":238},[228,1093,463],{"class":234},[228,1095,1097],{"class":230,"line":1096},46,[228,1098,396],{"emptyLinePlaceholder":395},[228,1100,1102],{"class":230,"line":1101},47,[228,1103,1104],{"class":713},"# CW query\n",[228,1106,1108,1110,1112,1114,1116],{"class":230,"line":1107},48,[228,1109,307],{"class":234},[228,1111,119],{"class":238},[228,1113,532],{"class":234},[228,1115,245],{"class":238},[228,1117,537],{"class":248},[228,1119,1121,1123,1125,1127,1129,1131,1133,1135,1137],{"class":230,"line":1120},49,[228,1122,307],{"class":234},[228,1124,119],{"class":238},[228,1126,487],{"class":234},[228,1128,245],{"class":238},[228,1130,492],{"class":248},[228,1132,354],{"class":238},[228,1134,497],{"class":234},[228,1136,348],{"class":238},[228,1138,502],{"class":248},[228,1140,1142,1144,1146,1148,1150,1152,1154,1156,1158,1160,1162,1164,1166],{"class":230,"line":1141},50,[228,1143,307],{"class":234},[228,1145,119],{"class":238},[228,1147,566],{"class":234},[228,1149,245],{"class":238},[228,1151,571],{"class":248},[228,1153,574],{"class":234},[228,1155,432],{"class":248},[228,1157,354],{"class":238},[228,1159,581],{"class":248},[228,1161,354],{"class":238},[228,1163,586],{"class":234},[228,1165,348],{"class":238},[228,1167,591],{"class":234},[228,1169,1171],{"class":230,"line":1170},51,[228,1172,396],{"emptyLinePlaceholder":395},[228,1174,1176],{"class":230,"line":1175},52,[228,1177,1178],{"class":713},"# Get response\n",[228,1180,1182,1184,1186,1188,1190,1192,1194,1196,1198,1200,1202],{"class":230,"line":1181},53,[228,1183,608],{"class":234},[228,1185,245],{"class":238},[228,1187,613],{"class":407},[228,1189,616],{"class":238},[228,1191,619],{"class":234},[228,1193,622],{"class":238},[228,1195,625],{"class":234},[228,1197,622],{"class":238},[228,1199,630],{"class":234},[228,1201,622],{"class":238},[228,1203,635],{"class":234},[228,1205,1207],{"class":230,"line":1206},54,[228,1208,396],{"emptyLinePlaceholder":395},[228,1210,1212],{"class":230,"line":1211},55,[228,1213,1214],{"class":713},"# Parse contact info to usable short table\n",[228,1216,1218,1221,1223,1226],{"class":230,"line":1217},56,[228,1219,1220],{"class":234},"$contactInfo ",[228,1222,245],{"class":238},[228,1224,1225],{"class":238}," @",[228,1227,1228],{"class":234},"()\n",[228,1230,1232,1235,1238,1241],{"class":230,"line":1231},57,[228,1233,1234],{"class":238},"foreach",[228,1236,1237],{"class":234}," ($contact ",[228,1239,1240],{"class":238},"in",[228,1242,1243],{"class":234}," $JSONResponse) {\n",[228,1245,1247,1249,1251],{"class":230,"line":1246},58,[228,1248,873],{"class":234},[228,1250,245],{"class":238},[228,1252,1253],{"class":407}," $null\n",[228,1255,1257,1260,1262],{"class":230,"line":1256},59,[228,1258,1259],{"class":234},"    $emails ",[228,1261,245],{"class":238},[228,1263,1253],{"class":407},[228,1265,1267,1270,1272,1274],{"class":230,"line":1266},60,[228,1268,1269],{"class":234},"    $obj ",[228,1271,245],{"class":238},[228,1273,408],{"class":407},[228,1275,1276],{"class":234}," PSObject\n",[228,1278,1280,1282,1285,1288,1290,1293,1295,1298,1301,1303],{"class":230,"line":1279},61,[228,1281,1269],{"class":234},[228,1283,1284],{"class":238},"|",[228,1286,1287],{"class":407}," Add-Member",[228,1289,616],{"class":238},[228,1291,1292],{"class":234},"MemberType NoteProperty ",[228,1294,622],{"class":238},[228,1296,1297],{"class":234},"Name ",[228,1299,1300],{"class":248},"\"id\"",[228,1302,616],{"class":238},[228,1304,1305],{"class":234},"Value $contact.id\n",[228,1307,1309,1311,1313,1315,1317,1319,1321,1323,1326,1328],{"class":230,"line":1308},62,[228,1310,1269],{"class":234},[228,1312,1284],{"class":238},[228,1314,1287],{"class":407},[228,1316,616],{"class":238},[228,1318,1292],{"class":234},[228,1320,622],{"class":238},[228,1322,1297],{"class":234},[228,1324,1325],{"class":248},"\"firstName\"",[228,1327,616],{"class":238},[228,1329,1330],{"class":234},"Value $contact.firstName\n",[228,1332,1334,1336,1338,1340,1342,1344,1346,1348,1351,1353],{"class":230,"line":1333},63,[228,1335,1269],{"class":234},[228,1337,1284],{"class":238},[228,1339,1287],{"class":407},[228,1341,616],{"class":238},[228,1343,1292],{"class":234},[228,1345,622],{"class":238},[228,1347,1297],{"class":234},[228,1349,1350],{"class":248},"\"lastName\"",[228,1352,616],{"class":238},[228,1354,1355],{"class":234},"Value $contact.lastName\n",[228,1357,1359,1362,1365,1367],{"class":230,"line":1358},64,[228,1360,1361],{"class":238},"    foreach",[228,1363,1364],{"class":234}," ($commtype ",[228,1366,1240],{"class":238},[228,1368,1369],{"class":234}," $contact.communicationItems) {\n",[228,1371,1373,1376,1378,1381,1384,1386,1389,1392,1395,1398,1401,1404],{"class":230,"line":1372},65,[228,1374,1375],{"class":234},"        $email ",[228,1377,245],{"class":238},[228,1379,1380],{"class":238}," $",[228,1382,1383],{"class":234},"($commtype ",[228,1385,1284],{"class":238},[228,1387,1388],{"class":407}," Where-Object",[228,1390,1391],{"class":234}," { ",[228,1393,1394],{"class":407},"$_",[228,1396,1397],{"class":234},".communicationType ",[228,1399,1400],{"class":238},"-eq",[228,1402,1403],{"class":248}," \"Email\"",[228,1405,1406],{"class":234}," }).value\n",[228,1408,1410,1413,1416,1419,1422],{"class":230,"line":1409},66,[228,1411,1412],{"class":238},"        if",[228,1414,1415],{"class":234}," ($email.length ",[228,1417,1418],{"class":238},"-gt",[228,1420,1421],{"class":407}," 2",[228,1423,1424],{"class":234},") {\n",[228,1426,1428,1431,1434,1436,1438],{"class":230,"line":1427},67,[228,1429,1430],{"class":234},"            $emails ",[228,1432,1433],{"class":238},"+=",[228,1435,497],{"class":234},[228,1437,348],{"class":238},[228,1439,1440],{"class":248}," \";\"\n",[228,1442,1444],{"class":230,"line":1443},68,[228,1445,1446],{"class":234},"        }\n",[228,1448,1450],{"class":230,"line":1449},69,[228,1451,1452],{"class":234},"    }\n",[228,1454,1456,1458,1460,1462,1464,1466,1468,1470,1473,1475],{"class":230,"line":1455},70,[228,1457,1269],{"class":234},[228,1459,1284],{"class":238},[228,1461,1287],{"class":407},[228,1463,616],{"class":238},[228,1465,1292],{"class":234},[228,1467,622],{"class":238},[228,1469,1297],{"class":234},[228,1471,1472],{"class":248},"\"emails\"",[228,1474,616],{"class":238},[228,1476,1477],{"class":234},"Value $emails\n",[228,1479,1481,1483,1485,1487,1489,1491,1493,1495,1498,1500],{"class":230,"line":1480},71,[228,1482,1269],{"class":234},[228,1484,1284],{"class":238},[228,1486,1287],{"class":407},[228,1488,616],{"class":238},[228,1490,1292],{"class":234},[228,1492,622],{"class":238},[228,1494,1297],{"class":234},[228,1496,1497],{"class":248},"\"company\"",[228,1499,616],{"class":238},[228,1501,1502],{"class":234},"Value $contact.company.name\n",[228,1504,1506,1508,1510,1512,1514,1516,1518,1520,1523,1525],{"class":230,"line":1505},72,[228,1507,1269],{"class":234},[228,1509,1284],{"class":238},[228,1511,1287],{"class":407},[228,1513,616],{"class":238},[228,1515,1292],{"class":234},[228,1517,622],{"class":238},[228,1519,1297],{"class":234},[228,1521,1522],{"class":248},"\"companyid\"",[228,1524,616],{"class":238},[228,1526,1527],{"class":234},"Value $contact.company.id\n",[228,1529,1531,1533,1535,1537,1539,1541,1543,1545,1548,1550],{"class":230,"line":1530},73,[228,1532,1269],{"class":234},[228,1534,1284],{"class":238},[228,1536,1287],{"class":407},[228,1538,616],{"class":238},[228,1540,1292],{"class":234},[228,1542,622],{"class":238},[228,1544,1297],{"class":234},[228,1546,1547],{"class":248},"\"companyidentifier\"",[228,1549,616],{"class":238},[228,1551,1552],{"class":234},"Value $contact.company.identifier\n",[228,1554,1556,1559,1561],{"class":230,"line":1555},74,[228,1557,1558],{"class":234},"    $contactInfo ",[228,1560,1433],{"class":238},[228,1562,1563],{"class":234}," $obj\n",[228,1565,1567],{"class":230,"line":1566},75,[228,1568,884],{"class":234},[228,1570,1572],{"class":230,"line":1571},76,[228,1573,396],{"emptyLinePlaceholder":395},[228,1575,1577,1579],{"class":230,"line":1576},77,[228,1578,864],{"class":238},[228,1580,1581],{"class":234}," ($contactInfo) {\n",[228,1583,1585,1588,1590,1593,1595,1598,1600,1603,1605,1608,1610,1613],{"class":230,"line":1584},78,[228,1586,1587],{"class":407},"    Out-File",[228,1589,616],{"class":238},[228,1591,1592],{"class":234},"Encoding Ascii ",[228,1594,622],{"class":238},[228,1596,1597],{"class":234},"FilePath $res ",[228,1599,622],{"class":238},[228,1601,1602],{"class":234},"InputObject ",[228,1604,235],{"class":238},[228,1606,1607],{"class":234},"($contactInfo ",[228,1609,1284],{"class":238},[228,1611,1612],{"class":407}," ConvertTo-Json",[228,1614,435],{"class":234},[228,1616,1618,1621,1624],{"class":230,"line":1617},79,[228,1619,1620],{"class":234},"} ",[228,1622,1623],{"class":238},"else",[228,1625,1626],{"class":234}," {\n",[228,1628,1630,1633],{"class":230,"line":1629},80,[228,1631,1632],{"class":238},"    return",[228,1634,1635],{"class":407}," $false\n",[228,1637,1639],{"class":230,"line":1638},81,[228,1640,884],{"class":234},[30,1642,1644],{"id":1643},"notes","Notes",[35,1646,1647],{},[38,1648,1649,1650,1653,1654,1657,1658,1661],{},"Update 2026-09-20 (v1.1): ",[42,1651,1652],{},"$Accept"," used to be ",[42,1655,1656],{},"\"Accept: application\u002Fvnd.connectwise.com+json; version=3.0\"",", which put a second ",[42,1659,1660],{},"Accept: "," inside the header value. It is now just the media type.",[1663,1664,1665],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":224,"searchDepth":252,"depth":252,"links":1667},[1668,1669,1670,1675,1676,1677],{"id":32,"depth":252,"text":33},{"id":83,"depth":252,"text":84},{"id":202,"depth":252,"text":203,"children":1671},[1672,1673,1674],{"id":210,"depth":267,"text":211},{"id":466,"depth":267,"text":467},{"id":594,"depth":267,"text":595},{"id":638,"depth":252,"text":639},{"id":699,"depth":252,"text":700},{"id":1643,"depth":252,"text":1644},"techcolumnist",[1680,1681],"ps","scripts","2018-12-27T10:56:24Z","A PowerShell script that queries ConnectWise contacts by email address through the REST API.","md",false,null,{},"\u002Fblog\u002F2018\u002F12\u002F27\u002Fpowershell-connectwise-rest-api-query-contacts-by-email-address",{"title":6,"description":1683},[1691,1678],"lasswell","both","blog\u002F2018\u002F12\u002F27\u002Fpowershell-connectwise-rest-api-query-contacts-by-email-address",[1695,223],"connectwise","2026-09-20T00:00:00Z","\u002F2018\u002F12\u002F27\u002Fpowershell-connectwise-rest-api-query-contacts-by-email-address\u002F","nObh8yVZ0oVJIWCH9f3ftgdPynkVIRW1mOhIZNHuJR0",{"title":1700,"description":1701,"date":1702,"url":1703,"categories":1704,"tags":1705,"image":1706,"readingTime":252,"canonical":1678,"sites":1707,"series":1686,"seriesOrder":1686},"PowerShell: ConnectWise Documents API, Uploading a Document or Attachment to a Ticket","PowerShell: upload a document or attachment to a ConnectWise ticket through the form-based Documents API.","2019-01-09T09:46:57Z","\u002F2019\u002F01\u002F09\u002Fpowershell-connectwise-documents-api-uploading-a-document-or-attachment-to-a-ticket\u002F",[1680,1681],[1695,223],"\u002Fuploads\u002F2019\u002F01\u002Fimage.png",[1691,1678],{"title":1709,"description":1710,"date":1711,"url":1712,"categories":1713,"tags":1714,"image":1686,"readingTime":231,"canonical":1678,"sites":1715,"series":1686,"seriesOrder":1686},"First post in a long time — changing hosting providers","Wow, it’s been a while since I’ve done a real post on this site. I’ve got many interesting things to discuss, but it has been a great last few years.","2018-03-28T22:59:53Z","\u002F2018\u002F03\u002F28\u002Ffirst-post-in-a-long-time-changing-hosting-providers\u002F",[],[],[1691,1678],[1699,1717,1726],{"title":1718,"description":1719,"date":1720,"url":1721,"categories":1722,"tags":1723,"image":1686,"readingTime":231,"canonical":1678,"sites":1725,"series":1686,"seriesOrder":1686},"PowerShell: Autotask – Enable Client Portal for All Users","This is a quick one, it’s been forever since I’ve posted here. After moving back to Autotask, there’s still a ton of things to automate.","2022-10-12T14:13:37Z","\u002F2022\u002F10\u002F12\u002Fautotask-powershell-enable-client-portal-for-all-users\u002F",[1680,1681],[1724,223],"autotask",[1691,1678],{"title":1727,"description":1728,"date":1729,"url":1730,"categories":1731,"tags":1732,"image":1686,"readingTime":231,"canonical":1678,"sites":1735,"series":1686,"seriesOrder":1686},"PowerShell: Get Exchange Mailboxes Over XXGB","Simple command turned crazy. I ended up coming up with this due to the fact we have duplicate display names and needed to update for Exchange Online to get mailbox sizes.","2021-02-18T14:46:29Z","\u002F2021\u002F02\u002F18\u002Fpowershell-get-exchange-mailboxes-over-xxgb\u002F",[1680,1681],[223,1733,1734],"exchange","exchange-online",[1691,1678],{"doc":1686,"posts":1737},[],1790949961520]