首页 > 解决方案 > 如何在此 PowerShell 脚本中产生错误

问题描述

有人可以告诉我,我怎样才能产生错误并在日志文件中捕获它?因为我想测试这个脚本的错误视角但无法得到它,如果你能让我知道如何手动测试这个脚本以获得错误视角,这将非常有帮助。

让我向你描述一下我通过这个脚本实现了什么。因为我想使用文件命名约定将文件移动到服务器上的各个文件夹并备份到现有文件(如果有的话),并且在整个过程生成 CSV 中的日志文件并发送一封包含成功或错误消息的电子邮件。

$Source       = 'c:\uploadtool\' # Source Location
$RetailSource = 'Retail P&C Sales Intelligence\*'
$GroupSource  = 'Group P&C Sales Intelligence\*'      
$UATSource = 'UAT\*'   
$RetailDest   = 'D:\ToolUpload\Retail-EIP'    # 1st Destination Location
$GroupDest    = 'D:\ToolUpload\Group-EIP'     # 2nd Destination location
$UATDest ='D:\ToolUpload\UAT' # Added 3rd destination location in this version 1.7.2V
$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)
$Sourcetest  = Test-Path -Path '$RetailSource','$GroupSource'  -PathType Leaf

#Email Params:
$EmailParams = @{
    SmtpServer ='xyz.smtp.com' 
    Port   = '25'
    Subject    ='File Upload Status'
    To         ="xyz@xyz.com"
    From       ="no-xyz@xyz.com"
}


# 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 don't 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*','*UAT*' -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 = {$ArchiveData}}, # initialize to Not Applicable
        Result
    
    # depending on its name, get the correct destination folder
    $destFolder = if($_.Name -match "Retail-EIP") { $RetailDest } elseif($_.Name -match "Group-EIP")  { $GroupDest } else {$UATDest}

    
    # 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 
    
    # 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 
            
            # 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 
        $out.Result = 'OK'
        Write-Host "File '$($_.FullName)' has been moved to '$destFolder'"
        $Body = " The File '$($_.FullName)' has been moved to '$destFolder'      'n  Size of the file is '$($_.Length)'   `n   file has been backed up on the location '$ArchiveData' "
    }
    catch 
    {   # ouch.. something went horribly wrong on a Move-Item action
      
        $Body = " Error occured trying to move the file '$($_.FullName)' to '$destFolder. `n$($_.Exception.Message)"
        Write-Warning "An error occurred: $_.Exception.Message"
        $out.Result = "Error: $($_.Exception.Message)" | Add-Content -Path $LogFile -Force
       
    }

    Send-MailMessage @EmailParams -Body $Body

    # 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 -Force

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

标签: powershell

解决方案


好的,我已经修改了您的代码并在其中添加了一些注释,希望能指出您的代码中的错误。

正如我从您之前的问题中收集到的,您还想报告具有“错误”文件名的文件(即不包含“Group-EIP”、“Retail-EIP”或“UAT”)。
当您将参数添加-Include '*Group-EIP*', '*Retail-EIP*','*UAT*'到 Get-ChildItem cmdlet 时,所有具有错误名称的文件甚至都不会进入 ForEach 循环,并且您将无法将它们记录为“错误:文件名不正确”,因此请将其删除。

接下来,所有这些的输出是一个结构化的 CSV 文件,并且您Add-Content -Path $LogFile -Force在代码中添加了一个点,这将破坏结构并使 CSV 无法使用。

您在循环中添加了一个 Send-MailMessage 调用,通过这样做,代码将在它处理的每个文件上发送一封电子邮件。我已将其移至代码末尾,因此它只会发送一封电子邮件。
对于演示,我将生成的 CSV 文件作为附件添加到这封电子邮件中,但您也可以创建一个漂亮的 HTML 表格,其中包含您在$result.
我将把它留给你,但在 StackOverflow 上可以找到很多例子。

$RetailSource = Join-Path -Path 'c:\uploadtool' -ChildPath 'Retail P&C Sales Intelligence'
$GroupSource  = Join-Path -Path 'c:\uploadtool' -ChildPath 'Group P&C Sales Intelligence'      
$UATSource    = Join-Path -Path 'c:\uploadtool' -ChildPath 'UAT'
####################################################################################
# now group these paths into a single array variable as I have shown you in my answer
# here: https://stackoverflow.com/a/67673422/9898643
####################################################################################
$Source       = $RetailSource, $GroupSource, $UATSource


$RetailDest   = 'D:\ToolUpload\Retail-EIP'    # 1st Destination Location
$GroupDest    = 'D:\ToolUpload\Group-EIP'     # 2nd Destination location
$UATDest      = 'D:\ToolUpload\UAT'           # Added 3rd destination location in this version 1.7.2V
$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 don't want output, we use $null = ..
$null = New-Item -Path $LogFolder -ItemType Directory -Force

# loop through the files in the source folders and collect the outputted objects.
####################################################################################
# $Source is an ARRAY of paths, so do not surround it with quotes!
# If you want to also log files that have a bad name, DO NOT USE 
# -Include '*Group-EIP*', '*Retail-EIP*','*UAT*', otherwise these files are ignored!
####################################################################################
$result = Get-ChildItem -Path $Source -File -Force -Recurse | ForEach-Object {
    Write-Host "Processing file '$($_.FullName)'"
    # create an object with (for now) 2 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 = {$ArchiveData}},
                              Result

     # test if the file has a correct name
     if ($_.BaseName -notmatch 'Group-EIP|Retail-EIP|UAT') {
        # file does not have the correct naming convention
        $out.Archive = $null
        $out.Result = "Error: Incorrect filename"
    }
    else {
        # depending on its name, get the correct destination folder
        $destFolder = if($_.Name -match "Retail-EIP") { $RetailDest } elseif($_.Name -match "Group-EIP")  { $GroupDest } else { $UATDest }

        # 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 

        # 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 
        
                # 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 
            $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)"
            ####################################################################
            # $LogFile will be saved later as CSV, Do not ruin the structure
            # by inserting  '| Add-Content -Path $LogFile -Force'
            ####################################################################
        }
    }
    # 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 -Force

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

# and send an email with the resulting CSV file as attachment 
# or create a nice HTML table from the objects in $result and put that in the body.
# Lots of examples for that can be found on SO

$EmailParams = @{
    SmtpServer = 'xyz.smtp.com' 
    Port       = '25'
    Subject    = 'File Upload Status'
    To         = "xyz@xyz.com"
    From       = "no-xyz@xyz.com"
    Body       = "Please see attached logfile" 
    Attachments = $LogFile
}

Send-MailMessage @EmailParams

推荐阅读