完成后从作业输出参数

时间:2018-10-31 08:53:19

标签: powershell

更新 我不为这个错误而苦恼An event with the name 'StateChanged' does not exist-请参阅下面的TRYOUTS(最后一个代码段)的完整代码


原始文本

如前所述,我正在执行一个代码,用于自动格式化文件并将文件传输到多个USB指驱动器。 并且它是并行/异步完成的

现在的问题是,我想在每个USB完成/工作完成时输出每个USB的驱动器号。该字母存储在job函数内部的var / param中,但是我不知道如何在完成工作后将其写出。

我有一个Register-ObjectEvent,当每个USB格式化和传输完成后会触发。 该脚本运行得很好,并写出了USB slot = Job...

但是我想将$driveLetter内部的$formatDrive写在USB slot = $driveLetter行中。

这里是我的代码。查找行$formatDrive$jobEvent

#Requires -version 2.0
ipmo storage
Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange

$formatDrive = {
    Param($driveLetter)
    Write-Host (Get-Date -Format s) "Erase disk..."
    $source = "C:\Users\myname\Desktop\test"
    Format-Volume -DriveLetter $driveLetter[0] -NewFileSystemLabel "test30" -FileSystem exFAT -Confirm:$false
    robocopy $source $driveLetter /S
    return $driveLetter
}

Write-Host (Get-Date -Format s) " Beginning script..."
do {
    $newEvent = Wait-Event -SourceIdentifier volumeChange
    $eventType = $newEvent.SourceEventArgs.NewEvent.EventType
    $eventTypeName = switch ($eventType) {
        1 {"Configuration changed"}
        2 {"Device arrival"}
        3 {"Device removal"}
        4 {"docking"}
    }
    if ($eventType -eq 2) {
        $driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName
        $driveLabel = ([wmi]"Win32_LogicalDisk='$driveLetter'").VolumeName
        Write-Host (Get-Date -Format s) "USB igang = " $driveLetter
        # Execute process if drive matches specified condition(s)
        $formatDrivejob = Start-Job -ScriptBlock $formatDrive -ArgumentList $driveLetter
        $jobEvent = Register-ObjectEvent $formatDrivejob StateChanged -Action {
            Write-Host (Get-Date -Format s) (' USB slot = Job #{0} ({1}) complete.' -f $sender.Id, $sender.Name)
            [media.SystemSounds]::("Hand").Play()
            $jobEvent | Unregister-Event
        }
    }
    Remove-Event -SourceIdentifier volumeChange
} while (1-eq1) #Loop until next event
Unregister-Event -SourceIdentifier volumeChange

我尝试将其写在$formatDrive的末尾-由于它在后台运行,因此无法正常工作。 您也可以在return中看到$formatDrive的尝试

试用:

#Requires -version 2.0
ipmo storage
Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange

$formatDrive = {
    param($driveLetter)
    write-host (get-date -format s) "Erase disk..."
    $source = "C:\Users\jbh\Desktop\test"
    Format-Volume -Driveletter $driveLetter[0] -NewFileSystemLabel "test30" -FileSystem exFAT -Confirm:$false
    robocopy $source $driveLetter /S
    return $driveLetter
}

write-host (get-date -format s) " Beginning script..."
do{
$newEvent = Wait-Event -SourceIdentifier volumeChange
$eventType = $newEvent.SourceEventArgs.NewEvent.EventType
$eventTypeName = switch($eventType)
{
1 {"Configuration changed"}
2 {"Device arrival"}
3 {"Device removal"}
4 {"docking"}
}
# initialize the array
$formatDrivejob = @()
if ($eventType -eq 2) {
    $driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName
    $driveLabel = ([wmi]"Win32_LogicalDisk='$driveLetter'").VolumeName
    Write-Host (Get-Date -Format s) "USB igang = " $driveLetter
    # Execute process if drive matches specified condition(s)
    $formatDrivejob += Start-Job -ScriptBlock $formatDrive -ArgumentList $driveLetter
    $jobEvent = Register-ObjectEvent $formatDrivejob StateChanged -Action {
        Write-Host (Get-Date -Format s) (' USB slot = Job #{0} ({1}) complete.' -f $sender.Id, $sender.Name)
        [media.SystemSounds]::("Hand").Play()
        foreach ($i in $formatDrivejob){
           if ($i.State -eq "Completed")
           {
             $letter = $formatDrivejob | receive-job | select -Last 1
             Write-Host "Drive has finished:" $letter
             $formatDrivejob.Remove($i)
           } 
        }
        $jobEvent | Unregister-Event
    }
}
Remove-Event -SourceIdentifier volumeChange
} while (1-eq1) #Loop until next event
Unregister-Event -SourceIdentifier volumeChange

2 个答案:

答案 0 :(得分:1)

也许您可以尝试这样的方法:

$DrivesToHandle = 5
$formatDrivejob = @()

Do {
    if ($eventType -eq 2) {
        $DrivesToHandle -= 1
        $driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName
        $driveLabel = ([wmi]"Win32_LogicalDisk='$driveLetter'").VolumeName
        write-host (Get-Date -format s) "USB igang = $driveLetter" 
        # Execute process if drive matches specified condition(s)
        $formatDrivejob += Start-Job -ScriptBlock $formatDrive -ArgumentList $driveLetter
    }
} while ($DrivesToHandle -ne 0)

# Wait for all jobs to finish
$formatDrivejob | Wait-Job | Out-Null

# Retrieve the job results
$JobResults = $formatDrivejob | Receive-Job

foreach ($Job in $JobResults) {
    Write-Host (get-date -format s) "Job result of job ID $($Job.Id): " $Job
}

# Remove all jobs
$formatDrivejob | Remove-Job -Force

使用jobs时,可以使用Wait-Job等待作业完成。但是您还必须通过使用Receive-Job CmdLet来检索作业结果。

答案 1 :(得分:1)

您可以使用Receive-job来获得结果:

# initialize the array
[System.Collections.ArrayList]$formatDrivejob
if ($eventType -eq 2) {
    $driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName
    $driveLabel = ([wmi]"Win32_LogicalDisk='$driveLetter'").VolumeName
    Write-Host (Get-Date -Format s) "USB igang = " $driveLetter
    # Execute process if drive matches specified condition(s)
    $formatDrivejob += Start-Job -ScriptBlock $formatDrive -ArgumentList $driveLetter
    $jobEvent = Register-ObjectEvent $formatDrivejob StateChanged -Action {
        Write-Host (Get-Date -Format s) (' USB slot = Job #{0} ({1}) complete.' -f $sender.Id, $sender.Name)
        [media.SystemSounds]::("Hand").Play()
        foreach ($i in $formatDrivejob){
           if ($i.State -eq "Completed")
           {
             $letter = $formatDrivejob | receive-job | select -Last 1
             Write-Host "Drive has finished:" $letter
             $formatDrivejob.Remove($i)
           } 
        }
        $jobEvent | Unregister-Event
    }
}