Выходной параметр из работы, когда закончите - PullRequest
0 голосов
/ 31 октября 2018

UPDATE Я не борюсь с этой ошибкой An event with the name 'StateChanged' does not exist - См. Полный код в TRYOUTS (последний фрагмент кода) ниже


оригинальный текст

Как упоминалось ранее, я делаю код для автоматического форматирования и передачи файлов на несколько USB-накопителей. И это делается параллельно / асинхронно

Теперь проблема заключается в том, что я хочу выводить букву диска каждого USB-устройства после их завершения / задания завершено. Это письмо хранится в var / param внутри функции job, но я не знаю, как записать его, когда работа завершена.

У меня есть 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 голосов
/ 31 октября 2018

Вы можете использовать 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
    }
}
0 голосов
/ 31 октября 2018

Может быть, вы можете попробовать такой подход:

$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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...