sgtoj / psconnectwise Goto Github PK
View Code? Open in Web Editor NEWPowerShell Module that provide several CmdLets to interact with ConnectWise REST API service.
License: MIT License
PowerShell Module that provide several CmdLets to interact with ConnectWise REST API service.
License: MIT License
Add -Name
w/ the ability to use wildcards and -Descending
parameters to each of the functions. These were partially implemented with Get-CWServiceBoard
and Get-CWServiceTicket
. Now going to implement to all functions and make it consistent.
Primary Issues
$null
should be on the left-side of a operand and condition check.ShouldProcess
(e.g. -WhatIf
, etc.) for the Remove functions.Linter/Analyzer: https://github.com/PowerShell/PSScriptAnalyzer
Create function to add expense entries.
Create Add-CWExpenseEntry Advanced Function
Create Get-CWExpenseEntry Advanced Function
Create Remove-CWExpenseEntry Advanced Function
Created Pester Tests for the Above
(copy/pasted from your CWTimeEntry issue - this would be a sweet addition and likely when I get some time I'll look through your code and see if I can build it out myself - if so i'll post the scripts up here)
Thought the ConnectWise's Service BoardType API did return subtypes too. Just tested it myself and realize it does not. So I will be looking in to how to request subtypes.
Hi Brian
Thank you for an excellent module.
I have found some issues in regards to some of the functions that should be easy fixes.
-Server $CWServer
is not referenced and needs to be changed to -Session $CWServer
to work.I have tried a couple of the functions with success but i am having issues with the one i really need.
Update-CWServiceTicket
When i call the function:
Update-CWServiceTicket -ID 751047 -StatusID 761 -Message "Changed Status" -Session $CWServer;
The ID is confirmed and exists in CW as new and i am trying to set Status to Completed.
This is the error that i get:
Update-CWServiceTicket : Parameter set cannot be resolved using the specified named parameters.
At line:40 char:2
+ Update-CWServiceTicket -ID 751047 -StatusID 761 -Message "Changed St ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Update-CWServiceTicket], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Update-CWServiceTicket
According to the synopsis the the supplied parameters are the only ones that are Mandatory.
I might be doing something wrong?
Thanks.
Example of Note Being Added:
#1 of 2 Time Entries: 2016-09-13 08:00:00 to 2016-09-13 08:00:00
Chg It To:
[Note: #1 of 2 Time Entries: 2016-09-13 08:00:00 to 2016-09-13 08:00:00]
Add support for the following parameters:
Need to expand the contributing document.
TODO:
-Detailed
switch for Get-CWTimeEntry
I'm trying to use the Update-CWServiceTicket function, but without proper documentation I'm just randomly trying the switches to see what they do and what they require when paired with different ones.
Is there documentation somewhere that I can look at? I don't see anything relevant under the docs folder, only instructions for creating keys.
Create function to retrieve CW member information
Get-CWMember
advanced functionGet-CWMember
Cannot retrieve a system member using the -Email
filter.
-Email
to be -Username
These past few months, I have been thinking about the future of this project. I have come to the conclusion that I need to rewrite this PowerShell module.
I do apologize to those, like @vedeht, who have been waiting on the continued development of this project. I have learned a lot about open develop projects since writing this one (it was my first OSS project). Now I want to put it all together.
It would be good to have the ability to update a company contact info to include firstname, last name, email, phone, etc
In trying to do a Create-CWConfig function, I ran into this terrible annoyance with the way that CW needs to receive [datetime] via the API. I wrote this little function that helps. Figured it would help you and your users so they didn't bang their head against the same problems I did.
function ConvertTo-CWTime
{
Param
(
[Parameter(Mandatory = $True,Position = 0)]
[datetime]$dateTime
)
$MyTZone = Get-TimeZone
$datetime = "{0:yyyy-MM-ddThh:mm:ssZ}" -f [System.TimeZoneInfo]::ConvertTimeToUtc($dateTime, $MyTZone)
return $datetime
}
[CwApiTimeEntrySvc].ReadTimeEntries()
- Updated logic to prevent sending CW API request to get empty array/list of timeentries due to the targeting ticket not having any time entries against it.
They will start requiring a generated GUID in the clientId header sometime in Mid-March. This will completely break this module.
I have modified my copy to add the extra parameter. To accomplish this you must modify the following files.
Public\CWSession.ps1
In the param section add a new parameter for ClientID. I added this between PrivateKey and OverrideSSL which ended in my lines 32-35 appearing thus:
[string]$PrivateKey,
[Parameter(ParameterSetName='Normal', Position=3, Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$ClientID,
Then modify the sections in Begin to include the new ClientID variable, so that that section appears Thus:
Begin
{
[CWApiRestSession] $cwSession = $null;
if (!$OverrideSSL)
{
$cwSession = [CWApiRestSession]::New($Domain, $CompanyName, $PublicKey, $PrivateKey, $ClientID);
}
else
{
$cwSession = [CWApiRestSession]::New($Domain, $CompanyName, $PublicKey, $PrivateKey, $ClientID, $true);
}
}
Then in the Private\PSCWApiClasses.ps1 file Near line 154 I added a line to define the $clientID variable. So the lines immediately following the CWApiRestSession declaration on line 162 now look *thus.
CWApiRestSession ([string] $domain, [string] $companyName, [string] $publicKey, [string] $privateKey, [string] $clientID)
{
$this.Domain = $domain;
$this.CompanyName = $companyName;
$this.PublicKey = $publicKey;
$this.PrivateKey = $privateKey;
$this.clientID = $clientID;
Then in the overload for including the overrideSSL function beginning around line 178 it it also included there.
CWApiRestSession ([string] $domain, [string] $companyName, [string] $publicKey, [string] $privateKey, [string] $clientID, [bool] $overrideSSL)
{
$this.Domain = $domain;
$this.CompanyName = $companyName;
$this.PublicKey = $publicKey;
$this.PrivateKey = $privateKey;
$this.OverrideSSL = $overrideSSL;
$this.ClientID = $clientID;
Then in the definition of the _buildHTTPHeader function, I added the header for clientId. So around line 211-213 it now looks like this:
hidden [void] _buildHttpHeader ()
{
$this.Header = [hashtable] @{
"Authorization" = $this._createCWAuthenticationString();
"Accept" = "application/vnd.connectwise.com+json;";
"Type" = "application/json";
"clientId" = $this.clientID;
}
if ($this.OverrideSSL)
{
$this.Header.Add("x-cw-overridessl", "True");
}
}
That's the end of the changes that I've made to date. It appears to be passing things correctly now, but I won't know for certain how well it works until they start requiring that clientId header.
Fix the 3 failures...
Invoking Pester...
Describing CWCompany
Context Get-CWCompany
[+] gets company and checks for the id field 1.08s
[+] gets company and pipes it through the Select-Object cmdlet for the id property 186ms
[+] gets the id and subject properties of a company by using the -Property param 159ms
[+] gets companies by passing array of company ids to the -ID param 427ms
[+] gets list of companies that were piped to the cmdlet 424ms
[+] gets company based on the -Filter param 297ms
[+] gets company based on the -Filter param and uses the SizeLimit param 284ms
[+] gets companies and sorts company id by descending piping cmdlet through Sort-Object cmdlet 405ms
[+] wildcard search using Identifier parameter with SizeLimit parameter 776ms
[+] get single company by Identifier parameter 272ms
[+] wildcard search using Name parameter with SizeLimit parameter 674ms
[+] get single company by Name parameter 288ms
[+] wildcard search using Name parameter with Descending parameter 767ms
Describing CWCompanyContact
Context Get-CWCompanyContact
[+] gets a single contact 302ms
[+] gets company contact entries for a company and check that the results is an array 268ms
[+] gets a single contact from a company and pipes it through the Select-Object cmdlet for the id property of the first object 250ms
[+] search for contact by first name 259ms
[+] gets a single contact 131ms
[+] search for contact by last name 265ms
[+] wildcard search for contact by first name 387ms
[+] wildcard search for contact by last name 376ms
[+] wildcard search with the Descending parameter 380ms
Describing CWConnectionInfo
Context Get-CWConnectionInfo
[+] gets server connection information and checks it for the domain 149ms
Describing CWServiceBoard
Context Get-CWServiceBoard
[+] gets board and checks for the id field 266ms
[+] gets board and pipes it through the Select-Object cmdlet for the id property 119ms
[+] gets boards by passing array of board ids to the -ID param 520ms
[+] gets list of boards that were piped to the cmdlet 515ms
[+] gets board based on the -Filter param 224ms
[+] gets board based on the -Filter param and uses the SizeLimit param 223ms
[+] gets boards and sorts board id by descending piping cmdlet through Sort-Object cmdlet 680ms
[+] wildcard search using Name parameter with SizeLimit parameter 216ms
[+] get single board by Name parameter 211ms
Describing CWServiceBoardStatus
Context Get-CWServiceBoardStatus
[+] gets board status and check that the results is an array 405ms
[+] gets board and pipes it through the Select-Object cmdlet for the id property of the first object 276ms
Describing CWServiceBoardSubtype
Context Get-CWServiceBoardSubtype
[+] gets board status and check that the results is an array 868ms
[+] gets board and pipes it through the Select-Object cmdlet for the id property of the first object 236ms
Describing CWServiceBoardType
Context Get-CWServiceBoardType
[+] gets board status and check that the results is an array 501ms
[+] gets board and pipes it through the Select-Object cmdlet for the id property of the first object 237ms
Describing CWServiceTicket
Context Get-CWServiceTicket
[+] gets ticket and checks for the id field 729ms
[+] gets ticket and pipes it through the Select-Object cmdlet for the id property 275ms
[+] gets the id and subject properties of a ticket by using the -Property param 283ms
[+] gets tickets by passing array of ticket ids to the -ID param 1.1s
[+] gets list of tickets that were piped to the cmdlet 1.14s
[+] gets ticket based on the -Filter param 755ms
[+] gets ticket based on the -Filter param and uses the SizeLimit param 1.14s
[+] gets tickets and sorts ticket id by descending piping cmdlet through Sort-Object cmdlet 1.12s
[-] wildcard search using Summary parameter with SizeLimit parameter 14.45s
at <ScriptBlock>, C:\Users\Brian\OneDrive\Development\GitHub\PSConnectWise\test\CWServiceTicket.Tests.ps1: line 78
Expected: {True}
But was: {False}
78: $count -gt 0 -and $count -le $sizeLimit | Should Be $true;
at <ScriptBlock>, C:\Users\Brian\OneDrive\Development\GitHub\PSConnectWise\test\CWServiceTicket.Tests.ps1: line 78
[+] get tickets by Summary parameter 4.12s
[+] wildcard search using Filter parameter with Descending parameter 3.2s
Context New-CWServiceTicket
[+] create a new service ticket and check for the ticket number 884ms
Context Update-CWServiceTicket
[+] change the subject of a ticket 833ms
WARNING: {
"code": "InvalidObject",
"message": "ticket object is invalid",
"errors": [
{
"code": "MissingRequiredField",
"message": "The summary field is required.",
"resource": "ticket",
"field": "summary"
}
]
}
[-] change the status of a ticket 324ms
at <ScriptBlock>, C:\Users\Brian\OneDrive\Development\GitHub\PSConnectWise\test\CWServiceTicket.Tests.ps1: line 137
Expected: {True}
But was: {False}
137: $ticket.status.id -eq $statusID | Should Be $true;
at <ScriptBlock>, C:\Users\Brian\OneDrive\Development\GitHub\PSConnectWise\test\CWServiceTicket.Tests.ps1: line 137
WARNING: {
"code": "InvalidObject",
"message": "ticket object is invalid",
"errors": [
{
"code": "MissingRequiredField",
"message": "The summary field is required.",
"resource": "ticket",
"field": "summary"
}
]
}
[-] change the status of a ticket and set the board ID 310ms
at <ScriptBlock>, C:\Users\Brian\OneDrive\Development\GitHub\PSConnectWise\test\CWServiceTicket.Tests.ps1: line 146
Expected: {True}
But was: {False}
146: $ticket.status.id -eq $statusID -and $ticket.board.id -eq $boardID | Should Be $true;
at <ScriptBlock>, C:\Users\Brian\OneDrive\Development\GitHub\PSConnectWise\test\CWServiceTicket.Tests.ps1: line 146
[+] add a ticket note to a ticket 958ms
Context Remove-CWServiceTicket
[+] deletes a ticket and check for a return value of true if successful 1.59s
Describing CWServiceTicketNote
Context Get-CWServiceTicketNote
[+] gets ticket note entries for a ticket and check that the results is an array 976ms
[+] gets a single note from a ticket and pipes it through the Select-Object cmdlet for the id property of the first object 277ms
Context Add-CWServiceTicketNote
[+] add a new ticket note to a ticket then checks the return object for the ticket id 376ms
Describing CWSystemMember
Context Get-CWSystemMember
[+] gets member and checks for the id field 285ms
[+] gets member and pipes it through the Select-Object cmdlet for the id property 135ms
[+] gets members by passing array of member ids to the -ID param 270ms
[+] gets list of members that were piped to the cmdlet 261ms
[+] gets member based on the -Filter param 273ms
[+] gets member based on the -Filter param and uses the SizeLimit param 271ms
[+] gets members and sorts member id by descending piping cmdlet through Sort-Object cmdlet 265ms
[+] get member using username parameter via Filter and SizeLimit parameter 263ms
[+] get single member by First and Last parameters 274ms
[+] get single member by Username parameter 160ms
Describing CWTimeEntry
Context Add-CWTimeEntry
[+] create a new time entry on a ticket 832ms
[+] create a new time entry on a ticket by passing a hashtable 619ms
[+] create a new multi-day time entry on a ticket 1s
Context Get-CWTimeEntry
[+] gets time entries for a ticket by using the TicketID parameter 568ms
[+] gets ticket and pipes it through the Select-Object cmdlet for the id property 192ms
[+] gets list of time entries that were piped to the cmdlet 729ms
[+] gets tickets and sorts ticket id by descending piping cmdlet through Sort-Object cmdlet 502ms
Context Update-CWTimeEntry
[+] change the internal note of a ticket 360ms
[+] change the status of a ticket and set the board ID 363ms
Context Remove-CWTimeEntry
What if: Performing the operation "Remove-CWTimeEntry" on target "9311309".
[+] deletes a ticket and check for a return value of true if successful with the WhatIf parameter 26ms
Describing PrivateHelpers
Context Split-TimeSpan
[+] splits time and checks correct number of returned entries 56ms
Tests completed in 56.89s
Passed: 76 Failed: 3 Skipped: 0 Pending: 0 Inconclusive: 0
Completed Test task in task runner.
Instead of return all unique time entries, it returns duplicates after the first 25 items.
Get all items without having to specify the ID?
Get-CWServiceBoard -Server $Server
Get-CWServiceTicket -Server $Server
All for the the -Identifier
parameter to be used as a wildcard search.
Create function to add time entries. This is because I care about JP.
Add-CWTimeEntry
Advanced FunctionGet-CWTimeEntry
Advanced FunctionRemove-CWTimeEntry
Advanced FunctionNever thought the Get-CWConnectionInfo
was the right name for the function. Session is definitely a better name for the function.
Get-CWConnectionInfo
to Set-CWSession
$Script:CWConnectionInfo
to $Script:CWSession
$Server
Parameter to $Session
Want to publish the module to PowerShellGallery.org.
Get-CWCompany -Filter 'id>0' -Server $Server | select name
Returns...
WARNING: {
"code": "InvalidObject",
"message": "pageSize object is invalid",
"errors": [
{
"code": "OutOfRange",
"message": "The field pageSize must be between 1 and 100.",
"resource": "pageSize",
"field": "pageSize"
}
]
}
Hi all,
I have a script going utilizing the PSConnectWise module
And so far everything is going well, we have automated ticket logging and imports form CSV files - however, we are currently facing an issue with setting the billable option.
When using the integrated switch on the command:
Add-CWTimeEntry
for instance: Add-CWTimeEntry -TicketID $ID -Start $StartTime -End $EndTime -Message $message -MemberID $MemberID -ChargeToType ServiceTicket -BillOption Billable
The bill option doesn't actually get set - and continues to revert to Do Not Bill.
I have gone through the module and replaced all references of DoNotBill (the code reference) and set to billable - this made the whole script break - which i actually found interesting.
and there were a number of other things tested as well.
i just wanted to ask - has anyone else had success setting billable options with this powershell module at all?
Assistance or pointers are appreciated!
i did a string search for all references to BillOption and replaced them with BillableOption - even manually did this (there arent too many - 2 files, Public/CWTimeEntry.ps1 and Private/PSCWApiClasses.ps1 - following this - for SOME reason - this breaks the connection function - Public/CWSession.ps1 which actually has no reference to either of these files - its so bizarre.
Any thoughts at all on this?
TestConnection()
method to CWApiRestConnectionInfo
Test-CWConnection
functionTest-CWConnection
functionI used to run a query to array ticket ids based on a filter (see below). These appears to no longer be working?
$aSR1 = @(Get-CWServiceTicket -Filter "status/name='Acknowledged' and board/id=20 and company/id!=2 and summary not like '%No AV Found' and summary not like '%Standard Services - {Severity1}%' and summary not like '%Critical Event 41' and closedDate>=[ $sYesterday T23:59:59Z]" -Server $oCWServer | select ID)
Hi,
I am having trouble importing this module onto Windows server 2012 machine. Please see attached error message that I am getting.
I have been able to import the module successfully onto my windows 10 workstation. I have tested it on the workstation and all works fine. However, the import is not working on the server.
This is more of support issue than a bug - hoping someone might be able to assist me.
Thanks!
Thought it might be good to correct these early on to help things down the line:
itemsLeftToRetrived > itemsLeftToRetrieve
queriedCompanys > queriedCompanies
Careful not to do a find/replace on just 'Companys', as you'll catch the CompanySvc variable
title says it all
I made big mistake how exceptions are handle. Need to completely review how all exception are handle. Nearly all exceptions need to bubble all the way up. So the consumer of the module can determine how to handle exceptions. This includes for HTTP 4xx and 5xx errors from CW API too.
/time/entries
POST requestUpdateEntry()
Method for the TimeEntry SvcUpdate-CWTimeEntry
functiontitle says it all
Hi there,
This is a great module and I am really enjoy using it.
When creating a ConnectWise session is it possible to pass the private key as an secure string? I have tried doing this but the session does not seem to accept the secure string? It does work fine when I pass the private key as a standard string.
Thanks.
Provided an option that opts-out of automation notes being added to InternalNote field of a time entry.
Example of Note Being Added:
#1 of 2 Time Entries: 2016-09-13 08:00:00 to 2016-09-13 08:00:00
Add-CWTimeEntry
Add-CWServiceTicketNote
Any idea how to make a ticket a child ticket? I can't see any example of how that would be done.
I updated our connectwise manage instance to 2018.4 last night, and found that some queries where I was looking for ServiceboardType by name of the type and the same for service board status weren't working correctly using PSConnectwise.
Through debugging and testing with PostMan I found that connectwise is no longer returning all fields when you specify the fields=* query parameter. Instead it was only returning the ID field. While I feel this is a bug in Connectwise at this point, it's also true that with their API, leaving the fields parameter out completely is the same as fields=*. Given that I modified my local instance of the PSCWAPIClasses.ps1 file in the BuildCWQueryString function, I added another check before it adds the parameter to the vettedqueryparams, where it basically looks for the parameter name fields, and the value to be * and doesn't add it if that is the case.
So that section of code for me now looks like this:
if (![String]::IsNullOrEmpty($p.Value))
{
if ( $p.Key -eq "fields" -and $p.Value -eq "*" )
{
Write-Debug "fields was for all, so leave it out"
}
else
{
$vettedQueryParams.Add($p.Key, $p.Value);
}
}
Per ConnectWise's Formatting Requests documentation, the max value for limit is 1000. Currently, the PS functions' validation range is between 1 and 2k.
Can the update-cwserviceticket update the due date on a ticket?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.