2013-03-20 15 views
6

Widziałem this question i this question, ale nie mogłem znaleźć rozwiązania mojego problemu.Jak wywołać funkcję powershell w skrypcie z zadania początkowego?

Oto sytuacja: Mam dwie funkcje: DoWork i DisplayMessage w pliku skryptu (.ps1). Oto kod:

### START OF SCRIPT ### 
function DoWork 
{ 
    $event = Register-EngineEvent -SourceIdentifier NewMessage -Action { 
     DisplayMessage($event.MessageData) 
    } 

    $scriptBlock = { 

    Register-EngineEvent -SourceIdentifier NewMessage -Forward 

    $message = "Starting work" 
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message 

    ### DO SOME WORK HERE ### 

    $message = "Ending work" 
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message 

    Unregister-Event -SourceIdentifier NewMessage 
    } 

    DisplayMessage("Processing Starts") 

    $array = @(1,2,3) 
    foreach ($a in $array) 
    { 
     Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array | Out-Null 
    } 

    #$jobs = Get-Job -Name "DoActualWork" 
    While (Get-Job -Name "DoActualWork" | where { $_.State -eq "Running" }) 
    { 
     Start-Sleep 1 
    } 

    DisplayMessage("Processing Ends") 

    Get-Job -Name "DoActualWork" | Receive-Job 
} 

function DisplayMessage([string]$message) 
{ 
    Write-Host $message -ForegroundColor Red 
} 

DoWork 

### END OF SCRIPT ### 

tworzę 3 oferty tle (przy użyciu $ tablicę z 3 elementów) i stosując zdarzenia do przekazywania wiadomości od pracy tła dla gospodarza. Spodziewam się, że host programu Powerhell wyświetli "Rozpoczęcie przetwarzania" i "Przetwarzanie zakończy się" 1 raz i "Rozpoczęcie pracy" i "Zakończenie pracy" trzy razy. Ale zamiast tego nie wyświetla się "Uruchomienie pracy"/"Kończenie pracy" w konsoli.

zdarzeń jest również traktowane jako zadanie w PowerShell, więc kiedy robię Get-Job, widzę następujący błąd związany z pracą zdarzenia:

{Termin „DisplayMessage” nie jest uznawane za nazwa funkcji cmdlet, , pliku skryptu lub obsługiwanego programu. Sprawdź pisownię nazwy , czy ścieżka została włączona, upewnij się, że ścieżka jest poprawna i spróbuj ponownie}

Moje pytanie. W jaki sposób można ponownie wykorzystać (lub odniesienia) funkcja (DisplayMessage w moim case) zdefiniowane w tym samym skrypcie, skąd wywołuję Start-Job? Czy to możliwe? Wiem, że możemy użyć -InitializationScript do przekazania funkcji/modułów do Start-Job, ale nie chcę pisać funkcji DisplayMessage dwa razy, jeden w skrypcie i inny w InitializationScript.

Odpowiedz

5

Zadania w tle są uruchamiane w oddzielnym procesie, więc zadania utworzone za pomocą Start-Job nie mogą wchodzić w interakcję z funkcjami, chyba że zostaną uwzględnione w $scriptblock.

Nawet jeśli obejmował funkcję w $scripblock, Write-Host nie wyjście jego zawartość do konsoli aż używane Get-Job | Receive-Job otrzymywać prowadzić zadania.

EDIT Problemem jest to, że funkcja DisplayMessage jest w lokalnej skryptu-Scope w czasie, gdy Podprogram działa w innym zakresie dominującej (jak globalny, który jest zakres sesji), tak że nie może znaleźć swoją funkcję. Jeśli utworzysz funkcję w zasięgu globalnym i wywołasz ją z zakresu globalnego, zadziała.

Zmodyfikowałem twój skrypt, aby zrobić to teraz. Ja również zmodyfikowany scriptblock i niezastrzeżone zdarzenia, gdy skrypt jest uczyniły, nie dostaniesz 10x wiadomości po uruchomieniu skryptu wielokrotnie :-)

Untitled1.ps1

function DoWork 
{ 
    $event = Register-EngineEvent -SourceIdentifier NewMessage -Action { 
     global:DisplayMessage $event.MessageData 
    } 

    $scriptBlock = { 

    Register-EngineEvent -SourceIdentifier NewMessage -Forward 

    $message = "Starting work $args" 
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message 

    ### DO SOME WORK HERE ### 

    $message = "Ending work $args" 
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message 

    Unregister-Event -SourceIdentifier NewMessage 
    } 

    DisplayMessage("Processing Starts") 

    $array = @(1,2,3) 
    foreach ($a in $array) 
    { 
     Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $a | Out-Null 
    } 

    #$jobs = Get-Job -Name "DoActualWork" 
    While (Get-Job -Name "DoActualWork" | where { $_.State -eq "Running" }) 
    { 
     Start-Sleep 1 
    } 

    DisplayMessage("Processing Ends") 

    #Get-Job -Name "DoActualWork" | Receive-Job 
} 

function global:DisplayMessage([string]$message) 
{ 
    Write-Host $message -ForegroundColor Red 
} 

DoWork 

Get-EventSubscriber | Unregister-Event 

testowym

PS > .\Untitled1.ps1 
Processing Starts 
Starting work 1 
Starting work 2 
Ending work 1 
Ending work 2 
Starting work 3 
Ending work 3 
Processing Ends 
+0

Dzięki. Wiem, że Start-Job nie może wchodzić w interakcje z zewnętrznymi funkcjami, stąd te pytania. Ponadto wiem, że Write-Host nie może bezpośrednio wyprowadzać na konsolę, dlatego używam zdarzenia, aby to zrobić.W moim przypadku jestem w stanie napisać do hosta, ale tylko wtedy, gdy użyję "Write-Host" bezpośrednio w zdarzeniu, ale nie przy wywołaniu go z funkcji. – digitguy

+0

Okey, myślę, że przegapiłem twoje pytanie, przepraszam za to. :) Zobacz nową treść na końcu mojego pytania. Czy to twój obecny problem? –

+0

Tak, masz rację. Pierwsze działa, ale drugie nie. – digitguy

6

Łatwym sposobem na to lokalne funkcje w pracy w tle:

$init=[scriptblock]::create(@" 
function DoWork {$function:DoWork} 
"@) 

Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array -InitializationScript $init | Out-Null 
+0

Podoba mi się twój sposób włączenia lokalnych funkcji w pracy w tle! Ale to nie rozwiązało mojego problemu (nie jestem pewien dlaczego :() .Mógłbym rozwiązać mój problem za pomocą powyższego rozwiązania @Graimer – digitguy

+0

Mam to do pracy, używając nawiasów '{}' do stworzenia bloku skryptu zamiast operatorem '' @ @ "' ponieważ nie przerywają poprawnie zmiennych Przykład: '$ init = {function DoWork {$ function: DoWork}}' Następnie wywołaj to w ten sam sposób używając 'Start-job' i' - InitializationScript'. – Richard

+0

Mam rozwiązanie mjolinora do pracy, ale w moim przypadku, włączając w to 'DoWork' za pomocą argumentu' init' nie działało, musiałem też uwzględnić dowolne funkcje/zmienne 'DoWork', do których się odwołałem, etc, rekursywnie. – Rob

Powiązane problemy