我正在尝试编写一个脚本,将大型共享的文件结构保存到文本文件中,其中每行是文件夹或路径+文件,并从已提取的大量文件中重建此结构保存在平面文件夹中。所以我想搜索文本文件,当我找到平面文件夹中的匹配项时,我想将该文件从平面文件夹中保存到新位置,但保留文件所在位置的文件夹结构(在文本中)文件)。如果文件在结构中多次(在文件夹结构中的其他文件夹中重复),我真的不在乎。
例如:我在原始结构的文本文件($outfile
)中有以下项目:
H:\
H:\a.doc
H:\b\c\d.pdf
H:\b\c\e\f\g.xls
然后我
a.doc
d.pdf
g.xls
所有在没有文件夹($extractpath
)的平面文件夹中,我想将它们复制到类似
I:\a.doc
I:\b\c.pdf
I:\b\c\e\f\g.xls
所以我需要
$outfile
c.doc
,H:\b\
和H:\b\c.doc
c.doc
复制到I:\b\
鉴于$outfile
对于每行文本文件(27m)来说有点大,我希望有一种优雅的方法来执行一次目录结构编写,然后将文件读入内存并检查每个文件名在$extractpath
中,从$filepath
中提取$outfile
,然后将此文件复制到$filepath
。
这是我到目前为止所做的事情(尚未开展工作):
# Path to log file date/timestamped
$logfile = "D:\Shares\Extracted\_extracted_2_$(Get-Date -format 'yyyyMMdd_hhmm').log"
# Path of root directory
$rootfolder = "H:\"
# Text file with Structure of the root directory, recursively
$outfile = "D:\Shares\Extracted\__struct.txt"
# Path of the files that were previously extracted with extract.ps1
$extractpath = "D:\Shares\Extracted"
# Path to move files to
$newpath = "D:\Shares\New"
if (!(Test-Path $outfile -PathType Leaf)) {
Get-ChildItem $rootfolder | select -Expand fullname > $outfile
Get-ChildItem $rootfolder -recurse | select -Expand fullname > $outfile
} else {
Write-Output "File $outfile exists.. Reading from it.."
}
$files = get-childitem $extractpath
foreach ($file in $files) {
$filepath = $null
$filepaths = (Get-Content -Path $outfile | Where-Object { $_ -like '*$filename'})
foreach ($filepath in $filepaths){
if ($filepath) {
Copy-Item $file -Destination "$newpath\$filename"
} else {
Write-Output "Not found: $filename..."
}
}
}
编辑:感谢下面的Ansgar Wiechers,我不是最多15个帖子所以我还不能投票给你。这就是我创建的并最终在我的测试数据上完美运行(我的testpath()函数目前已被破坏,因此忽略了我在那里的范围问题)..
$outfile = "d:\Shares\Extracted\__struct.txt"
$outfolder = "d:\Shares\Extracted\__folder.txt"
$extract = "d:\Shares\Extracted"
$oldpath = "H:\"
$newpath = "d:\newH\" #Make sure this has trailing backslash
$multfile = "d:\newH\__multiple.log"
$logfile = "d:\newH\__ext2_$(get-date -format `"yyyyMMdd_hhmm`").log"
$tpok=$false
function log($string, $color)
{
if ($Color -eq $null) {$color = "white"}
write-host $string -foregroundcolor $color
$string | out-file -Filepath $logfile -append
}
function multlog($string, $color)
{
if ($Color -eq $null) {$color = "white"}
write-host $string -foregroundcolor $color
$string | out-file -Filepath $logfile -append # put in both log files but output to screen only once
$string | out-file -Filepath $multfile -append
}
function testpath($tpok)
{
$outpath = Split-Path -Path $outfile
$logpath = Split-Path -Path $logfile
$multpath = Split-Path -Path $multfile
if (!(Test-Path $outpath)) { log "bad Output path: $outfile" red return $false }
if (!(Test-Path $multpath)) { log "bad Multiples path: $multpath" red return $false }
if (!(Test-Path $extract)) { log "bad Extract path: $extract" red return $false }
if (!(Test-Path $oldpath)) { log "bad Oldpath path: $oldpath" red return $false }
if (!(Test-Path $newpath)) { log "bad Newpath: $newpath" red return $false }
if (!(Test-Path $logpath)) { log "bad Logfile: $logfile" red return $false}
log "Paths test good.." yellow
$tpok = $true
return $true
}
function buildstructfiles()
{
$testoutfile=(Test-Path $outfile -PathType Leaf)
if (!($testoutfile)) {
log "Writing $outfile.." yellow
log "Files in the root only.." yellow
get-childitem $oldpath | where {!($_.psiscontainer)} | select -expand fullname > $outfile |
log "Recursive directory export.." yellow
get-childitem $oldpath -recurse | where {!($_.psiscontainer)} | select -expand fullname >> $outfile
log "Done." yellow
} else {
log "File $outfile exists.. Reading from it.." yellow
}
$testoutfolder=(Test-Path $outfolder -PathType Leaf)
if (!($testoutfolder)) {
log "Writing $outfolder.." yellow
log "Folders in the root only.." yellow
get-childitem $oldpath | where {($_.psiscontainer)} | select -expand fullname > $outfolder
log "Folders recursively.." yellow
get-childitem $oldpath -recurse | where {($_.psiscontainer)} | select -expand fullname >> $outfolder
} else {
log "File $outfolder exists.. Reading from it.." yellow
}
}
function Main()
{
$destination = @{}
if (!(testpath)) { Exit }
buildstructfiles
# Read full path+filenames from $outfile and create new destinations for each file in array $destination
log "$(get-date -format `"yyyyMMdd_HHmm`") Reading $outfile check and writing $newpath destinations.. " yellow
Get-Content $outfile | Where-Object {
$_ -notmatch '\\$' # remove folders (lines with trailing backslash)
} | ForEach-Object {
$filename = Split-Path -Leaf $_
log "Filename: $filename"
$chgoldpath = Split-Path -Path $_ # take path of current object
$chg = $chgoldpath -replace [regex]::Escape($oldpath), $newpath #replace $oldpath with $newpath
if ($destination.Contains($filename)) {
# it has already been found. Log this in a separate file as well for later comparison
multlog "$filename has already been found in $($destination[$filename]), now in $chgoldpath" red
}
$destination[$filename]=$chg #save this into an array
log "New Destination: $($destination[$filename])"
log "----"
}
# create directory structure from saved txt file $outfolder
log "$(get-date -format `"yyyyMMdd_HHmm`") Create folders in new structure $newpath" red
Get-Content $outfolder | ForEach-Object {
log "object: $_"
$d = ($_ -replace [regex]::Escape($oldpath), $newpath)
log "New Directory to be created: $d" yellow
if (!(Test-Path($d))) {
new-item $d -itemtype directory
} else {
log "Directory already exists! $d" gray
}
}
# Or use robocopy to replicate folder structure
# log "$(get-date -format `"yyyyMMdd_HHmm`") Starting folder structure Robocopy.." yellow
# robocopy $oldPath $newPath /e /xf /LOG+:$logFile
# Copy the files from $extractpath to new $destination
Get-ChildItem $extract | ForEach-Object {
$dname = Split-Path -Leaf $_
$dfolder = Split-Path -Path $_
if ($destination.Contains($dname)) {
log "$($dname): Destination $($destination[$dname])" darkcyan
Copy-Item $_ -Destination ($destination[$dname])
} else {
log "$($dname) does not exist in $oldpath, not restored." red
}
}
}
Main
答案 0 :(得分:0)
假设您的所有文件名都是唯一的(因为它们位于单个文件夹中),您可以将目标文件读入哈希表,将每个文件名映射到其目标路径:
$outfile = 'D:\Shares\Extracted\__struct.txt'
$rootdrive = 'H:'
$newpath = 'D:\Shares\New'
$destination = @{}
Get-Content $outfile | Where-Object {
$_ -notmatch '\\$' # remove folders (lines with trailing backslash)
} | ForEach-Object {
$filename = Split-Path -Leaf $_
$destination[$filename] = $_ -replace "^$rootdrive", $newpath
}
如果您需要(重新)创建丢失的文件夹(原始问题没有提及),您可以在同一步骤中执行此操作:
$destination = @{}
Get-Content $outfile | Where-Object {
$_ -notmatch '\\$' # remove folders (lines with trailing backslash)
} | ForEach-Object {
$path = $_ -replace "^$rootdrive", $newpath
$filename = Split-Path -Leaf $path
$folder = Split-Path -Parent $path
$destination[$filename] = $path
if (-not (Test-Path -PathType Container -LiteralPath $folder)) {
New-Item -Type Directory $folder | Out-Null
}
}
然后您可以像这样复制$extractpath
中的文件:
$extractpath = 'D:\Shares\Extracted'
Get-ChildItem $extractpath | Copy-Item -Destination {$destination[$_.Name]}