首页 > 解决方案 > 如果我上传与条件不匹配的文件,Catch 块不会捕获错误

问题描述

   $Source='c:\uploadtool\*'  #Source Location 
    $RetailDest= "D:\ToolUpload\Retail-EIP" #1st Destination Location 
    $GroupDest= "D:\ToolUpload\Group-EIP"   #2nd Destination location
    $RetailBack="D:\ToolUpload\Retail-EIP\*"  #Backup location which copy the existing file if the file match to Retail-EIP.
    $GroupBack="D:\ToolUpload\Group-EIP\*"    # 2nd Backup location which copy the existing file if the file match to Group-EIP.
    $Backupdata="D:\Backup"   #Backup Location
    $filename = Get-ChildItem -Path $Source -File -Force -Recurse
    #$logname=New-Item "D:\logs\uploadlog_$(Get-Date -Format 'yyyyMMdd').txt" -ItemType file -Force
    $lognamefolder="D:\logs"
    
    $logname="D:\logs\uploadlog_$(Get-Date -Format 'yyyyMMdd').txt"
    
    $checkLocalFolderExist = Test-Path -Path $lognamefolder
    
    $checkLocalFileExist = Test-Path -Path $logname  -PathType Leaf
     if(-NOT $checkLocalFolderExist)
    {
      New-Item -Path $lognamefolder -ItemType Directory
    }
    
    if(-NOT $checkLocalFileExist)
    {
      New-Item -Path $logname -ItemType File
    }
    
    echo "              " (Get-Date) | Add-Content -Path $logname -PassThru
    
    echo "Copying file start" |  Add-Content -Path $logname -PassThru
    
    echo "Source is:$filename" | Add-Content -Path $logname -PassThru
    
    echo  "File size = "($filename).Length  | Add-Content -Path $logname -PassThru
    
    echo "               " | Add-Content -Path $logname -PassThru
    
    $ArchiveData = New-Item -Path "$Backupdata\backup_$(Get-Date -Format 'yyyyMMddHHMM')" -Force -ItemType Directory
    foreach($file in $filename)
    {
    try
    {
    if($file -match "Retail-EIP")
    {
    
     $fname=$file.fullname
     Move-Item -Path $RetailBack -Destination $ArchiveData
     echo "File has been backed up :$ArchiveData" | Add-Content -Path $logname -PassThru 
     Move-Item -Path $fname -Destination $RetailDest
     echo "File has been upload to Retail Platform: $RetailDest" |Add-Content -Path $logname -PassThru |Format-Table
     
    }
    
    if($file -match "Group-EIP")
    {
    
     $fname=$file.fullname
     Move-Item -Path $GroupBack -Destination $ArchiveData
     echo "File has been backed up :$ArchiveData" | Add-Content -Path $logname -PassThru 
     Move-Item -Path $fname -Destination $GroupDest 
     echo "File has been upload to Group Platform: $GroupDest" |Add-Content -Path $logname -PassThru | Format-Table
    }
    }
    catch  # Catch statement doesn't produce the error and capture in the log file.
    {
    Write-output "Exception Message: $($_.Exception.Message)" -ErrorAction Stop | Add-Content $logname -passthru
    }
    }
  1. 我正在尝试从源位置复制文件并将现有文件备份到备份位置,所有设置和脚本都按预期工作,但我只想更改一些东西,比如

    首先,如果我上传了与条件不匹配的错误,脚本不会捕获 catch 语句。其次,我想以表格格式捕获日志,我该怎么做?

标签: powershell

解决方案


如前所述,为了能够使用try{}..catch{},您需要添加ErrorAction Stop实际上可以引发异常的 cmdlet,例如两个 Move-Item cmdlet,以便还捕获非终止异常。

然后,您希望获得表格样式的输出,而不是文本日志文件。
在这种情况下,您需要输出具有某些属性的对象,然后您可以将日志文件保存为结构化 CSV 文件(实际上是一个表格),您可以在 Excel 中打开。

现在,如果我有这个正确的代码需要:

  1. 从包含子文件夹的源文件夹中获取所有文件,其中文件名包含“Retail-EIP”或“Group-EIP”
  2. 对于这些文件中的每一个,都定义了一个备份目标文件夹,$GroupDest并且$RetailDest
  3. 我在这些备份文件夹中的任何一个中,已存在具有该名称的文件,需要将其移动到定义的存档文件夹中$ArchiveData
  4. 然后应该将文件从其源文件夹移动到目标文件夹
  5. 您希望将移动包装在try{}..catch{}结构中,以便可以捕获任何异常
  6. 日志应作为结构化对象维护,因此您可以在屏幕上和文件中输出表格

在这种情况下,我会更改(相当多)您的代码:

