programing

How do I Start a job of a function i just defined?

css3 2023. 11. 1. 22:32

How do I Start a job of a function i just defined?

How do I Start a job of a function i just defined?

function FOO { write-host "HEY" }

Start-Job -ScriptBlock { FOO } |
  Receive-Job -Wait -AutoRemoveJob

Result:

Receive-Job: The term 'FOO' is not recognized as the name of cmdlet,
function ,script file or operable program.

What do I do? Thanks.

@Shay가 지적했듯이,FOO작업에 대한 정의가 필요합니다.이를 위한 또 다른 방법은-InitializationScript세션을 준비하기 위한 매개 변수.

For your example:

$functions = {
    function FOO { write-host "HEY" }
}

Start-Job -InitializationScript $functions -ScriptBlock {FOO}|
    Wait-Job| Receive-Job

This can be useful if you want to use the same functions for different jobs.

@Rynant의 제안은InitializationScript훌륭합니다

I thought the purpose of (script) blocks is so that you can pass them around. So depending on how you are doing it, I would say go for:

$FOO = {write-host "HEY"}

Start-Job -ScriptBlock $FOO | wait-job |Receive-Job

Of course you can parameterize script blocks as well:

$foo = {param($bar) write-host $bar}

Start-Job -ScriptBlock $foo -ArgumentList "HEY" | wait-job | receive-job

It worked for me as:

Start-Job -ScriptBlock ${Function:FOO}

An improvement to @Rynant's answer:

You can define the function as normal in the main body of your script:

Function FOO 
{ 
  Write-Host "HEY" 
} 

and then recycle this definition within a scriptblock:

