我怎样才能与 Powershell 和 RoboCopy 一起将一系列文件动态移动到 固定大小的子文件夹?
原标题:How can I move an array of files dynamically with Powershell and RoboCopy to individual subfolders of a fixed size?
I am creating a script that splits a target folder s files into subfolders of n length, where n is a number specified dynamically.
So basically, if Folder A has 9000 files, and I limit the number of files to 1000 per folder, the script would create nine sub-directories inside of Folder A with 1000 files each.
Here is working code:
param (
[Parameter(Mandatory,Position=0)]
[String]
$FileList,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName)]
[Int32]
$NumFilesPerFolder = 1000,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName)]
[Int32]
$FolderNumberPadding = 2
)
$Folders = Get-Content $FileList
Set-Location -LiteralPath ([IO.Path]::GetTempPath())
function Move-Files {
[CmdletBinding()]
param (
[Parameter(Mandatory,Position=0)]
[System.Collections.ArrayList]
$List,
[Parameter(Mandatory)]
[Int32]
$Index
)
$BaseFolder = [System.IO.Path]::GetDirectoryName($List[0])
$DestFolderName = $Index.ToString().PadLeft($FolderNumberPadding, 0 )
$DestFolder = New-Item -Path (Join-Path $BaseFolder $DestFolderName) -Type Directory -Force
Move-Item $List -Destination $DestFolder -Force
}
foreach ($Folder in $Folders) {
$Files = Get-ChildItem -LiteralPath $Folder -File -Force
$filesidx = 1
$totalidx = $null
$groupidx = 0
$FilesToMove = [System.Collections.ArrayList]@()
foreach ($File in $Files) {
if($null -eq $totalidx){
$totalidx = $Files.Length
}
if($filesidx -eq 1){
$groupidx++
}
$FilesToMove.Add($File)
if($filesidx -eq $NumFilesPerFolder){
Move-Files -List $FilesToMove -Index $groupidx
$FilesToMove.Clear()
$filesidx = 1
}elseif($totalidx -eq 1){
Move-Files -List $FilesToMove -Index $groupidx
$FilesToMove.Clear()
break
}else{
$filesidx++
}
$totalidx--
}
}
Remove-Item $FileList -Force
$app = New-Object -ComObject Shell.Application
$appwin = $app.Windows()
foreach ($window in $appwin) {
if($window.Name -eq "File Explorer"){
$window.Refresh()
}
}
Invoke-VBMessageBox "Operation Complete" -Title "Operation Complete" -Icon Information -BoxType OKOnly
This code runs reasonably well, but it heavily bottlenecks when actually moving the files with Move-Item. I d like to try and use RoboCopy here, but I am perplexed as to how I can implement it.
What I m having trouble with is that the items I need to move are stored in a list (see the Move-Files function), and every item that needs to be moved are all in the same sub-directory. So I can t just do RoboCopy.exe C:Source C:Destination /mov.
How can I integrate RoboCopy here to accomplish my goal? I really need multi-threaded performance as this function will be responsible for moving thousands of files around in production on a frequent basis.
Any help would be greatly appreciated - please let me know if I can provide more information to further clarify my objective.
Thanks for any help at all!
问题回答
Following zett42s very helpful clues, i created the following script. Its taking the path to the folder with the files that supposed to be split up and the desired number of files per folder as paramter. After counting the files and declaring the number of folder shifts it creates a robocopy job file for each folder, listing the included files. Afterwards these multi threaded jobs are executed.
param (
[Parameter(Mandatory,Position=0)]
[String]
$FilePath,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName)]
[Int32]
$NumFilesPerFolder = 1000
)
$scriptPath= split-path -parent $MyInvocation.MyCommand.Definition
$rcjPath= $scriptPath +"RCJs"
if(-not(test-path -path $rcjPath)){New-Item -Path $scriptPath -Name RCJs"" -ItemType Directory}
$Files = gci -path $FilePath |?{$_ -is [System.IO.FileInfo]}| sort creationtime
$numberOfFiles= $Files.count
$numberOfFolderChanges= [math]::floor(($numberOfFIles / $NumFilesPerFolder))
write-host "$FilePath / $numberOfFiles /$numberOfFolderChanges /$scriptPath / $rcjPath"
for($indexOfFile=0;$indexOfFile -lt $numberOfFIles; $indexOfFile++){
$currentFile=$Files[$indexOfFile]
$nameOfCurrentFile=$currentFile.Name
#$CurrentFilePath=$currentFile.fullName
$indexOfRCJob=[math]::floor(($indexOfFile / $NumFilesPerFolder))
$pathcurrentRCJob= $rcjPath +"rcJob($indexOfRCJob).rcj"
if(test-path -path $pathcurrentRCJob){add-content -path $pathcurrentRCJob -value $nameOfCurrentFile}
else{
add-content -path $pathcurrentRCJob -value "/SD:$FilePath"
add-content -path $pathcurrentRCJob -value "/DD:$FilePathsubfolder$indexOfRCJob"
add-content -path $pathcurrentRCJob -value "/mov"
add-content -path $pathcurrentRCJob -value "/MT:20"
add-content -path $pathcurrentRCJob -value "IF"
add-content -path $pathcurrentRCJob -value $nameOfCurrentFile
}
}
gci -path $rcjPath | % {robocopy /job:"$($_.fullName)"}
相关问题
Why running a service as Local System is bad on windows?
I am trying to find out the difference between difference service account types. I tumbled upon this question.
The answer was because it has powerful access to local resources, and Network Service ...
Programmatically detect Windows cluster configuration?
Does anyone know how to programatically detect that a Windows server is part of a cluster?
Further, is it possible to detect that the server is the active or passive node?
[Edit] And detect it from ...
get file icon for Outlook appointment (.msg)
I ve read Get File Icon used by Shell and the other similar posts - and already use SHFileInfo to get the associated icon for any given extension, and that works great.
However, Outlook uses ".msg" ...
How can I create an empty file at the command line in Windows?
How can I create an empty file at the DOS/Windows command-line?
I tried:
copy nul > file.txt
But it always displays that a file was copied.
Is there another method in the standard cmd?
It should ...
Identifying idle state on a windows machine
I know about the GetLastInputInfo method but that would only give me the duration since last user input - keyboard or mouse. If a user input was last received 10 minutes ago, that wouldn t mean the ...
Terminating a thread gracefully not using TerminateThread()
My application creates a thread and that runs in the background all the time. I can only terminate the thread manually, not from within the thread callback function.
At the moment I am using ...
How do I set/clear the Windows archive bit with cygwin s find/chmod?
Yes, I know, the archive bit is evil.
That being said, is there support for querying it with find , and modifying it with chmod ?
My googling has turned up nothing......
Windows Executable to run Java application deleted by anti virus scanner
I built a Java application that is delivered on USB sticks. To ensure compatibility, I ship an appropriate JVM on the sticks. I made an EXE that simply invokes this JVM with the application jar.
Now ...