【问题标题】:How to append GUID to existing filenames and save to CSV如何将 GUID 附加到现有文件名并保存到 CSV
【发布时间】:2019-02-03 15:01:02
【问题描述】:

我目前有一个 CSV,其中包含 1 列,其中列出了许多文件全名。 (即“\\server\sub\folder\file.ext”)。

我正在尝试导入此 CSV,将文件移动到单独的位置,并将 GUID 附加到新位置的文件名开头(即 GUID_File.ext)。我已经能够移动文件,生成 GUID_,但无法存储和重用现有的 filename.ext,它只是被切断,文件最终只是一个 GUID_。我只是不确定如何存储现有文件名以供重复使用。

$Doc = Import-CSV C:\Temp\scripttest.csv

ForEach ($line in $Doc)
{
 $FileBase = $Line.basename 
 $FileExt = $Line.extension 
Copy-Item -path  $line.File -Destination "\\Server\Folder\$((new-guid).guid.replace('-',''))_$($Filebase)$($FileExt)"
}

如果可能,我还需要将所有新的 GUID_File.ext 存储并放回 CSV,并将所有错误存储到另一个文件中。

【问题讨论】:

  • CSV 文件的标题是什么?
  • 脚本中的逻辑没有任何问题,但我怀疑您的 CSV 文件或其标题存在问题。如果您注释掉Copy-Item 行并将其替换为$line.File | Out-host 如果会显示您的错误,我怀疑路径是NULL。另一种方法是只做一个$Doc 并查看它向您的控制台输出的内容。
  • 列的标题是“文件”,其内容是文件的完整共享路径。 (即 \\Server\sub\folder\file.ext)。如果我猜测问题出在哪里,那就是路径和文件包含在同一列中。

标签: windows shell powershell scripting guid


【解决方案1】:

我目前有一个 CSV,其中包含 1 列,其中列出了许多文件全名。 (即“\server\sub\folder\file.ext”)。

这不是 CSV。它只是一个带有列表的纯文本文件。

但是,您可以通过以下方式实现目标:

foreach ($path in (Get-Content -Path C:\Temp\scripttest.csv))
{
    $file = [System.IO.FileInfo]$path
    $prefix = (New-Guid).Guid -replace '-'
    Copy-Item -Path $file.FullName -Destination "\\Server\Folder\${prefix}_$file"
}

这将获取您的列表,将项目转换为它可以使用的 FileInfo 类型,然后执行其余的逻辑。

【讨论】:

  • CSV 中还有很多其他列,但在这部分脚本中使用我只使用此列。一旦我可以访问单独的虚拟机,我会在早上尝试一下。谢谢。
【解决方案2】:

基于:

$FileBase = $line.basename
$FileExt = $line.extension

听起来您错误地认为代表从Import-Csv C:\Temp\scripttest.csv 返回的对象的$line 实例是[System.IO.FileInfo] 实例,但它们不是:

Import-Csv 的输出是[pscustomobject] 实例,其属性 反映了输入 CSV 的列值,并且这些属性的值总是字符串 .

因此,您必须使用 $line.<column1Name> 来引用包含完整文件名的列,其中 <column1Name> 是为输入 CSV 文件的标题行(第一行)中感兴趣的列定义的名称。

如果 CSV 文件没有标题行,您可以通过将列名数组传递给 Import-Csv-Header 参数来指定列名,例如,
Import-Csv -Header Path, OtherCol1, OtherCol2, ... C:\Temp\scripttest.csv

我假设在以下解决方案中感兴趣的列名为Path

$Doc = Import-Csv C:\Temp\scripttest.csv

