如果超过阈值,则执行PowerShell脚本

时间:2017-09-14 18:22:50

标签: powershell if-statement move

首先,对于长篇帖子感到抱歉 - 我正在努力提供详细信息!

我希望自动解决我发现的问题。我有一个工作人员,一旦“工作”目录中有超过100,000个文件,就会定期炸弹。预防性地我可以停止进程并将工作目录重命名为“HOLD”并创建新的工作目录以使其继续运行。然后我将文件从HOLD文件夹一次一点地移回到工作目录中,直到它陷入其中。

我想要做的是通过任务计划程序使用2个PowerShell脚本自动完成整个过程。

----脚本1 ----

这是条件:

  • 如果工作目录中的文件数大于60,000

我发现( [System.IO.Directory]::EnumerateFiles($Working)Get-ChildItem更快。

行动:

  • Stop-Service for Service1,Service2,Service3
  • Rename-Item -Path "C:\Prod\Working\" -NewName "Hold"或“Hold1”,“2”,“3”等。如果文件夹已经存在 - 我不是特别关于数字,只要它是一致的,所以如果它更容易让系统将其命名为HOLD,HOLD(1),HOLD(2)等。或者在HOLD之后追加日期,那就没事了。
  • New-Item C:\Prod\Working -type directory
  • Start-Service Service1,Service2,Service3

---脚本2 ----

条件:

  • 如果工作目录中的文件数小于50,000

操作:

  • 从HOLD *文件夹移动5,000个文件 - 从HOLD文件夹中移动5k文件直到空,然后跳过空文件夹并开始从HOLD1移动文件。此过程应该是动态的,并重复到下一个文件夹。

在它出现之前,我很清楚将文件从工作文件夹移动到Hold文件夹会更容易,但是文件的大小可能非常大并且移动它们似乎总是花费更长的时间

我非常感谢任何意见,我渴望看到一些可靠的答案!

修改

这就是我正在运行的剧本2 -courtesy of Bacon

#Setup
$restoreThreshold = 30000;  # Ensure there's enough room so that restoring $restoreBatchSize
$restoreBatchSize = 500;   # files won't push $Working's file count above $restoreThreshold
$Working = "E:\UnprocessedTEST\"
$HoldBaseDirectory = "E:\"

while (@(Get-ChildItem -File -Path $Working).Length -lt $restoreThreshold - $restoreBatchSize)
{
    $holdDirectory = Get-ChildItem -Path $HoldBaseDirectory -Directory -Filter '*Hold*' | 
    Select-Object -Last 1;
               
    if ($holdDirectory -eq $null)
    {
        # There are no Hold directories to process; don't keep looping
        break;
    }
# Restore the first $restoreBatchSize files from $holdDirectory and store the count of files restored
    $restoredCount = Get-ChildItem $holdDirectory -File `
    | Select-Object -First $restoreBatchSize | Move-Item -Destination $Working -PassThru | 
     Measure-Object | Select-Object -ExpandProperty 'Count';

   # If less than $restoreBatchSize files were restored then $holdDirectory is now empty; delete it
    if ($restoredCount -lt $restoreBatchSize)
    {
        Remove-Item -Path $holdDirectory; 
                                           }
}

1 个答案:

答案 0 :(得分:0)

第一个脚本可能如下所示:

$rotateThreshold = 60000;
$isThresholdExceeded = @(
    Get-ChildItem -File -Path $Working `
        | Select-Object -First ($rotateThreshold + 1) `
).Length -gt $rotateThreshold;
#Alternative: $isThresholdExceeded = @(Get-ChildItem -File -Path $Working).Length -gt $rotateThreshold;

if ($isThresholdExceeded)
{
    Stop-Service -Name 'Service1', 'Service2', 'Service3';

    try
    {
        $newName = 'Hold_{0:yyyy-MM-ddTHH-mm-ss}' -f (Get-Date);

        Rename-Item -Path $Working -NewName $newName;
    }
    finally
    {
        New-Item -ItemType Directory -Path $Working -ErrorAction SilentlyContinue;
        Start-Service -Name 'Service1', 'Service2', 'Service3';
    }
}

按照我的方式分配$isThresholdExceeded的原因是因为我们不关心文件的确切数量,只要它高于或低于该阈值。一旦我们知道已超出阈值,我们就不需要Get-ChildItem的任何进一步结果(或[System.IO.Directory]::EnumerateFiles($Working)的相同结果),因此opimization Select-Object将终止管道达到阈值后的元素。在SSD上有100,000个文件的目录中,我发现这比允许Get-ChildItem枚举所有文件(4.12对6.72秒)快了近40%。使用foreachForEach-Object的其他实现证明比@(Get-ChildItem -File -Path $Working).Length慢。

至于为'Hold'目录生成新名称,您可以在某处保存和更新标识符,或者只是生成带有递增后缀的新名称,直到找到一个未使用的名称。我认为将名称基于当前时间更容易。只要脚本每秒运行不超过一次就会知道名称是唯一的,它们的排序和数字一样好,而且它会给你一些诊断信息(目录被旋出的时间)免费。

以下是第二个脚本的一些基本代码:

$restoreThreshold = 50000;
$restoreBatchSize = 5000;

# Ensure there's enough room so that restoring $restoreBatchSize
# files won't push $Working's file count above $restoreThreshold
while (@(Get-ChildItem -File -Path $Working).Length -lt $restoreThreshold - $restoreBatchSize)
{
    $holdDirectory = Get-ChildItem -Path $HoldBaseDirectory -Directory -Filter 'Hold_*' `
        | Select-Object -First 1;

    if ($holdDirectory -eq $null)
    {
        # There are no Hold directories to process; don't keep looping
        break;
    }

    # Restore the first $restoreBatchSize files from $holdDirectory and store the count of files restored
    $restoredCount = Get-ChildItem -File -Path $holdDirectory.FullName `
        | Select-Object -First $restoreBatchSize `
        | Move-Item -Destination $Working -PassThru `
        | Measure-Object `
        | Select-Object -ExpandProperty 'Count';

    # If less than $restoreBatchSize files were restored then $holdDirectory is now empty; delete it
    if ($restoredCount -lt $restoreBatchSize)
    {
        Remove-Item -Path $holdDirectory.FullName;
    }
}

正如while循环之前的评论中所述,条件是确保$Working中的文件数量远离$restoreBatchSize至少$restoreThreshold个文件,以便如果$restoreBatchSize文件已恢复,则不会超过该过程中的阈值。如果您不关心这一点,或者所选阈值已经考虑到了这一点,您可以将条件更改为与$restoreThreshold而不是$restoreThreshold - $restoreBatchSize进行比较。或者,保持条件相同并将$restoreThreshold更改为55000

我编写循环的方式,在每次迭代时最多$restoreBatchSize个文件将从它找到的第一个'Hold_*'目录中恢复,然后重新评估$Working中的文件计数。考虑到这一点,据我所知,有些文件是从这个脚本外部的$Working添加和删除的,并且同时执行它,这可能是最安全的方法,也是最简单的方法。你当然可以通过计算你的$restoreThreshold以下的距离并从一个或多个'Hold_*'目录中执行必要数量的批量恢复来增强这一点,所有这些都在循环的一次迭代中完成。