Private/Invoke-JiraMethod.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
function Invoke-JiraMethod {
    #Requires -Version 3
    [CmdletBinding()]
    param
    (
        # REST API to invoke
        [Parameter( Mandatory )]
        [Uri]
        $URI,

        # Method of the invokation
        [ValidateSet('GET', 'POST', 'PUT', 'DELETE')]
        [String]
        $Method = "GET",

        # Body of the request
        [String]
        $Body,

        # Body of the request should not be encoded
        [Switch]
        $RawBody,

        # Custom headers for the HTTP request
        [Hashtable]
        $Headers = @{},

        # Authentication credentials
        [PSCredential]
        $Credential
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"

        # Validation of parameters
        if (
            ($Method -in ("POST", "PUT")) -and
            (-not ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Body")))
        ) {
            $message = "The following parameters are required when using the $Method parameter: Body."
            $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message
            Throw $exception
        }

        # load DefaultParameters for Invoke-WebRequest
        # as the global PSDefaultParameterValues is not used
        $PSDefaultParameterValues = $global:PSDefaultParameterValues

        # pass input to local variable
        # this allows to use the PSBoundParameters for recursion
        $_headers = $Headers

        # Check if a Session is available
        $session = Get-JiraSession -ErrorAction SilentlyContinue

        if ($Credential) {
            $SecureCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(
                    $('{0}:{1}' -f $Credential.UserName, $Credential.GetNetworkCredential().Password)
                ))
            $_headers.Add('Authorization', "Basic $SecureCreds")
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Using HTTP Basic authentication with username $($Credential.UserName)"
        }
        elseif ($session) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Using WebSession (Username=[$($session.Username)])"
        }
        else {
            $session = $null
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] No Credentials or WebSession provided; using anonymous access"
        }
    }

    process {
        Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)"
        Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)"

        $iwrSplat = @{
            Uri             = $Uri
            Headers         = $_headers
            Method          = $Method
            ContentType     = 'application/json; charset=utf-8'
            UseBasicParsing = $true
            ErrorAction     = 'SilentlyContinue'
            Verbose = $false
        }

        if ($_headers.ContainsKey("Content-Type")) {
            $iwrSplat["ContentType"] = $_headers["Content-Type"]
            $_headers.Remove("Content-Type")
            $iwrSplat["Headers"] = $_headers
        }

        if ($Body) {
            if ($RawBody) {
                $iwrSplat.Add('Body', $Body)
            }
            else {
                # http://stackoverflow.com/questions/15290185/invoke-webrequest-issue-with-special-characters-in-json
                $iwrSplat.Add('Body', [System.Text.Encoding]::UTF8.GetBytes($Body))
            }
        }

        if ($session) {
            $iwrSplat.Add('WebSession', $session.WebSession)
        }

        try {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] $($iwrSplat.Method) $($iwrSplat.Uri)"
            Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoke-WebRequest with `$iwrSplat: $($iwrSplat | Out-String)"
            $webResponse = Invoke-WebRequest @iwrSplat
        }
        catch {
            # Invoke-WebRequest is hard-coded to throw an exception if the Web request returns a 4xx or 5xx error.
            # This is the best workaround I can find to retrieve the actual results of the request.
            $webResponse = $_.Exception.Response
        }
    }

    end {
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Status code: $($webResponse.StatusCode.value__) - $($webResponse.StatusCode) `n`t`t Executed WebRequest. Access `$webResponse to see details"

        if ($webResponse) {
            if ($webResponse.StatusCode.value__ -gt 399) {
                # Retrieve body of HTTP response - this contains more useful information about exactly why the error occurred
                $readStream = New-Object -TypeName System.IO.StreamReader -ArgumentList ($webResponse.GetResponseStream())
                $responseBody = $readStream.ReadToEnd()
                $readStream.Close()
                Write-Debug "[$($MyInvocation.MyCommand.Name)] Retrieved body of HTTP response for more information about the error (`$responseBody)"
                $result = ConvertFrom-Json2 -InputObject $responseBody
            }
            else {
                if ($webResponse.Content) {
                    $result = ConvertFrom-Json2 -InputObject $webResponse.Content
                }
            }

            if ($result) {
                if (Get-Member -Name "Errors" -InputObject $result -ErrorAction SilentlyContinue) {
                    Resolve-JiraError $result -WriteError
                }
                else {
                    Write-Output $result
                }
            }
        }
        else {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] No Web result object was returned from JIRA. This is unusual!"
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended"
    }
}