XAML 如何在PowerShell中呈现HTML而不使用MSIE或写入文件?

pgpifvop  于 2022-12-07  发布在  Shell
关注(0)|答案(1)|浏览(121)

我正在寻找一种简洁的方法来呈现PowerShell中HTML字符串的显示,而不使用MSIE或将结果写入文件。
有没有办法在XAML中使用WebBrowser来实现这一点?
当我尝试这样做时,WebBrowser似乎没有DocumentText或Document.Text成员设置为所需的文本。
您可以指定一个源,所以我尝试了将数据URL作为源,但是WebBrowser似乎不支持将数据URL作为源。
如果HTML能够以某种方式内联在XAML中,或者作为文档文本的属性发送到浏览器,那就太好了。

  • 我不想写文件。我知道怎么做,但认为这是不好的做法。
  • 我不想依赖MSIE,因为MS放弃了t,并且不再推荐使用它。如果代码很少,我不介意使用Add-Type调用VB或C#之类的东西。
  • 我不想下载任何特殊的软件。我想知道如何用PowerShell来做这件事。这看起来很简单,你会认为会有一个内置的Show-HTML Cmdlet来做这件事,就像ogv一样简单。(毕竟,有很多命令可以转换成html或将html生成为字符串)

几年前,这里有一个关于堆栈溢出的类似问题的答案,建议将MSIE作为答案,但现在MSIE已被弃用,不再是一个选项。PS、XAML和.net自那时以来肯定有所进步。

gupuwyp2

gupuwyp21#

您可以简单地将XAML嵌入到PowerShell中,然后从那里开始。

(动态)PowerShell BGInfo示例:

[CmdletBinding()]param(
    [TimeSpan]$RefreshInterval = '00:05:00',    # Refresh every 5 minutes
    [switch]$OnTop,                             # Put the information on top
    [switch]$EnableClose,                       # Click on a visible item and click <alt>-<F4> to close
    [switch]$ShowPSWindow                       # Don't hide PowerShell window
)

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName presentationframework

