当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 简单的 PowerShell 自定义格式

作者:精品下载站 日期:2024-12-14 20:38:19 浏览:13 分类:玩电脑

简单的 PowerShell 自定义格式


我真正喜欢 PowerShell 的功能之一是能够以我想要的形式呈现我需要的信息。这是一个很好的例子。运行 Get-Process 非常简单,并且输出非常完整。但对我来说更好的一件事是,有时我想要一种简单的方法来查看高内存使用属性。是的,我可以通过管道将 Get-Process 传输到 Sort-Object 和Where-Object。然而,在这种特殊情况下,我真正想要的是看到高内存使用进程显示为红色。也许那些接近我的任意极限的东西我希望看到黄色。使用 ANSI 转义序列实现这一点并不困难。

为了尝试这一点,我定义了一组自定义属性,本质上是复制 Get-Process 的默认输出。

$props = @(
    "Handles",
    @{Name = "NPM(K)"; Expression = { [int]($_.npm / 1kb) } },
    @{Name = "PM(K)"; Expression = { [int]($_.pm / 1kb) } },
    @{Name = "WS(M)"; Expression = {
            if ($_.ws -ge 500MB) {
                "$([char]0x1b)[91m$([int]($_.ws/1mb))$([char]0x1b)[0m"
            }
            elseif ($_.ws -ge 250MB) {
                "$([char]0x1b)[93m$([int]($_.ws/1mb))$([char]0x1b)[0m"
            }
            else {
                [int]($_.ws / 1mb)
            }
        }
    },
    @{Name = "CPU"; Expression = { New-TimeSpan -Seconds $_.cpu } },
    "ID",
    @{Name = "ProcessName"; Expression = {
            if ($_.ws -ge 500MB) {
                "$([char]0x1b)[1;91m$($_.processname)$([char]0x1b)[0m"
            }
            elseif ($_.ws -ge 250MB) {
                "$([char]0x1b)[1;93m$($_.processname)$([char]0x1b)[0m"
            }
            else {
                $_.processname
            }
        }
    }
)

自定义属性被定义为哈希表,就像使用 Select-Object 时一样。在此代码中,如果 WorkingSet 值大于或等于 MB,则 WS 和进程名称值将使用适用于 Windows PowerShell 和 PowerShell 7 的 ANSI 转义序列将其格式化为红色。

"$([char]0x1b)[1;91m$($_.processname)$([char]0x1b)[0m"

我还重命名了 WS 标题,以将 MB 中的值反映为 [INT]。当我这样做时,我意识到 CPU 属性实际上是秒数,因此我将其显示为时间跨度。

@{Name = "CPU"; Expression = { New-TimeSpan -Seconds $_.cpu } }

将此数组加载到我的 PowerShell 会话中后,我可以运行这样的命令。

Get-Process | Where-Object WS -ge 100MB | Format-Table -Property $props -AutoSize

我添加了一些过滤以使屏幕截图更易于阅读。

[玩转系统] 简单的 PowerShell 自定义格式

现在是有趣的部分。

我不想为自定义属性键入所有代码。我可以做的一件事是创建一个名称如WS的自定义表格视图。自定义格式是通过 .ps1xml 文件完成的。是的。 XML。但我让它成为一个简单的过程,上周我让它变得更加容易。

您可以从 PowerShell Gallery 下载 PSScriptTools 模块,该模块有一个名为 New-PSFormatXML 的命令。前提是您通过管道将示例对象传递给命令,指定所需的自定义格式类型(包括属性),然后它将为您创建 .ps1xml 文件。上周,我添加了支持脚本块的功能,它将自动在文件中创建 ScriptBlock 标签。在以前的版本中,您必须手动创建它们。安装 PSScriptTools 模块后,我可以使用之前定义的自定义属性数组运行这样的命令来生成文件。

