Search-WolframAlpha
Searches Wolfram Alpha for information on anything

function Search-WolframAlpha {             
            
    <#
    .Synopsis
        Searches Wolfram Alpha
    .Description
        Searches Wolfram Alpha for information on anything
    .Example
        Search-WolframAlpha -For "Micrososft" -ApiKeySetting WolframAlphaApiKey
    .Link
        Get-SecureSetting
    .Link
        Search-Engine
    #>            
    [OutputType([PSObject])]            
    param(            
    # The term to search for.            
    [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]            
    [String]$For,            
                
    # The WolframAlpha pod state to return            
    [string]$PodState,            
                   
    # The PodID of interest            
    [string]$PodId,            
                
    # If set, renders output as HTML            
    [Switch]$AsHtml,            
                
    # If set, renders the output as input to Mathemetica            
    [Switch]$AsMathematicaInput,            
                
    # If set, renders the output as output to Mathemetica            
    [Switch]$AsMathematicaOutput,            
               
    # If set, renders the output as MathML            
    [Switch]$AsMathML,            
                
    # Requests information as if the user was from a specific IP            
    [string]$FromIP,            
                
    # Requests information as if the user was from a specific location            
    [string]$Location,                
            
    # Returns the XML result            
    [Switch]$AsXml,            
                
    # The API Key            
    [string]$ApiKey,            
                
    # A web.config or SecureSetting containing the ApiKey            
    [string]$ApiKeySetting,            
                
    # If set, will run the query as a background job            
    [switch]$AsJob,            
                
    # If set, will always refetch the data            
    [Switch]$Force                     
    )            
                
    begin {            
        #region Setup Result Cache            
        Set-StrictMode -Off            
        if (-not ($script:cachedRawResults)) {             
            $script:cachedRawResults = @{}                        
        }            
        #endregion Setup Result Cache            
    }            
                
                
    process {            
        if ($apiKey) {            
            $script:WolframAlphaAPIKey = $apiKey            
        }            
        if ($apiKeySetting) {            
            $apiKey= Get-WebConfigurationSetting -Setting $apiKeySetting             
            if (-not $apiKey) {                            
                $apiKey= Get-SecureSetting -Name $apiKeySetting -ValueOnly            
            }            
            if ($apiKey) {            
                $script:WolframAlphaAPIKey = $apiKey            
            }            
                        
        }            
                    
        $psBoundParameters.ApiKey = $script:WolframAlphaAPIKey            
            
        if ($AsJob) {            
            $myDefinition = [ScriptBLock]::Create("function Search-WolframAlpha {
$(Get-Command Search-WolframAlpha | Select-Object -ExpandProperty Definition)
}
")            
            $null = $psBoundParameters.Remove('AsJob')                        
            $myJob= [ScriptBLock]::Create("" + {            
                param([Hashtable]$parameter)             
                            
            } + $myDefinition + {            
                            
                Search-WolframAlpha @parameter            
            })             
                        
            Start-Job -ScriptBlock $myJob -ArgumentList $psBoundParameters             
            return            
        }            
        $script:WolframAlphaWebClient = New-Object Net.WebClient            
        $queryBase = "http://api.wolframalpha.com/v2/query?"            
        $queryTerm = "input=$($For.Replace(' ', '%20'))"                    
        if (-not $script:WolframAlphaAPIKey) {            
        }            
                    
        $queryAPIKey = "appid=$Script:WolframAlphaAPIKey"            
                    
        if ($psboundParameters.PodState) {            
            $queryTerm+="&podstate=$podstate"            
        }            
        if ($psboundParameters.PodId) {            
            $queryTerm+="&includepodid=$PodId"            
        }            
            
        $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}"            
        if ($AsHTML) {            
            $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}&format=html"            
            $result = $script:WolframAlphaWebClient.DownloadString($query)            
            $result            
        } elseif ($AsMathematicaInput) {            
            $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}&format=minput"            
            $result = $script:WolframAlphaWebClient.DownloadString($query)            
            $result            
                    
        } elseif ($AsMathematicaOutput) {            
            $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}&format=moutput"            
            $result = $script:WolframAlphaWebClient.DownloadString($query)            
            $result                    
        } elseif ($AsMathML) {            
            $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}&format=mathml"            
            $result = $script:WolframAlphaWebClient.DownloadString($query)            
            $result                   
        } elseif ($AsXML) {            
            $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}"            
            $result = $webClient.DownloadString($query)            
            $result            
        } else {            
            # Turn regular XML output into a psuedo object            
            $query = "${QueryBase}${QueryTerm}&${QueryAPIKey}"                        
            if ($location) {            
                $query += "&location=$location"            
            }            
                        
                        
            if ($fromIP) {                            
                $query += "&ip=$fromIP"            
            }            
            $result = if ($script:CachedRawResults[$query] -and (-not $Force)) {            
                $script:cachedRawResults[$query]            
            } else {                            
                $script:cachedRawResults[$query] = $script:WolframAlphaWebClient.DownloadString($query)            
                $script:cachedRawResults[$query]            
            }            
            $resultError = ([xml]$result).SelectSingleNode("//error")                        
            if ($resultError) {                        
                Write-Error -Message $resultError.msg -ErrorId "WolframAlphaWebServiceError$($resultError.Code)"                
                return            
            }            
            $pods = @{}            
                        
                Write-Verbose "$result"            
            # Scrape the results from the pods            
            $result |             
                Select-Xml //pod |             
                ForEach-Object  -Begin {            
                    $psObject = New-Object PSObject            
                } {                    
                    $pod = $_.Node                        
                    if ($pod.Id -eq 'Input') {            
                        $psObject.psobject.Properties.Add(            
                            (New-Object Management.Automation.PSNoteProperty "InputInterpretation","$($pod.subpod.plaintext)"            
                        ))            
                    }            
                                
                    if ($pod.Id -ne 'Input') {            
                        # Try and try and try            
                        $textInPods = $pod.SubPod  |Select-Object -ExpandProperty plaintext            
                        $textInPods = $textInPods -join ([Environment]::NewLine)            
                        $lines = $textInPods.Split([Environment]::NewLine, [StringSplitOptions]'RemoveEmptyEntries')            
                        # Since Wolfram|Alpha is a data-oriented search engine that strangely enough, returns text instead of data, it's time to parse (and pray)            
                        $averageItemsPerLine = $lines |             
                            ForEach-Object {            
                                $_.ToCharArray() |            
                                    Where-Object {$_ -eq '|' } |            
                                    Measure-Object            
                            } | Measure-Object -Average -Property Count |            
                            Select-Object -ExpandProperty Average            
                                    
                        # If there's more than one item per line average, it's probably a series of items            
                        if ($averageItemsPerLine -lt 1) {            
                            if (-not $lines) {            
                                $psNoteProperty = New-Object Management.Automation.PSNoteProperty $pod.Title, $pod.Subpod.img.src            
                                $null = $psObject.psobject.Properties.Add($psNoteProperty)                                        
                            } else {            
                                $psNoteProperty = New-Object Management.Automation.PSNoteProperty $pod.Title, $lines            
                                $null = $psObject.psobject.Properties.Add($psNoteProperty)                                        
                            }            
                                        
                        } elseif ($averageItemsPerLine -ge 1 -and $averageItemsPerLine -lt 2) {            
                            # It's probably a table of properties, but it could also be a result list            
                            $outputObject = New-Object PSObject            
                            $lastProperty = $null            
                            foreach ($line in $lines) {            
                                $chunks = @($line.Split('|', [StringSplitOptions]'RemoveEmptyEntries'))            
                                # If it's greater than 1, treat it as a pair of values            
                                            
                                if ($chunks.Count -gt 1) {            
                                    # Heading and value.            
                                    $lastProperty = $chunks[0]            
                                    if ("$lastProperty".Trim()) {            
                                        $value = $chunks[1] |             
                                            Where-Object {"$_".Trim() -notlike "(*)"}            
                                        $outputObject | Add-Member NoteProperty $chunks[0] "$value".Trim() -Force            
                                    }            
                                } elseif ($chunks.Count -eq 1) {            
                                    # Additional value            
                                    $newValue = @($outputObject.$lastProperty) +  "$($chunks[0])".Trim()            
                                    if ("$lastProperty".Trim()) {            
                                        $outputObject | Add-Member NoteProperty $lastProperty $newValue -Force            
                                    }            
                                }            
                            }            
                            $psNoteProperty = New-Object Management.Automation.PSNoteProperty $pod.Title, $outputObject            
                            $null = $psObject.psobject.Properties.Add($psNoteProperty)                                        
                        } else {            
                            # It's probably a table            
                                        
                            if ($lines.Count -eq 1) {            
                                $itemValue, $itemSource = $lines[0] -split "[\(\)]"            
                                            
                                $outputObject =New-Object PSOBject |            
                                    Add-Member NoteProperty Value $itemValue -PassThru |             
                                    Add-Member NoteProperty Source $itemSource -PassThru            
                                $psNoteProperty = New-Object Management.Automation.PSNoteProperty $pod.Title, $outputObject                
                                $null = $psObject.psobject.Properties.Add($psNoteProperty)                                        
                            } else {            
                                $columns = $lines[0] -split "\|" | ForEach-Object {$_.Trim() }             
                                $rows = foreach ($l in $lines[1..($lines.Count -1)]) {                
                                    $l -split "\|" | ForEach-Object { $_.Trim() }             
                                }            
            
                                $outputObject =             
                                    for ($i =0;$i -lt $rows.Count; $i+=$columns.Count) {            
                                        $outputObject = New-Object PSObject             
                                        foreach ($n in 1..$columns.Count) {            
                                            $columnName =            
                                                if (-not $columns[$n -1]) {            
                                                    "Name"            
                                                } else {            
                                                    $columns[$n -1]            
                                                }            
                                            $outputObject |             
                                                Add-Member NoteProperty $columnName ($rows[$i + $n - 1]) -Force            
                                                         
                                        }            
                                        $outputObject             
                                    }            
                                $psNoteProperty = New-Object Management.Automation.PSNoteProperty $pod.Title, $outputObject                
                                $null = $psObject.psobject.Properties.Add($psNoteProperty)                                        
                            }            
                        }             
                    }            
                                
                    # Append pod details into the result            
                    $pods[$pod.Id] = New-Object PSObject -Property @{            
                        PodText = $pod.subpod | Select-Object -ExpandProperty plaintext -ErrorAction SilentlyContinue            
                        PodImage = $pod.subpod |             
                            Select-Object -ExpandProperty img -ErrorAction SilentlyContinue |            
                            Select-Object -ExpandProperty src            
                        PodXml = $pod            
                    }                                
                } -End {            
                    # Add on the raw output            
                    $psObject.psobject.Properties.Add(            
                        (New-Object Management.Automation.PSNoteProperty "OutputXml",([xml]$result)            
                    ))            
                    try {            
                        # Add on specific pod information            
                    $psObject.psObject.Properties.Add(            
                        (New-Object Management.Automation.PSNoteProperty "Pods",(New-Object PSObject -Property $pods)            
                    ))            
                    } catch {            
                        # If there weren't any pods, add a null property            
                    $psObject.psObject.Properties.Add(            
                        (New-Object Management.Automation.PSNoteProperty "Pods", $null            
                    ))                
                    }            
                    # Give the search result the correct typename, so PowerShell can display it sanely            
                    $psObject.pstypenames.Clear()            
                    $psObject.pstypenames.add('WolframAlphaResult')            
                    $psObject            
                                
                                
                }            
        }            
    }            
            
}