关于对 PowerShell 输出进行着色已经存在几个问题,例如:
这对我来说在最新的 PowerShell 7 版本中工作得很好,但我想让我的模块向下兼容 Windows PowerShell 5.1,如果相关的彩色字符串被截断(例如以表格格式),则颜色不会重置。
最小的、可重复的示例:
$Esc = [Char]0x1b
[PSCustomObject]@{
Path = 'Person.Address'
Node = "$Esc[36m@{City='New York';..;PostalCode='10021-3100'}$Esc[39m"
Test = 'Optional'
Issue = "$Esc[91m[X] The actual item contains unapproved child items: PostalCode. Expected an item with optional child items listed in @{State=@{..};..;City=@{..}}.$Esc[39m"
}
(注意第二行的
Path
属性的颜色和提示颜色都变成了red,如果Issue
属性适合屏幕的话不会发生什么)
PowerShell 5.1 是否有一种方法可以确保始终重置字符串的 ANSI 颜色(即使它被截断)?
如果您同意不对输入内联进行颜色编码,您可以使用 format.ps1xml 文件定义自定义视图。 请参阅此处如何创建您自己的视图。
例如,对于我的一个模块,我定义了一个如下所示的视图:
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<ViewDefinitions>
<View>
<Name>Kra.TimeTrackerTime</Name>
<ViewSelectedBy>
<TypeName>TimeTrackerTime</TypeName>
</ViewSelectedBy>
<GroupBy>
<!--<PropertyName>Date</PropertyName>-->
<ScriptBlock>"$($_.Date.DayOfWeek), $($_.Date.ToString('dd.MM.yyyy'))"</ScriptBlock>
<Label>Group</Label>
</GroupBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>TaskName</Label>
<Width>20</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>BookingCode</Label>
<Width>14</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Status</Label>
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Date</Label>
<Width>12</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>StartTime</Label>
<Width>5</Width>
<Alignment>Right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>EndTime</Label>
<Width>7</Width>
<Alignment>Right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Duration</Label>
<Width>8</Width>
<Alignment>Right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Comment</Label>
<Width>68</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<Wrap />
<TableColumnItems>
<TableColumnItem>
<ScriptBlock>
$Value = $_.TaskName
$Esc = [char]27
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"
}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.BookingCode
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.Status -join ";`n"
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if('Pikett' -in $_.Status) {
$Color = '38;2;255;150;60'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.Date.ToString('dd.MM.yyyy')
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"
}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.StartTime.ToString('HH:mm')
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"
}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.EndTime.ToString('HH:mm')
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"
}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.Duration.ToString('hh\hmm')
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"
}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$Value = $_.Comment
$Esc = [char]27
if($_.IsBreakTime) {
$Color = '38;2;80;130;255'
$Format = $true
}
if($_.IsRunning) {
$Color = '38;2;66;224;22'
$Format = $true
}
if($_.IsArchived) {
$Color = '38;2;120;120;120'
$Format = $true
}
if($Format) {
"$Esc[$($Color)m$($Value)$Esc[0m"
}
else {
$Value
}
</ScriptBlock>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
注意“ViewSelectedBy”标签。它有一个指定的 TypeName。在您的代码中,您必须将该 TypeName 添加到您想要在此视图中显示的任何对象,如下所示:
#create the object and store it in a variable
$Obj = [PsCustomObject]@{
TaskName = $_.TaskName
BookingCode = $Task.BookingCode
Status = $Status
IsBreakTime = $Task.IsBreakTime
Date = $ObjDate
StartTime = $_.StartTime
EndTime = $_.EndTime
Duration = $Duration
Comment = $_.Comment
IsRunning = $null -eq $_.EndTime
IsArchived = $_.IsArchived
}
#the object has a list of TypeNames
#insert the TypeName specified in the view
$Obj.PsTypeNames.Insert(0,'TimeTrackerTime')
Write-Output $Obj
只要您按照链接文章中的指定加载视图(您可以将其放入 PowerShell 配置文件脚本中),任何具有指定 TypeName 的对象都将自动在控制台中显示该视图。
如果您的代码位于 PowerShell 模块中,您可以将 format.ps1xml 文件添加到模块目录中,并在“FormatsToProcess”下的模块清单中指定路径。