programing

스크립트에서 사용할 커스텀 타입을 PowerShell에서 작성하려면 어떻게 해야 합니까?

skycolor 2023. 4. 22. 09:10
반응형

스크립트에서 사용할 커스텀 타입을 PowerShell에서 작성하려면 어떻게 해야 합니까?

일부 PowerShell 스크립트에서 커스텀 유형을 정의하고 사용할 수 있기를 원합니다.예를 들어 다음과 같은 구조를 가진 객체가 필요하다고 가정해 보겠습니다.

Contact
{
    string First
    string Last
    string Phone
}

어떻게 하면 다음과 같은 기능을 사용할 수 있을까요?

function PrintContact
{
    param( [Contact]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

PowerShell에서 이와 같은 기능이 가능합니까, 아니면 권장되는 기능이라도 있습니까?

PowerShell 3 이전 버전

PowerShell의 Extensible Type System에서는 원래 파라미터에서 테스트한 방법과 비교하여 구체적인 유형을 만들 수 없었습니다.만약 그 테스트가 필요하지 않다면, 위의 다른 방법으로도 괜찮습니다.

샘플 스크립트에서와 같이 캐스트 또는 타이프 체크할 수 있는 실제 유형을 원하는 경우...C# 또는 VB.net에 작성하여 컴파일하지 않으면 불가능합니다.PowerShell 2에서는 "Add-Type" 명령을 사용하여 다음과 같이 간단하게 수행할 수 있습니다.

add-type @"
public struct contact {
   public string First;
   public string Last;
   public string Phone;
}
"@

이력 메모:PowerShell 1에서는 더 어려웠습니다.CodeDom을 수동으로 사용해야 했습니다.PoshCode.org에는 매우 오래된 함수 new-discript가 있어 도움이 됩니다.다음은 예를 제시하겠습니다.

New-Struct Contact @{
    First=[string];
    Last=[string];
    Phone=[string];
}

「」를 사용합니다.Add-Type ★★★★★★★★★★★★★★★★★」New-Struct 실제로 자신의 를 할 수 .param([Contact]$contact) 새로 요.$contact = new-object Contact★★★★★★★★★★…

PowerShell 3의 경우

캐스팅할 수 있는 "진짜" 클래스가 필요하지 않다면, Steven과 다른 사람들이 위에서 시연했던 추가 멤버 방식을 사용할 필요가 없습니다.

PowerShell 2에서는 New-Object에 Property 파라미터를 사용할 수 있습니다.

$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }

에서는 PowerShell 3을 할 수 .PSCustomObjectTypeName 액namename 。

[PSCustomObject]@{
    PSTypeName = "Contact"
    First = $First
    Last = $Last
    Phone = $Phone
}

오브젝트는1개를 .New-Contact나오도록 에 「 검증할 수 되었습니다.PSTypeName★★★★

function PrintContact
{
    param( [PSTypeName("Contact")]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

PowerShell 5의 경우

에서는 모든 바뀌어 PowerShell 5가 되었습니다.class ★★★★★★★★★★★★★★★★★」enum 언어 키워드로 수 있습니다.struct하지만 괜찮습니다.)

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone

    # optionally, have a constructor to 
    # force properties to be set:
    Contact($First, $Last, $Phone) {
       $this.First = $First
       $this.Last = $Last
       $this.Phone = $Phone
    }
}

,, 로, 로, 로, 로, without, without, without, without, without, without, without, without, without, without, without, without, without, without, without, without, without, without, without, without, ,New-Object[Contact]::new()하고 컨스트럭터를해시 를 만들 수 가 없으면 모든 할 수 없습니다 "모든 을 설정할 수

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone
}

$C = [Contact]@{
   First = "Joel"
   Last = "Bennett"
}

PowerShell을 사용합니다.
Kirk Munro는 실제로 그 과정을 상세히 설명하는 두 개의 훌륭한 게시물을 가지고 있다.

