【问题标题】:PowerShell script to execute if threshold exceeded超过阈值时执行的 PowerShell 脚本
【发布时间】:2017-09-20 03:39:46
【问题描述】:

首先,很抱歉这篇文章太长了——我正在尝试详细说明!

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

我想做的是通过带有 2 个 PowerShell 脚本的任务计划程序自动化整个过程。

----脚本 1----

条件如下:

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

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

动作:

  • Stop-Service 用于 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服务1,服务2,服务3

---脚本 2----

条件:

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

动作:

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

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

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

编辑

这是我为脚本 2 运行的内容 - 由 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; 
                                           }
}

【问题讨论】:

  • 看起来您已经具备了完成这项工作的基础。你有什么问题?你有什么问题?
  • 将您的代码粘贴到问题中。

标签: powershell if-statement move


【解决方案1】:

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

$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) 相同),因此优化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_*' 目录执行必要数量的批量恢复来增强这一点,所有这些都在循环的一次迭代中完成。

【讨论】:

  • 对,第二个脚本将枚举Hold* 目录列表并从那里处理每个目录。第二个脚本有点不清楚它是否按照与第一个脚本相同的时间表运行,以及您希望该过程是“动态的”是什么意思。至于if 语句,对ForEach-Object 的调用与以#Alternative: 为前缀的代码完成相同的事情,它只是试图更有效地执行此操作,因为您正在处理可能大量的文件。跨度>
  • 所以第二个脚本的重要部分是,我可以将它设置为每隔几个小时运行一次,将 5,000 个文件从保留文件夹移回工作文件夹,以便处理它们。这可以与第一个脚本并行运行,因为如果“WORKING”中当前存在的文件数量少于 50,000,它应该只开始将文件移回工作目录。这让我可以使用 10,000 个文件增量,并且应该确保处理实时文件和积压文件永远不会停止。我希望这有助于澄清。
  • 是的,抱歉,我在看到第二段涵盖了第二个脚本正在做什么之后,重新阅读了这个问题并编辑了我的评论。因此,您只是将文件移出工作目录以低于 100,000 个文件的“限制”,现在我看到您将它们移回以便在“安全”时进行处理。我假设一旦外部方法处理了文件,文件就会自动从工作目录中删除,但是它们排队等待处理的速度比处理速度快?
  • 非常感谢您的意见!我正在测试第二个脚本,但出现错误。 Get-ChildItem:找不到路径“C:\Windows\system32\UnprocessedHOLD3”,因为它不存在。在 line:20 char:22 + $restoredCount = Get-ChildItem -File -Path $holdDirectory | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (C:\ Windows\system32\UnprocessedHOLD3:String) [Get-Chi ldItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
  • HOLD3 目录的实际位置是什么?它是C:\Windows\system32\Unprocessed 目录的子目录吗? C:\Windows\system32 是这些文件操作的基目录对吗?
猜你喜欢
  • 2011-06-15
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 2019-08-15
  • 1970-01-01
相关资源
最近更新 更多