Powershell 文件夹监视/批处理执行

Powershell 文件夹监视/批处理执行

我是 Powershell 新手。我找到了一个可以满足我需求的脚本。

我正在寻找一个脚本来监视文件夹中的特定文件名/类型。根据文件名/类型,我希望它执行某个批处理文件来执行服务器实用程序的命令。

我究竟该如何实现这一点?我找到了这个脚本并添加了一个调用项,用于在文件夹中出现 PDF 等文件时启动一个 batfile。但是,我需要对其进行过滤,并让它根据文件名启动不同的 bat 文件。我目前的做法是,它会为文件夹中我不想要的每个文件调用 bat 文件。我的知识很少,我只知道足够危险的知识。

如果 XXXX.PDF、XXRX.PDF、XXLX.PDF 进入文件夹,我需要它知道 XXXX.PDF 是否进入,仅运行 XXXX.bat。如果 XXRX.PDF 进入,仅运行 XXRX.BAT,等等。

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = "D:\XXXX\XXXX"
    $watcher.Filter = "*.PDF"
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true 

### DEFINE ACTIONS AFTER A EVENT IS DETECTED

    $action = {Invoke-Item "D:\BATCH FILES\XXXXX.bat" -filter = "XXXXX.pdf"}    

### DECIDE WHICH EVENTS SHOULD BE WATCHED + SET CHECK FREQUENCY  
    $created = Register-ObjectEvent $watcher "Created" -Action $action
###    $changed = Register-ObjectEvent $watcher "Changed" -Action $action
###    $deleted = Register-ObjectEvent $watcher "Deleted" -Action $action
###    $renamed = Register-ObjectEvent $watcher "Renamed" -Action $action
    while ($true) {sleep 5}

答案1

FileWatchers 有怪癖,取决于文件的创建方式

在某些情况下,您可能会注意到,单个创建事件会生成多个由组件处理的 Created 事件。例如,如果您使用 FileSystemWatcher 组件监视目录中新文件的创建,然后使用记事本创建文件对其进行测试,您可能会看到生成两个 Created 事件,尽管只创建了一个文件。这是因为记事本在写入过程中执行了多个文件系统操作。记事本分批写入磁盘,先创建文件内容,然后创建文件属性。其他应用程序可能以相同的方式执行。由于 FileSystemWatcher 监视操作系统活动,因此这些应用程序触发的所有事件都将被拾取。

注意:记事本还可能导致其他有趣的事件生成。例如,如果您使用 ChangeEventFilter 指定只想监视属性更改,然后使用记事本写入您正在监视的目录中的文件,则会引发事件。这是因为记事本在此操作期间更新了文件的存档属性。

因此,对于您的情况,我将使用普通目录比较。以下是将监视目录更改并运行文件的脚本。将此脚本另存为MonitorAndExecute.ps1。它接受以下参数:

  • 小路要监视的文件夹。如果未指定,则使用当前目录。
  • 筛选匹配的文件扩展名。默认为*,即匹配所有文件。
  • 跑步当发现新文件时运行的文件扩展名。默认值为bat
  • 递归是否递归目录。默认为 false。
  • 间隔文件夹扫描之间的休眠时间(以秒为单位)。默认值为5秒。
  • 详细脚本将通过消息告诉您发生了什么Write-Verbose

示例(从 PowerShell 控制台运行)。

监视*.pdf文件夹中的文件D:\XXXX\XXXX,递归,如果发现新文件,则运行具有相同基本名称和扩展名的文件*.bat,详细:

.\MonitorAndExecute.ps1 -Path 'D:\XXXX\XXXX' -Filter '*.pdf' -Run 'bat' -Recurse -Interval 10 -Verbose

MonitorAndExecute.ps1脚本:

Param
(
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [ValidateScript({
        if(!(Test-Path -LiteralPath $_ -PathType Container))
        {
            throw "Input folder doesn't exist: $_"
        }
        $true
    })]
    [ValidateNotNullOrEmpty()]
    [string]$Path = (Get-Location -PSProvider FileSystem).Path,

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$Filter = '*',

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$Run = 'bat',

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [switch]$Recurse,

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [int]$Interval = 5
)

# Scriptblock that gets list of files
$GetFileSet = {Get-ChildItem -LiteralPath $Path -Filter $Filter -Recurse:$Recurse | Where-Object {!($_.PSIsContainer)}}

Write-Verbose 'Getting initial list of files'
$OldFileSet = @(. $GetFileSet)
do
{
    Write-Verbose 'Getting new list of files'
    $NewFileSet = @(. $GetFileSet)

    Write-Verbose 'Comaparing two lists using file name and creation date'
    Compare-Object -ReferenceObject $OldFileSet -DifferenceObject $NewFileSet -Property Name, CreationTime -PassThru |
        # Select only new files
        Where-Object { $_.SideIndicator -eq '=>' } |
            # For each new file...
            ForEach-Object {
                Write-Verbose "Processing new file: $($_.FullName)"
                # Generate name for file to run
                $FileToRun = (Join-Path -Path (Split-Path -LiteralPath $_.FullName) -ChildPath ($_.BaseName + ".$Run"))

                # If file to run exists
                if(Test-Path -LiteralPath $FileToRun -PathType Leaf)
                {
                    Write-Verbose "Running file: $FileToRun"
                    &$FileToRun
                }
                else
                {
                    Write-Verbose "File to run not found: $FileToRun"
                }
            }

    Write-Verbose 'Setting current list of files as old for the next loop'
    $OldFileSet = $NewFileSet

    Write-Verbose "Sleeping for $Interval seconds..."
    Start-Sleep -Seconds $Interval
}
while($true)

相关内容