PowerShell通过作业快速Ping子网 [英] PowerShell quickly Ping Subnet with Jobs
问题描述
以下功能将使用PingRange 1 254
ping我的子网以检查IP:
The following function will ping my subnet with PingRange 1 254
to check IP's:
function PingRange ($from, $to) {
$from..$to | % {"192.168.0.$($_): $(Test-Connection -BufferSize 2 -TTL 5 -ComputerName 192.168.0.$($_ ) -quiet -count 1)"}
}
但是,这很慢,所以我想知道是否可以同时对它们全部执行ping操作,然后收集结果.我想这将意味着:
However, this is slow, so I was wondering if it's possible to ping them all concurrently, then collect the results. I guess that this would mean:
-
在每个Test-Connection上使用Start-Job(我可以做到,这一部分很简单).
Using Start-Job on each Test-Connection (which I can do, that part is easy).
等待所有完成.
仅收集ping成功结果并将其排序.
Collecting only the ping success results and sorting them.
function PingRange $from $to {
$from..$to | % {Start-Job { "192.168.0.$($_): $(Test-Connection -BufferSize 2 -TTL 5 -ComputerName 192.168.0.$($_ ) -quiet -count 1)"} }
Wait-Job *some test to check if all jobs are complete*
Receive-Job some way to get each result, discard all failures, then sort and output to screen
}
function PingRange $from $to {
$from..$to | % {Start-Job { "192.168.0.$($_): $(Test-Connection -BufferSize 2 -TTL 5 -ComputerName 192.168.0.$($_ ) -quiet -count 1)"} }
Wait-Job *some test to check if all jobs are complete*
Receive-Job some way to get each result, discard all failures, then sort and output to screen
}
是否有一种简便的方法来进行等待作业,该等待作业将等待所有 产生的作业完成?
Is there a shorthand way to do a Wait-Job that will just wait for all spawned jobs to complete?
接收信息似乎也很棘手,当我尝试接收信息时,我总是从Receive-Job那里得到任何东西(通常是一个讨厌的错误).希望有更多关于PowerShell Jobs的专家知道如何轻松获得这些结果?
Receiving the information also seems tricky, and when I try it, I invariable get nothing back from Receive-Job (or a nasty error usually). Hopefully someone more expert on PowerShell Jobs knows how to grab these results easily?
推荐答案
注意:在 Windows PowerShell 中,最简单的解决方案是使用Test-Connection -AsJob
,如js2010的答案.但是,PowerShell [Core] 6+不再支持-AsJob
.
该答案集中在与命令无关的方法上,以实现与作业的并发.
Note: In Windows PowerShell the simplest solution is to use Test-Connection -AsJob
, as shown in js2010's answer. -AsJob
is no longer supported in PowerShell [Core] 6+, however.
This answer focuses on command-agnostic ways to achieve concurrency with jobs.
In PowerShell v7+, you'll be able to use ForEach-Object -Parallel
, which can greatly simplify your function, by running your commands in parallel, using different threads:
function PingRange ($from, $to) {
$from..$to | ForEach-Object -Parallel {
"192.168.0.$_`: $(Test-Connection -BufferSize 2 -TTL 5 -ComputerName 192.168.0.$_ -quiet -count 1)"
} -ThrottleLimit ($to - $from + 1) 2>$null -ErrorVariable err | Sort-Object
}
-
-ThrottleLimit
的默认值为5
,这意味着最多可以并行运行5个命令,其余的排队直到池中的一个线程再次可用,如先前的命令结束.-ThrottleLimit
defaults to5
, which means that up to 5 commands run in parallel, which additional ones queued until one threads in the pool become available again, as previous commands finish.- 在这里,我选择允许所有 all 线程并行运行,但是您必须测试该线程是否在实际中有效-可能适用于诸如此类的网络绑定任务,但这并不是CPU密集型任务的正确选择.请参见此博客文章以获取指导.
- Here, I've chosen to allow all threads to run in parallel, but you'll have to test if that works in practice - it may work for network-bound tasks such as here, but it's not right choice for CPU-bound tasks; see this blog post for guidance.
2>$null
使错误输出静音,但-ErrorVariable err
收集变量$err
中的所有错误以供以后检查:2>$null
silences error output, but-ErrorVariable err
collects any errors in variable$err
for later inspection:- 注意:从v7.0开始,只有
2>$null
可以解决沉默错误;不支持通用的-ErrorAction
参数(-WarningAction
,-InformationAction
,-PipelineVariable
都不支持);请注意,如果$ErrorActionPreference = 'Stop'
恰好生效,则2>$null
可以触发脚本终止错误.
- Note: As of v7.0, only
2>$null
works for silencing errors; the common-ErrorAction
parameter is not supported (and neither are-WarningAction
,-InformationAction
,-PipelineVariable
); note that2>$null
can trigger a script-terminating error if$ErrorActionPreference = 'Stop'
happens to be in effect.
线程的输出将以没有保证的顺序到达,但是将在到达时进行打印.
Output from the threads will arrive in no guaranteed order, but will print as it arrives.
- 考虑到您想要的排序输出,在这里这不是问题.
- 如果确实需要按输入顺序的输出,请使用
-AsJob
参数,将生成的作业对象与Wait-Job
一起使用,以等待所有线程完成,此时可以调用Receive-Job
以输入顺序接收所有输出.
- Given that your want sorted output anyway, that is not a problem here.
- If you do need the output in input order, use the
-AsJob
parameter, use the resulting job object withWait-Job
to wait for all threads to finish, at which point you can callReceive-Job
to receive all the outputs in input order.
在PowerShell v6-中,使用
Start-ThreadJob
比Start-Job
更好.因为线程作业的开销要比标准后台作业(子进程)少得多. -基于过程.In PowerShell v6-, it's better to use
Start-ThreadJob
thanStart-Job
, because thread jobs have much less overheads than the standard background jobs, which are child-process-based.注意:PowerShell 6.x附带实现的
ThreadJob
模块;在Windows PowerShell中,您可以按需安装它;例如.:Install-Module ThreadJob -Scope CurrentUser
.Note: The implementing
ThreadJob
module ships with PowerShell 6.x; in Windows PowerShell you can install it on demand; e.g.:Install-Module ThreadJob -Scope CurrentUser
.function PingRange ($from, $to) { $from..$to | ForEach-Object { Start-ThreadJob -ThrottleLimit ($to - $from + 1) { "192.168.0.$using:_`: $(Test-Connection -BufferSize 2 -TTL 5 -ComputerName 192.168.0.$using:_ -quiet -count 1)" } } | Receive-Job -Wait -AutoRemove -ErrorAction SilentlyContinue -ErrorVariable err | Sort-Object }
请注意需要
$using:_
以便引用封闭的ForEach-Object
脚本块的$_
变量.Note the need for
$using:_
in order to reference the enclosingForEach-Object
script block's$_
variable.虽然
Start-ThreadJob
使用线程(运行空间)运行其作业,但是可以使用标准作业cmdlet(即Wait-Job
,Receive-Job
和Remove-Job
)管理生成的作业对象.While
Start-ThreadJob
uses threads (runspaces) to run its jobs, the resulting job objects can be managed with the standard job cmdlets, namelyWait-Job
,Receive-Job
andRemove-Job
.-
Start-ThreadJob
使用线程(通过PowerShell SDK分离进程内PowerShell runspaces )进行并发,而不是使用子进程Start-Job
使用.基于线程的并发速度更快,资源占用更少.
Start-ThreadJob
uses threads (separate in-process PowerShell runspaces via the PowerShell SDK) for concurrency rather than the child processesStart-Job
uses. Thread-based concurrency is much faster and less resource-intensive.
- 有关
Start-ThreadJob
带来的性能提升的示例,请参见此答案.
- See this answer for an example of the performance gains that
Start-ThreadJob
brings.
线程作业的输出保留其原始类型.
- 相反,在
Start-Job
作业中,输入和输出必须跨越进程边界,这需要在PowerShell remoting 中使用相同类型的基于XML的序列化和反序列化,其中丢失了类型保真度,除了一些已知类型以外:请参见此答案.
- By contrast, in
Start-Job
jobs input and output must cross process boundaries, necessitating the same kind of XML-based serialization and deserialization that is used in PowerShell remoting, where type fidelity is lost except for a few known types: see this answer.
Start-ThreadJob
唯一的-很大程度上是假想的-崩溃的线程可能会使整个过程崩溃,但请注意,即使使用Throw
创建的脚本终止错误也只会终止手头的线程(运行空间),而不是来电者.The only - largely hypothetical - downside of
Start-ThreadJob
is that a crashing thread could crash the entire process, but note even a script-terminating error created withThrow
only terminates the thread (runspace) at hand, not the caller.简而言之:仅当需要完全隔离进程时使用
Start-Job
;也就是说, if 您需要确保以下内容:In short: use
Start-Job
only if you need full process isolation; that is, if you need to ensure the following:-
崩溃的作业不能使调用者崩溃.
A crashing job must not crash the caller.
作业不应看到将.NET类型加载到调用者的会话中.
A job should not see .NET types loaded into the caller's session.
作业不应能够修改调用方的环境变量(在两种类型的作业中,调用方的环境变量值均存在 ,但在这种情况下它们是份的后台作业.)
A job should not be able to modify the caller's environment variables (in jobs of both types the caller's environment variable values are present, but in the case of background jobs they are copies).
请注意,在
Start-ThreadJob
和Start-Job
作业中,这些作业 not 均以以下方式查看呼叫者的状态::Note that in both
Start-ThreadJob
andStart-Job
jobs, the jobs do not see the caller's state in terms of:-
通过交互方式或通过
-
变量,函数,别名或PSv5 + 自定义类添加到调用者的会话中-作业不会不加载
$PROFILE
文件.
$PROFILE
文件将Variables, functions, aliases, or PSv5+ custom classes added to the caller's session, either interactively or via a
$PROFILE
file - jobs do not load$PROFILE
files.
- 但是,线程作业确实会看到 .NET 类(类型)已加载到调用者的会话中,并且与常规作业不同,它们不仅可以看到调用者的环境变量的值,而且还可以修改它们.
- However, thread jobs do see .NET classes (types) loaded into the caller's session, and, unlike regular jobs, they not only see the values of the caller's environment variables, but can also modify them.
在PowerShell 6-中,作业的初始当前目录(文件系统位置)与调用方的不同.幸运的是,此问题已在v7 +中修复;一旦启动,作业将保持其自己的当前位置,并且对其进行更改不会影响调用者.
In PowerShell 6-, the initial current directory (filesystem location) for jobs was not the same as the caller's; fortunately, this is fixed in v7+; once started, jobs maintain their own current location and changing it does not affect the caller.
这篇关于PowerShell通过作业快速Ping子网的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!