2017-02-03 2 views
1

Это довольно прямой вопрос. У меня есть dll, который отвечает за чтение множества файлов. Каждое завершение файла указывается событием. Консольное приложение обрабатывает его корректно отображая информацию из args, как только оно появляется..NET Событие в Powershell не обрабатывается до конца

С другой стороны, я хочу запустить эту dll из сценария powershell и отобразить индикатор выполнения. Он не работает должным образом. Индикатор выполнения отображается в самом конце исполнения, быстро поднимается в пределах милисекунд от 0 до 100% и исчезает.

$isVerbose = $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent 

$finder = New-Object ContentFinder.LogFinder 

if($isVerbose) 
{ 
    Register-ObjectEvent -InputObject $finder -EventName "FileQueueProgress" -Action {Write-Progress ($EventArgs.Percent)} -SourceIdentifier "FileReadingProgressIndicator" | Out-Null 
} 

try 
{ 
    $path = GetPath 
    $date = GetDate 

    return $finder.GetErrorLogs($path, $date) 
} 
catch 
{ 
    Write-Host ($_.Exception.Message) 
} 
finally 
{ 
    if($isVerbose) 
    { 
     Unregister-Event -SourceIdentifier "FileReadingProgressIndicator" 
    } 

    Write-Host "Done" 
} 

и это называется так: Get-ErrorLogs -Verbose. Обычно я назначаю его переменной, чтобы иметь возможность фильтровать результаты и все, что работает. Есть ли что-то, что я могу сделать, чтобы PS реагировал на события в тот же момент, когда они поднимают?

EDIT: ОТВЕТ от комментариев Это работает точно так же, как и ожидалось. Выполняет отчеты во время выполнения, а не в конце сценария.

if($isVerbose) 
{ 
    $Handler = {Write-Progress ($args[1].Percent)} -as $finder. PSObject. Members. Match('FileQueueProgress')[0]. Value. EventHandlerType; 
    $finder. add_FileQueueProgress($Handler); 
    #Register-ObjectEvent -InputObject $finder -EventName "FileQueueProgress" -Action {Write-Progress ($EventArgs.Percent)} -SourceIdentifier "FileReadingProgressIndicator" | Out-Null 
} 

try 
{ 
    $path = GetPath 
    $date = GetDate 

    return $finder.GetErrorLogs($path, $date) 
} 
catch{ 
    Write-Host ($_.Exception.Message) 
} 
finally 
{ 
    if($isVerbose) 
    { 
     #Unregister-Event -SourceIdentifier "FileReadingProgressIndicator" 
     $finder. remove_FileQueueProgress($Handler) 
    } 

    Write-Host "Done" 
} 
+0

Как работает 'GetErrorLogs'? Блокирует ли он до конца операции? Является ли 'FileQueueProgress' поднятым в том же потоке, где вызывается' GetErrorLogs'? – PetSerAl

+0

Да, он работает синхронно, и события поднимаются в тот же поток тем временем. – yoger

+0

Как версия консоли сравнивается с версией PowerShell? Я думаю, что поведение, которое вы видите, ожидается. У вас нет ничего асинхронного в PowerShell, поэтому все будет стоять в очереди. По крайней мере, так я понимаю это. –

ответ

1

В однотридовой сценарии вы на самом деле не нужно использовать Register-ObjectEvent. PowerShell позволяет конвертировать блоки скриптов в объекты типа делегата. И вы можете присоединить/отсоединить этих делегатов от события, вызвав соответствующий аксессуар событий (add_EventName/remove_EventName).

$finder = New-Object ContentFinder.LogFinder 

if($isVerbose) 
{ 
    $Handler = {Write-Progress ($args[1].Percent)} -as $finder.PSObject.Members.Match('FileQueueProgress')[0].Value.EventHandlerType 
    $finder.add_FileQueueProgress($Handler) 
} 

try 
{ 
    $path = GetPath 
    $date = GetDate 

    return $finder.GetErrorLogs($path, $date) 
} 
catch 
{ 
    Write-Host ($_.Exception.Message) 
} 
finally 
{ 
    if($isVerbose) 
    { 
     $finder.remove_FileQueueProgress($Handler) 
    } 

    Write-Host "Done" 
} 

Примечание: Я сохранить объект делегата для $Handler переменной, так что я могу правильно отделить его позже.