Forum Discussion

Procradminator's avatar
Procradminator
Copper Contributor
Oct 16, 2023

API calls with Invoke-RestMethod being funny!

Hello all

 

I suspect I'm missing something simple and hopefully someone will quickly point me in the right direction.

 

Please excuse the terrible code - I'll try and sort it once it works.....honest!

 

I'll calling the API of my DNS hosting company and using two calls, one to enable DNSSEC and the second to retreive the DS records so I can then post them to my domain registrar.

 

The frustrating thing is if I do one call followed by the second at the PS prompt I get a response from each as expected. If I do it in a script I don't get a response from the second call and I can't figure out what to do to make it work.

 

InvokeRestMethod - Uri "https://api.cloudns.net/dns/activate-dnssec.json?auth-id=12345&auth-password=mypassword&domain-name=somedomain.com"

 

Output is (all good) :

status statusDescription
------ -----------------
Success The DNSSEC is activated for your zone. The keys will be generated soon.

 

InvokeRestMethod - Uri https://api.cloudns.net/dns/get-dnssec-ds-records.json?auth-id=12345&auth-password=mypassword&domain-name=somedomain.com

 

Output is (all good) :

status : 1
ds : {somedomain.com. 3600 IN DS 48181 13 2 565D376B80152SDF88GDH9HDF76DGSGSDGD0F9DGHGF993D2AD87BD311E0}
ds_records : {@{digest=565D376B80152002711100B3B691046C31686C81DFE40690993D2AD87BD311E0; key_tag=48181; algorithm=13; algorithm_name=ECDSA SHA-256;
digest_type=2; digest_type_name=SHA-256}}
dnskey : {somedomain.com. 3600 IN DNSKEY 257 3 13 9xxxxxxxxxxxxxxxxxxxxxxxxxx0OMfevVvMaox96NH+UxuL1Eg+WV/gVLC/UxzX+bx/BkTDYjtirA3EztQ==,
somedomain.com. 3600 IN DNSKEY 256 3 13 iNrR5+Hlt4pf3nnBxxxxxxxxxxxxxxxxxxxxxxxxxxstGA3PsaJInL1LenhYGQOoi1aV1SnJK1V13ujfsQQMA==}
optout : 1

 

Run them together from a script (two lines, nothing else) and the output is :

status statusDescription
------ -----------------
Success The DNSSEC is activated for your zone. The keys will be generated soon.
1

 

Makes no sense to me.

TIA

Andrew

 

 

  • Procradminator 

     

    Hi, Andrew.

     

    This is expected, as the stream output from your first command produces an object that is not the same as the stream output from the second command.

     

    When you run the two commands together within the script, generally, their separate output will be written to the parent script's output stream, meaning what was separate is now "concatenated" into one stream.

     

    When you have objects of different types written to the same stream in close proximity like what you've described, PowerShell only looks at the first object type from the stream (from which it builds a dictionary of attribute names) and outputs - to the screen - attributes from subsequent objects that existed in the first object.

     

    You can reproduce this "first object type wins" scenario with the following contrived example.

     

    Example

    $Output = @(
        # First object with two properties.
        [PSCustomObject] @{
            "Property1" = "Value1";
            "Property2" = "Value2";
        },
    
        # Second object with three different properties.
        [PSCustomObject] @{
            "Property3" = 3;
            "Property4" = 4;
            "Property5" = $true;
        }
    )

     

    Output

    The first command shows PowerShell only displaying the first object within Output since the second doesn't match, yet it's still present as shown when the second object is explicitly referenced.

     

    Notice how the second object is not written to the screen at all since it has no attributes in common with the first object? Yet it still clearly exists in the data?

     

     

    So, how does this relate to your script? After all, you're running separate commands, not an array like my example.

     

    This comes back to what I said about "close proximity".

     

    From the first command, you're getting output that includes two attributes:

     

    • status
    • statusDescription

     

    From the second command, you get seven attributes, however, only one of those is common with the first command:

     

    • status

     

    This is why you see the full output from your first command but only the "status" attribute from the second.

     

    If all you care about is the displayed output rather than the actual data stream, you can "control" this "issue" by appending a "Out-Default" command to the end of each command like so:

     

    # First command.
    Invoke-RestMethod <blah blah blah> | Out-Default;
    
    # Second command.
    Invoke-RestMethod <blee blee blee> | Out-Default;

     

    The Out-Default will force the output of each command to be written to the display (which is typically the default device).

     

    In summary, the issue is that the two commands produce different output which impacts what is displayed on the screen when run inside a script, but not what is returned in the data stream of that script.

     

    You can "fix" the screen output by appending Out-Default to your individual commands.

     

    Cheers,

    Lain

  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    Procradminator 

     

    Hi, Andrew.

     

    This is expected, as the stream output from your first command produces an object that is not the same as the stream output from the second command.

     

    When you run the two commands together within the script, generally, their separate output will be written to the parent script's output stream, meaning what was separate is now "concatenated" into one stream.

     

    When you have objects of different types written to the same stream in close proximity like what you've described, PowerShell only looks at the first object type from the stream (from which it builds a dictionary of attribute names) and outputs - to the screen - attributes from subsequent objects that existed in the first object.

     

    You can reproduce this "first object type wins" scenario with the following contrived example.

     

    Example

    $Output = @(
        # First object with two properties.
        [PSCustomObject] @{
            "Property1" = "Value1";
            "Property2" = "Value2";
        },
    
        # Second object with three different properties.
        [PSCustomObject] @{
            "Property3" = 3;
            "Property4" = 4;
            "Property5" = $true;
        }
    )

     

    Output

    The first command shows PowerShell only displaying the first object within Output since the second doesn't match, yet it's still present as shown when the second object is explicitly referenced.

     

    Notice how the second object is not written to the screen at all since it has no attributes in common with the first object? Yet it still clearly exists in the data?

     

     

    So, how does this relate to your script? After all, you're running separate commands, not an array like my example.

     

    This comes back to what I said about "close proximity".

     

    From the first command, you're getting output that includes two attributes:

     

    • status
    • statusDescription

     

    From the second command, you get seven attributes, however, only one of those is common with the first command:

     

    • status

     

    This is why you see the full output from your first command but only the "status" attribute from the second.

     

    If all you care about is the displayed output rather than the actual data stream, you can "control" this "issue" by appending a "Out-Default" command to the end of each command like so:

     

    # First command.
    Invoke-RestMethod <blah blah blah> | Out-Default;
    
    # Second command.
    Invoke-RestMethod <blee blee blee> | Out-Default;

     

    The Out-Default will force the output of each command to be written to the display (which is typically the default device).

     

    In summary, the issue is that the two commands produce different output which impacts what is displayed on the screen when run inside a script, but not what is returned in the data stream of that script.

     

    You can "fix" the screen output by appending Out-Default to your individual commands.

     

    Cheers,

    Lain

    • Procradminator's avatar
      Procradminator
      Copper Contributor
      I really apprecaite you taking the time to answer so well and comprehensively @Lain. You explained beautifully so I not only understand but have a workaround.

      Many thanks.

      Cheers
      Andrew

Resources