# report processes hanging for more than 3 seconds $timeout = 3
# use a hash table to keep track of processes $hash = @{}
# use an endless loop and test processes do { Get-Process | # look at processes with a window only Where-Object MainWindowTitle | ForEach-Object { # use process ID as key to the hash table $key = $_.id # if the process is responding, reset the counter if ($_.Responding) { $hash[$key] = 0 } # else, increment the counter by one else { $hash[$key]++ } }
# copy the hash table keys so that the collection can be # modified $keys = @($hash.Keys).Clone()
# emit all processes hanging for longer than $timeout seconds # look at all processes monitored $keys | # take the ones not responding for the time specified in $timeout Where-Object { $hash[$_] -gt$timeout } | ForEach-Object { # reset the counter (in case you choose not to kill them) $hash[$_] = 0 # emit the process for the process ID on record Get-Process-id$_ } | # exclude those that already exited Where-Object { $_.HasExited -eq$false } | # show properties Select-Object-Property Id, Name, StartTime, HasExited | # show hanging processes. The process(es) selected by the user will be killed Out-GridView-Title"Select apps to kill that are hanging for more than $timeout seconds"-PassThru | # kill selected processes Stop-Process-Force
PS> Test-NetConnection-ComputerName microsoft.com WARNING: Ping to 40.76.4.15 failed with status: TimedOut WARNING: Ping to 40.112.72.205 failed with status: TimedOut WARNING: Ping to 13.77.161.179 failed with status: TimedOut WARNING: Ping to 40.113.200.201 failed with status: TimedOut WARNING: Ping to 104.215.148.63 failed with status: TimedOut
HTTP: Port 80
HTTPS: Port 443
FTP: Port 21
FTPS/SSH: Port 22
TELNET: Port 23
POP3: Port 110
POP3 SSL: Port 995
IMAP: Port 143
IMAP SSL: Port 993
WMI: Port 135
RDP: Port 3389
DNS: Port 53
DHCP: Port 67, 68
SMB/NetBIOS: 139
NetBIOS over TCP: 445
PowerShell Remoting: 5985
PowerShell Remoting HTTPS: 5986
PS> # works: PS> $switch.Children | Select-Object HasChildren, Children
HasChildren Children ------------------- True System.__ComObject
PS> # fails: PS> $switch.Children.HasChildren PS> $switch.Children.Children PS> $switch.Children[0].HasChildren Value does not fall within the expected range. PS> $switch.Children[0].Children Value does not fall within the expected range.
失败的原因是 COM 数组的一个特异性。它们使用一个非常规的枚举器,和普通的对象数组不同,所以 PowerShell 无法直接存取数组元素。一个简单的解决方案是使用 ForEach-Object:
$UPnPFinder = New-Object-ComObject UPnP.UPnPDeviceFinder # the UDN is unique, so you need to find out the UDN for your device first # you cannot use the UDN I used $myNetgearSwitch = $UPnPFinder.FindByUDN('uuid:4d696e69-444c-164e-9d42-3894ed0e1db5') $myNetgearSwitch
这次,几乎立即识别出我的设备。要列出它的服务,我只需要获取它的 “Services” 属性,并且 PowerShell 自动将该 COM 对象转为可见的属性:
1 2 3 4 5
PS> $myNetgearSwitch.Services
ServiceTypeIdentifier Id LastTransportStatus ------------------------------------------ urn:schemas-upnp-org:service:Layer3Forwarding:1 urn:upnp-org:serviceId:L3Forwarding1 0