首先,对于长篇帖子感到抱歉 - 我正在努力提供详细信息!
我希望自动解决我发现的问题。我有一个工作人员,一旦“工作”目录中有超过100,000个文件,就会定期炸弹。预防性地我可以停止进程并将工作目录重命名为“HOLD”并创建新的工作目录以使其继续运行。然后我将文件从HOLD文件夹一次一点地移回到工作目录中,直到它陷入其中。
我想要做的是通过任务计划程序使用2个PowerShell脚本自动完成整个过程。
----脚本1 ----
这是条件:
我发现( [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 ----
条件:
操作:
在它出现之前,我很清楚将文件从工作文件夹移动到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;
}
}
答案 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%。使用foreach
或ForEach-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_*'
目录中执行必要数量的批量恢复来增强这一点,所有这些都在循环的一次迭代中完成。