GreyNoisePS.psm1

function Get-GNIpInfo {
    <#
    .Description
    Returns information for the provided Ips from the greynoise community endpoint.
    .Parameter Ip
    Specify one or many IP addresses that you want to look up
    .Parameter Key
    Specify the API key to use. A blank key works for this. See viz.greynoise.io/account/ for API key.
    .Example
    > Get-GNIpInfo -Ip 8.8.8.8 -key $key
 
        Returns IP information about the provided IP address.
    .Example
    > Get-NetTcpConnection | Where state -like 'established' | Get-GNIpInfo
 
        Returns IP reputation information for all established tcp connections on this computer.
    .Link
    https://developer.greynoise.io/reference/community-api#get_v3-community-ip
    #>

    param(
        [parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Alias('RemoteAddress','IPAddress')]
        [ipaddress[]]$Ip,
        [string]$Key = ''
    )
    process {
        foreach ($Address in $Ip) {
            try {
                $out = Invoke-RestMethod -Uri "https://api.greynoise.io/v3/community/$Address" -Headers @{key = $Key }
                
                [pscustomobject]@{
                    ip             = $out.ip
                    noise          = $out.noise
                    riot           = $out.riot
                    classification = $out.classification
                    name           = $out.name
                    link           = $out.link
                    last_seen      = $out.last_seen
                    message        = $out.message
                }
            } Catch {

                # Grab message from web response
                $msg = ($_.ErrorDetails.Message | ConvertFrom-Json | Select -Expandproperty message)

                # grab
                if (-not $msg) {
                    $msg = $_.ErrorDetails.Message
                }
                #$_
                [pscustomobject]@{
                    ip             = $Address
                    noise          = 'N/A'
                    riot           = 'N/A'
                    classification = 'N/A'
                    NAme           = 'N/A'
                    link           = 'N/A'
                    last_seen      = 'N/A'
                    message        = $msg
                }
            }
        }
    }
}

function Get-GNPing {
    <#
    .Description
    Checks if the GreyNoise API is accessable
 
    .Parameter Key
    Specify the API key to use.
     
    .Example
    > Get-GNPing -Key $key
    Checks if the greynoise API is accessible using API key $key
 
    .Link
    https://developer.greynoise.io/reference/ping-service#get_ping
    #>

    [cmdletbinding()]
    param(
        [Parameter(Mandatory)]$Key
    )
    
    Invoke-RestMethod -Uri 'https://api.greynoise.io/ping' -Headers @{'User-Agent' = 'API-Reference-Test'; key = $Key}

}

function Get-GNMultiIpContext {
    <#
    .Description
    Get more information about a set of IP addresses. Returns time ranges, IP metadata (network owner, ASN, reverse DNS pointer, country), associated actors, activity tags, and raw port scan and web request information.
    .Parameter Key
    Specify the API key to use.
    .Parameter Ips
    Array of IP Addresses to use
     
    .Example
    > $ips = 'reddit.com','microsoft.com' | % {(Resolve-DnsName $_)[0].ipaddress}
    > Get-GNMultiIpContext -Ips $ips -Key $key
 
    Gets the IP information about the IPs that are returned for reddit.com and microsoft.com.
    .Link
    https://developer.greynoise.io/reference/ip-lookup-1
    #>

    [cmdletbinding()]
    param(
        [Parameter(Mandatory)]
        $Key,
        [Alias('IP','IPAddress','RemoteAddress')]
        [ipaddress[]]$Ips
    )


    $params = @{
        Method  = 'POST'
        URI     = "https://api.greynoise.io/v2/noise/multi/context"
        
        Headers = @{
            'key' = $Key
  }
        Body    = (@{ips = $Ips.IPAddressToString} | ConvertTo-Json)
    }

    $out = Invoke-RestMethod @params
    $out

}

