powershellinvoke-restmethodobject-graph

PowerShell odd behavior with Invoke-RestMethod Object returned from VirusTotal API


I am following the directions according to https://docs.virustotal.com/reference/url-info

And I successfully get a response from VirusTotal API when I:

$id="u-31ca9778a9aca7d961f20e0ac4a6cf9cb6de2122046a947049404b06d2b55c74-1744337837"
$Method = get
$EndPoint = "https://www.virustotal.com/api/v3/urls/$id"

$URLReport = Invoke-RestMethod -Uri $EndPoint -Method $Method -Headers $Headers -ErrorVariable InvokeRestMethodError

When I ConvertTo-JSON -InputObject $URLReport, and output to a file, I get:

{
    "data":  {
                 "id":  "31ca9778a9aca7d961f20e0ac4a6cf9cb6de2122046a947049404b06d2b55c74",
                 "type":  "url",
                 "links":  {
                               "self":  "https://www.virustotal.com/api/v3/urls/31ca9778a9aca7d961f20e0ac4a6cf9cb6de2122046a947049404b06d2b55c74"
                           },
                 "attributes":  {
                                    "total_votes":  "@{harmless=0; malicious=1}",
                                    "last_modification_date":  1744337850,
                                    "first_submission_date":  1347658566,
                                    "last_http_response_code":  200,
                                    "html_meta":  "@{title=System.Object[]; description=System.Object[]; robots=System.Object[]; viewport=System.Object[]; og:type=System.Object[]; og:locale=System.Object[]; og:site_name=System.Object[]; og:title=System.Object[]; og:description=System.Object[]; og:url=System.Object[]}",
                                    "trackers":  "@{Google Tag Manager=System.Object[]; AppNexus=System.Object[]; Bing Ads=System.Object[]; Facebook Connect=System.Object[]; Facebook Custom Audience=System.Object[]; New Relic=System.Object[]}",
                                    "last_submission_date":  1744337837,
                                    "tags":  "trackers third-party-cookies multiple-redirects external-resources iframes",
                                    "reputation":  -1,
                                    "last_analysis_stats":  "@{malicious=0; suspicious=0; undetected=29; harmless=68; timeout=0}",
                                    "url":  "http://water.com/",
                                    "outgoing_links":  "https://www.primobrands.com/ https://www.google.com/url?sa=t\u0026source=web\u0026rct=j\u0026opi=89978449\u0026url=https://www.instagram.com/primowater/\u0026ved=2ahUKEwi6jaGwtc-IAxVPMlkFHa4ZFpUQFnoECBgQAQ\u0026usg=AOvVaw3T72_bgrJOFFTpYD8Z27Ad https://policies.google.com/terms https://a4ws.org/ https://primowatercorp.com/careers/ https://www.linkedin.com/company/primobrands/ https://www.primobrands.com/privacy-policy/ https://www.google.com/url?sa=t\u0026source=web\u0026rct=j\u0026opi=89978449\u0026url=https://www.youtube.com/%40primowaterco\u0026ved=2ahUKEwilu-i8tc-IAxVHMVkFHfmaKj8QFnoECBgQAQ\u0026usg=AOvVaw0ZCVB1lwBuHbIU3JEhYQYF https://www.facebook.com/PrimoWaterCorp/ https://policies.google.com/privacy",
                                    "last_analysis_results":  "@{Artists Against 419=; Acronis=; Abusix=; ADMINUSLabs=; Lionic=; Criminal IP=; AILabs (MONITORAPP)=; AlienVault=; alphaMountain.ai=; AlphaSOC=; Antiy-AVL=; ArcSight Threat Intelligence=; AutoShun=; Axur=; benkow.cc=; Bfore.Ai PreCrime=; BitDefender=; Bkav=; BlockList=; Blueliv=; Certego=; Chong Lua Dao=; CINS Army=; Snort IP sample list=; Cluster25=; CMC Threat Intelligence=; Xcitium Verdict Cloud=; CRDF=; CSIS Security Group=; Cyan=; Cyble=; CyRadar=; desenmascara.me=; DNS8=; Dr.Web=; Emsisoft=; Ermes=; ESET=; ESTsecurity=; EmergingThreats=; Feodo Tracker=; Fortinet=; G-Data=; Google Safebrowsing=; GCP Abuse Intelligence=; GreenSnow=; Gridinsoft=; Heimdal Security=; Hunt.io Intelligence=; IPsum=; Juniper Networks=; Kaspersky=; Lumu=; Malwared=; MalwareURL=; MalwarePatrol=; malwares.com URL checker=; Mimecast=; Netcraft=; OpenPhish=; 0xSI_f33d=; Phishing Database=; PhishFort=; PhishLabs=; Phishtank=; PREBYTES=; PrecisionSec=; Quick Heal=; Quttera=; Rising=; SafeToOpen=; Sangfor=; Sansec eComscan=; Scantitan=; SCUMWARE.org=; Seclookup=; SOCRadar=; Sophos=; Spam404=; StopForumSpam=; Sucuri SiteCheck=; securolytics=; Threatsourcing=; ThreatHive=; Trustwave=; Underworld=; URLhaus=; URLQuery=; Viettel Threat Intelligence=; VIPRE=; ViriBack=; VX Vault=; Webroot=; Forcepoint ThreatSeeker=; Yandex Safebrowsing=; ZeroCERT=; ZeroFox=}",
                                    "last_analysis_date":  1744337837,
                                    "threat_names":  "",
                                    "categories":  "@{alphaMountain.ai=Business/Economy, Marketing/Merchandising (alphaMountain.ai); BitDefender=business; Xcitium Verdict Cloud=food \u0026 dining; Sophos=general business; Forcepoint ThreatSeeker=business and economy}",
                                    "last_http_response_content_sha256":  "7522a990d6362284f5eda4eec6024b8ad1ee0923cb321ac5060239b42a62bcfd",
                                    "last_http_response_headers":  "@{Connection=keep-alive; Content-Length=1363806; pragma=cache; x-content-type-options=nosniff; content-type=text/html; charset=UTF-8; x-frame-options=SAMEORIGIN; x-platform-server=i-287071de55a66ebd, i-287071de55a66ebd; x-debug-info=eyJyZXRyaWVzIjowfQ==; x-xss-protection=1; mode=block; expires=Fri, 11 Apr 2025 21:43:38 GMT; x-timer=S1744321418.704391,VS0,VE1583; traceresponse=00-183513166d2068323e89918bf134842c-0f3da5997317ffa9-01; content-security-policy-report-only=font-src fonts.gstatic.com use.typekit.net data: \u0027self\u0027 \u0027unsafe-inline\u0027; form-action https://api.bazaarvoice.com https://stg.api.bazaarvoice.com \u0027self\u0027 \u0027unsafe-inline\u0027; frame-ancestors https://app.storyblok.com \u0027self\u0027; frame-src bid.g.doubleclick.net https://www.google.com/recaptcha/ https://api.bazaarvoice.com https://stg.api.bazaarvoice.com https://display.ugc.bazaarvoice.com https://www.googletagmanager.com https://player.vimeo.com https://*.doubleclick.net https://insight.adsrvr.org https://*.adsrvr.org \u0027self\u0027 \u0027unsafe-inline\u0027; img-src widgets.magentocommerce.com data: www.googleadservices.com www.google-analytics.com googleads.g.doubleclick.net www.google.com bid.g.doubleclick.net analytics.google.com www.googletagmanager.com p.typekit.net https://images.unsplash.com https://maps.googleapis.com https://*.gstatic.com https://ib.adnxs.com https://secure.adnxs.com https://*.bazaarvoice.com https://bat.bing.com https://www.facebook.com https://adservice.google.com https://flask.nextdoor.com https://i.vimeocdn.com https://sp.analytics.yahoo.com https://img.youtube.com https://*.doubleclick.net https://cdn.cookielaw.org https://*.monetate.net data: \u0027self\u0027 \u0027unsafe-inline\u0027; script-src www.googleadservices.com www.google-analytics.com googleads.g.doubleclick.net analytics.google.com www.googletagmanager.com *.newrelic.com *.nr-data.net https://www.gstatic.com/recaptcha/ https://www.google.com/recaptcha/ assets.adobedtm.com amcglobal.sc.omtrdc.net *.magento-ds.com use.typekit.net https://app.storyblok.com *.tokenex.com https://maps.googleapis.com https://cdn.jsdelivr.net https://acdn.adnxs.com https://*.bazaarvoice.com https://bat.bing.com https://mpsnare.iesnare.com https://resources.digital-cloud-west.medallia.com https://ads.nextdoor.com https://container.pepperjam.com https://cdn.resonate.com https://www.upsellit.com https://vimeo.com https://player.vimeo.com https://www.vimeo.com https://connect.facebook.net https://js.adsrvr.org https://cdn.cookielaw.org https://*.fullstory.com https://*.monetate.net \u0027self\u0027 \u0027unsafe-inline\u0027 \u0027unsafe-eval\u0027; style-src fonts.googleapis.com https://*.googletagmanager.com https://cdn.jsdelivr.net https://display.ugc.bazaarvoice.com \u0027self\u0027 \u0027unsafe-inline\u0027; object-src \u0027self\u0027 \u0027unsafe-inline\u0027; media-src \u0027self\u0027 \u0027unsafe-inline\u0027; manifest-src \u0027self\u0027 \u0027unsafe-inline\u0027; connect-src www.google-analytics.com www.googleadservices.com analytics.google.com www.googletagmanager.com *.newrelic.com *.nr-data.net *.adobe.io performance.typekit.net *.sentry.io data: https://*.readyrefresh.com https://*.googleapis.com https://ib.adnxs.com https://*.bazaarvoice.com https://bat.bing.com https://bat.bing.net https://*.google.com https://geolocation.onetrust.com https://ds.reson8.com https://cdn.cookielaw.org https://*.fullstory.com https://*.doubleclick.net \u0027self\u0027 \u0027unsafe-inline\u0027; child-src http: https: blob: \u0027self\u0027 \u0027unsafe-inline\u0027; default-src \u0027self\u0027 \u0027unsafe-inline\u0027 \u0027unsafe-eval\u0027; base-uri \u0027self\u0027 \u0027unsafe-inline\u0027;; x-built-with=Hyva Themes; Content-Encoding=br; Accept-Ranges=bytes; Date=Fri, 11 Apr 2025 02:17:19 GMT; Age=16420; X-Served-By=cache-iad-kjyo7100160-IAD, cache-iad-kjyo7100160-IAD, cache-chi-klot8100083-CHI; X-Cache=MISS, HIT, HIT; X-Cache-Hits=0, 7, 1; Cache-Control=no-store, no-cache, must-revalidate, max-age=0; Vary=Accept-Encoding,Cookie; Strict-Transport-Security=max-age=31557600}",
                                    "last_final_url":  "https://www.water.com/",
                                    "tld":  "com",
                                    "last_http_response_content_length":  1363806,
                                    "times_submitted":  618,
                                    "title":  "Water Delivery for Your Home \u0026 Business | Primo Water",
                                    "redirection_chain":  "http://water.com/ https://water.com/"
                                }
             }
}

