Reputation: 39
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 ()
Upvotes: 1
Views: 1464
Reputation: 439842
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.
Upvotes: 0
Reputation: 746
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.
Upvotes: 1