$Source      = 'C:\uploadtool'               # Source Location
$RetailDest  = 'D:\ToolUpload\Retail-EIP'    # 1st Destination Location
$GroupDest   = 'D:\ToolUpload\Group-EIP'     # 2nd Destination location
$ArchiveData = 'D:\Backup\backup_{0:yyyyMMddHHmm}' -f (Get-Date)
$LogFolder   = 'D:\logs'
# because of your wish to get a Table-style log, use CSV format you can open in Excel
$LogFile     = 'D:\logs\uploadlog_{0:yyyyMMdd}.csv'-f (Get-Date)

# make sure the output LogFolder exist
# by adding the -Force switch there is no need to use Test-Path first, because if
# the folder already exists, the cmdlet will return the DirectoryInfo of that,
# otherwise it will create a new folder. Since we dont want output, we use $null = ..
$null = New-Item -Path $LogFolder -ItemType Directory -Force

# loop through the files in the source folder and collect the outputted objects
$result = Get-ChildItem -Path $Source -Include '*Group-EIP*', '*Retail-EIP*' -File -Force -Recurse | 
    ForEach-Object {
        Write-Host "Processing file '$($_.FullName)'"
        # create an object with (for now) 3 empty properties
        $out = $_ | Select-Object @{Name = 'Date'; Expression = {(Get-Date)}},
                                  @{Name = 'Source'; Expression = {$_.FullName}},
                                  @{Name = 'FileSize'; Expression = {$_.Length}},
                                  Destination,                                     # depends on the file name
                                  @{Name = 'Archive'; Expression = {'N/A'}},       # initialize to Not Applicable
                                  Result
        # depending on its name, get the correct destination folder
        $destFolder = if($_.Name -match "Retail-EIP") { $RetailDest } else { $GroupDest }
        # create the backup destination folder if it didn't already exist
        # the first file in column 'Source' is now responsible for creating the backup folder
        $null = New-Item -Path $destFolder -ItemType Directory -Force
        # get the full path and filename for the destination
        $existingFile = Join-Path -Path $destFolder -ChildPath $_.Name -PathType Leaf
        # add the destination folder to the output object
        $out.Destination = $destFolder
        try {
            # if a file with that name already exists in the destination, move it to the Archive folder
            if (Test-Path -Path $existingFile -PathType Leaf) {
                # create the Archive folder if it didn't already exist
                $null = New-Item -Path $ArchiveData -ItemType Directory -Force
                Move-Item -Path $existingFile -Destination $ArchiveData -ErrorAction Stop -WhatIf
                # add the archived file to the output object
                $out.Archive = $existingFile
                Write-Host "File '$existingFile' has been backed-up to '$ArchiveData'"
            }
            # next move the file from the source folder to its destination (either $RetailDest or $GroupDest)
            $_ | Move-Item -Destination $destFolder -ErrorAction Stop -WhatIf
            $out.Result = 'OK'
            Write-Host "File '$($_.FullName)' has been moved to '$destFolder'"
        }
        catch {
            # ouch.. something went horribly wrong on a Move-Item action
            Write-Warning "An error occurred: $_.Exception.Message"
            $out.Result = "Error: $($_.Exception.Message)"
        }

        # output the object so it gets collected in variable $result
        $out
    }

# now you can save the results as structured CSV file to open in Excel
$result | Export-Csv -Path $LogFile -UseCulture -NoTypeInformation -Append

# and display on screen using Out-GridView as the data will probably be too wide for Format-Table
$result | Out-GridView -Title 'Backup results'

请注意,我已向-WhatIfMove-Item cmdlet 添加了一个开关。这是一项安全措施,使用该开关,您只会在控制台中看到一条线,告诉您执行什么操作。实际上没有任何东西被移动。
一旦您对所有控制台消息感到满意,一切都按预期进行,您可以删除这些-WhatIf开关。

请阅读(希望)解释每一步的代码注释


这时间太长了……

导出中的内容是返回的对象中收集的内容:

柱子 描述
日期 处理文件的当前日期
来源 从源文件夹处理的文件的完整路径和文件名
文件大小 正在处理的文件的大小(以字节为单位)
目的地 源文件移动到的目标文件夹的完整路径,从$RetailDest$GroupDest
档案 “N/A”或已在目标文件夹中且必须先移动到存档文件夹的文件的完整路径和文件名
结果 如果出现问题,则为“OK”或异常消息Move-Item

因为-Include '*Group-EIP*', '*Retail-EIP*',只有文件名中包含一个或另一个字符串的文件才会被处理,所有其他文件都被忽略。这就是为什么您从未收到有关您尝试过的那些错误文件的异常消息的原因..(在我的回答中遵循注释1 )


推荐阅读