1

I am running a PowerShell script on a server to check on other machines on the network. I want the result of the check to be outputted in JSON format so I can send this JSON data via an api request to a web dashboard build with angular.

My set up:

Get-Request from Angular front end -> Express server -> run PowerShell script with Node-Powershell

Now I want to return the result in proper format to be used in the front end. What is the best way to accomplish this? I want to use the data to fill a material data table.

PowerShell Script status.ps1:

$Computers = @('ExampleComputer01', 'ExampleComputer02', 'ExampleComputer03', 'ExampleComputer04')
foreach ($computer in $Computers) {
gsv -cn $computer -Name ExampleProgram -ErrorAction 'SilentlyContinue'| select-object machinename, status | ConvertTo-Json 
}

Api from express server.js (using Node-Powershell):

app.get('/api/psjson', (request, response) => {
  ps.addCommand('./status.ps1');
  ps.invoke().then(output => {
    console.log(output);
    response.send(JSON.parse(output));
  }).catch(err => {
    console.log(err);
    response.send(err);
    ps.dispose();
  });
});

I tried using | ConvertTo-Json inside the loop but it is causing in error in node:

SyntaxError: Unexpected token { in JSON at position 55 at JSON.parse ()

5
  • "but that is not having the desired effect." - well, what effect is it having, and how does that deviate from your expectations? Commented Feb 24, 2021 at 16:21
  • I am getting an error in node:SyntaxError: Unexpected token { in JSON at position 55 at JSON.parse (<anonymous>) Commented Feb 24, 2021 at 16:25
  • And what is the raw value of output? The error indicates it's not valid JSON, but hard to say what's wrong with it without seeing it :-) Commented Feb 24, 2021 at 16:28
  • you are correct. It is not valid json. Output is: { "MachinenName": "Computer01", "Status": 4 } { "MachinenName": "Computer02", "Status": 4 } and so on... I am looking for a way to get valid json output from the powershelgl script. Commented Feb 24, 2021 at 16:34
  • I think the problem is running ConvertTo-Json inside the loop. Is there a way to run through the loop, check all Machines and then output all the results as on valid JSON? Commented Feb 24, 2021 at 16:36

2 Answers 2

1

Please try the following:

$Computers = @('ExampleComputer01', 'ExampleComputer02', 'ExampleComputer03', 'ExampleComputer04')
$Results = @()
foreach ($computer in $Computers) {
    $Result = $null
    $Result = gsv -cn $computer -Name ExampleProgram -ErrorAction 'SilentlyContinue'| select-object machinename, status
    If ($Result -ne $null){
        $Results += $Result
    }
}

$Results | ConvertTo-Json

This builds an array of the results and then converts the array to JSON.

I think the issue you are experiencing is due to converting inside a loop and therefore the structure is incorrect.

Sign up to request clarification or add additional context in comments.

1 Comment

Kudos for recognizing the need to feed all input objects to a single ConvertTo-Json call, but note that, in general, incrementally "extending" an array in a loop is inefficient, because a new array must be created behind the scenes in every iteration, because arrays are immutable; a much more efficient approach is to use the foreach loop as an expression and let PowerShell automatically collect the outputs in an array: [array] $outputs = foreach (...) { ... } - see this answer.
0

CraftyB's answer diagnoses the problem correctly, but there's a simpler, more PowerShell-idiomatic solution that uses a single pipeline:

$computers = 'ExampleComputer01', 'ExampleComputer02', 'ExampleComputer03', 'ExampleComputer04'

gsv -cn $computers -Name Example -ErrorAction SilentlyContinue |
  | Select-Object machinename, status | 
      ConvertTo-Json
  • The crucial aspect is that all input objects are passed to a single ConvertTo-Json call - see the bottom section for an explanation.

  • In Windows PowerShell, Get-Service (gsv) the -ComputerName (-cn) parameter directly accepts an array of computer names.

    • Note: In PowerShell (Core) 7+, this form of remoting is no longer supported, so there is no -ComputerName parameter; there, assuming that the target computers are set up for PowerShell remoting, you could use:

      Invoke-Command -ComputerName $computers { Get-Service -Name Example -ErrorAction SilentlyContinue }
      

As for what you tried:

If you call ConvertTo-Json inside a loop, per input object, you will implicitly output multiple, independent JSON strings instead of a single JSON string representing the input objects as a JSON array:

Given the following sample input objects:

$objects = [pscustomobject] @{ foo=1 }, [pscustomobject] @{ foo=2 }

It is the difference between:

# !! BROKEN: *multiple* ConvertTo-Json calls.
# !! When the result is stringified, you get a space-separated list of the 
# !! individual JSON strings, which is NOT valid JSON.
PS> @"
$(
  foreach ($object in $objects) { $object | ConvertTo-Json -Compress }
)
"@

{"foo":1} {"foo":2}  # NOT valid JSON.

and:

# OK: *Single* ConvertTo-Json call, which outputs a valid JSON array.
PS> $objects | ConvertTo-Json -Compress

[{"foo":1},{"foo":2}]  # OK: valid JSON array.

3 Comments

This works, and thank you for the further insight into PowerShell. Is it ok to add a follow up question? I have a "lookup-table" in my powershell script, assigning more easy to understand names to the computers (eg. W12345 = 'East Building PC 1') is there an elegant way to include this information into the json output?
Thanks for accepting, @JohnBauer. As for the follow-up question: You need to use a calculated property, something along the lines of: Select-Object machinename, status, @{ name='Comment'; e={ $lookupTable[$_.machinename] } If you need further assistance, please create a new question post.
thanks for the follow-up. this worked as well!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.