我正在尝试用Electron写一个小工具来调用Powershell脚本。
我知道如何从此线程将Powershell输出输出到我的脚本中:
https://stackoverflow.com/a/10181488/3161671
所以我有
<script>
var spawn = require("child_process").spawn,child;
child = spawn("powershell.exe",["C:\\PowershellScript\\get-process.ps1"]);
child.stdout.on("data",function(data){
console.log("Powershell Data: " + data);
});
child.stderr.on("data",function(data){
console.log("Powershell Errors: " + data);
});
child.on("exit",function(){
console.log("Powershell Script finished");
});
child.stdin.end(); //end input
</script>
但是,我不太了解如何从PS输出(例如
child.stdout.ProcessName
)中调用对象成员。我希望能够遍历输出并格式化表中的某些成员(如果这是合理的):
<table>
<tr>
<th>CPU(s)</th>
<th>Id</th>
<th>ProcessName</th>
</tr>
<tr>
<td>0,35</td>
<td>1824</td>
<td>conhost</td>
</tr>
<tr>
<td>1.725</td>
<td>3115</td>
<td>firefox</td>
</tr>
</table>
什么是最干净的方法来实现这一目标?我见过人们在他们的Powershell脚本中嵌入HTML标记,但是我认为使用JavaScript进行对象到HTML和格式设置更有意义,不是吗?
最佳答案
根据我的理解,在这种情况下,标准输出将无法正常工作,因为它将具有自己的格式化显示方式。除了 native Powershell转换外,我几乎没有其他转换功能。您应该尝试使用它们,然后再解析输出。
干得好:
为了便于理解,在注释部分中提到了用法。
<#
.SYNOPSIS
Creates a new PSObject where all properties of the original object that are not able to be
properly serialized to JSON are converted to a value which can be properly converted to JSON.
This includes the following types:
* DateTime
This conducts a deep property search
.Example
Convert an custom PSObject to have parsable dates in Json
$customObject = New-Object -TypeName PSobject -Property @{ Date = Get-Date; Number = 23; InnerDate = New-Object -TypeName PSObject -Property @{Date=Get-Date;} }
## BAD Json
PS C:\dev> $customObject | ConvertTo-Json
{
"Date": {
"value": "\/Date(1410372629047)\/",
"DisplayHint": 2,
"DateTime": "Wednesday, September 10, 2014 2:10:29 PM"
},
"Number": 23,
"InnerDate": {
"Date": {
"value": "\/Date(1410372629047)\/",
"DisplayHint": 2,
"DateTime": "Wednesday, September 10, 2014 2:10:29 PM"
}
}
}
## Good Json
PS C:\dev> $customObject | ConvertTo-JsonifiablePSObject | ConvertTo-Json
{
"Date": "2014-09-10T14:10:29.0477785-04:00",
"Number": 23,
"InnerDate": {
"Date": "2014-09-10T14:10:29.0477785-04:00"
}
}
#>
function ConvertTo-JsonifiablePSObject
{
param
(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[PSObject]$Object
)
$newObjectProperties = @{}
foreach ($property in $Object.psobject.properties)
{
$value = $property.Value
if ($property.TypeNameOfValue -eq "System.Management.Automation.PSCustomObject")
{
$value = ConvertTo-JsonifiablePSObject -Object $property.Value
}
elseif ($property.TypeNameOfValue -eq "System.DateTime")
{
$value = $property.Value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK")
}
$newObjectProperties[$property.Name] = $value
}
return New-Object -TypeName PSObject -Property $newObjectProperties
}
$json=$kbm | ConvertTo-Json
function ConvertTo-PSON
{
<#
.SYNOPSIS
creates a powershell object-notation script that generates the same object data
.DESCRIPTION
This produces 'PSON', the powerShell-equivalent of JSON from any object you pass to it. It isn't suitable for the huge objects produced by some of the cmdlets such as Get-Process, but fine for simple objects
.EXAMPLE
$array=@()
$array+=Get-Process wi* | Select-Object Handles,NPM,PM,WS,VM,CPU,Id,ProcessName
ConvertTo-PSON $array
.PARAMETER Object
the object that you want scripted out
.PARAMETER Depth
The depth that you want your object scripted to
.PARAMETER Nesting Level
internal use only. required for formatting
#>
[CmdletBinding()]
param (
[parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][AllowNull()] $inputObject,
[parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $false)] [int] $depth = 16,
[parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $false)] [int] $NestingLevel = 1,
[parameter(Position = 3, Mandatory = $false, ValueFromPipeline = $false)] [int] $XMLAsInnerXML = 0
)
BEGIN { }
PROCESS
{
If ($inputObject -eq $Null) { $p += '$Null'; return $p } # if it is null return null
$padding = [string]' ' * $NestingLevel # lets just create our left-padding for the block
$ArrayEnd=0; #until proven false
try
{
$Type = $inputObject.GetType().Name # we start by getting the object's type
if ($Type -ieq 'Object[]') { $Type = "$($inputObject.GetType().BaseType.Name)" } # see what it really is
if ($depth -ilt $NestingLevel) { $Type = 'OutOfDepth' } #report the leaves in terms of object type
elseif ($Type -ieq 'XmlDocument' -or $Type -ieq 'XmlElement')
{
if ($XMLAsInnerXML -ne 0) { $Type = 'InnerXML' }
else
{ $Type = 'XML' }
} # convert to PS Alias
# prevent these values being identified as an object
if (@('boolean', 'byte', 'char', 'datetime', 'decimal', 'double', 'float', 'single', 'guid', 'int', 'int32',
'int16', 'long', 'int64', 'OutOfDepth', 'RuntimeType', 'PSNoteProperty', 'regex', 'sbyte', 'string',
'timespan', 'uint16', 'uint32', 'uint64', 'uri', 'version', 'void', 'xml', 'datatable', 'List`1',
'SqlDataReader', 'datarow', 'ScriptBlock', 'type') -notcontains $type)
{
if ($Type -ieq 'OrderedDictionary') { $Type = 'HashTable' }
elseif ($Type -ieq 'PSCustomObject') { $Type = 'PSObject' } #
elseif ($inputObject -is "Array") { $Type = 'Array' } # whatever it thinks it is called
elseif ($inputObject -is "HashTable") { $Type = 'HashTable' } # for our purposes it is a hashtable
elseif (($inputObject | gm -membertype Properties | Select name | Where name -like 'Keys') -ne $null) { $Type = 'generic' } #use dot notation
elseif (($inputObject | gm -membertype Properties | Select name).count -gt 1) { $Type = 'Object' }
}
write-verbose "$($padding)Type:='$Type', Object type:=$($inputObject.GetType().Name), BaseName:=$($inputObject.GetType().BaseType.Name) $NestingLevel "
switch ($Type)
{
'ScriptBlock'{ "[$type] {$($inputObject.ToString())}" }
'InnerXML' { "[$type]@'`r`n" + ($inputObject.OuterXMl) + "`r`n'@`r`n" } # just use a 'here' string
'DateTime' { "[datetime]'$($inputObject.ToString('s'))'" } # s=SortableDateTimePattern (based on ISO 8601) local time
'Boolean' {
"[bool] $(&{
if ($inputObject -eq $true) { "`$True" }
Else { "`$False" }
})"
}
'string' {
if ($inputObject -match '[\r\n]') { "@'`r`n$inputObject`r`n'@" }
else { "'$($inputObject -replace '''', '''''')'" }
}
'Char' { [int]$inputObject }
{ @('byte', 'decimal', 'double', 'float', 'single', 'int', 'int32', 'int16', 'long', 'int64', 'sbyte', 'uint16', 'uint32', 'uint64') -contains $_ }
{ "$inputObject" } # rendered as is without single quotes
'PSNoteProperty' { "$(ConvertTo-PSON -inputObject $inputObject.Value -depth $depth -NestingLevel ($NestingLevel))" }
'Array' { "`r`n$padding@(" + ("$($inputObject | ForEach {$ArrayEnd=1; ",$(ConvertTo-PSON -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd)) + "`r`n$padding)" }
'HashTable' { "`r`n$padding@{" + ("$($inputObject.GetEnumerator() | ForEach {$ArrayEnd=1; "; '$($_.Name)' = " + (ConvertTo-PSON -inputObject $_.Value -depth $depth -NestingLevel ($NestingLevel + 1)) })".Substring($ArrayEnd) + "`r`n$padding}") }
'PSObject' { "`r`n$padding[pscustomobject]@{" + ("$($inputObject.PSObject.Properties | ForEach {$ArrayEnd=1; "; '$($_.Name)' = " + (ConvertTo-PSON -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1)) })".Substring($ArrayEnd) + "`r`n$padding}") }
'Dictionary' { "`r`n$padding@{" + ($inputObject.item | ForEach {$ArrayEnd=1; '; ' + "'$_'" + " = " + (ConvertTo-PSON -inputObject $inputObject.Value[$_] -depth $depth -NestingLevel $NestingLevel+1) }) + '}' }
'Generic' { "`r`n$padding@{" + ("$($inputObject.Keys | ForEach {$ArrayEnd=1; "; $_ = $(ConvertTo-PSON -inputObject $inputObject.$_ -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding}") }
'Object' { "`r`n$padding@{" + ("$($inputObject | Get-Member -membertype properties | Select-Object name | ForEach {$ArrayEnd=1; "; $($_.name) = $(ConvertTo-PSON -inputObject $inputObject.$($_.name) -depth $NestingLevel -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding}") }
'XML' { "`r`n$padding@{" + ("$($inputObject | Get-Member -membertype properties | where name -ne 'schema' | Select-Object name | ForEach {$ArrayEnd=1; "; $($_.name) = $(ConvertTo-PSON -inputObject $inputObject.$($_.name) -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding}") }
'Datatable' { "`r`n$padding@{" + ("$($inputObject.TableName)=`r`n$padding @(" + "$($inputObject | ForEach {$ArrayEnd=1; ",$(ConvertTo-PSON -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding )`r`n$padding}") }
'DataRow' { "`r`n$padding@{" + ("$($inputObject | Get-Member -membertype properties | Select-Object name | ForEach {$ArrayEnd=1; "; $($_.name)= $(ConvertTo-PSON -inputObject $inputObject.$($_.name) -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "}") }
default { "'$inputObject'" }
}
}
catch
{
write-error "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($inputObject.Name)' Class: $($inputObject.GetType().Name) BaseClass: $($inputObject.GetType().BaseType.Name) "
}
finally { }
}
END { }
}
function ConvertTo-YAML
{
<#
.SYNOPSIS
creates a YAML description of the data in the object
.DESCRIPTION
This produces YAML from any object you pass to it. It isn't suitable for the huge objects produced by some of the cmdlets such as Get-Process, but fine for simple objects
.EXAMPLE
$array=@()
$array+=Get-Process wi* | Select-Object Handles,NPM,PM,WS,VM,CPU,Id,ProcessName
ConvertTo-YAML $array
.PARAMETER Object
the object that you want scripted out
.PARAMETER Depth
The depth that you want your object scripted to
.PARAMETER Nesting Level
internal use only. required for formatting
#>
[CmdletBinding()]
param (
[parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][AllowNull()] $inputObject,
[parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $false)] [int] $depth = 16,
[parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $false)] [int] $NestingLevel = 0,
[parameter(Position = 3, Mandatory = $false, ValueFromPipeline = $false)] [int] $XMLAsInnerXML = 0
)
BEGIN { }
PROCESS
{
If ($inputObject -eq $Null) { $p += 'null'; return $p } # if it is null return null
if ($NestingLevel -eq 0) { '---' }
$padding = [string]' ' * $NestingLevel # lets just create our left-padding for the block
try
{
$Type = $inputObject.GetType().Name # we start by getting the object's type
if ($Type -ieq 'Object[]') { $Type = "$($inputObject.GetType().BaseType.Name)" } #what it really is
if ($depth -ilt $NestingLevel) { $Type = 'OutOfDepth' } #report the leaves in terms of object type
elseif ($Type -ieq 'XmlDocument' -or $Type -ieq 'XmlElement')
{
if ($XMLAsInnerXML -ne 0) { $Type = 'InnerXML' }
else
{ $Type = 'XML' }
} # convert to PS Alias
# prevent these values being identified as an object
if (@('boolean', 'byte', 'char', 'datetime', 'decimal', 'double', 'float', 'single', 'guid', 'int', 'int32',
'int16', 'long', 'int64', 'OutOfDepth', 'RuntimeType', 'PSNoteProperty', 'regex', 'sbyte', 'string',
'timespan', 'uint16', 'uint32', 'uint64', 'uri', 'version', 'void', 'xml', 'datatable', 'List`1',
'SqlDataReader', 'datarow', 'ScriptBlock', 'type') -notcontains $type)
{
if ($Type -ieq 'OrderedDictionary') { $Type = 'HashTable' }
elseif ($Type -ieq 'PSCustomObject') { $Type = 'PSObject' } #
elseif ($inputObject -is "Array") { $Type = 'Array' } # whatever it thinks it is called
elseif ($inputObject -is "HashTable") { $Type = 'HashTable' } # for our purposes it is a hashtable
elseif (($inputObject | gm -membertype Properties |
Select name | Where name -like 'Keys') -ne $null) { $Type = 'generic' } #use dot notation
elseif (($inputObject | gm -membertype Properties | Select name).count -gt 1) { $Type = 'Object' }
}
write-verbose "$($padding)Type:='$Type', Object type:=$($inputObject.GetType().Name), BaseName:=$($inputObject.GetType().BaseType.Name) "
switch ($Type)
{
'ScriptBlock'{ "{$($inputObject.ToString())}" }
'InnerXML' { "|`r`n" + ($inputObject.OuterXMl.Split("`r`n") | foreach{ "$padding$_`r`n" }) }
'DateTime' { $inputObject.ToString('s') } # s=SortableDateTimePattern (based on ISO 8601) using local time
'Boolean' {
"$(&{
if ($inputObject -eq $true) { '`true' }
Else { '`false' }
})"
}
'string' {
$String = "$inputObject"
if ($string -match '[\r\n]' -or $string.Length -gt 80)
{
# right, we have to format it to YAML spec.
">`r`n" # signal that we are going to use the readable 'newlines-folded' format
$string.Split("`n") | foreach {
$bits = @(); $length = $_.Length; $IndexIntoString = 0; $wrap = 80
while ($length -gt $IndexIntoString + $Wrap)
{
$earliest = $_.Substring($IndexIntoString, $wrap).LastIndexOf(' ')
$latest = $_.Substring($IndexIntoString + $wrap).IndexOf(' ')
$BreakPoint = &{
if ($earliest -gt ($wrap + $latest)) { $earliest }
else { $wrap + $latest }
}
if ($earliest -lt (($BreakPoint * 10)/100)) { $BreakPoint = $wrap } # in case it is a string without spaces
$padding + $_.Substring($IndexIntoString, $BreakPoint).Trim() + "`r`n"
$IndexIntoString += $BreakPoint
}
if ($IndexIntoString -lt $length) { $padding + $_.Substring($IndexIntoString).Trim() + "`r`n" }
else { "`r`n" }
}
}
else { "'$($string -replace '''', '''''')'" }
}
'Char' { "([int]$inputObject)" }
{
@('byte', 'decimal', 'double', 'float', 'single', 'int', 'int32', 'int16', `
'long', 'int64', 'sbyte', 'uint16', 'uint32', 'uint64') -contains $_
}
{ "$inputObject" } # rendered as is without single quotes
'PSNoteProperty' { "$(ConvertTo-YAML -inputObject $inputObject.Value -depth $depth -NestingLevel ($NestingLevel + 1))" }
'Array' { "$($inputObject | ForEach { "`r`n$padding- $(ConvertTo-YAML -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1))" })" }
'HashTable'{
("$($inputObject.GetEnumerator() | ForEach {
"`r`n$padding $($_.Name): " +
(ConvertTo-YAML -inputObject $_.Value -depth $depth -NestingLevel ($NestingLevel + 1))
})")
}
'PSObject' { ("$($inputObject.PSObject.Properties | ForEach { "`r`n$padding $($_.Name): " + (ConvertTo-YAML -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1)) })") }
'generic' { "$($inputObject.Keys | ForEach { "`r`n$padding $($_): $(ConvertTo-YAML -inputObject $inputObject.$_ -depth $depth -NestingLevel ($NestingLevel + 1))" })" }
'Object' { ("$($inputObject | Get-Member -membertype properties | Select-Object name | ForEach { "`r`n$padding $($_.name): $(ConvertTo-YAML -inputObject $inputObject.$($_.name) -depth $NestingLevel -NestingLevel ($NestingLevel + 1))" })") }
'XML' { ("$($inputObject | Get-Member -membertype properties | where-object { @('xml', 'schema') -notcontains $_.name } | Select-Object name | ForEach { "`r`n$padding $($_.name): $(ConvertTo-YAML -inputObject $inputObject.$($_.name) -depth $depth -NestingLevel ($NestingLevel + 1))" })") }
'DataRow' { ("$($inputObject | Get-Member -membertype properties | Select-Object name | ForEach { "`r`n$padding $($_.name): $(ConvertTo-YAML -inputObject $inputObject.$($_.name) -depth $depth -NestingLevel ($NestingLevel + 1))" })") }
# 'SqlDataReader'{$all = $inputObject.FieldCount; while ($inputObject.Read()) {for ($i = 0; $i -lt $all; $i++) {"`r`n$padding $($Reader.GetName($i)): $(ConvertTo-YAML -inputObject $($Reader.GetValue($i)) -depth $depth -NestingLevel ($NestingLevel+1))"}}
default { "'$inputObject'" }
}
}
catch
{
write-error "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($inputObject)' Class: $($inputObject.GetType().Name) BaseClass: $($inputObject.GetType().BaseType.Name) "
}
finally { }
}
END { }
}
注意:除了所有这些以外,还请尝试Convertto-json。
希望能帮助到你...
关于javascript - 将Powershell对象传递给Node.JS/Electron并将其 package 在HTML标记中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41353314/