rannn505 / child-shell

Node.js bindings 🔗 for shell
http://rannn505.github.io/child-shell/
MIT License
299 stars 71 forks source link

getting powershell output back into javascript #147

Open Thraxll opened 2 years ago

Thraxll commented 2 years ago

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()
Danielv123 commented 2 years ago

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.

Danielv123 commented 2 years ago

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

image

Output when running through child-shell:

WARNING: The 'Accessible' property of Datastore type is deprecated. Use the 'State' property instead.
[{"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":"/VIServer=root@192.168.10.52: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":"/VIServer=root@192.168.10.52: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":"/VIServer=root@192.168.10.52: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":"/VIServer=root@192.168.10.52:443/Datastore=Datastore-192.168.10.160:&slash;mnt&slash;hddpool&slash;vmware/"}]

I solved it by adding $WarningPreference = 'SilentlyContinue'; before calling my command.

mayerlench commented 2 years ago

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) })

stuieordie commented 2 years ago

Here's an example I'm using with node-powershell version 5.0.1 Things to note:

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")
msdiniz commented 1 year ago

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)...