[powershell] PowerShell의 함수 반환 값

SharePoint Team 사이트 구축 과 관련된 여러 작업을 수행하는 PowerShell 기능을 개발했습니다 . 궁극적으로 함수가 프로비저닝 된 사이트의 URL을 문자열로 반환하기를 원하므로 함수 끝에서 다음 코드를 갖습니다.

$rs = $url.ToString();
return $rs;

이 함수를 호출하는 코드는 다음과 같습니다.

$returnURL = MyFunction -param 1 ...

그래서 String을 기대하지만 그렇지 않습니다. 대신 System.Management.Automation.PSMethod 유형의 개체입니다. 왜 문자열 유형 대신 해당 유형을 반환합니까?



답변

PowerShell은 적어도 더 전통적인 프로그래밍 관점에서 볼 때 실제로 이상한 반환 의미를 가지고 있습니다. 머리를 감싸는 두 가지 주요 아이디어가 있습니다.

  • 모든 출력이 캡처되어 반환됩니다
  • return 키워드는 실제로 논리적 종료점을 나타냅니다.

따라서 다음 두 스크립트 블록은 정확히 동일한 기능을 수행합니다.

$a = "Hello, World"
return $a

 

$a = "Hello, World"
$a
return

두 번째 예의 $ a 변수는 파이프 라인의 출력으로 유지되며 언급 된 것처럼 모든 출력이 반환됩니다. 실제로 두 번째 예에서는 리턴을 완전히 생략하고 동일한 동작을 수행 할 수 있습니다 (기능이 자연스럽게 완료되고 종료됨에 따라 리턴이 암시됩니다).

더 많은 함수 정의가 없으면 PSMethod 객체를 얻는 이유를 말할 수 없습니다. 내 생각에는 캡처되지 않고 출력 파이프 라인에 배치되는 몇 줄이있을 것입니다.

또한 한 줄에 여러 표현식을 중첩하지 않는 한 세미콜론이 필요하지 않을 수도 있습니다.

TechNet 의 about_Return 페이지에서 또는 help returnPowerShell 자체 에서 명령을 호출하여 리턴 시맨틱에 대해 자세히 읽을 수 있습니다 .


답변

PowerShell의이 부분은 아마도 가장 어리석은 부분 일 것입니다. 함수 중에 생성 된 외부 출력은 결과를 오염시킵니다. 때때로 출력이없는 경우가 있습니다. 일부 조건에서는 계획된 반환 값 외에 계획되지 않은 다른 출력이있을 수 있습니다.

따라서 원래 함수 호출에서 할당을 제거하므로 출력이 화면에서 끝난 다음 디버거 창에서 계획하지 않은 것이 튀어 나올 때까지 ( PowerShell ISE 사용 ) 단계별로 진행 합니다.

외부 스코프에 변수를 예약하는 것과 같은 것조차도 출력을 유발 [boolean]$isEnabled합니다 [boolean]$isEnabled = $false.

또 다른 좋은 방법 $someCollection.Add("thing")은 새로운 수집 카운트를 내뿜는 것입니다.


답변

PowerShell 5를 사용하면 이제 클래스를 만들 수 있습니다. 함수를 클래스로 변경 하면 return은 바로 앞의 객체 반환합니다. 여기에 간단한 예가 있습니다.

class test_class {
    [int]return_what() {
        Write-Output "Hello, World!"
        return 808979
    }
}
$tc = New-Object -TypeName test_class
$tc.return_what()

이것이 함수라면 예상되는 결과는

Hello World
808979

그러나 클래스로 반환되는 유일한 것은 정수 808979입니다. 클래스는 선언되거나 void 인 유형 만 반환한다는 보장과 같습니다.


답변

해결 방법으로 함수에서 돌아온 배열의 마지막 객체를 반환했습니다 … 훌륭한 솔루션은 아니지만 아무것도 아닌 것보다 낫습니다.

someFunction {
   $a = "hello"
   "Function is running"
   return $a
}

$b = someFunction
$b = $b[($b.count - 1)]  # Or
$b = $b[-1]              # Simpler

대체로 같은 것을 작성하는 한 줄짜리 방법은 다음과 같습니다.

$b = (someFunction $someParameter $andAnotherOne)[-1]


답변

콘솔에 출력하고 싶을 때 리턴 크래쉬를 피하기 위해 단일 결과 멤버와 함께 간단한 Hashtable 오브젝트를 전달합니다. 그것은 참조로 통과를 통해 작동합니다.

function sample-loop($returnObj) {
  for($i = 0; $i -lt 10; $i++) {
    Write-Host "loop counter: $i"
    $returnObj.result++
  }
}

function main-sample() {
  $countObj = @{ result = 0 }
  sample-loop -returnObj $countObj
  Write-Host "_____________"
  Write-Host "Total = " ($countObj.result)
}

main-sample

GitHub 프로젝트 unpackTunes 에서 실제 예제 사용법을 볼 수 있습니다 .


답변

코드를 보지 않고 말하기는 어렵습니다. 함수가 둘 이상의 객체를 반환하지 않아야하며 다른 호출에서 수행 된 결과를 캡처해야합니다. 무엇을 얻습니까?

@($returnURL).count

어쨌든, 두 가지 제안 :

객체를 문자열로 캐스팅하십시오.

...
return [string]$rs

또는 위와 동일하지만 입력하기에는 짧은 큰 따옴표로 묶습니다.

...
return "$rs"


답변

이러한 시나리오에서 함수 결과대한 Luke의 설명은 올바른 것으로 보입니다. 근본 원인 만 이해하고 싶습니다. PowerShell 제품 팀은이 동작에 대해 무언가를 수행 할 것입니다. 꽤 일반적이며 디버깅 시간이 너무 많이 걸립니다.

이 문제를 해결하기 위해 함수 호출에서 값을 반환하고 사용하는 대신 전역 변수를 사용했습니다.

전역 변수 사용에 대한 또 다른 질문이 있습니다
. 전역 변수 이름이 함수에 전달 된 변수 인 함수에서 전역 PowerShell 변수 설정