PowerShell v5 모듈에서 클래스를 내보내는 방법
다른 스크립트들을 위한 라이브러리와 같은 모듈 설정이 있습니다.스크립트 범위 호출에 클래스 선언을 가져오는 방법을 알 수 없습니다.저는 준비를 하려고 했습니다.Export-Module
-class
,면 같은 -function
, 하지만 그런 건 없습니다.-class
이용할 수 있는.모든 대본에 수업을 선언하면 되는 건가요?
설정:
- holidays.psm1 in ~\documents\windows\powershell\modules\holidays\
import-module holidays
- holidays.psm1에는 클래스 개체를 올바르게 반환하는 다른 기능이 있지만 가져온 후 활성 스크립트에서 클래스의 새 멤버를 만드는 방법을 모릅니다.
클래스의 모습은 다음과 같습니다.
Class data_block
{
$array
$rows
$cols
data_block($a, $r, $c)
{
$this.array = $a
$this.rows = $r
$this.cols = $c
}
}
PSA: 오래된 클래스 복사본을 메모리에 저장하는 알려진 문제가 있습니다.수업 관련 일을 하는 것은 모르는 사람들에게 정말 혼란을 줍니다.여기서 읽어보실 수 있습니다.
using
다에 .
using
키워드는 다음과 같이 다양한 함정에 빠지기 쉽습니다.
-
using
다에 에 대해 .PSModulePath
에 지정하지 않는 한using
진술. 이것은 다소 놀라운 일입니다를 모듈을 할 수 입니다. 왜냐하면 모듈은 다음을 통해 사용할 수 있기 때문입니다.Get-Module
using
모듈이 로드된 방식에 따라 문이 작동하지 않을 수 있습니다. -
using
statement다의 맨 할 수 ..[scriptblock]::Create()
아니면New-Module
이를 극복한 것 같습니다.문자열이 전달되었습니다.Invoke-Expression
의 스크립트 다.using
그러한 종류의 작업의 시작 부분에 있는 진술.은,Invoke-Expression "using module $path"
성공할 수는 있지만 모듈의 내용을 사용할 수 있는 범위는 다소 이해할 수 없는 것 같습니다.를 들어,어일 ,Invoke-Expression "using module $path"
는 Pester 스크립트 블록 내에서 사용되며, 모듈 내부의 클래스는 동일한 Pester 스크립트 블록에서 사용할 수 없습니다.
ScriptsToProcess
정의 ScriptsToProcess
모듈에서 클래스를 내보내는 것으로 보입니다.그러나 클래스를 내보내는 대신 "모듈의 클래스 대신 글로벌 SessionState에 클래스를 생성하므로...개인 기능에 액세스할 수 없습니다."내가 아는 한, 사용하는 것은ScriptsToProcess
과 같은 하는 것과 .다.
# this is like defining c in class.ps1 and referring to it in ScriptsToProcess
class c {
[string] priv () { return priv }
[string] pub () { return pub }
}
# this is like defining priv and pub in module.psm1 and referring to it in RootModule
New-Module {
function priv { 'private function' }
function pub { 'public function' }
Export-ModuleMember 'pub'
} | Import-Module
[c]::new().pub() # succeeds
[c]::new().priv() # fails
호출하면 다음과(와)
public function
priv : The term 'priv' is not recognized ...
+ [string] priv () { return priv } ...
priv
할 수 없음에도 priv
해당 모듈을 가져올 때 정의된 클래스에서 호출됩니다.이것이 당신이 원하는 것일 수도 있지만, 클래스 메소드는 일반적으로 내가 비공개로 유지하고 싶은 모듈의 일부 기능에 액세스해야 한다는 것을 알게 되었기 때문에 사용할 수 있는 방법을 찾지 못했습니다.
.NewBoundScriptBlock()
안정적으로 작동하는 것 같습니다.
를 내보내는 데것, 의 .using
실행합니다. 클래스를 포함하고 가져온 다음 모듈을 고려합니다.
New-Module 'ModuleName' { class c {$p = 'some value'} } |
Import-Module
중인 [c]::new()
됩니다의 됩니다.[c]
:
PS C:\> $c = & (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
PS C:\> $c.p
some value
.NewBoundScriptBlock()
의 더 이 있는 것 ..NewBoundScriptBlock()
다음 두 . 합니다에 되는 모듈의 합니다.Get-Module
:
& (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
& (Get-Module 'ModuleName') {[c]::new()}}
후자는 객체가 파이프라인에 쓰여질 때 파이프라인 미드스크립트 블록에 제어 흐름을 줄 수 있다는 장점이 있습니다..NewBoundScriptBlock()
반면 파이프라인에 쓰여진 모든 개체를 수집하고 전체 스크립트 블록의 실행이 완료된 후에만 생성됩니다.
모듈을 사용할 필요 없이 수업을 로드할 수 있는 방법을 찾았습니다.MyModule.psd1 파일에서 다음 줄을 사용합니다.
ScriptsToProcess = @('Class.ps1')
그런 다음 클래스를 Class.ps1 파일에 입력합니다.
class MyClass {}
업데이트: 이 방법으로 "module MyModule"을 사용할 필요는 없지만 다음 중 하나를 수행해야 합니다.
- "module MyModule(내 모듈 사용
- 또는 "내 모듈 가져오기"를 실행합니다.
- 또는 모듈에 있는 모든 기능을 호출하여 도중에 모듈을 자동으로 가져올 수 있습니다).
업데이트 2: 기능 를 기능 수 .이렇게 하면 Class가 현재 범위로 로드되므로 예를 들어 기능 내에서 Module을 가져오면 Class가 기능 외부에서 액세스할 수 없습니다.가 볼 수 있는 할 수 있는 를 C를 C#입니다로 입니다.Add-Type -Language CSharp -TypeDefinition 'MyClass...'
.
여기와 여기에 따르면 PowerShell 5에서 다음을 수행하여 모듈에 정의된 클래스를 사용할 수 있습니다.
using module holidays
사용명세서를 사용하는 것이 당신에게 적합하다면 선택할 수 있는 방법입니다.그렇지 않으면 이것도 효과가 있는 것 같습니다.
파일 test class.psm1
함수를 사용하여 클래스를 전달합니다.
class abc{
$testprop = 'It Worked!'
[int]testMethod($num){return $num * 5}
}
function new-abc(){
return [abc]::new()
}
Export-ModuleMember -Function new-abc
일부 Script.ps1
Import-Module path\to\testclass.psm1
$testclass = new-abc
$testclass.testProp # Returns 'It Worked!'
$testclass.testMethod(500) # Returns 2500
$testclass | gm
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
testMethod Method int testMethod(System.Object num)
ToString Method string ToString()
testprop Property System.Object testprop {get;set;}
당신은 거의 그럴 수 없습니다.에 의하면.about_Classes
도움말:
클래스키워드
새 클래스를 정의합니다.이것은 사실입니다.NET Framework 유형.클래스 구성원은 공용이지만 모듈 범위 내에서만 공용입니다.유형 이름을 문자열로 참조할 수 없으며(예: New-Object가 작동하지 않음), 이번 릴리스에서는 클래스가 정의된 스크립트/모듈 파일 외부에 유형 리터럴(예: [MyClass])을 사용할 수 없습니다.
말은, 을 , 을 해야 한다는 을 의미합니다.data_block
를 들어,어,다와 같은 또는 .New-DataBlock
그리고 그것이 새로운 것으로 돌아오게 합니다.data_block
인스턴스(instance)를 사용하여 클래스 메서드 및 속성(정적 메서드 포함 likely)을 가져올 수 있습니다.
이것은 확실히 기대했던 것처럼 작동하지 않습니다.
PowerShell 5에서는 클래스를 .psm1 확장자를 사용하여 별도의 파일로 정의할 수 있습니다.
그런 다(예) 할 수
using module C:\classes\whatever\path\to\file.psm1
스크립트의 첫 번째 행(댓글 뒤)이어야 합니다.
이처럼 고통을 주는 것은 클래스 정의가 스크립트에서 호출되더라도 전체 세션에 대해 모듈이 로드되기 때문입니다.다음을 실행하면 이를 확인할 수:
Get-Module
로드한 파일의 이름이 나타납니다.스크립트를 다시 실행해도 클래스 정의를 다시 로드하지 않습니다! (PSM1 파일을 읽지도 않습니다.)이것은 치아의 많은 갈림길을 일으킵니다.
스크립트를 실행하기 전에 다음 명령을 실행할 수 있습니다. 그러면 새로 고침된 클래스 정의로 모듈이 다시 로드됩니다.
Remove-Module file
여기서 file은 경로나 확장명이 없는 이름입니다.그러나 제정신을 발휘하지 않도록 PowerShell 세션을 다시 시작해 보는 것이 좋습니다.이것은 분명히 번거로운 일입니다. 마이크로소프트는 어떻게든 이 문제를 해결해야 합니다.
v5에서도 PowerShell 클래스와 관련하여 여러 가지 문제가 발생했습니다.
저는 이것이 완벽하게 호환되기 때문에 일단 다음과 같은 해결책을 사용하기로 결정했습니다.NET 및 PowerShell:
Add-Type -Language CSharp -TypeDefinition @"
namespace My.Custom.Namespace {
public class Example
{
public string Name { get; set; }
public System.Management.Automation.PSCredential Credential { get; set; }
// ...
}
}
"@
유형 정의를 추가하는 데 사용자 정의 어셈블리가 필요하지 않다는 장점이 있습니다.PowerShell 스크립트 또는 모듈에서 클래스 정의를 인라인으로 추가할 수 있습니다.
유일한 단점은 가 처음 로드된 후 클래스 정의를 다시 로드하려면 새 런타임을 생성해야 한다는 것입니다(C#/에 어셈블리를 로드하는 것과 마찬가지).NET 도메인).
이 문제를 해결하는 방법은 사용자 지정 클래스 정의를 동일한 이름의 빈 .ps1 파일로 이동시킨 다음 닷 소싱을 통해 모듈 정의와 종속 코드 모두에 로드하는 것입니다.이것이 좋지 않다는 것을 알지만, 저에게는 여러 파일에 걸쳐 동일한 클래스의 여러 정의를 유지하는 것보다 낫습니다.
개발하는 동안 클래스 정의를 업데이트하려면 클래스의 코드를 선택하고 를 눌러 선택한 코드를 실행합니다.그것은 그것만큼 깨끗하지 않습니다.-Force
Import-Module
지휘.
다음으로 보기using Module
PowerShell ISE를 종료하고 다시 시작할 필요 없이 클래스를 개발하고 결과를 확인할 수 있는 최선의 방법입니다.
의의 .using module
모듈 외부로 노출할 클래스는 모듈의 psm1 파일 자체에 있어야 합니다.
모듈 외부로 노출할 클래스 정의를 모듈의 별도 ps1 파일에서 psm1 파일로 '도트 소싱'할 수 없습니다.
...이는 v5.1 이후의 문서에 따른 것입니다(최소 7.2까지).
using module 문은 스크립트 모듈 또는 이진 모듈의 루트 모듈(Module ToProcess)에서 클래스를 가져옵니다.중첩된 모듈에 정의된 클래스 또는 도트 소싱된 스크립트에 정의된 클래스를 모듈로 지속적으로 가져오지 않습니다.모듈 외부의 사용자가 사용할 클래스는 루트 모듈에서 정의해야 합니다.
따라서 (다른 답변에서 논의된 바와 같이) 가장 간단한 옵션은 다음과 같습니다.
클래스 인스턴스를 정의 모듈 외부에서 참조하기만 하면 되는 경우 클래스 인스턴스를 반환하는 공용 함수를 만듭니다.
function Get-MyModulesClass { [MyModuleClass]::New() }
모듈 외부의 클래스 유형을 참조하려면(예: 함수 인수의 유형 지정) 클래스가 모듈의 psm1 파일에 직접 정의되어 있어야 하며, 이 psm1 파일은 다음을 통해 외부 스크립트에 포함되어 있어야 합니다.
using module
:예:using module <relativePathToModulePsm1File>
).
...물론 이 모든 것을 파악하는 데 도움이 되지 않는 것은 클래스가 다시 로드되지 않기 때문에 클래스를 변경할 때마다 새로운 파워셸 세션을 시작해야 한다는 것입니다.
예제 모듈
/My Library Module/MyPrivateClass.ps1:
class MyPrivateClass {
[void] Test(){ Write-Host "Accessed private class methods!"}
}
/My Library Module/My Library Module.psm1
class MyPublicClass {} # Exposed classes MUST be defined in this file
. $PSScriptRoot\MyPrivateClass.ps1
function Get-MyPrivateClassInstance { [MyPrivateClass]::new()}
/Script.ps1 예시
using module .\MyLibraryModule\MyLibraryModule.psm1
[MyPublicClass]$myVar1 # Works
[MyPrivateClass]$myVar2 # Errors
Import-Module .\MyLibraryModule\MyLibraryModule.psm1
$object = Get-MyPrivateClassInstance
$object.GetType().Name
$object.Test() # works
산출량
InvalidOperation:
Line |
5 | [MyPrivateClass]$myVar2 # Errors
| ~~~~~~~~~~~~~~
| Unable to find type [MyPrivateClass].
MyPrivateClass
Accessed private class methods!
언급URL : https://stackoverflow.com/questions/31051103/how-to-export-a-class-in-a-powershell-v5-module
'programing' 카테고리의 다른 글
명명된 문자 벡터를 data.frame으로 변환 (0) | 2023.09.27 |
---|---|
MySQL에서 연결 시간대 변경 (0) | 2023.09.27 |
6자리 고유 번호를 생성하려면 어떻게 해야 합니까? (0) | 2023.09.27 |
우커머스에서 받은 페이지 순으로 텍스트 변경 (0) | 2023.09.27 |
검토를 기다리는 일반적인 시간은? (0) | 2023.09.27 |