文件系统监视程序,使用虚拟机空闲时间运行脚本

问题描述 投票:0回答:1

我有3个虚拟机(VM1,VM2,VM3),对于所有三个VM,我有三个单独的powershell脚本。

1)VM1-Script1.ps1将监视文件扩展名为* .txt的目录更改并将其重命名为 前缀为* .host1.txt和* .host2.txt的文件)。2)VM2-Script2.ps1将监视扩展名为* .host1.txt的文件并触发外部程序3)VM3-Script3.ps1将监视扩展名为* .host2.txt的文件并触发外部程序

这绝对正常。但是,要求是,例如,如果VM2完成操作,并且如果扩展名为* host1.txt的目录中没有可用文件,则将其闲置,VM1上的脚本应监视并观察VM2是否空闲,因此应使用文件* .host1重命名。 txt,以便空闲VM可以运行该操作。

逻辑的基本思想是VM2和VM3不应闲置,script1.ps1监视目录中的文件,根据可用的VM重命名文件以运行执行。请提出任何建议,有关详细脚本的信息,请参见下面的链接。

File system watcher to run script based on virtual machine Idle time

powershell powershell-2.0 powershell-3.0 powershell-4.0
1个回答
0
投票

我还没有测试脚本,所以如果您可以帮助我调试它,那就太好了。我所写的内容是您要完成的工作的一个良好的开始,但是增加了用于将来扩展的功能。例如,它将允许您指定要在其上运行命令的更多VM,因此如果您需要通过在启动时指定正在运行的VM来扩展处理.bat文件的计算机数量。

我对您的脚本设计进行了几项重大修改。最明显的是,我没有在VM2和VM3上设置事件监视器,而是让VM1处理发送给VM2和VM3的命令。我还从每个事件中删除了$action字段,因为我认为这对您要完成的工作的总体设计没有帮助。

每五分钟将完成以下操作:

  • 从虚拟机池中删除所有已完成的作业
  • 获取从FileSystemWatcher触发的所有事件(拉出.bat路径)
  • 将命令推送到运行最少工作量的虚拟机
#Requires -Version 7
#Requires -PSEdition Desktop
# Remove space between # and Requires if VM needs permission to create files in D:\
# Requires -RunAsAdministrator
# Key: CO = Can optimize
class VirtualMachine {
    [String]$vmName
    [Object[]]$jobs
    VirtualMachine ([string]$vmName) {
        $this.jobs   =  @()
        $this.vmName =  $vmName
    }
    # Make it an array
    [boolean] RemoveJob ([int[]]$jobNumber) {
        $jobNumber = $jobNumber | 
                    Where-Object -FilterScript {
                        ($_ -gt 0) -and
                        ($_ -lt $this.jobs.count)
                    }
        if (    (-not ($null -eq $jobNumber)) -and 
                ($this.jobs.count -gt 0)    ) {
            # Set jobs object array skip $jobNumber
            $this.jobs = $this.jobs | Select-Object -SkipIndex $jobNumber
            return $true
        }
        return $false
    }
    [boolean] AddJob ([object]$job)
    {
        if (-not ($null -eq $job)) {
            $this.jobs += $job
            return $true
        }
        return $false
    }
}
### You will need to define VM's
# Can import vm names as a manual entry, or import from CSV
$VM = @()
if ($VM.count -eq 0) {
    throw "No VM's to run .bat files on"
}
$VMPool = @()
$VM |
ForEach-Object {
    # Generate a pool of virtual machines which each contain a job array
    $VMPool += [VirtualMachine]::new($_)
}
# Parameters for System.IO.FileSystemWatcher to be constructed with
$watcherParameters = @{
    Path                    = "C:\Test"
    Filter                  = "*.bat"
    IncludeSubdirectories   = $false
    EnableRaisingEvents     = $true
}
# Triggered when a .bat file is placed in C:\Test\
$watcher  = New-Object    -TypeName System.IO.FileSystemWatcher `
                          -Property $watcherParameters
#Parameters for Register-ObjectEvent
$objEventParameters = @{
    InputObject = $watcher
    EventName = "Created"
}                           
# If you ever need to modify this, make sure to catch the registered event so you can unregister if needed.
Register-ObjectEvent  @objEventParameters
while ($true)   {
                    $batFiles = @()
                    ### Clean up virtual machine jobs if unneeded (CO)
                    $VMPool |
                    ForEach-Object {
                        $FinishedJobs = @()
                        $count = 0
                        $_.jobs |
                        ForEach-Object {
                            if ($_.State -eq "Completed") {
                                $FinishedJobs += $count
                            }
                            $count += 1
                        }
                        if (-not ($null -eq $FinishedJobs)) {
                            $_.RemoveJob($FinishedJobs)
                        }
                    }
                    ### Running virtual machine jobs if needed
                    # Get list of current .bat files to process from FileSystemWatcher
                    Get-Event |
                    ForEach-Object {
                        $batFiles += $_.SourceEventArgs.FullPath
                    }
                    #Remove all the file creation events
                    Get-Event | 
                    ForEach-Object {
                        Remove-Event -SourceIdentifier $_.SourceIdentifier
                    }
                    if ($batFiles.count -gt 0) {
                        # Log current queued bat files in "D:\log.txt"
                        $logline = "QUEUED BAT FILES $(Get-Date)"                        
                        $batFiles | 
                        ForEach-Object {
                            $logline += $_ + "`n"
                        }
                        Add-content "D:\log.txt" -value $logline
                        # Pull total jobs from VMPool (CO)
                        $batFiles |
                        ForEach-Object {
                            $path = $_
                            $VMPoolJobsTotal =  $VMPool |
                                                ForEach-Object { 
                                                    $_.jobs.Count
                                                }
                            $minValue = [int]($VMPoolJobsTotal | Measure-Object -Minimum).Minimum
                            $VMPool |
                            ForEach-Object
                            {
                                #First VM we find with minimum jobs (CO)
                                if ( $_.jobs.Count -eq $minValue )
                                {
                                    $Task = Invoke-Command      -FilePath       $path      `
                                                                -ComputerName   $_.vmName  `
                                                                -AsJob
                                    #Add job to Virtual Machine's jobs
                                    $_.AddJob($Task)
                                    #Exit the loop, we don't need to go through any other VM's since we found one with least jobs.
                                    break
                                }
                            }
                        }
                    }
                    # Chill for a bit afterward, will push out batch commands every five minutes.
                    # Can integrate this with a GUI to push out the .bat's to VM's
                    Start-Sleep -Seconds 300
                }
# Created by Riley Carney
# Q&A: https://stackoverflow.com/questions/62098957/file-system-watcher-to-run-scripts-using-virtual-machine-idle-time
© www.soinside.com 2019 - 2024. All rights reserved.