public/ConvertFrom-TNRestResponse.ps1
function ConvertFrom-TNRestResponse { <# .SYNOPSIS Converts Nessus and tenable.sc responses to a readable, PowerShell-styled format .DESCRIPTION Converts Nessus and tenable.sc responses to a readable, PowerShell-styled format .PARAMETER InputObject The rest response to parse from pipeline .EXAMPLE PS C:\> $session = Connect-TNServer -ComputerName nessus -Credential admin PS C:\> $params = @{ SessionObject = $session Path = "/folders" Method = "GET" EnableException = $EnableException } PS C:\> Invoke-TNRequest @params | ConvertFrom-TNRestResponse Connects to https://nessus:8834 using the admin credential, gets the results in JSON format then converts to PowerShell styled output #> [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [PSCustomObject[]]$InputObject, [switch]$NoUri, [switch]$ExcludeEmptyResult ) begin { function Convert-Name ($string) { if ($string -match "_") { $whole = @() $split = $string -split "_" foreach ($name in $split) { $first = $name.Substring(0, 1).ToUpperInvariant() $rest = $name.Substring(1, $name.length - 1) $whole += "$first$rest" } $string = -join $whole } return $string } function Convert-Value { param ( [string]$Key, $Value ) if ($Key -notmatch 'date' -and $Key -notmatch 'time' -or $Key -match 'Updates') { if ("$Value".StartsWith("@") -or "$Value".StartsWith("{")) { return $Value | ConvertFrom-TNRestResponse -NoUri } else { return $Value } } elseif ([double]::TryParse($value,[ref]$null)) { if ($Value -cnotlike "*T*") { return $script:origin.AddSeconds($Value).ToLocalTime() } else { return [datetime]::ParseExact($Value, "yyyyMMddTHHmmss", [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::None) } } else { return $Value } } function Convert-Row { param ( [object[]]$Object, [string]$Type ) # get columns to convert to camel case if ($null -eq $Object) { return } try { $fields = $Object | Get-Member -Type NoteProperty -ErrorAction Stop | Sort-Object Name } catch { return } foreach ($row in $Object) { if (-not $session) { $tempsession = Get-TNSession if ($tempsession.SessionId.Count -eq 1) { $session = $tempsession } } if ($session) { $uri = [uri]$session.Uri $hash = @{ ServerUri = "$($uri.Host):$($uri.Port)" } } else { $hash = @{} } if ($Type) { $hash["Type"] = $Type } if ($script:includeid) { $hash["Id"] = $script:includeid } foreach ($name in $fields.Name) { # Proper case first letter, tenable takes care of the rest $first = $name.Substring(0, 1).ToUpperInvariant() $rest = $name.Substring(1, $name.length - 1) $column = "$first$rest" # some columns need special attention switch ($column) { "Shared" { $hash["Shared"] = $(if ($row.shared -eq 1) { $true } elseif ($row.shared -eq 0) { $false } else { $row.shared }) } "Status" { $hash["Status"] = $(if ($row.status -eq 1) { $true } elseif ($row.status -eq 0) { $false } else { $row.status }) } "User_permissions" { $hash["UserPermissions"] = $permidenum[$row.user_permissions] } { $PSItem -match "Modifi" } { $value = Convert-Value -Key $column -Value $row.$column $hash["Modified"] = $value } { $PSItem -match "Creat" } { $value = Convert-Value -Key $column -Value $row.$column $hash["Created"] = $value } { $PSItem -match "Last.Login" -or $PSItem -eq "LastLogin" } { $value = $script:origin.AddSeconds($row.$column).ToLocalTime() $hash["LastLogin"] = $value } default { # remove _, cap all words $key = Convert-Name $column $value = Convert-Value -Key $column -Value $row.$column $hash[$key] = $value } } } # Set column order $order = New-Object System.Collections.ArrayList $keys = $hash.Keys if ($session -and -not $NoUri) { $null = $order.Add("ServerUri") } if ('Id' -in $keys) { $null = $order.Add("Id") } if ($Type) { $null = $order.Add("Type") } if ('Username' -in $keys) { $null = $order.Add("Username") } if ('Title' -in $keys) { $null = $order.Add("Title") } if ('Name' -in $keys) { $null = $order.Add("Name") } if ('Description' -in $keys) { $null = $order.Add("Description") } foreach ($column in ($keys | Sort-Object | Where-Object { $PSItem -notin "ServerUri", "Id", "Type", "Name", "Description", "Title", "Username" })) { $null = $order.Add($column) } Write-Debug "Columns: $order" Write-Debug "Count: $($hash.Count)" [pscustomobject]$hash | Select-Object -Property $order } } } process { if ($null -eq $InputObject -or ($ExcludeEmptyResult -and $InputObject.type -eq "regular")) { return } foreach ($object in $InputObject) { Write-Debug "Processing object" # determine if it has an inner field to extract $fields = $object | Get-Member -Type NoteProperty # IF EVERY ONE HAS MULTIPLES INSIDE if ($fields.Count -eq 0) { Write-Debug "Found no inner objects" if ($object.StartsWith("{")) { try { $object = $object.Replace("\","\\") | ConvertFrom-Json $fields = $object | Get-Member -Type NoteProperty } catch { $object = $object.Replace("\","\\") | ConvertTo-Hashtable $fields = $object | Get-Member -Type NoteProperty } } elseif ($object.StartsWith("@{")) { $object = $object.Substring(2, $object.Length - 3) -split ';' | ConvertFrom-StringData | ConvertTo-PSCustomObject $fields = $object | Get-Member -Type NoteProperty } else { try { $object = $object | ConvertFrom-Json -ErrorAction Stop $fields = $object | Get-Member -Type NoteProperty -ErrorAction Stop } catch { # nothing } } } if ($fields.Count -eq 1) { Write-Debug "Found one inner object" $name = $fields.Name Convert-Row -Object $object.$name -Type $null } else { Write-Debug "Found multiple inner objects" $result = $true foreach ($definition in $fields.Definition) { if (-not $definition.Contains("Object[]")) { $result = $false } } if ($result) { foreach ($field in $fields) { $name = (Get-Culture).TextInfo.ToTitleCase($field.Name) Convert-Row -Object $object.$name -Type $name } } else { Convert-Row -Object $object } } } } } |