【问题标题】:How to copy a file then save the destination path to CSV如何复制文件然后将目标路径保存到 CSV
【发布时间】:2018-08-08 04:53:28
【问题描述】:

我正在尝试将一批文件(文件名以 6 位开头的文件)从临时文件夹复制到永久位置,不包括新位置中已存在的文件。

复制完成后,我想将复制文件的文件名和新路径导出为 CSV。

获取旧文件位置并导出为 CSV 非常容易,我只是不太确定如何获取新文件位置。

我的脚本如下所示:

# Prompt for file origin
$file_location = Read-Host -Prompt "Where do you want your files to come from?"
# Prompt for file destination 
$file_destination = Read-Host -Prompt "Where do you want your files to go? `n(They won't be copied if they're already there)"

# Save contents of file destination - used to check for duplicates
$dest_contents = Get-ChildItem $file_destination

<# For all of the files of interest (those whose names begin with 6 digits) in $file_location, 
     determine whether that filename already exists in the target directory ($file_destination)
     If it doesn't, copy the file to the destination
     Then save the filename and the new** filepath to a CSV #>

Get-ChildItem -Path $file_location |      
    Where-Object { $_.Name -match '^\d{6}' -And !($dest_contents -Match $_.Name ) } |
    Copy-Item -Destination $file_destination -PassThru | 
    Select-Object -Property Name, FullName |             # **Note: This saves the old filepath, not the new one
    Export-CSV -Path "$file_location\files_copied.csv" -NoClobber

【问题讨论】:

    标签: powershell powershell-2.0 export-to-csv


    【解决方案1】:

    您可以通过对代码进行一些更改来做到这一点

    # Prompt for file origin
    $file_location = Read-Host -Prompt "Where do you want your files to come from?"
    # Prompt for file destination 
    $file_destination = Read-Host -Prompt "Where do you want your files to go? `n(They won't be copied if they're already there)"
    
    # Save contents of file destination - used to check for duplicates
    $dest_contents = Get-ChildItem $file_destination | Select-Object -ExpandProperty Name
    
    <# For all of the files of interest (those whose names begin with 6 digits) in $file_location, 
         determine whether that filename already exists in the target directory ($file_destination)
         If it doesn't, copy the file to the destination
         Then save the filename and the new** filepath to a CSV #>
    
    Get-ChildItem -Path $file_location |      
        Where-Object { $_.Name -match '^\d{6}' -and ($dest_contents -notcontains $_.Name ) } |
        ForEach-Object { 
            Copy-Item -Path $_.FullName -Destination $file_destination 
            # emit a PSObject storing the Name and (destination) FullName of the file that has been copied
            # This will be used to generate the output in the 'files_copied.csv'
            New-Object -TypeName PSObject -Property ([ordered]@{ Name = $_.Name; FullName = (Join-Path $file_destination $_.Name)})
        } | 
        Export-CSV -Path "$file_location\files_copied.csv" -NoTypeInformation -Force
    

    请注意,我只收集目标路径中已有文件的名称,而不是 fileInfo 对象。这使它变得更“精简”,因为收集的唯一原因是有一组文件名进行比较。

    现在,'files_copied.csv' 有一个固定的名称,我个人认为最好通过添加当前日期来使其更通用,例如

    Export-CSV -Path ("{0}\files_copied_{1}.csv" -f $file_location, (Get-Date).ToString("yyyy-MM-dd")) -NoTypeInformation -Force 
    

    附:我在这里使用[ordered],因此输出将始终具有相同顺序的属性。但是,这需要 PowerShell v3 或更高版本。 另外,如果您需要确保代码只复制文件而不是目录,我建议查看Get-ChildItem 命令上的-File-Attributes 开关。如果您的 PowerShell 版本是 2.0,则可以使用 Where-Object { !$_.PSIsContainer } 构造仅过滤掉文件。

    【讨论】:

      【解决方案2】:
      • 在迭代源文件时,我会使用不同的方法测试目标是否存在。

      • 要附加到现有的 csv(日志)文件,您需要删除新文件的标题。

      • 由于 Get-ChildItem 允许范围 [0-9],您可以直接选择前导数字

      ## Q:\Test\2018\08\08\SO_51738853.ps1
      # Prompt for file origin
      $SrcDir = Read-Host -Prompt "Where do you want your files to come from?"
      
      # Prompt for file destination 
      $DstDir = Read-Host -Prompt "Where do you want your files to go? `n(They won't be copied if they're already there)"
      
      $SrcFiles = Join-Path (Get-Item $SrcDir).Fullname [0-9][0-9][0-9][0-9][0-9][0-9]*
      
      $CopiedFiles = ForEach ($SrcFile in (Get-ChildItem -Path $SrcFiles)){
          $DstFile = Join-Path $DstDir $SrcFile.Name
          If (!(Test-Path $DstFile)){
              $SrcFile | Copy-Item  -Destination $DstFile -PassThru | 
                  Select-Object -Property Name, FullName
          }
      }    
      
      # Check if log file exists, if yes append, otherwise export.
      $LogFile = Join-Path $SrcDir "files_copied.csv"
      If ($CopiedFiles){
          If (!(Test-Path $LogFile)){
              Export-CSV -Path $LogFile -InputObject $CopiedFiles -NoTypeInformation
          } else {
              # We need to remove the Header appending to the present csv
              $CopiedFiles | ConvertTo-Csv -NoType | Select-Object -Skip 1 | Add-Content -Path $LogFile
          }
      }
      

      【讨论】:

      • 这也太棒了! Theo 建议的解决方案对原始代码进行了最小的更改,并提供了对问题的准确答案。但是这个解决方案允许附加到日志文件,而不是为每个副本创建新文件。那是我的待办事项清单上的下一个!
      • 虽然,当您使用-InputObject 时,Export-CSV cmdlet 会将副本的摘要而不是文件名输出到日志文件。 else 语句适当地附加了现有的 CSV,因此我将该管道从:Export-CSV -Path $LogFile -InputObject $CopiedFiles -NoTypeInformation 更改为:$CopiedFiles | Export-CSV -Path $LogFile
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 1970-01-01
      • 2020-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-13
      相关资源
      最近更新 更多