ForEach ($rowObject in $Doc)
{
  $fileName = Split-Path -Leaf $rowObject.Path
  Copy-Item -Path $rowObject.Path `
            -Destination "\\Server\Folder\$((new-guid).guid.replace('-',''))_$fileName"
}

注意Split-Path -Leaf 如何用于从完整输入路径中提取文件名,包括扩展名。

【讨论】:

  • CSV 中有更多数据将在另一个过程中使用,但对于这个移动/复制项目片段仅使用您所称的“路径”列。我喜欢您使用 Split-Path 将文件路径与实际 file.ext 分开的方式。我认为这是问题所在,但解决方案并没有出现。谢谢你。一旦我早上可以访问虚拟机,我将进行测试并做出回应。谢谢。
【解决方案3】:

如果我仔细阅读了您的问题,您希望:

  • 复制“文件”列中 CSV 文件中列出的文件。
  • 新文件应在文件名前附加一个 GUID
  • 您需要一个新的 CSV 文件,其中存储了新的文件名以供以后参考
  • 您想要跟踪任何错误并将其写入(日志)文件

假设您有一个如下所示的输入 CSV 文件:

File,Author,MoreStuff
\\server\sub\folder\file.ext,Someone,Blah
\\server\sub\folder\file2.ext,Someone Else,Blah2
\\server\sub\folder\file3.ext,Same Someone,Blah3

然后下面的脚本希望你想要什么。 它通过在新文件名前添加 GUID 来创建新文件名,并将File 列中列出的 CSV 中的文件复制到某个目标路径。 它在目标文件夹中输出一个新的 CSV 文件,如下所示:

OriginalFile,NewFile
\\server\sub\folder\file.ext,\\anotherserver\sub\folder\38f7bec9e4c0443081b385277a9d253d_file.ext
\\server\sub\folder\file2.ext,\\anotherserver\sub\folder\d19546f7a3284ccb995e5ea27db2c034_file2.ext
\\server\sub\folder\file3.ext,\\anotherserver\sub\folder\edd6d35006ac46e294aaa25526ec5033_file3.ext

所有错误都列在日志文件中(也在目标文件夹中)。

$Destination = '\\Server\Folder'
$ResultsFile = Join-Path $Destination 'Copy_Results.csv'
$Logfile     = Join-Path $Destination 'Copy_Errors.log'
$Doc         = Import-CSV C:\Temp\scripttest.csv

# create an array to store the copy results in
$result = @()
# loop through the csv data using only the column called 'File'
ForEach ($fileName in $Doc.File) {
    # check if the given file exists; if not then write to the errors log file
    if (Test-Path -Path $fileName -PathType Leaf) {
        $oldBaseName = Split-Path -Path $fileName.Path -Leaf
        # or do $oldBaseName = [System.IO.Path]::GetFileName($fileName)
        $newBaseName = "{0}_{1}" -f $((New-Guid).toString("N")), $oldBaseName
        # (New-Guid).toString("N") returns the Guid without hyphens, same as (New-Guid).Guid.Replace('-','')

        $destinationFile = Join-Path $Destination $newBaseName
        try {
            Copy-Item -Path $fileName -Destination $destinationFile -Force -ErrorAction Stop
            # add an object to the results array to store the original filename and the full filename of the copy
            $result += New-Object -TypeName PSObject -Property @{
                'OriginalFile' = $fileName
                'NewFile'      = $destinationFile
            }
        }
        catch {
            Write-Error "Could not copy file to '$destinationFile'"
            # write the error to the log file
            Add-content $Logfile -Value "$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) - ERROR: Could not copy file to '$destinationFile'"
        }
    }
    else {
        Write-Warning "File '$fileName' does not exist"
        # write the error to the log file
        Add-content $Logfile -Value "$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) - WARNING: File '$fileName' does not exist"
    }
}
# finally create a CSV with the results of this copy.
# the CSV will have two headers 'OriginalFile' and 'NewFile'
$result | Export-Csv -Path $ResultsFile -NoTypeInformation -Force

【讨论】:

  • 这可以完成我需要做的所有事情。谢谢西奥。
  • @AJD25 哎呀,只是一个小错误:它说$((Get-Date).ToString("yyy-MM-dd HH:mm:ss")) 应该是$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss"))。 (四个 ys 而不是三个)
【解决方案4】:

感谢大家的解决方案。他们都工作得很好。我选择 Theo 作为答案,因为他的解决方案解决了错误日志记录并将所有新重命名的文件与 GUID_File.ext 一起存储到现有 CSV 信息中。

谢谢大家。

【讨论】:

    猜你喜欢
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多