child-shell
child-shell copied to clipboard
getting powershell output back into javascript
How can I get Powershell's output back into javascript as a object or array? My code is below. I'd like to be able to display the output of the command via html page.
const { PowerShell } = require('node-powershell');
const poshInstance = async () => {
const ps = new PowerShell({
executionPolicy: 'Bypass',
noProfile: true
});
const getLG = PowerShell.command`Get-LocalGroup`
const output = await ps.invoke(getLG)
await ps.dispose()
console.log(output)
}
poshInstance()
Hi, I have been doing this for an automation project
let output = await shell.invoke(`Get-VM -Server ${server.ip} | Select-Object -Property Name,Uid,PowerState | ConvertTo-Json -Compress -Depth 99`);
The output includes some whitespace and stuff, so I remove that
console.log(JSON.parse(output.raw.replace("\u001b[?1h\u001b[?1l", "").replace("[?1h[?1l[?1h[?1l", "")));
And thats it. Seems a bit fragile though, but I run everything in a docker container so hopefully won't have to worry.
New update on this. It seems that different commands produce different junk around the command. It seems deterministic, but very annoying. I do not get those warnings when running the same command in my normal powershell window, so not sure where they come from.
Command: Get-Datastore -Server ${server.ip} | Select-Object -Property FileSystemVersion, DatacenterId, ParentFolderId, DatastoreBrowserPath, FreeSpaceMB, CapacityMB, Accessible, Type, StorageIOControlEnabled, CongestionThresholdMillisecond, State, CapacityGB, FreeSpaceGB, Name, Id, Uid | ConvertTo-Json -Compress -Depth 99
Output when running through child-shell:
[33;1mWARNING: The 'Accessible' property of Datastore type is deprecated. Use the 'State' property instead.[0m
[{"FileSystemVersion":"6.82","DatacenterId":"Datacenter-ha-datacenter","ParentFolderId":"Folder-ha-folder-datastore","DatastoreBrowserPath":"vmstores:/192.168.10.52@443/ha-datacenter/ssd1","FreeSpaceMB":603047.0,"CapacityMB":953600.0,"Accessible":true,"Type":"VMFS","StorageIOControlEnabled":true,"CongestionThresholdMillisecond":30,"State":0,"CapacityGB":931.25,"FreeSpaceGB":588.9130859375,"Name":"ssd1","Id":"Datastore-61e490a4-59f7bc8a-f1d8-90b11c5a54ae","Uid":"/[email protected]:443/Datastore=Datastore-61e490a4-59f7bc8a-f1d8-90b11c5a54ae/"},{"FileSystemVersion":"6.82","DatacenterId":"Datacenter-ha-datacenter","ParentFolderId":"Folder-ha-folder-datastore","DatastoreBrowserPath":"vmstores:/192.168.10.52@443/ha-datacenter/ssd2","FreeSpaceMB":245392.0,"CapacityMB":953600.0,"Accessible":true,"Type":"VMFS","StorageIOControlEnabled":true,"CongestionThresholdMillisecond":30,"State":0,"CapacityGB":931.25,"FreeSpaceGB":239.640625,"Name":"ssd2","Id":"Datastore-61e490ad-d1082309-7bc2-90b11c5a54ae","Uid":"/[email protected]:443/Datastore=Datastore-61e490ad-d1082309-7bc2-90b11c5a54ae/"},{"FileSystemVersion":"6.82","DatacenterId":"Datacenter-ha-datacenter","ParentFolderId":"Folder-ha-folder-datastore","DatastoreBrowserPath":"vmstores:/192.168.10.52@443/ha-datacenter/ssd3","FreeSpaceMB":569929.0,"CapacityMB":953600.0,"Accessible":true,"Type":"VMFS","StorageIOControlEnabled":true,"CongestionThresholdMillisecond":30,"State":0,"CapacityGB":931.25,"FreeSpaceGB":556.5712890625,"Name":"ssd3","Id":"Datastore-61e490b8-58dac0d8-f426-90b11c5a54ae","Uid":"/[email protected]:443/Datastore=Datastore-61e490b8-58dac0d8-f426-90b11c5a54ae/"},{"FileSystemVersion":"3.0","DatacenterId":"Datacenter-ha-datacenter","ParentFolderId":"Folder-ha-folder-datastore","DatastoreBrowserPath":"vmstores:/192.168.10.52@443/ha-datacenter/TRUENAS","FreeSpaceMB":20457549.0,"CapacityMB":20582128.0,"Accessible":true,"Type":"NFS","StorageIOControlEnabled":false,"CongestionThresholdMillisecond":30,"State":0,"CapacityGB":20099.734375,"FreeSpaceGB":19978.0751953125,"Name":"TRUENAS","Id":"Datastore-192.168.10.160:/mnt/hddpool/vmware","Uid":"/[email protected]:443/Datastore=Datastore-192.168.10.160:&slash;mnt&slash;hddpool&slash;vmware/"}]
I solved it by adding $WarningPreference = 'SilentlyContinue';
before calling my command.
Hi, I have been doing this for an automation project
let output = await shell.invoke(`Get-VM -Server ${server.ip} | Select-Object -Property Name,Uid,PowerState | ConvertTo-Json -Compress -Depth 99`);
The output includes some whitespace and stuff, so I remove that
console.log(JSON.parse(output.raw.replace("\u001b[?1h\u001b[?1l", "").replace("�[?1h�[?1l�[?1h�[?1l", "")));
And thats it. Seems a bit fragile though, but I run everything in a docker container so hopefully won't have to worry.
You are seeing that "junk" output because all your PS logs are getting clumped into one output.
Do something like this and you will get a clean JSON output
Using the stream from the instance of node-powershell you can log each time data is output
You will see that you have multiple outputs
ps.streams.stdout.on('data', function (data) { console.log(data) })
Here's an example I'm using with node-powershell version 5.0.1 Things to note:
- inside the back-ticks after Shell.Powershell, you can basically write a power shell script (you need to escape pipes) but you can use variables, multiples lines etc
- If the code executes successfully, a response object is returned with the field 'raw' which contains the output. You can turn this field back into a Node JSON object to do further processing with the JSON.parse() method as long as you convert the powershell to JSON first
- If PowerShell returns an error, it gets caught in the catch block where you can print the errors or whatever you like with it
const Shell = require('node-powershell');
let psOut = await Shell.PowerShell.$`
$myuser = "stuieordie"
Get-ADUser $myuser \| ConvertTo-Json
`
.then(response => {
// return the entire response object
// return response
// Or parse the raw field and return a JSON object of the command output
return JSON.parse(response.raw)
})
.catch(err => {
console.log(err)
});
console.log(psOut.SamAccountName)
'stuieordie'
Alternatively if you want to use async/await this is another example
async function getADUser(username) {
try {
let getUserObj = await Shell.PowerShell.$`
$strDC = Get-ADDomainController -Discover -DomainName example.com \| Select-Object -ExpandProperty HostName
Get-ADUser -Server $strDC -Identity ${getObj.value} \| ConvertTo-Json
`
let userObj = {
"userName": JSON.parse(getUserObj.raw).SamAccountName,
"active": JSON.parse(getUserObj.raw).Enabled.toString().toLowerCase(),
"id": JSON.parse(getUserObj.raw).SamAccountName
}
return userObj
} catch (error) {
let userObj = []
return userObj
}
}
getADUser("stuieordie")
Here's an example I'm using with node-powershell version 5.0.1 Things to note:
- inside the back-ticks after Shell.Powershell, you can basically write a power shell script (you need to escape pipes) but you can use variables, multiples lines etc
- If the code executes successfully, a response object is returned with the field 'raw' which contains the output. You can turn this field back into a Node JSON object to do further processing with the JSON.parse() method as long as you convert the powershell to JSON first
- If PowerShell returns an error, it gets caught in the catch block where you can print the errors or whatever you like with it
const Shell = require('node-powershell'); let psOut = await Shell.PowerShell.$` $myuser = "stuieordie" Get-ADUser $myuser \| ConvertTo-Json ` .then(response => { // return the entire response object // return response // Or parse the raw field and return a JSON object of the command output return JSON.parse(response.raw) }) .catch(err => { console.log(err) }); console.log(psOut.SamAccountName) 'stuieordie'
Alternatively if you want to use async/await this is another example
async function getADUser(username) { try { let getUserObj = await Shell.PowerShell.$` $strDC = Get-ADDomainController -Discover -DomainName example.com \| Select-Object -ExpandProperty HostName Get-ADUser -Server $strDC -Identity ${getObj.value} \| ConvertTo-Json ` let userObj = { "userName": JSON.parse(getUserObj.raw).SamAccountName, "active": JSON.parse(getUserObj.raw).Enabled.toString().toLowerCase(), "id": JSON.parse(getUserObj.raw).SamAccountName } return userObj } catch (error) { let userObj = [] return userObj } } getADUser("stuieordie")
Thanks for the neat code. Any suggestions how to pass { executionPolicy: 'Bypass', noProfile: true } to Shell.PowerShell? I tried but it did not work, saying that only newing it we can provide parameters.
let psOut = await Shell.PowerShell({
executionPolicy: 'Bypass',
noProfile: true
}).$`
$myuser = "stuieordie"
Get-ADUser $myuser \| ConvertTo-Json
If no other way, I think that I'll need to new it and psOut.invoke(somecmd)...