$List = [Ordered]@{ # ScriptBlocks will be dynamicaly updated
    'Description'     = 'PowerShell BGInfo Example'
    1                 = '-'
    'Host Name:'      = $Env:ComputerName
    'Logon Server:'   = $Env:LogonServer
    'Pagefile:'       = { @(Get-CimInstance Win32_PageFileUsage).ForEach{ "$($_.Name) ($($_.CurrentUsage)Mb)" } }
    'IP Addres:'      = { (Get-CimInstance Win32_NetworkAdapterConfiguration -Filter 'IPEnabled="true"').IPAddress.Where{ $_ -Match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' } }
    'OS:'             = (Get-CimInstance Win32_OperatingSystem).Caption
    'Boot Time:'      = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
    'Free Space:'     = { @(Get-CimInstance Win32_LogicalDisk).ForEach{ "$($_.DeviceID) $(Format-ByteSize $_.FreeSpace)" } -Join ', ' }
}

$Xaml = [xml](@'
<?xml version="1.0" encoding="UTF-8"?>
<Window FontFamily="Calibri, Arial" FontSize="14" TextElement.Foreground="White"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="SSO_BGInfo" WindowStyle="None" ResizeMode="NoResize" WindowState="Maximized" ShowInTaskbar="False" AllowsTransparency="True">
    <Window.Background>
        <SolidColorBrush Opacity="0"/>
    </Window.Background>
    <WrapPanel Margin="40" Orientation="Vertical" HorizontalAlignment="Right" VerticalAlignment="Bottom">
        <Grid VerticalAlignment="Top" HorizontalAlignment="Left" Name="List">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="10" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
        </Grid>
        <Grid Height="40" />
        <!-- Control bar spacer in case aligned to bottom -->
    </WrapPanel>
</Window>
'@)

$Script:User32 = Add-Type -Debug:$False -MemberDefinition '
    [DllImport("user32.dll")] public static extern bool ShowWindow(int handle, int state);
    [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,int Y, int cx, int cy, uint uFlags);
' -Name "User32Functions" -namespace User32Functions -PassThru

if (!$ShowPSWindow) { [Void]($User32::ShowWindow((Get-Process -id $PID).MainWindowHandle, 0)) }

$Processes = @(Get-CimInstance win32_process -Filter "name='powershell.exe'").Where{
    (Invoke-CimMethod -InputObject $_ -MethodName GetOwner).User -eq $Env:Username
}
$MyProcess = $Processes.Where{ $_.ProcessId -eq $PID }
if ($MyProcess.CommandLine) {
    $Processes.Where{
        $_.ProcessName -eq $MyProcess.ProcessName -and
        $_.CommandLine -eq $MyProcess.CommandLine -and
        $_.ProcessId -ne $MyProcess.ProcessId
    }.ForEach{
        Stop-Process $_.ProcessId
    }
}

$Script:Shlwapi = Add-Type -MemberDefinition '
    [DllImport("Shlwapi.dll", CharSet=CharSet.Auto)]public static extern int StrFormatByteSize(long fileSize, System.Text.StringBuilder pwszBuff, int cchBuff);
' -Name "ShlwapiFunctions" -namespace ShlwapiFunctions -PassThru

function Script:Format-ByteSize([Long]$Size) {
    $Bytes = New-Object Text.StringBuilder 20
    $Return = $Shlwapi::StrFormatByteSize($Size, $Bytes, $Bytes.Capacity)
    if ($Return) {$Bytes.ToString()}
}

function Script:Update {
    $Handle = [System.Windows.Interop.WindowInteropHelper]::new($Script:Window).Handle
    $InsertAfter = if ($OnTop) { -1 } else { 1 }
    [Void]$Script:User32::SetWindowPos($Handle, $InsertAfter, 0, 0, 0, 0, 0x53)

    $Script:Dynamic.GetEnumerator().ForEach{
        $Value = &$_.Value.Tag
        if ($_.Value.Text -cne $Value) { # Only update UI when required
            $_.Value.Text = $Value
        }
    }
}

$Script:Window = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader($Xaml)))

$Script:Dynamic = @{}
$Grid = $Window.FindName('List')
$Row = 0
$List.GetEnumerator().ForEach{
    $Grid.RowDefinitions.add([System.Windows.Controls.RowDefinition]::new())
    if ($_.Value -Match '^\s*-+\s*') {
        $Separator = [System.Windows.Controls.Separator]::new()
        $Grid.AddChild($Separator)
        [System.Windows.Controls.Grid]::SetRow($Separator, $Row)
        [System.Windows.Controls.Grid]::SetColumn($Separator, 0)
        [System.Windows.Controls.Grid]::SetColumnSpan($Separator, 99)
    }
    else {
        $TextBlock = [System.Windows.Controls.TextBlock]@{ Text = $_.Name; TextAlignment = 'Right' }
        $Grid.AddChild($TextBlock)
        [System.Windows.Controls.Grid]::SetRow($TextBlock, $Row)
        [System.Windows.Controls.Grid]::SetColumn($TextBlock, 0)
        if ($_.Value -is [ScriptBlock]) {
            $TextBlock = [System.Windows.Controls.TextBlock]@{ Tag = $_.Value }
            $Script:Dynamic[$_.Name] = $TextBlock
        }
        else {
            $TextBlock = [System.Windows.Controls.TextBlock]@{ Text = $_.Value }
        }
        $Grid.AddChild($TextBlock)
        [System.Windows.Controls.Grid]::SetRow($TextBlock, $Row)
        [System.Windows.Controls.Grid]::SetColumn($TextBlock, 2)
    }
    $Row++
}

$Script:Window.Add_Loaded({ Update })
$Script:Window.Add_Activated({ Update })
if (!$EnableClose) { $Script:Window.Add_Closing({ $_.Cancel = $True }) }
$Timer = [System.Windows.Forms.Timer]::new()
$Timer.Interval = ([TimeSpan]$RefreshInterval).TotalMilliseconds
$Timer.Add_Tick({ Update })
$Timer.Start()
[Void]$Script:Window.ShowDialog()
$Timer.Stop()
$Timer.Dispose()

用途

.\BGInfo.ps1

要进行故障排除和调试,请使用以下命令:

.\BGInfo.ps1 -EnableClose -ShowPSWindow

相关问题