Powershell同时唤醒多个媒体驱动器



我有一个服务器,有很多媒体驱动器~43TB。areca 1882ix-16被设置为在30分钟不活动后旋转驱动器,因为大多数日子单个驱动器甚至不使用。这很好地防止了不必要的电力和热量。在这种情况下,驱动器仍然显示在windows资源管理器中,但当你点击访问它们时,文件夹列表需要大约10秒才能显示,因为它必须等待驱动器启动。

对于管理工作,我需要启动所有的驱动器,以便能够在其中进行搜索。在windows资源管理器中单击每个驱动器,然后在单击下一个驱动器之前等待它启动是非常繁琐的。显然,多个资源管理器窗口使它更快,但它仍然是乏味的。我想一个powershell脚本可以减轻痛苦。

所以我从下面开始:

$mediaDrives = @('E:', 'F:', 'G:', 'H:', 'I:', 'J:', 'K:', 'L:',
    'M:','N:', 'O:', 'P:', 'Q:', 'R:', 'S:')
get-childitem $mediaDrives  | foreach-object -process { $_.Name }

这只是请求数组中的每个驱动器都列出其根文件夹名称。这可以唤醒驱动器,但它还是一个线性函数。脚本在打印之前暂停每个驱动器。寻找如何同时唤醒每个驱动器的解决方案。是否有办法多线程或其他东西?

这里有一个脚本可以做你想做的事情,但是它必须在powershell下使用MTA线程模式运行(这是powershell.exe 2.0的默认模式,但是powershell.exe 3.0必须使用-MTA开关启动)

#require -version 2.0
# if running in ISE or in STA console, abort
if (($host.runspace.apartmentstate -eq "STA") -or $psise) {
    write-warning "This script must be run under powershell -MTA"
    exit
}
$mediaDrives = @('E:', 'F:', 'G:', 'H:', 'I:', 'J:', 'K:', 'L:',
    'M:','N:', 'O:', 'P:', 'Q:', 'R:', 'S:')
# create a pool of 8 runspaces   
$pool = [runspacefactory]::CreateRunspacePool(1, 8)
$pool.Open()
$jobs = @()
$ps = @()
$wait = @()     
$count = $mediaDrives.Length
for ($i = 0; $i -lt $count; $i++) {
    # create a "powershell pipeline runner"
    $ps += [powershell]::create()  
    # assign our pool of 8 runspaces to use
    $ps[$i].runspacepool = $pool   
    # add wake drive command
    [void]$ps[$i].AddScript(
        "dir $($mediaDrives[$i]) > `$null")
    # start script asynchronously    
    $jobs += $ps[$i].BeginInvoke();         
    # store wait handles for WaitForAll call
    $wait += $jobs[$i].AsyncWaitHandle
}
# wait 5 minutes for all jobs to finish (configurable)
$success = [System.Threading.WaitHandle]::WaitAll($wait,
    (new-timespan -Minutes 5))     
write-host "All completed? $success"
# end async call   
for ($i = 0; $i -lt $count; $i++) {     
    write-host "Completing async pipeline job $i"    
    try {       
        # complete async job           
        $ps[$i].EndInvoke($jobs[$i])     
    } catch {   
        # oops-ee!          
        write-warning "error: $_"      
    }   
    # dump info about completed pipelines       
    $info = $ps[$i].InvocationStateInfo
    write-host "State: $($info.state) ; Reason: $($info.reason)"  
}

例如,保存为warmup.ps1,然后运行:powershell -mta c:scriptswarmup.ps1

要了解更多关于运行空间池和上述一般技术的信息,请查看我关于runspacepools的博客文章:

http://nivot.org/blog/post/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators

我选择了8作为并行因子,这几乎是任意的——你可以用更低或更高的数字来做实验。

为每个驱动器启动一个单独的powershell实例或使用powershell 3.0中的工作流。无论如何,您可以直接将驱动器传递给Path参数,并一起跳过Foreach-Object:

Get-ChildItem $mediaDrives

您是否考虑过使用Start-Job cmdlet来解决这个问题:

$mediaDrives = @('E:', 'F:', 'G:', 'H:', 'I:', 'J:', 'K:')
$mediaDrives | ForEach-Object {
  Start-Job -ArgumentList $_ -ScriptBlock {param($drive)
    Get-ChildItem $drive
  }
}

唯一聪明的部分是您需要在Start-Job cmdlet上使用-ArgumentList参数来为每次迭代传递正确的值。这将创建一个与脚本执行并行运行的后台任务。如果你很好奇

如果你不想等待,那就不要等待:在后台启动那些唤醒电话。

bash中可以写

foreach drive ($mediadrives) {tickle_and_wake $drive &}

(注意&符号,这意味着:在后台启动命令,不要等待它完成)

在PowerShell中会转换成类似

的内容
foreach ($drive in $mediadrives)  {
   Start-Job {param($d) tickle_and_wake $d} -Arg $drive 
}

如果您想确认所有后台任务已经完成,在Powershell

中使用bashWait-Job中的wait

相关内容

  • 没有找到相关文章

最新更新