BUT when I try to access the $URLReport data I get $null values. See Below

$URLData | Add-Member -MemberType NoteProperty -Name 'URLReport_title' -Value $URLReport.attributes.title -ErrorVariable AddMemberError -ErrorAction 1

            try{

                $URLData.URLReport_title.GetType()

            } catch {

                $ErrorMessage = $_.Exception.Message

                $LogEntry = "SYSTEM ERROR $ErrorMessage"

                Write-Host $LogEntry

            } finally { $ErrorActionPreference = 2 }

            try{

                $URLReport.attributes.title.GetType()

            } catch {

                $ErrorMessage = $_.Exception.Message

                $LogEntry = "SYSTEM ERROR $ErrorMessage"

                Write-Host $LogEntry

            } finally { $ErrorActionPreference = 2 }

OUTPUT:

SYSTEM ERROR You cannot call a method on a null-valued expression.

SYSTEM ERROR You cannot call a method on a null-valued expression.

SO, I URLReport.GetType(), and this is what I get

START

    Module                     : System.Management.Automation.dll
    Assembly                   : System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
    TypeHandle                 : System.RuntimeTypeHandle
    DeclaringMethod            :
    BaseType                   : System.Object
    UnderlyingSystemType       : System.Management.Automation.PSCustomObject
    FullName                   : System.Management.Automation.PSCustomObject
    AssemblyQualifiedName      : System.Management.Automation.PSCustomObject, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
    Namespace                  : System.Management.Automation
    GUID                       : 5f6aa156-8585-35c9-a6ae-2aefd06aaa4a
    IsEnum                     : False
    GenericParameterAttributes :
    IsSecurityCritical         : True
    IsSecuritySafeCritical     : False
    IsSecurityTransparent      : False
    IsGenericTypeDefinition    : False
    IsGenericParameter         : False
    GenericParameterPosition   :
    IsGenericType              : False
    IsConstructedGenericType   : False
    ContainsGenericParameters  : False
    StructLayoutAttribute      : System.Runtime.InteropServices.StructLayoutAttribute
    Name                       : PSCustomObject
    MemberType                 : TypeInfo
    DeclaringType              :
    ReflectedType              :
    MetadataToken              : 33554741
    GenericTypeParameters      : {}
    DeclaredConstructors       : {Void .ctor(), Void .cctor()}
    DeclaredEvents             : {}
    DeclaredFields             : {SelfInstance}
    DeclaredMembers            : {System.String ToString(), Void .ctor(), Void .cctor(), SelfInstance}
    DeclaredMethods            : {System.String ToString()}
    DeclaredNestedTypes        : {}
    DeclaredProperties         : {}
    ImplementedInterfaces      : {}
    TypeInitializer            : Void .cctor()
    IsNested                   : False
    Attributes                 : AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
    IsVisible                  : True
    IsNotPublic                : False
    IsPublic                   : True
    IsNestedPublic             : False
    IsNestedPrivate            : False
    IsNestedFamily             : False
    IsNestedAssembly           : False
    IsNestedFamANDAssem        : False
    IsNestedFamORAssem         : False
    IsAutoLayout               : True
    IsLayoutSequential         : False
    IsExplicitLayout           : False
    IsClass                    : True
    IsInterface                : False
    IsValueType                : False
    IsAbstract                 : False
    IsSealed                   : False
    IsSpecialName              : False
    IsImport                   : False
    IsSerializable             : False
    IsAnsiClass                : True
    IsUnicodeClass             : False
    IsAutoClass                : False
    IsArray                    : False
    IsByRef                    : False
    IsPointer                  : False
    IsPrimitive                : False
    IsCOMObject                : False
    HasElementType             : False
    IsContextful               : False
    IsMarshalByRef             : False
    GenericTypeArguments       : {}
    CustomAttributes           : {}

I have never seen this before. I am using PowerShell 5.1

I was under the assumption that I can access the members of an object through dot notation (i.e, URLReport.Attributes.title)

How can access the keys and values for the Invoke-RestMethod object I got?

Thanx


Solution

  • A couple things:

    1. The property requires a reference to data. data.attributes.title instead of attributes.title.

    2. Then use URLReport consistency, you are just adding a property to the existing object, rather than creating a new object. No separate variable needed.

    $URLReport | Add-Member -MemberType NoteProperty -Name 'URLReport_title' -Value 
    $URLReport.data.attributes.title -ErrorVariable AddMemberError -ErrorAction 1 
    
    $URLReport.URLReport_title