function Get-GNIpContext {
    <#
    .Description
    Get more information about a given IP address. Returns time ranges, IP metadata (network owner, ASN, reverse DNS pointer, country), associated actors, activity tags, and raw port scan and web request information.
    .Parameter Ip
    IP address to query
    .Parameter Key
    Specify the API key to use.
 
    .Example
    Get-GNIpContext -Key $key -Ip $ip
    returns information about $ip
     
    .Link
    https://developer.greynoise.io/reference/ip-lookup-1#noisecontextip-1
    #>

    [cmdletbinding()]
    param(
        [parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [Alias('IPAddress','RemoteAddress')]    
        [ipaddress[]]$Ip,

        [parameter(Mandatory)]
        $Key

    )

    process {
        foreach ($address in $ip) {
            try {
                $params = @{
                    Uri     = "https://api.greynoise.io/v2/noise/context/$($address.IPAddressToString)"
                    Headers = @{key = $key}
                }
                Invoke-RestMethod  @params | 
                    Add-Member -MemberType NoteProperty -Name 'error' -Value '' -PassThru
            } catch {
                [pscustomobject]@{
                    ip    = $address.IPAddressToString
                    seen  = 'N/A'
                    error = "$(($_.ErrorDetails.message | ConvertFrom-Json).error)"
                }
            }
        } 
    }
}

function Get-GNIpQuickCheck {
    <#
    .Description
    Check whether a given IP address is “Internet background noise”, or has been observed scanning or attacking devices across the Internet.
    .Parameter Ip
    IP address to query
    .Parameter Key
    Specify the API key to use.
    .Notes
    This API endpoint is real-time
    This API endpoint contains a “code” which correlates to why GreyNoise labeled the IP as "noise"
    An IP delivered via this endpoint does not include a “malicious” or “benign” categorizations
    This API endpoint only checks against the last 60 days of Internet scanner data
    .Example
    > Get-GnIpQuickCheck -Ip $ip -Key $key
    returns information about $ip
    .Link
    https://developer.greynoise.io/reference/ip-lookup-1#quickcheck-1
    #>

    [cmdletbinding()]
    param(
        [parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [Alias('RemoteAddress','IPAddress')]    
        [ipaddress[]]$Ip,

        [parameter(Mandatory)]
        $Key
    )
    process {
        $dict = @{
            '0x00' = 'The IP has never been observed scanning the Internet'
            '0x01' = 'The IP has been observed by the GreyNoise sensor network'
            '0x02' = 'The IP has been observed scanning the GreyNoise sensor network, but has not completed a full connection, meaning this can be spoofed'
            '0x03' = 'The IP is adjacent to another host that has been directly observed by the GreyNoise sensor network'
            '0x04' = 'Reserved'
            '0x05' = 'This IP is commonly spoofed in Internet-scan activity'
            '0x06' = 'This IP has been observed as noise, but this host belongs to a cloud provider where IPs can be cycled frequently'
            '0x07' = 'This IP is invalid'
            '0x08' = 'This IP was classified as noise, but has not been observed engaging in Internet-wide scans or attacks in over 60 days'
        }


        foreach ($Address in $Ip) {

            $params = @{
                Uri     = "https://api.greynoise.io/v2/noise/quick/$($Address.IPAddressToString)"
                Headers = @{key = $key}
            }
            try {
                $out =    Invoke-RestMethod @params
             [pscustomobject]@{
                    ip      = $address.IPAddressToString
                    noise   = $out.noise
                    code    = $out.code
                    codeMsg = $dict[$out.Code]
                } 
            } catch {
                [pscustomobject]@{
                    ip      = $address.IPAddressToString
                    noise   = 'N/A'
                    code    = $out.code
                    codeMsg = $dict[$out.Code]
                } 
            }
        }
    }
}

function Get-GNMultiIpQuickCheck {
    <#
    .Description
    Check whether a set of IP addresses are "Internet background noise", or have been observed scanning or attacking devices across the Internet. This endpoint is functionality identical to the /v2/noise/quick/{ip} endpoint, except it processes more than one checks simultaneously. This endpoint is useful for filtering through large log files.
    .Parameter Ips
    Array of IP addresses to query
    .Parameter Key
    Specify the API key to use.
    .Example
    > Get-GNMultiIpQuickCheck -Ips $ips -Key $key
    returns information about a set of IP addresses
    .Notes
    This API endpoint updates in real-time
    This API endpoint can either be used via GET parameter or within the body of the request
    This API endpoint contains a “code” which correlates to why GreyNoise labeled the IP as "noise"
    An IP delivered via this endpoint does not include "malicious" or "benign" categorizations
    This API endpoint only checks against the last 60 days of Internet scanner data
    .Link
    https://developer.greynoise.io/reference/ip-lookup-1#postquickcheckmulti
    #>

    [cmdletbinding()]
    param(
        [parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [Alias('RemoteAddress','IPAddress','IP')]    
        [ipaddress[]]$Ips,

        [parameter(Mandatory)]
        $Key
    )
    process {
        $dict = @{
            '0x00' = 'The IP has never been observed scanning the Internet'
            '0x01' = 'The IP has been observed by the GreyNoise sensor network'
            '0x02' = 'The IP has been observed scanning the GreyNoise sensor network, but has not completed a full connection, meaning this can be spoofed'
            '0x03' = 'The IP is adjacent to another host that has been directly observed by the GreyNoise sensor network'
            '0x04' = 'Reserved'
            '0x05' = 'This IP is commonly spoofed in Internet-scan activity'
            '0x06' = 'This IP has been observed as noise, but this host belongs to a cloud provider where IPs can be cycled frequently'
            '0x07' = 'This IP is invalid'
            '0x08' = 'This IP was classified as noise, but has not been observed engaging in Internet-wide scans or attacks in over 60 days'
        }

        $params = @{
            Body    = (@{ips = $Ips.IPAddressToString} | ConvertTo-Json)
            Uri     = 'https://api.greynoise.io/v2/noise/multi/quick'
            Headers = @{key = $Key}
            Method  = 'POST'
        }
    
        $out = Invoke-RestMethod @params  
                
        foreach ($output in $out) {
            [pscustomobject]@{
                ip      = $output.ip
                noise   = $output.noise
                code    = $output.code
                codeMsg = $dict[$output.Code]
            } 
        }
    }
}

function Get-GNRiotIpLookup {
    <#
    .Description
    RIOT identifies IPs from known benign services and organizations that commonly cause false positives in network security and threat intelligence products. The collection of IPs in RIOT is continually curated and verified to provide accurate results.
    .Parameter Ip
    IP address to query
    .Parameter Key
    Specify the API key to use.
    .Link
    https://developer.greynoise.io/reference/ip-lookup-1#riotip
    .Example
    > Get-GNRiotIpLookup -Ip $ip -key $key
 
    returns riot information about $ip
    #>

    [cmdletbinding()]
    param(
        [parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [Alias('RemoteAddress','IPAddress')]    
        [ipaddress[]]$Ip,

        [parameter(Mandatory)]
        $Key
    )

    process {
        foreach ($address in $Ip) {
            $params = @{
                Uri     = "https://api.greynoise.io/v2/riot/$($address.IPAddressToString)"
                Headers = @{key = $Key}
            }
            try {Invoke-RestMethod @params }
            catch {
                [pscustomobject]@{
                    ip           = ($_.ErrorDetails.Message | ConvertFrom-Json).ip
                    riot         = ($_.ErrorDetails.Message | ConvertFrom-Json).riot
                    category     = ''
                    name         = ''
                    description  = ''
                    explanation  = ''
                    last_updated = ''
                    logo_url     = ''
                    reference    = ''
                } 
   }
        }
    }
}

function Get-GNQLQuery {
    <#
    .Description
    GNQL (GreyNoise Query Language) is a domain-specific query language that uses Lucene deep under the hood. GNQL aims to enable GreyNoise Enterprise and Research users to make complex and one-off queries against the GreyNoise dataset as new business cases arise. GNQL is built with self-defeat and fully featured product lines in mind. If we do our job correctly, each individual GNQL query that brings our users and customers sufficient value will eventually be transitioned into it's own individual offering.
    .Parameter Key
    Specify the API key to use.
    .Parameter GNQLQuery
    specify the GNQL query string. See the greynoise docs for usage details.
    .Parameter Size
    Maximum amount of results to grab
    .Parameter Scroll
    Scroll token to paginate through results
    .Link
    https://developer.greynoise.io/reference/gnql-1#gnqlquery-1
    .Example
    > Get-GNQLQuery -GNQLQuery 'last_seen:today' -Key $key
    returns information
    #>

    [cmdletbinding()]
    param(
        [Parameter(Mandatory)]
        $GNQLQuery,
        [parameter(Mandatory)]
        $Key,
        [Int32]$Size = 10000,
        $Scroll
    )
    $Uri = "https://api.greynoise.io/v2/experimental/gnql?query=$GNQLQuery&size=$Size"
    if ($scroll) {$uri = "$uri&scroll=$scroll"}
    $params = @{
        Headers = @{key = $Key}
        Uri     = $uri
    }
    Invoke-RestMethod @params
}

function Get-GNQLStats {
    <#
    .Description
    Get aggregate statistics for the top organizations, actors, tags, ASNs, countries, classifications, and operating systems of all the results of a given GNQL query.
    .Parameter GNQLQuery
    specify the GNQL query string. See the greynoise docs for usage details.
    .Parameter Count
    Number of top aggregates to grab
    .Parameter Key
    Specify the API key to use.
    .Example
    > Get-GNQLStats -Key $key -GNQLQuery '(raw_data.scan.port:445 and raw_data.scan.protocol:TCP) metadata.os:Windows*'
    Returns information
    .Link
    https://developer.greynoise.io/reference/gnql-1#gnqlstats-1
    #>

    [cmdletbinding()]
    param(
        [Parameter(Mandatory)]
        $GNQLQuery,
        [Int32]$count = 10000,
        [parameter(Mandatory)]
        $Key

    )
    $Uri = "https://api.greynoise.io/v2/experimental/gnql/stats?query=$GNQLQuery&count=$count"
    $params = @{
        Headers = @{key = $Key}
        Uri     = $uri
    }
    Invoke-RestMethod @params
}

function Get-GNTagMetadata {
    <#
    .Description
    Get a list of tags and their respective metadata
    .Parameter Key
    Specify the API key to use.
    .Example
    > Get-GNTagMetadata -key $key
    returns tags and their respective metadata
    .Link
    https://developer.greynoise.io/reference/metadata-2#metadata-3
    #>


    [cmdletbinding()]
    param(
        [parameter(Mandatory)]
        $Key
    )
    Invoke-RestMethod -Uri 'https://api.greynoise.io/v2/meta/metadata' -Headers @{key = $Key}
}