1

我有一个将Office文档转换为PDF的Powershell脚本。我想多线程,但无法根据我见过的其他例子来弄清楚。主脚本(OfficeToPDF.ps1)扫描文件列表,并为每个文件类型/办公应用程序调用单独的脚本(例如调用WordToPDF.ps1以转换)。主脚本一次将1个文件名传递给子脚本(出于几个原因,我这样做了)。Powershell多线程

这里是主脚本的一个示例:

$documents_path = "C:\Documents\Test_Docs" 
    $pdf_out_path = "C:\Documents\Converted_PDFs" 
    $failed_path = "C:\Documents\Failed_to_Convert" 

    # Sets the root directory of this script 
    $PSScriptRoot = Split-Path -parent $MyInvocation.MyCommand.Definition 

    $date = Get-Date -Format "MM_dd_yyyy" 
    $Logfile = "$PSScriptRoot\logs\OfficeToTiff_$Date.log" 

    $word2PDF = "$PSScriptRoot\WordToPDF.ps1" 
    $arguments = "'$documents_path'", "'$pdf_out_path'", "'$Logfile'" 

    # Function to write to log file 
    Function LogWrite 
    { 
     Param ([string]$logstring) 
     $time = Get-Date -Format "hh:mm:ss:fff" 

     Add-content $Logfile -value "$date $time $logstring" 
    } 


################################################################################ 
# Word to PDF                 # 
################################################################################ 

    LogWrite "*** BEGIN CONVERSION FROM DOC, DOCX, RTF, TXT, HTM, HTML TO PDF ***" 

    Get-ChildItem -Path $documents_path\* -Include *.docx, *.doc, *.rtf, *.txt, *.htm? -recurse | ForEach-Object { 

      $original_document = "$($_.FullName)" 

      # Verifies that a document exists before calling the convert script 
      If ($original_document -ne $null) 
      { 

       Invoke-Expression "$word2PDF $arguments" 

       #checks to see if document was successfully converted and deleted. If not, doc is moved to another directory 
       If(Test-Path -path $original_document) 
       { 
       Move-Item $original_document $failed_path 
       } 
      } 
     } 

    $original_document = $null 

    [gc]::collect() 
    [gc]::WaitForPendingFinalizers() 

这里是脚本(WordToPDF.ps1),其由主脚本调用:

Param($documents, $pdf_out_path, $Logfile) 

# Function to write to the log file 
Function LogWrite 
{ 
    Param ([string]$logstring) 
    $time = Get-Date -Format "hh:mm:ss:fff" 

    Add-content $Logfile -value "$date $time $logstring" 
} 

$word_app = New-Object -ComObject Word.Application 

$document = $word_app.Documents.Open($_.FullName) 
$original_document = "$($_.FullName)" 

# Creates the output file name with path 
$pdf_document = "$($pdf_out_path)\$($_.BaseName).pdf" 

LogWrite "Converting: $original_document to $pdf_document" 
$document.SaveAs([ref] $pdf_document, [ref] 17) 
$document.Close() 

# Deletes the original document after it has been converted 
Remove-Item $original_document 
LogWrite "Deleting: $original_document" 

$word_app.Quit() 

任何建议,将不胜感激。 谢谢。

回答

1

我只是要评论并将您链接到此问题:Can PowerShell run commands in Parallel。然后我注意到这个问题的日期和答案,并且在PowerShell v3.0中,有一些新功能可能对您更好。

问题在于使用PowerShell jobs。哪些可以工作,但需要你跟上工作状态,所以可以添加一些额外的编码来管理。

PowerShell v3以workflow打开了一扇门,它基于Windows Workflow Foundation。关于这个新命令如何工作的基础知识的好文章可以是found on Script Guy's blog here。基本上你可以调整你的代码运行通过工作流程转换,它会并行地执行这样的:

workflow foreachfile { 
    foreach -parallel ($f in $files) { 
    #Put your code here that does the work 
    } 
} 

从什么我能找到线程限制这已经是在一个时间5个线程。我不确定这是多么准确,但是blog post here noted the limitation。但是,由于应用程序COM对象的Word和Excel可能非常耗费CPU时间,因此一次执行5个线程可能效果不错。

+0

对于性能,我会避免PSJobs。如果OP升级到PS v4.0,则在Foreach工作流程中有“-ThrottleLimit”选项。不过,我发现后台运行空间比工作流更容易理解。 – xXhRQ8sD2L7Z

+0

谢谢,我会试试这个并发布我的结果。 – DaveC

0

我有一个多线程的powershell环境,用于在所有AD设备上进行折衷扫描指示器 - 与Gearman进行了625次的连接。 http://gearman.org

它是开源的,允许跨平台的选项。它与服务器工作流进行线程连接,并通过Python运行。真正被你们非常推荐的人 - 滥用PowerShell中的线程的人。这不是一个答案,而是我从来没有听说过的东西,但是每天都爱和使用。传递它。开放源码的胜利:)

我也使用psjobs之前,他们是伟大的,直到一定的数量级。也许这是我的.net专业知识的缺乏,但ps有一些令人毛骨悚然的细微记忆细微差别,大规模可能会产生一些令人讨厌的效果。