Get-Process -Id $pid | New-PSFormatXML -Properties $props -ViewName WS -FormatType Table -Path c:\scripts\wsprocess.format.ps1xml -Passthru

该函数只需要一个对象。顺便说一句,如果您在 VSCode 中运行此命令并使用 -Passthru 参数,将自动打开新的 .ps1xml 文件。这是我的结果。

<?xml version="1.0" encoding="UTF-8"?>
<!--
Format type data generated 10/11/2020 13:02:12 by PROSPERO\Jeff
This file was created using the New-PSFormatXML command that is part
of the PSScriptTools module.
https://github.com/jdhitsolutions/PSScriptTools
-->
<Configuration>
  <ViewDefinitions>
    <View>
      <!--Created 10/11/2020 13:02:12 by PROSPERO\Jeff-->
      <Name>WS</Name>
      <ViewSelectedBy>
        <TypeName>System.Diagnostics.Process</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.-->
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
            <Label>Handles</Label>
            <Width>10</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>NPM(K)</Label>
            <Width>20</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>PM(K)</Label>
            <Width>19</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>WS(M)</Label>
            <Width>212</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>CPU</Label>
            <Width>31</Width>
            <Alignment>center</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Id</Label>
            <Width>8</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>ProcessName</Label>
            <Width>210</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Handles</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>[int]($_.npm/1kb)</ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>[int]($_.pm/1kb)</ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                  if ($_.ws -ge 500MB) {
                      "$([char]0x1b)[91m$([int]($_.ws/1mb))$([char]0x1b)[0m"
                  }
                  elseif ($_.ws -ge 250MB) {
                      "$([char]0x1b)[93m$([int]($_.ws/1mb))$([char]0x1b)[0m"
                  }
                  else {
                      [int]($_.ws/1mb)
                  }
                </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>New-Timespan -Seconds $_.cpu</ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Id</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                  if ($_.ws -ge 500MB) {
                      "$([char]0x1b)[1;91m$($_.processname)$([char]0x1b)[0m"
                  }
                  elseif ($_.ws -ge 250MB) {
                      "$([char]0x1b)[1;93m$($_.processname)$([char]0x1b)[0m"
                  }
                  else {
                      $_.processname
                  }
                </ScriptBlock>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

.ps1xml 文件默认为自动调整大小,这对我来说没问题。我所要做的就是将该文件加载到我的 PowerShell 会话中。

Update-FormatData C:\scripts\wsprocess.format.ps1xml

如果我只是运行 Get-Process,则该文件不起作用。但如果我想使用它,我需要做的就是指定视图名称。

Get-Process | Where-Object WS -ge 100MB | Format-Table -View ws

为了演示,我再次添加了一些过滤。

[玩转系统] 简单的 PowerShell 自定义格式

如果我希望它始终可用,我可以将 Update-FormatData 表达式放入我的 PowerShell 配置文件脚本中。提醒一下,当您通过管道传输到其中一个格式 cmdlet 时,您是在告诉 PowerShell 您想要的只是一些好看的东西。您无法再次通过管道发送到命令 Sort-Object 或 Export-CSV。您所能做的就是将输出通过管道传输到 Out-File 或 Out-Printer。

现在,我可以使用 PowerShell 来完成我的工作。我一眼就能看出哪些进程使用了最多的内存,哎呀,我可以进一步深化这个概念,并在我的配置文件中定义一个“作弊者”功能。

function ws { Get-Process | Format-Table -view ws}

我只会在控制台中交互地使用它,因此我不遵循动词-名词命名约定这一事实是无关紧要的。

我可以进一步修改 ps1xml。以下是我(或您)可能会考虑的一些事项:

  • 删除 AutoSize 并调整列宽。
  • 修改 PM 等其他属性并将其格式设置为 MB。
  • 添加诸如运行时之类的属性。
  • 使我的彩色视图成为 Process 对象的默认视图。

我很想听听您提出了哪些自定义格式以及它解决了哪些问题。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