Public/Get-AtwsInvoiceInfo.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#Requires -Version 4.0
<#
 
    .COPYRIGHT
    Copyright (c) ECIT Solutions AS. All rights reserved. Licensed under the MIT license.
    See https://github.com/ecitsolutions/Autotask/blob/master/LICENSE.md for license information.
 
#>


Function Get-AtwsInvoiceInfo {
    <#
        .SYNOPSIS
            This function collects information about a specific Autotask invoice object and returns a generic
            powershell object with all relevant information as a starting point for import into other systems.
        .DESCRIPTION
            The function accepts an invoice object or an invoice id and makes a special API call to get a
            complete invoice description, including billingitems. For some types of billingitems additional
            information may be collected. All information is collected and stored in a PSObject which is
            returned.
        .INPUTS
            An Autotask invoice object or an invoice id
        .OUTPUTS
            A custom PSObject with detailed information about an invoice
        .EXAMPLE
            $Invoice | Get-AtwsInvoiceInfo
            Gets information about invoices passed through the pipeline
        .EXAMPLE
            Get-AtwsInvoiceInfo -InvoiceID $Invoice.id
            Gets information about invoices based on the ids passed as a parameter
        .NOTES
            NAME: Get-AtwsInvoiceInfo
       
  #>

    
    [cmdletbinding(
        DefaultParameterSetName = 'By_parameters'
    )]
    Param
    (
        [Parameter(
            Mandatory = $true,
            ValueFromPipeLine = $true,
            ParameterSetName = 'Input_Object'
        )]
        [Parameter(
            Mandatory = $true,
            ValueFromPipeLine = $true,
            ParameterSetName = 'Input_Object_as_XML'
        )]
        [Parameter(
            Mandatory = $true,
            ValueFromPipeLine = $true,
            ParameterSetName = 'Input_Object_as_XLSX'
        )]
        [Autotask.Invoice[]]
        $InputObject,

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'By_parameters'
        )]
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'By_parameters_as_XML'
        )]
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'By_parameters_as_XLSX'
        )]
        [string[]]
        $InvoiceId,

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'Input_Object_as_XML'
        )]
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'By_parameters_as_XML'
        )]
        [switch]
        $XML,

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'Input_Object_as_XLSX'
        )]
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'By_parameters_as_XLSX'
        )]
        [switch]
        $XLSX,

        [Parameter(
            ParameterSetName = 'Input_Object_as_XML'
        )]
        [Parameter(
            ParameterSetName = 'Input_Object_as_XLSX'
        )]
        [Parameter(
            ParameterSetName = 'By_parameters_as_XML'
        )]
        [Parameter(
            ParameterSetName = 'By_parameters_as_XLSX'
        )]
        [String]
        $OutputFile
    )
  
  begin {
    
        # Enable modern -Debug behavior
        if ($PSCmdlet.MyInvocation.BoundParameters['Debug'].IsPresent) { $DebugPreference = 'Continue' }

        Write-Debug ('{0}: Begin of function' -F $MyInvocation.MyCommand.Name)
    
        if (-not($Script:Atws.integrationsValue)) {
            Throw [ApplicationException] 'Not connected to Autotask WebAPI. Re-import module with valid credentials.'
        }    
    
        # Empty container to return with results
        if ($XML.IsPresent) {
            $result = New-Object XML.XmlDocument
            $root = $result.CreateNode('element', 'invoice_batch_generic', $null)
            $null = $result.AppendChild($root) 
        }
        else { 
            $result = @()
        }

        # If $OutputFile is relative, make sure it is relative to $PWD, not module directory
        if ($OutputFile) { 
            if (-not(Split-Path -Path $OutputFile -IsAbsolute)) {
                $OutputFile = Join-Path $PWD -ChildPath $OutputFile
            }
        }
    }

    process {
        
        # Input was by object. Extract invoice ids into an array and proceed
        if ($PSCmdlet.ParameterSetName -eq 'Input_Object') {
            $InvoiceId = $InputObject.id
        }

        # Get detailed invoice info through special API call. Have to call
        # API once for each invoice. Second parameter says we want the result
        # as XML. Actually we don't, but the alternative (HTML) is worse.
    
    Write-Verbose ('{0}: Asking for details on Invoice IDs {1}' -F $MyInvocation.MyCommand.Name, ($InvoiceId -join ', '))
       
    ForEach ($id in $InvoiceId) {
           
            # The API call. Make sure to query the correct WebServiceProxy object
            # specified by the $Prefix name. If the Id does not exist we get a
            # SOAP exception for some inexplicable reason
            try { 
                [Xml]$invoiceInfo = $Script:Atws.GetInvoiceMarkup($Script:Atws.integrationsValue, $id, 'XML')
            }
            catch {
                Write-Warning ('{0}: FAILED on Invoice ID {1}. No data returned.' -F $MyInvocation.MyCommand.Name, $id)
              
        # try the next ID
        Continue
      }
      
      Write-Verbose ('{0}: Converting Invoice ID {1} to a PSObject' -F $MyInvocation.MyCommand.Name, $id)
           
            if ($XML.IsPresent) { 
                # Import node with deep clone = $true
                $batch = $result.ImportNode($invoiceInfo.invoice_batch_generic.invoice_batch, $true)
                $account = $result.ImportNode($invoiceInfo.invoice_batch_generic.account, $true)
                $null = $batch.LastChild.AppendChild($account)
                $null = $result.FirstChild.AppendChild($batch)
            }
            else { 
                $result += $invoiceInfo.invoice_batch_generic | ConvertFrom-XML
            }

            
        }

    }

    end {

        if ($XLSX.IsPresent) {

            Write-Verbose ('{0}: Output as XLSX has been requested, loading ImportExcel module.' -F $MyInvocation.MyCommand.Name)

            # Import the ImportExcel module or fail
            Import-Module -Name ImportExcel -ErrorAction Stop

            # Make Excel package
            $excelOptions = @{
                PassThru      = ($OutputFile) -xor $true # If ($outputfile), no passthrough
                AutoSize      = $true
                AutoFilter    = $true
                ClearSheet    = $true
                TableName     = 'AutotaskInvoiceInfo'
                WorksheetName = 'AutotaskInvoiceInfo'
            }

            if ($OutputFile) {
                # Add .xlsx file extension if missing
                if (-not($OutputFile -like '*.xlsx')) {
                    $OutputFile = '{0}{1}' -f $OutputFile, '.xlsx'
                }

                $excelOptions['Path'] = $OutputFile
            }
            if ($excelOptions.Passthru) {
                Write-Verbose ('{0}: Returning {1} lines as an Excel Package ' -F $MyInvocation.MyCommand.Name, $result.account.invoice.invoice_item.count)
            }
            else { 
                Write-Verbose ('{0}: Writing output to file {1}' -F $MyInvocation.MyCommand.Name, $OutputFile)
            }

            $result = $result.account.invoice.invoice_item | Export-Excel @excelOptions
        }
        elseif ($OutputFile -and $XML.IsPresent) {
            
            # Add .xml file extension if missing
            if (-not($OutputFile -like '*.xml')) {
                $OutputFile = '{0}{1}' -f $OutputFile, '.xml'
            }

            Write-Verbose ('{0}: Writing output to file {1}' -F $MyInvocation.MyCommand.Name, $OutputFile)


            $result.save($OutputFile)
        }


        
        Write-Debug ('{0}: End of function' -F $MyInvocation.MyCommand.Name)
        If (-not($OutputFile)) { 
            return $result
        }
    }
}