繁体   English   中英

在 PowerShell 7 中尝试捕获后访问变量时出错

[英]Error access to variable after try catch in PowerShell 7

我在 PowerShell 7 上收到此错误:

Total Urls to process: 12496
i: 1 | total:
RuntimeException:
Line |
  45 |      $percent = [int](100 * $i / $lines)
     |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Attempted to divide by zero.

开发这个脚本:

$srcfile = "C:\Users\wnune\OneDrive\Escritorio\imagenes\cardlist.txt"
$urls = Get-Content $srcfile
$lines = 0
switch -File $srcfile { default { ++$lines } }
Write-Host "Total Urls to process: $lines "
$i = 0
Write-Progress -Activity "Downloading files" -Status "In progress" -PercentComplete $i;
$urls | ForEach-Object -Parallel {
    $url = $_
    try {
        $filename = Split-Path $url -Leaf
        $destination = "C:\Users\wnune\OneDrive\Escritorio\imagenes\$filename"
        $ProgressPreference = 'SilentlyContinue'
        $response = Invoke-WebRequest -Uri $url -ErrorAction SilentlyContinue
        if ($response.StatusCode -ne 200) {
            Write-Warning "============================================="
            Write-Warning "Url $url return Error. "
            continue
        }
        if (Test-Path $destination) {
            Write-Warning "============================================="
            Write-Warning "File Exist in Destination: $filename "
            continue
        }
        $job = Start-BitsTransfer -Source $url -Destination $destination -Asynchronous
        while (($job | Get-BitsTransfer).JobState -eq "Transferring" -or ($job | Get-BitsTransfer).JobState -eq "Connecting")
        {
            Start-Sleep -m 250
        }
        Switch(($job | Get-BitsTransfer).JobState)
        {
            "Transferred" {
                Complete-BitsTransfer -BitsJob $job
            }
            "Error" {
                $job | Format-List
            }
        }
    }
    catch 
    {
        Write-Warning "============================================="
        Write-Warning "There was an error Downloading"
        Write-Warning "url:         $url"
        Write-Warning "file:        $filename"
        Write-Warning "Exception Message:"
        Write-Warning "$($_.Exception.Message)"
    }
    
    $i++
    Write-Host "i: $i | total: $lines"
    $percent = [int](100 * $i / $lines)
    Write-Progress -Activity "Downloading files" -Status "In progress" -PercentComplete $percent
}
Write-Progress -Activity "Downloading files" -Status "Completed" -Completed

假设这是因为我正在实施 -Parallel 尝试使用同步对象:

$syncObject = [System.Object]::new()
$srcfile = "C:\Users\wnune\OneDrive\Escritorio\imagenes\cardlist.txt"
$urls = Get-Content $srcfile
$lines = 0
switch -File $srcfile { default { ++$lines } }
Write-Host "Total Urls to process: $lines "
$i = 0
Write-Progress -Activity "Downloading files" -Status "In progress" -PercentComplete $i;
$urls | ForEach-Object -Parallel {
    [System.Threading.Monitor]::Enter($syncObject)
    try {
        $url = $_
        $filename = Split-Path $url -Leaf
        $destination = "C:\Users\wnune\OneDrive\Escritorio\imagenes\$filename"
        $ProgressPreference = 'SilentlyContinue'
        $response = Invoke-WebRequest -Uri $url -ErrorAction SilentlyContinue
        if ($response.StatusCode -ne 200) {
            Write-Warning "============================================="
            Write-Warning "Url $url return Error. "
            continue
        }
        if (Test-Path $destination) {
            Write-Warning "============================================="
            Write-Warning "File Exist in Destination: $filename "
            continue
        }
        $job = Start-BitsTransfer -Source $url -Destination $destination -Asynchronous
        while (($job | Get-BitsTransfer).JobState -eq "Transferring" -or ($job | Get-BitsTransfer).JobState -eq "Connecting")
        {
            Start-Sleep -m 250
        }
        Switch(($job | Get-BitsTransfer).JobState)
        {
            "Transferred" {
                Complete-BitsTransfer -BitsJob $job
            }
            "Error" {
                $job | Format-List
            }
        }
    }
    catch 
    {
        Write-Warning "============================================="
        Write-Warning "There was an error Downloading"
        Write-Warning "url:         $url"
        Write-Warning "file:        $filename"
        Write-Warning "Exception Message:"
        Write-Warning "$($_.Exception.Message)"
    }
    finally 
    {
        $i++
        Write-Host "i: $i | total: $lines"
        $percent = [int](100 * $i / $lines)
        Write-Progress -Activity "Downloading files" -Status "In progress" -PercentComplete $percent
        [System.Threading.Monitor]::Exit($syncObject)
    }
}
Write-Progress -Activity "Downloading files" -Status "Completed" -Completed

得到另一个错误:

Total Urls to process: 12496
MethodInvocationException:
Line |
   2 |      [System.Threading.Monitor]::Enter($syncObject)
     |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Exception calling "Enter" with "1" argument(s): "Value cannot be null."

如果我遵守执行顺序并且从头开始创建同步对象,我不知道出了什么问题或为什么会发生这种情况; 有人可以帮我弄这个吗???

主要思想是处理 12496 个 Urls... 并根据并行处理的 Urls 数量创建一个进度条。

这个提示不是这个的重复:

https://stackoverflow.com/a/60012780/20780615

注意:此答案不涵盖 PowerShell 工作流,因为它们是 PowerShell [Core] v6+ 不再支持的过时技术

阅读 First intead of Close Question。 并且与Invoke-Command无关

PowerShell v7+ ForEach-Object -Parallel功能使用独立的、基于线程的运行空间来并行执行代码。

对于在运行空间外执行任何 PowerShell 代码,您必须使用$using:作用域来引用调用者作用域中的变量值。

  • 此答案概述了需要$using : 的所有上下文。

一个简单的例子:

$i = 42
1..3 |
  ForEach-Object -Parallel {
    [pscustomobject] @{
      'Thread-local $i' = $i
      '$using:i value' = $using:i
    }
  }  

输出:

Thread-local $i $using:i value
--------------- --------------
                            42
                            42
                            42

如您所见, $i变量没有值,因为它引用了一个尚未初始化的线程局部(运行空间局部)变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM