有选择地格式化PowerShell管道中的数据并以HTML格式输出的技术

hal*_*000 2 html css xml powershell

假设您想要对powershell的某些表格输出进行一些奇特的格式化,目标是html(对于Web服务器,或者要通过电子邮件发送).例如,假设您希望某些数值具有不同的背景颜色.随你.我可以想到两种可靠的编程方法来实现这一点:使用XSLT输出XML和转换,或输出HTML并使用CSS进行装饰.

XSLT可能是两者中较难的(我说是因为我不知道),但是从我记忆中的一点点来看,它具有能够嵌入上述花式格式的选择标准(xpath?)的好处.另一方面,CSS需要帮助.如果你想要特殊处理某个单元格,那么你需要将它与兄弟姐妹的类别,id或类似的东西区分开来.PowerShell本身并没有办法实现这一点,因此这意味着在离开convertto-html并添加例如"强调"类时解析HTML:

<td class="emphasis">32MB</td>
Run Code Online (Sandbox Code Playgroud)

我不喜欢所需文本解析的想法,特别是考虑到我希望能够以某种方式强调在击中HTML之前需要在Powershell中强调什么.

XSLT是最好的方法吗?有关于如何在转换为HTML或其他方式的想法后标记HTML的建议吗?

Jay*_*kul 7

如何使用JQuery,并插入带有JQUery脚本和一些样式的头文件,如:

Get-Process | ConvertTo-Html -Head @'

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {

   $("table tr td:nth-child(" + ( $("table th:contains('WS')").index() + 1 ) + ")").each(function() {
      if($(this).html() > 209715200) { // 200MB
         $(this).css("background", "red" );
      } else if($(this).html() > 20971520) { // 20MB
         $(this).css("background", "orange" );
      } else if($(this).html() > 10485760) { // 10MB
         $(this).css("background", "yellow" );
      }
   });

})
</script>

'@ | Out-File procs.html; ii .\procs.html
Run Code Online (Sandbox Code Playgroud)

  • +1帮助JQuery从Silver Bullet演变为Silver Nuke.但是,如果在帖子中指出用于HTML电子邮件,则可能不是最佳解决方案. (2认同)

Jay*_*kul 7

嘿,我想出了另一个我更喜欢的答案.这个不依赖于支持JavaScript的浏览器......

Add-Type -AssemblyName System.Xml.Linq

# Get the running processes to x(ht)ml
$xml = [System.Xml.Linq.XDocument]::Parse( "$(Get-Process | ConvertTo-Html)" )

# Find the index of the column you want to format:
$wsIndex = (($xml.Descendants("{http://www.w3.org/1999/xhtml}th") | Where-Object { $_.Value -eq "WS" }).NodesBeforeSelf() | Measure-Object).Count

# Format the column based on whatever rules you have:
switch($xml.Descendants("{http://www.w3.org/1999/xhtml}td") | Where { ($_.NodesBeforeSelf() | Measure).Count -eq $wsIndex } ) {
   {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
   {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
   {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue } 
}
# Save the html out to a file
$xml.Save("$pwd/procs2.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html
Run Code Online (Sandbox Code Playgroud)

是否有特殊徽章可以自行窃取"标记为答案"?;-)

  • 缺少"Add-Type -AssemblyName System.Xml.Linq". (2认同)

Jay*_*kul 6

一个更快的方法:

好吧,我一直向自己承诺,我不会再把时间花在已解决的问题上了,但是...我的第二个回答中的switch语句在我的系统上运行需要10秒以上 - 因为它正在做"哪里"的东西在PowerShell而不是在LINQ中.

由于PowerShell不支持LINQ,我通过在Add-Type调用中编写静态辅助方法来解决它(并将该switch语句加速大约1000倍):

Add-Type -Language CSharpVersion3 -ReferencedAssemblies System.Xml, System.Xml.Linq -UsingNamespace System.Linq -Name XUtilities -Namespace Huddled -MemberDefinition @"    
    public static System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement> GetElementByIndex( System.Xml.Linq.XContainer doc, System.Xml.Linq.XName element, int index) {
        return from e in doc.Descendants(element) where e.NodesBeforeSelf().Count() == index select e;
    }
    public static System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement> GetElementByValue( System.Xml.Linq.XContainer doc, System.Xml.Linq.XName element, string value) {
        return from e in doc.Descendants(element) where e.Value == value select e;
    }
"@

# Get the running processes to x(ht)ml
$xml = [System.Xml.Linq.XDocument]::Parse( "$(Get-Process | ConvertTo-Html)" )

# Find the index of the column you want to format:
$wsIndex = [Huddled.XUtilities]::GetElementByValue( $xml, "{http://www.w3.org/1999/xhtml}th", "WS" ) | %{ ($_.NodesBeforeSelf() | Measure).Count }


switch([Huddled.XUtilities]::GetElementByIndex( $xml, "{http://www.w3.org/1999/xhtml}td", $wsIndex )) {
   {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
   {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
   {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue } 
}

# Save the html out to a file
$xml.Save("$pwd/procs2.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html
Run Code Online (Sandbox Code Playgroud)

PowerShell 3:

在有人链接到这篇文章后,我在PowerShell 3中重新编写了这个,你不再需要编译类型来快速获取它:

Add-Type -AssemblyName System.Xml.Linq

$Process = $(Get-Process | Select Handles, NPM, PM, WS, VM, CPU, Id, ProcessName)

$xml = [System.Xml.Linq.XDocument]::Parse( "$($Process | ConvertTo-Html)" )
if($Namespace = $xml.Root.Attribute("xmlns").Value) {
    $Namespace = "{{{0}}}" -f $Namespace
}

# Find the index of the column you want to format:
$wsIndex = [Array]::IndexOf( $xml.Descendants("${Namespace}th").Value, "WS")

foreach($row in $xml.Descendants("${Namespace}tr")){
    switch(@($row.Descendants("${Namespace}td"))[$wsIndex]) {
       {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
       {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
       {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue } 
    }
}
# Save the html out to a file
$xml.Save("$pwd/procs1.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html
Run Code Online (Sandbox Code Playgroud)