我正在尝试使用 PowerShell 中的NETSH。我想看到这个命令的结果,比如一个对象,但是netsh返回一个字符串:
netsh wlan show hostednetwork | Get-Member
TypeName: System.String
...
我的脚本必须在具有相当本地化功能的系统上运行,并且我不能使用-match将字符串直接解析为对象。
我该如何解决我的烦恼?
我正在尝试使用 PowerShell 中的NETSH。我想看到这个命令的结果,比如一个对象,但是netsh返回一个字符串:
netsh wlan show hostednetwork | Get-Member
TypeName: System.String
...
我的脚本必须在具有相当本地化功能的系统上运行,并且我不能使用-match将字符串直接解析为对象。
我该如何解决我的烦恼?
$netshResult = Invoke-Command -Computername localhost {netsh int tcp show global}
$result = @{}
$netshObject = New-Object psobject -Property @{
ReceiveSideScalingState = $Null
ChimneyOffloadState = $Null
NetDMAState = $Null
}
$netshResult = $netshResult | Select-String : #break into chunks if colon only
$i = 0
while($i -lt $netshResult.Length){
$line = $netshResult[$i]
$line = $line -split(":")
$line[0] = $line[0].trim()
$line[1] = $line[1].trim()
$result.$($line[0]) = $($line[1])
$i++
}
$netshObject.ReceiveSideScalingState = $result.'Receive-Side Scaling State'
$netshObject.ChimneyOffloadState = $result.'Chimney Offload State'
$netshObject.NetDMAState = $result.'NetDMA State'
你有几个选择,没有一个很好。
1) 将netsh
输出读入 astring[]
并使用自定义记录解析器创建您自己的对象。也就是说,查看不同语言环境的输出并找出是否Hosted newtork settings
始终是第一个标题,然后是一堆-
字符。如果是这种情况,假设数组中的下一个元素是Mode
等等。这很容易出错,但通常 MS 命令行工具只翻译消息,而不是它们的顺序。
2) 查找 .Net API 以获得相同的信息。其中System.Net.NetworkInformation
包含一堆连接的东西。这是一个开始,虽然我不确定它是否有你需要的信息。
3) 前面的选项失败,使用P/Invoke调用原生 Win32 API。这是很多工作,所以在滚动你自己的之前寻找预先存在的包装器库。
我最近编写了一个 cmdlet 来使用正则表达式解析任意多行文本,称为ConvertFrom-Text
. (如果您问我,这不是一个好名字,但它符合 PowerShell 命名规则;欢迎提出建议!)因此,假设您有该 cmdlet,这是您问题的一种可能解决方案。(警告购买者!给出的正则表达式来自一个非常小的 netsh 输出样本,因此可能需要一些调整。)
$regex = [regex] '(?ms)(?:^\s*$\s*)?^(?<section>.*?)\s*-+\s*(?<data>.*?)\s*^\s*$'
$result = netsh wlan show hostednetwork | Out-String |
ConvertFrom-Text -pattern $regex -multiline
$result | % {
$dataObj = [PsCustomObject]@{}
$_.Data -split "`r`n" | % {
$element = $_ -split '\s*:\s*'
Add-Member -InputObject $dataObj -MemberType NoteProperty -Name $element[0].Trim() -Value $element[1].Trim()
}
$_.Data = $dataObj # Replace data text with data object
}
$result
在我的测试系统上,netsh wlan show hostednetwork
返回:
Hosted network settings
-----------------------
Mode : Allowed
Settings : <Not configured>
Hosted network status
---------------------
Status : Not available
上面代码中变量的输出$result
产生了这个:
section data
------- ----
Hosted network settings @{Mode=Allowed; Settings=<Not configured>}
Hosted network status @{Status=Not available}
section
所以 $result 是一个具有和data
属性的对象数组,后者是一个具有由 netsh 命令的输出定义的属性的对象。
ConvertFrom-Text
当然,如果没有cmdlet ,上述内容不会让您走得太远。所以这里是实现。(我有大量的文档和示例,一旦我最终将它添加到我的开源 PowerShell 库中,它们就会公开可用。)
filter ConvertFrom-Text
{
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true,Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[string[]]$InputObject,
[Parameter(Mandatory=$true,Position=1)]
[regex]$Pattern,
[switch]$RequireAll,
[switch]$Multiline
)
if ($Multiline) {
$dataString = $InputObject -join "`n"
IterateByMatch $dataString $Pattern
}
else {
IterateByLine $InputObject $Pattern
}
}
function IterateByLine([string[]]$data, [regex]$regex)
{
$data | ForEach-Object {
if ($PSItem -match $regex)
{
New-Object PSObject -Property (GetRegexNamedGroups $matches)
}
elseif ($RequireAll) {
throw "invalid line: $_"
}
}
}
function IterateByMatch([string[]]$data, [regex]$regex)
{
$regex.matches($data) | Foreach-Object {
$match = $_
$obj = new-object object
$regex.GetGroupNames() |
Where-Object {$_ -notmatch '^\d+$'} |
Foreach-Object {
Add-Member -InputObject $obj NoteProperty `
$_ $match.groups[$regex.GroupNumberFromName($_)].value
}
$obj
}
}
function Get-RegexNamedGroups($hash)
{
$newHash = @{};
$hash.keys | ? { $_ -notmatch '^\d+$' } | % { $newHash[$_] = $hash[$_] }
$newHash
}