好的,所以我必须创建一个需要将协议名称作为参数传递的脚本。该脚本将在 c:\ windows \ system32 \ drivers \ etc \ protocol 文件中搜索所述协议。如果找到协议,则脚本需要返回分配给它的端口。
如果协议在该文件中,我获取整行信息(包括分配的端口)没有问题......当我需要提取端口字段时,问题出现了。
现在,我在标题中指定该行来自文本文件的原因是因为我将字段与特定行隔离没有任何问题,而这些行反过来在这些行中与一串行隔离cmdlet的输出,例如 get-process 。例如,
get-process | where-object {$_.ProcessName -eq "ServerManager"}
将产生整行,但
get-process | where-object {$_.ProcessName -eq "ServerManager"} | Select-Object CPU
将从该行生成特定字段。
无论如何,如果比较毫无意义或不必要,我道歉。这是脚本的代码,需要抛光/完成:
param (
[string]$protocol
)
$lines=get-content -path c:\windows\system32\drivers\etc\protocol
if ($lines -match $protocol) {
$line=$($lines -match $protocol)
write-host $line #prints the entire line, port field is the second
write-host $line.split()[0] #this prints only the first field (the protocol name)
write-host $line.split()[1] #shouldn't this print only the second field (the assigned port)?
}
else {write-host "Protocol not found"}
好的,所以,再次,抱歉,如果我不必要地发布这个帖子...提前感谢
答案 0 :(得分:1)
所以,这就是你正在使用的.Split()方法在Space字符上的分割。每个空间角色。因此,如果协议名称后面有8个空格,并且在端口之前,那么[0] = protocol,[8] = port。不太有用。对我来说什么会更好,我认为这将是一场RegEx比赛。类似的东西:
$lines=get-content -path c:\windows\system32\drivers\etc\protocol | Where {$_ -match "^$Protocol\s+?(\d+?)"} | ForEach{$Matches[1]}
If($lines.count -gt 0){
"$Protocol protocol found using port $Lines"
}
Else{"Protocol not found"}
该匹配查找您的协议字符串,后跟任意数量的空格(空格,制表符等),然后捕获其后面的数字。 ForEach循环输出要由$ Lines捕获的数字(端口)。其余的应该很容易遵循。
编辑:要扩展它为什么不像Get-Process示例那样工作,因为cmdlet Get-Process返回一组对象和那些对象有几个属性,如CPU,PID,路径等。您可以选择其中一个属性来显示。文本文件中的行只是字符串。字符串是对象,当然,但它们只有一个功能属性,而且它们是存储在其中的文本(是的,它们有方法,但我们只是在谈论可以存储值的属性)。因此,没有像运行Get-Process时那样选择属性。我希望这有助于明确这一点。
Edit2:好的,如果我们想要避免RegEx(您应该完全阅读并了解您是否计划进行任何解析或字符串操作),我们可以使用split still。勉强,但它可以做到。我甚至可以像马特的例子那样制作漂亮的小物件,因为它们更容易使用,而且更好,我之前只是懒惰而且马特是对的。
$Lines = Get-Content c:\windows\system32\drivers\etc\protocol |Where{$_ -notlike "#*" -and !([string]::IsNullOrEmpty($_))}
$Protocols = ForEach($Line in $Lines){
$SplitLine = $Line.split()|Where{!([String]::IsNullOrEmpty($_))}
[PSCustomObject][Ordered]@{
'ProtocolName' = $SplitLine[0]
'Port' = $SplitLine[1]
'Aliases' = $SplitLine[2]
'Comment' = $SplitLine[4..($SplitLine.count)] -join " "
}
}
现在$ Protocols将输出如下内容:
PS C:\Windows\System32\WindowsPowerShell\v1.0> $Protocols
ProtocolName Port Aliases Comment
------------ ---- ------- -------
ip 0 IP Internet protocol
icmp 1 ICMP Internet control message protocol
ggp 3 GGP Gateway-gateway protocol
tcp 6 TCP Transmission control protocol
egp 8 EGP Exterior gateway protocol
pup 12 PUP PARC universal packet protocol
udp 17 UDP User datagram protocol
hmp 20 HMP Host monitoring protocol
xns-idp 22 XNS-IDP Xerox NS IDP
rdp 27 RDP "reliable datagram" protocol
ipv6 41 IPv6 Internet protocol IPv6
ipv6-route 43 IPv6-Route Routing header for IPv6
ipv6-frag 44 IPv6-Frag Fragment header for IPv6
esp 50 ESP Encapsulating security payload
ah 51 AH Authentication header
ipv6-icmp 58 IPv6-ICMP ICMP for IPv6
ipv6-nonxt 59 IPv6-NoNxt No next header for IPv6
ipv6-opts 60 IPv6-Opts Destination options for IPv6
rvd 66 RVD MIT remote virtual disk
你可以根据需要过滤它,比如Matt所描述的,比如
$Protocols | Where{$_.ProtocolName -ieq $Protocol}
答案 1 :(得分:1)
赞美TheMadTechnicians的回答。这应该将文本文件转换为您可以引用的对象,如其他cmdlet的输出。
$protocols = get-content -path c:\windows\system32\drivers\etc\protocol | Where-Object{$_ -and ($_ -notmatch "^#")} | ForEach-Object{
$protocol = $_ -split '\s+'
[pscustomobject]@{
ProtocolName = $protocol[0]
Port = $protocol[1]
Alias = $protocol[2]
Comment = $protocol[4..$($protocol.Count)] -join " "
}
}
然后你可以做这样的事情
$protocols | Where-Object{$_.ProtocolName -eq "udp"}
哪会净回报
ProtocolName Port Alias Comment
------------ ---- ----- -------
udp 17 UDP User datagram protocol