$export_functions = [scriptblock]::Create(@"
  Function Foo { $function:FOO }
"@)

(실질적인 기능체를 가지고 있다면 좀 더 의미 있는 makes을) 다음으로 전달합니다.Start-Job위와 같이:

Start-Job -ScriptBlock {FOO} -InitializationScript $export_functions| Wait-Job | Receive-Job

I like this way, as it is easier to debug jobs by running them locally under the debugger.

The function needs to be inside the scriptblock:

Start-Job -ScriptBlock { function FOO { write-host "HEY" } ; FOO } | Wait-Job | Receive-Job

As long as the function passed to the InitializationScript param on Start-Job isn't large Rynant's answer will work, but if the function is large you may run into the below error.

[localhost] There is an error launching the background process. Error reported: The filename or extension is too long"

Capturing the function's definition and then using Invoke-Expression on it in the ScriptBlock is a better alternative.

function Get-Foo {
    param
    (
        [string]$output
    )

    Write-Output $output
}

$getFooFunc = $(Get-Command Get-Foo).Definition

Start-Job -ScriptBlock {
    Invoke-Expression "function Get-Foo {$using:getFooFunc}"
    Get-Foo -output "bar"
}

Get-Job | Receive-Job

PS C:\Users\rohopkin> Get-Job | Receive-Job
bar

A slightly different take. A function is just a scriptblock assigned to a variable. Oh, it has to be a threadjob. It can't be foreach-object -parallel.

$func = { 'hi' } # or
function hi { 'hi' }; $func = $function:hi

start-threadjob { & $using:func } | receive-job -auto -wait

hi

@Ben Power의 수락된 답변 아래 코멘트 또한 저의 관심사였습니다. 그래서 구글에서 함수 정의를 구하는 방법을 검색해보니Get-Command- 이것은 기능체만 얻을 수 있습니다.그러나 이 기능은 점으로 표시된 파일과 같이 다른 곳에서 오는 경우에도 사용할 수 있습니다.그래서 저는 다음과 같이 생각해냈습니다. (이름 짓기 규칙을 유지합니다. :) 이 아이디어는 새로운 줄로 구분된 함수 정의를 다시 만드는 것입니다.

Filter Greeting {param ([string]$Greeting) return $Greeting}
Filter FullName {param ([string]$FirstName, [string]$LastName) return $FirstName + " " + $LastName}
$ScriptText = ""
$ScriptText += "Filter Greeting {" + (Get-Command Greeting).Definition + "}`n"
$ScriptText += "Filter FullName {" + (Get-Command FullName).Definition + "}`n"
$Job = Start-Job `
            -InitializationScript $([ScriptBlock]::Create($ScriptText)) `
            -ScriptBlock {(Greeting -Greeting "Hello") + " " + (FullName -FirstName "PowerShell" -LastName "Programmer")}
$Result = $Job | Wait-Job | Receive-Job
$Result
$Job | Remove-Job

There's good information in the existing answers, but let me attempt a systematic summary:

  • PowerShell의 백그라운드 작업[1] 프로세스를 종료하지 않은 실행 공간(숨겨진 하위 프로세스)에서 실행되므로 호출자와 상태를 공유하지 않습니다.

  • 따라서 세션 중인 호출자에 의해 생성된 정의는 백그라운드 작업에 표시되지 않으므로 작업의 컨텍스트에서 다시 생성해야 합니다.[2]

  • 함수 정의를 다시 만드는 가장 간단한 방법네임스페이스 변수 표기법(예:$function:FOO- 아래와 같이 를 사용하여 이 답변을 참조합니다.

    • 슬프게도 오랜 벌레 때문에$using:이 글을 쓰는 시점(Windows PowerShell, PowerShell (Core) 7.3.6)에서 참조는 의 매개 변수(및 의 매개 변수)로 전달된 스크립트 블록에서 작동하지 않습니다. - GitHub 문제 #4530

자체적인 예로 다음과 같습니다.

function FOO { "HEY" }

Start-Job -ScriptBlock { 

  # Redefine function FOO in the context of this job.
  $function:FOO = "$using:function:FOO" 
  
  # Now FOO can be invoked.
  FOO

} | Receive-Job -Wait -AutoRemoveJob

위 출력 문자열HEY, 뜻대로

참고:

  • 할당 대상 $function:FOO함수를 은연중에 만듭니다.FOO(요구에 따라) 그리고 할당된 값을 함수 본문으로 만듭니다. 할당된 값은 인스턴스(instance) 또는 a일 수 있습니다.[string], 소스 코드 텍스트입니다.

  • 참조 $function:FOO기존의 것을 검색합니다.FOO신체를 a로 기능시키다[scriptblock]사례.가림막을 치고 있습니다.$using:범위()$using:function:FOO)의 본문을 검색합니다.FOO호출자의 범위에서 기능합니다.

  • 참고:

    • 때문에$using:,$using:function:FOO 아닙니다.[scriptblock]예를 들면, 그러나 a[string]의 경우에는Start-Job, 의 놀라운 방식 때문에.[scriptblock]교차 프로세스 직렬화를 수행할 때 인스턴스는 역직렬화됩니다. 동작은 설계에 의한 것으로 선언되었습니다. 자세한 내용은 GitHub issue #11698을 참조하십시오.

    • 이와 같이."..."주위에$using:function:FOO을 위해 불필요한Start-Job, 하지만 그렇지는 않습니다.Start-ThreadJob, 여기서는 직렬화가 수반되지 않으며 상태 손상을 방지하기 위해 문자열에서 본문을 재생성해야 합니다(자세한 내용은 GitHub issue #16461 참조).

      • 그 사실은Start-ThreadJob허용한다$using:function:FOO참조는 아마도 과 함께 사용되는 스크립트 블록에서 명시적으로 허용되지 않은 것을 고려할 때 감독일 것입니다.ForEach-Object -Parallel(PowerShell v7+) - GitHub 이슈 #12378 참조.

      • 따라서, 와 함께ForEach-Object -Parallel호출자 측에서 함수 본문을 먼저 문자열화하는 도우미 변수가 필요합니다. 이 답변을 참조하십시오.


[1] 이 답변은 에 의해 생성된 하위 프로세스 기반 작업에만 적용되는 것이 아니라 에 의해 생성된 일반적으로 선호되는 스레드 기반 작업과 에 의해 생성된 PowerShell(Core) 7+에서 사용할 수 있는 스레드 기반 병렬화에도 유사하게 적용됩니다. -Parallel, 또한 PowerShell 원격 via - 즉, PowerShell이 다른 실행 공간에서 Out-of-run space를 실행하는 모든 시나리오에 적용됩니다.

[2] 스크립트 파일을 통해 이러한 정의를 제공하는 것이 대안입니다.*.ps1또는 도트 소스(). 를 가져오거나 가져와야 하는 모듈입니다.

언급URL : https://stackoverflow.com/questions/7162090/how-do-i-start-a-job-of-a-function-i-just-defined