Manning의 "Windows PowerShell In Action" 에도 도메인별 언어를 생성하여 사용자 정의 유형을 만들기 위한 코드 샘플이 나와 있습니다.그 책은 모든 면에서 훌륭해서 정말 추천해요.

위의 간단한 방법을 찾고 있다면 다음과 같은 커스텀오브젝트를 작성하는 함수를 만들 수 있습니다.

function New-Person()
{
  param ($FirstName, $LastName, $Phone)

  $person = new-object PSObject

  $person | add-member -type NoteProperty -Name First -Value $FirstName
  $person | add-member -type NoteProperty -Name Last -Value $LastName
  $person | add-member -type NoteProperty -Name Phone -Value $Phone

  return $person
}

숏컷 방법은 다음과 같습니다.

$myPerson = "" | Select-Object First,Last,Phone

Steven Murawski의 답변은 훌륭하지만, 나는 짧은 것을 좋아한다(또는 add-member 구문을 사용하는 대신 오히려 더 깔끔한 선택 객체).

function New-Person() {
  param ($FirstName, $LastName, $Phone)

  $person = new-object PSObject | select-object First, Last, Phone

  $person.First = $FirstName
  $person.Last = $LastName
  $person.Phone = $Phone

  return $person
}

놀랍게도 커스텀 오브젝트를 작성하기 위한 이 간단한 옵션(3 이후가 아님)에 대해서는 아무도 언급하지 않았습니다.

[PSCustomObject]@{
    First = $First
    Last = $Last
    Phone = $Phone
}

유형은 실제 사용자 지정 유형이 아닌 PSCustomObject입니다.그러나 커스텀 오브젝트를 작성하는 가장 쉬운 방법이 될 수 있습니다.

사용할 수 있는 PSObject와 Add-Member의 개념이 있습니다.

$contact = New-Object PSObject

$contact | Add-Member -memberType NoteProperty -name "First" -value "John"
$contact | Add-Member -memberType NoteProperty -name "Last" -value "Doe"
$contact | Add-Member -memberType NoteProperty -name "Phone" -value "123-4567"

출력은 다음과 같습니다.

[8] » $contact

First                                       Last                                       Phone
-----                                       ----                                       -----
John                                        Doe                                        123-4567

다른 방법으로는 C#/VB에서 유형을 정의하는 방법이 있습니다.직접 사용할 수 있도록 해당 어셈블리를 PowerShell에 로드합니다.

이 동작은 다른 스크립트 또는 스크립트의 섹션이 실제 개체와 함께 작동할 수 있도록 하기 때문에 확실히 권장됩니다.

다음은 사용자 지정 유형을 생성하여 컬렉션에 저장하는 하드 경로입니다.

$Collection = @()

$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "John"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "123-4567"
$Collection += $Object

$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "Jeanne"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "765-4321"
$Collection += $Object

Write-Ouput -InputObject $Collection

Jaykul이 언급한 PSTypeName 솔루션과 유사한 아이디어를 사용하는 옵션이 하나 더 있습니다(따라서 PSv3 이상도 필요합니다).

  1. TypeName 만듭니다.유형을 정의하는 Types.ps1xml 파일.예.Person.Types.ps1xml:
<?xml version="1.0" encoding="utf-8" ?>
<Types>
  <Type>
    <Name>StackOverflow.Example.Person</Name>
    <Members>
      <ScriptMethod>
        <Name>Initialize</Name>
        <Script>
            Param (
                [Parameter(Mandatory = $true)]
                [string]$GivenName
                ,
                [Parameter(Mandatory = $true)]
                [string]$Surname
            )
            $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName
            $this | Add-Member -MemberType 'NoteProperty' -Name 'Surname' -Value $Surname
        </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>SetGivenName</Name>
        <Script>
            Param (
                [Parameter(Mandatory = $true)]
                [string]$GivenName
            )
            $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName -Force
        </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>FullName</Name>
        <GetScriptBlock>'{0} {1}' -f $this.GivenName, $this.Surname</GetScriptBlock>
      </ScriptProperty>
      <!-- include properties under here if we don't want them to be visible by default
      <MemberSet>
        <Name>PSStandardMembers</Name>
        <Members>
        </Members>
      </MemberSet>
      -->
    </Members>
  </Type>
