Invoke-OdinApi.ps1
<#
class Base64 { [string]$ItemName Base64([string]$String) { $this.ItemName = $String } [string]ToString() { return $this.ItemName } } #> if (!([System.Management.Automation.PSTypeName]'Base64').Type) { Add-Type -Language CSharp -TypeDefinition @" public class Base64 { public string ItemName; public Base64(string Str) { ItemName = Str; } public override string ToString() { return ItemName; } } "@ } function ConvertFrom-OdinApiXml { <# .SYNOPSIS convert API XML response to Object .DESCRIPTION If "-OutputXml" switch was used on Invoke-OdinApi you can then run this to convert the XML .EXAMPLE ConvertFrom-OdinApiXml -Xml $Xml .LINK https://github.com/ili101/Invoke-OdinApi #> [CmdletBinding(HelpURI='https://github.com/ili101/Invoke-OdinApi')] param ( [Parameter(Mandatory=$true, Position=1)] $Xml ) if ($Xml -is [System.Xml.XmlDocument]) { $Xml = $Xml.methodResponse } if ($Xml.Name -eq 'methodResponse') { $Xml = $Xml.FirstChild } if ($Xml.Name -eq 'params') { $Xml = $Xml.FirstChild } if ($Xml.Name -eq 'param') { $Xml = $Xml.FirstChild } if ($Xml.Name -eq 'value') { $Xml = $Xml.FirstChild } if ($Xml.Name -eq 'struct') { $Response = @{} $Xml.member | ForEach-Object -Process { $Response.Add($_.name, (ConvertFrom-OdinApiXml -Xml ($_.value))) } $Response = New-Object -TypeName PSObject -Property $Response } elseif($Xml.Name -eq 'array') { $Response = @() $Xml.data.value | ForEach-Object -Process { $Response += , (ConvertFrom-OdinApiXml -Xml ($_)) } } elseif($Xml.Name -eq 'fault') { $Response = ConvertFrom-OdinApiXml -Xml ($Xml.value) if ($Response.faultCode -eq -1) { $Response.faultString = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Response.faultString))) } Write-Error -Message ('Odin Error: faultCode: "{0}", faultString: "{1}"' -f $Response.faultCode,$Response.faultString) -ErrorAction Stop } elseif($Xml.Name -eq 'i4') { [int]$Response = $Xml.InnerXml } elseif($Xml.Name -eq 'boolean') { [boolean]$Response = [int]::Parse($Xml.InnerXml) } else { $Response = $Xml.InnerXml } Write-Verbose -Message ($Response | Out-String) $Response } function Invoke-OdinApi { <# .SYNOPSIS Execute OA/BA API commands .DESCRIPTION Execute Odin "Operations Automation" and "Business Automation" API commands .EXAMPLE Invoke-OdinApi -OA -Method 'pem.statistics.getStatisticsReport' -Parameters @{reports=@(@{name='poaVersion'; value='0'})} -SendTo '123.123.123.123:8440' .LINK https://github.com/ili101/Invoke-OdinApi #> [CmdletBinding(HelpURI='https://github.com/ili101/Invoke-OdinApi')] param ( # Send Business Automation API command, See http://download.automation.odin.com/oa/7.0/oapremium/portal/en/billing_api_reference/55879.htm for the list of methods and parameters. [Parameter( ParameterSetName='Business Automation', Mandatory=$true, Position=0)] [switch] $BA, # Send Operations Automation API command, See http://download.automation.odin.com/oa/7.0/oapremium/portal/en/operations_api_reference/55879.htm for the list of methods and parameters. [Parameter( ParameterSetName='Operations Automation', Mandatory=$true, Position=0)] [switch] $OA, # The Method name. [Parameter(Mandatory=$true, Position=1)] [System.String] $Method, # The methods parameters, Ordered hashtable required for BA, ordered hashtable or a normal hashtable required for OA. [Parameter(Mandatory=$true, Position=2)] $Parameters, # IP to send the call to, if not provided the API request is returned. [Parameter(Mandatory=$false, Position=3)] [System.String] $SendTo = $null, # Return the unconverted result XML [Parameter(Mandatory=$false, Position=4)] [switch] $OutputXml ) if ($BA) { if ($Parameters -isnot [System.Collections.Specialized.OrderedDictionary]) { Write-Error -Message 'Error: Parameters is not an ordered hashtable' -ErrorAction Stop } # Create The Document $RequestXML = New-Object -TypeName xml $null = $RequestXML.AppendChild($RequestXML.CreateXmlDeclaration('1.0','UTF-8',$null)) $TempElement = $RequestXML.AppendChild($RequestXML.CreateElement('methodCall')) $TempElement.AppendChild($RequestXML.CreateElement('methodName')).InnerText = 'Execute' $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('params')) $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('param')) $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('value')) $structElement = $TempElement.AppendChild($RequestXML.CreateElement('struct')) $TempElement = $structElement.AppendChild($RequestXML.CreateElement('member')) $TempElement.AppendChild($RequestXML.CreateElement('name')).InnerText = 'Server' $TempElement.AppendChild($RequestXML.CreateElement('value')).InnerText = 'BM' $TempElement = $structElement.AppendChild($RequestXML.CreateElement('member')) $TempElement.AppendChild($RequestXML.CreateElement('name')).InnerText = 'Method' $TempElement.AppendChild($RequestXML.CreateElement('value')).InnerText = $Method $TempElement = $structElement.AppendChild($RequestXML.CreateElement('member')) $TempElement.AppendChild($RequestXML.CreateElement('name')).InnerText = 'Params' $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('value')) $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('array')) $dataElement = $TempElement.AppendChild($RequestXML.CreateElement('data')) ForEach ($Parameter in $Parameters.GetEnumerator()) { $null = $dataElement.AppendChild($RequestXML.CreateComment($Parameter.Key)) $TempElement = $dataElement.AppendChild($RequestXML.CreateElement('value')) if ($Parameter.Value -is [int]) { $TempElement.AppendChild($RequestXML.CreateElement('i4')).InnerText = $Parameter.Value } elseif ($Parameter.Value -is [double]) { $TempElement.AppendChild($RequestXML.CreateElement('double')).InnerText = $Parameter.Value } elseif ($Parameter.Value -is [string]) { $TempElement.InnerText = $Parameter.Value } else { Write-Error -Message ('Parameter "{0}" is of unsupported type "{1}"' -f $Parameter.Key,$Parameter.GetType().Name) -ErrorAction Stop } } } elseif ($OA) { if ($Parameters -isnot [System.Collections.Hashtable] -and $Parameters -isnot [System.Collections.Specialized.OrderedDictionary] -and $Parameters -isnot [System.Array]) { Write-Error -Message 'Error: Parameters is not a hashtable or array' -ErrorAction Stop } # Create The Document $RequestXML = New-Object -TypeName xml $null = $RequestXML.AppendChild($RequestXML.CreateXmlDeclaration('1.0','UTF-8',$null)) $TempElement = $RequestXML.AppendChild($RequestXML.CreateElement('methodCall')) $TempElement.AppendChild($RequestXML.CreateElement('methodName')).InnerText = $Method $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('params')) ForEach ($Parameter in $Parameters) { if ($Parameter -isnot [System.Collections.Hashtable] -and $Parameter -isnot [System.Collections.Specialized.OrderedDictionary]) { Write-Error -Message 'Error: Parameters array do not contain a hashtable' -ErrorAction Stop } $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('param')) function Set-Members { param ($Parameter = $null) $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('value')) if ($Parameter -is [int]) { $TempElement.AppendChild($RequestXML.CreateElement('int')).InnerText = $Parameter } elseif ($Parameter -is [Int64]) { $TempElement.AppendChild($RequestXML.CreateElement('bigint')).InnerText = $Parameter } elseif ($Parameter -is [string]) { $TempElement.AppendChild($RequestXML.CreateElement('string')).InnerText = $Parameter } elseif ($Parameter -is [Boolean]) { $TempElement.AppendChild($RequestXML.CreateElement('boolean')).InnerText = if ($Parameter) {1} else {0} } elseif ($Parameter -is [Base64]) { $TempElement.AppendChild($RequestXML.CreateElement('base64')).InnerText = $Parameter } elseif ($Parameter -is [System.Collections.Hashtable] -or $Parameter -is [System.Collections.Specialized.OrderedDictionary]) #struct { $structElement = $TempElement.AppendChild($RequestXML.CreateElement('struct')) ForEach ($Param in $Parameter.GetEnumerator()) { Write-Verbose -Message ($Param | Out-String) $TempElement = $structElement.AppendChild($RequestXML.CreateElement('member')) $TempElement.AppendChild($RequestXML.CreateElement('name')).InnerText = $Param.Key Set-Members -Parameter $Param.Value } } elseif ($Parameter -is [System.Array]) #array { $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('array')) $TempElement = $TempElement.AppendChild($RequestXML.CreateElement('data')) ForEach ($Item in $Parameter) { Write-Verbose -Message ($Item | Out-String) Set-Members -Parameter $Item } } else { Write-Error -Message ('Parameter "{0}" is of unsupported type "{1}"' -f $Parameter,$Parameter.GetType().Name) -ErrorAction Stop } } Set-Members -Parameter $Parameter } } if ($SendTo) { Write-Verbose -Message $RequestXML.InnerXml if ($BA) {$Port = '5224'} else {$Port = '8440'} $Url = 'http://' + $SendTo + ':' + $Port $ResponseXML = Invoke-RestMethod -Uri $Url -Body $RequestXML -Method Post $ResponseXML = [xml][System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding('ISO-8859-1').GetBytes($ResponseXML.InnerXml)) if ($OutputXml) { $ResponseXML } else { ConvertFrom-OdinApiXml -Xml $ResponseXML } } else { $RequestXML } } |