</Types>
  1. Import합니다.Update-TypeData -AppendPath .\Person.Types.ps1xml
  2. 타입의 .$p = [PSCustomType]@{PSTypeName='StackOverflow.Example.Person'}
  3. 합니다.$p.Initialize('Anne', 'Droid')
  4. 모든 속성이 정의되어 있습니다.$p | Format-Table -AutoSize
  5. 을 갱신하려면 합니다.「 」 。$p.SetGivenName('Dan')
  6. 한 번 해 보세요.$p | Format-Table -AutoSize

설명.

  • PS1XML 파일을 사용하면 유형에 대한 사용자 지정 속성을 정의할 수 있습니다.
  • 설명서에 나와 있는 것처럼 .net 유형으로 제한되지 않으므로 'PSTypeName'과(와) 일치하는 'PSTypeName'으로 생성된 개체는 이 유형에 대해 정의된 멤버를 상속합니다.
  • 멤버 추가 방법:PS1XML또는Add-Member한정되어 있다NoteProperty,AliasProperty,ScriptProperty,CodeProperty,ScriptMethod,그리고.CodeMethod(또는PropertySet/MemberSet(단, 이러한 제한은 동일합니다).이러한 속성은 모두 읽기 전용입니다.
  • 를 정의함으로써ScriptMethod우리는 위의 제한을 어길 수 있다.예를 들어, 방법을 정의할 수 있습니다(예:Initialize)는 새로운 속성을 생성하여 값을 설정합니다.따라서 오브젝트에 다른 스크립트가 동작하는 데 필요한 모든 속성이 포함되어 있는지 확인합니다.
  • 예시와 같이 이 방법을 사용하여 속성을 직접 할당이 아닌 메서드를 통해 업데이트할 수 있습니다.SetGivenName.

이 접근방식은 모든 시나리오에 이상적인 것은 아닙니다.다만, 커스텀 타입에 클래스 타입의 동작을 추가하는 경우에 도움이 됩니다.다른 답변에 기재되어 있는 다른 방법과 조합해 사용할 수도 있습니다.예를 들어, 실제 세계에서는 아마도 다음과 같이 정의했을 것입니다.FullNamePS1XML에서 속성을 지정한 후 함수를 사용하여 다음과 같이 필요한 값을 가진 개체를 만듭니다.

상세 정보

매뉴얼 또는 OOTB 타입 파일을 참조해 주세요.Get-Content $PSHome\types.ps1xml영감을 얻으려고요

# have something like this defined in my script so we only try to import the definition once.
# the surrounding if statement may be useful if we're dot sourcing the script in an existing 
# session / running in ISE / something like that
if (!(Get-TypeData 'StackOverflow.Example.Person')) {
    Update-TypeData '.\Person.Types.ps1xml'
}

# have a function to create my objects with all required parameters
# creating them from the hash table means they're PROPERties; i.e. updatable without calling a 
# setter method (note: recall I said above that in this scenario I'd remove their definition 
# from the PS1XML)
function New-SOPerson {
    [CmdletBinding()]
    [OutputType('StackOverflow.Example.Person')]
    Param (
        [Parameter(Mandatory)]
        [string]$GivenName
        ,
        [Parameter(Mandatory)]
        [string]$Surname
    )
    ([PSCustomObject][Ordered]@{
        PSTypeName = 'StackOverflow.Example.Person'
        GivenName = $GivenName
        Surname = $Surname
    })
}

# then use my new function to generate the new object
$p = New-SOPerson -GivenName 'Simon' -Surname 'Borg'

# and thanks to the type magic... FullName exists :)
Write-Information "$($p.FullName) was created successfully!" -InformationAction Continue

언급URL : https://stackoverflow.com/questions/59819/how-do-i-create-a-custom-type-in-powershell-for-my-scripts-to-use

반응형