about_Types.ps1xml — Types.ps1xml 파일로 PowerShell 객체 형식 확장하기

about_Types.ps1xml — Types.ps1xml 파일로 PowerShell 객체 형식 확장하기

PowerShell에서 쓰는 객체에 기본 프로퍼티 말고 추가 프로퍼티나 메서드를 붙이고 싶을 때가 있어요. 예를 들어 모든 System.DateTime 객체에 DateTime이라는 프로퍼티가 들어 있는 걸 본 적이 있으실 거예요. 이런 확장을 어떻게 정의하고 세션에 로드하는지, 이 문서에서는 Types.ps1xml 파일을 중심으로 하나씩 풀어볼게요.

출처: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_types.ps1xml

본문

간단한 설명

Types.ps1xml 파일을 사용해서 PowerShell에서 쓰는 객체의 형식을 확장하는 방법을 설명해요.

자세한 설명

확장 형식 데이터(extended type data)는 PowerShell 객체 형식에 추가 프로퍼티와 메서드("멤버")를 정의해요. PowerShell 세션에 확장 형식 데이터를 추가하는 방법은 두 가지가 있어요.

  • Types.ps1xml 파일: 확장 형식 데이터를 정의하는 XML 파일이에요.
  • Update-TypeData: Types.ps1xml 파일을 다시 로드하고 현재 세션의 형식에 확장 데이터를 정의하는 cmdlet이에요.

이 문서에서 다루는 건 Types.ps1xml 파일이에요. 현재 세션에 동적 확장 형식 데이터를 추가하는 Update-TypeData cmdlet 사용법은 Update-TypeData를 참고해요.

확장 형식 데이터란

확장 형식 데이터는 PowerShell 객체 형식에 추가 프로퍼티와 메서드("멤버")를 정의해요. PowerShell이 지원하는 어떤 형식이든 확장할 수 있고, 추가한 프로퍼티와 메서드는 객체 형식에 원래 정의된 프로퍼티와 똑같은 방식으로 쓸 수 있어요.

예를 들어 PowerShell은 모든 System.DateTime 객체에 DateTime 프로퍼티를 추가해요. Get-Date cmdlet이 반환하는 System.DateTime 객체들이 그 대표적인 예시예요.

(Get-Date).DateTime

Sunday, January 29, 2012 9:43:57 AM

System.DateTime 구조체 설명에는 DateTime 프로퍼티가 안 보여요. 어디에도 없는 이 프로퍼티는 PowerShell이 직접 추가한 거고, 그래서 PowerShell 안에서만 볼 수 있죠.

PowerShell은 내부적으로 기본 확장 형식 집합을 정의해요. 이 형식 정보는 모든 PowerShell 세션이 시작할 때 자동으로 로드돼요. DateTime 프로퍼티도 이 기본 집합에 들어 있어요. PowerShell 6 이전에는 이 형식 정의를 PowerShell 설치 디렉터리($PSHOME)의 Types.ps1xml 파일에 저장했어요.

PowerShell에 확장 형식 데이터 추가하기

PowerShell 세션의 확장 형식 데이터는 세 가지 출처가 있어요.

  • PowerShell이 정의해서 모든 세션에 자동으로 로드하는 데이터. PowerShell 6부터 이 정보는 PowerShell 안에 컴파일되어 더 이상 Types.ps1xml 파일로 배포되지 않아요.
  • 모듈이 내보내는 Types.ps1xml 파일. 모듈이 현재 세션으로 가져오면(import) 로드돼요.
  • Update-TypeData cmdlet으로 정의한 확장 형식 데이터. 현재 세션에만 추가되고 파일로 저장되지는 않아요.

세션 안에서 이 세 출처의 확장 형식 데이터는 객체에 동일한 방식으로 적용돼요. 지정된 형식의 모든 객체가 같은 확장을 갖게 되죠.

TypeData cmdlet

다음 cmdlet은 PowerShell 3.0 이상의 Microsoft.PowerShell.Utility 모듈에 포함되어 있어요.

  • Get-TypeData: 현재 세션의 확장 형식 데이터를 가져와요.
  • Update-TypeData: Types.ps1xml 파일을 다시 로드하고 현재 세션에 확장 형식 데이터를 추가해요.
  • Remove-TypeData: 현재 세션에서 확장 형식 데이터를 제거해요.

이 cmdlet들에 대한 자세한 내용은 각 cmdlet의 도움말 항목을 참고해요.

기본 제공 Types.ps1xml 파일

$PSHOME 디렉터리의 Types.ps1xml 파일은 모든 세션에 자동으로 추가돼요. PowerShell 설치 디렉터리($PSHOME)의 Types.ps1xml 파일은 XML 기반 텍스트 파일로, PowerShell에서 사용하는 객체에 프로퍼티와 메서드를 추가할 수 있게 해줘요. PowerShell에는 .NET 형식에 여러 요소를 추가하는 기본 제공 Types.ps1xml 파일이 있는데, 원하면 추가 Types.ps1xml 파일을 만들어서 형식을 더 확장할 수도 있어요.

예를 들어 기본적으로 배열 객체(System.Array)에는 배열 안의 객체 수를 알려주는 Length 프로퍼티가 있어요. 그런데 Length라는 이름은 프로퍼티가 뭘 뜻하는지 잘 드러나지 않아서, PowerShell은 같은 값을 보여주는 Count라는 별칭 프로퍼티(alias property)를 추가해요. 다음 XML은 System.Array 형식에 Count 프로퍼티를 추가해요.

<Type>
  <Name>System.Array</Name>
  <Members>
    <AliasProperty>
      <Name>Count</Name>
      <ReferencedMemberName>
        Length
      </ReferencedMemberName>
    </AliasProperty>
  </Members>
</Type>

AliasProperty를 확인하려면 아무 배열에 Get-Member 명령을 실행해보면 돼요.

Get-Member -InputObject (1,2,3,4)

명령은 다음과 같은 결과를 반환해요.

Name       MemberType    Definition
----       ----------    ----------
Count      AliasProperty Count = Length
Address    Method        System.Object& Address(Int32)
Clone      Method        System.Object Clone()
CopyTo     Method        System.Void CopyTo(Array array, Int32 index):
Equals     Method        System.Boolean Equals(Object obj)
Get        Method        System.Object Get(Int32)
# ...

결론적으로 PowerShell에서 배열의 Count 프로퍼티와 Length 프로퍼티를 둘 다 쓸 수 있어요. 예를 들어:

(1, 2, 3, 4).Count
4

(1, 2, 3, 4).Length
4

새 Types.ps1xml 파일 만들기

PowerShell과 함께 설치되는 .ps1xml 파일은 디지털 서명되어 있어서 변조를 막아요. 형식에 scriptblock이 포함될 수 있기 때문이에요. 그래서 .NET 형식에 프로퍼티나 메서드를 추가하려면, 직접 Types.ps1xml 파일을 만들어서 PowerShell 세션에 추가해야 해요.

새 파일을 만드려면 먼저 기존 Types.ps1xml 파일을 복사하는 것부터 시작해요. 새 파일 이름은 뭐든 괜찮지만 확장자는 반드시 .ps1xml이어야 해요. 파일을 둘 곳은 PowerShell이 접근할 수 있는 디렉터리면 어디든 돼요. 다만 PowerShell 설치 디렉터리($PSHOME)나 그 하위 디렉터리에 두면 편리해요.

파일을 저장했으면 Update-TypeData cmdlet으로 새 파일을 현재 세션에 추가해요. 내가 정의한 형식이 기본 제공 형식보다 우선하도록 하려면 Update-TypeDataPrependData 매개 변수를 사용해요. Update-TypeData는 현재 세션에만 영향을 줘요. 앞으로 생길 모든 세션에 적용하려면 콘솔을 내보내거나 Update-TypeData 명령을 PowerShell 프로필에 추가해요.

Types.ps1xml과 Add-Member

Types.ps1xml 파일은 영향받는 PowerShell 세션에서 지정한 .NET 형식의 모든 인스턴스에 프로퍼티와 메서드를 추가해요. 그런데 객체 하나의 인스턴스에만 프로퍼티나 메서드를 추가하고 싶다면 Add-Member cmdlet을 사용해요. 자세한 내용은 Add-Member를 참고해요.

예시: FileInfo 객체에 Age 멤버 추가하기

이 예시는 System.IO.FileInfo 객체에 Age 프로퍼티를 추가하는 방법을 보여줘요. 파일의 나이는 생성 시각과 현재 시각의 차이를 일(day) 단위로 계산한 값이에요.

Age 프로퍼티는 scriptblock으로 계산되니까, 새 Age 프로퍼티의 본보기로 쓸 <ScriptProperty> 태그를 찾아요. 다음 XML 코드를 $PSHOME\MyTypes.ps1xml 파일로 저장해요.

<?xml version="1.0" encoding="utf-8" ?>
<Types>
  <Type>
    <Name>System.IO.FileInfo</Name>
    <Members>
      <ScriptProperty>
        <Name>Age</Name>
        <GetScriptBlock>
          ((Get-Date) - ($this.CreationTime)).Days
        </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
</Types>

Update-TypeData를 실행해서 새 Types.ps1xml 파일을 현재 세션에 추가해요. 명령은 PrependData 매개 변수를 사용해서 새 파일을 원래 정의보다 더 높은 우선순위에 둬요. Update-TypeData에 대한 자세한 내용은 Update-TypeData를 참고해요.

Update-TypeData -PrependPath $PSHOME\MyTypes.ps1xml

변경 사항을 테스트하려면 Get-ChildItem 명령으로 $PSHOME 디렉터리의 powershell.exe 파일을 가져온 다음, Format-List cmdlet으로 파이프해서 파일의 모든 프로퍼티를 나열해요. 변경 덕분에 목록에 Age 프로퍼티가 나타나는 걸 확인할 수 있어요.

Get-ChildItem $PSHOME\pwsh.exe | Select-Object Age

142

Types.ps1xml 파일의 XML

전체 스키마 정의는 GitHub의 PowerShell 소스 코드 저장소에 있는 Types.xsd에서 볼 수 있어요.

<Types> 태그는 파일에 정의된 모든 형식을 감싸요. <Types> 태그는 하나만 있어야 해요. 파일에 언급된 각 .NET 형식은 <Type> 태그로 표현돼요. <Type> 태그는 다음 태그를 포함해야 해요.

<Name>: 영향받는 .NET 형식의 이름을 감싸요. <Members>: .NET 형식에 정의할 새 프로퍼티와 메서드의 태그를 감싸요.

<Members> 태그 안에는 다음 멤버 태그 중 어떤 것이든 들어갈 수 있어요.

AliasProperty

기존 프로퍼티의 새 이름을 정의해요. <AliasProperty> 태그에는 새 프로퍼티의 이름을 지정하는 <Name> 태그와 기존 프로퍼티를 지정하는 <ReferencedMemberName> 태그가 있어야 해요.

예를 들어 Count 별칭 프로퍼티는 배열 객체의 Length 프로퍼티에 대한 별칭이에요.

<Type>
  <Name>System.Array</Name>
  <Members>
    <AliasProperty>
      <Name>Count</Name>
      <ReferencedMemberName>Length</ReferencedMemberName>
    </AliasProperty>
  </Members>
</Type>

CodeMethod

.NET 클래스의 정적 메서드를 참조해요. <CodeMethod> 태그에는 새 메서드의 이름을 지정하는 <Name> 태그와 메서드가 정의된 코드를 지정하는 <CodeReference> 태그가 있어야 해요.

예를 들어 ToString 메서드는 PowerShell의 Microsoft.PowerShell.ToStringCodeMethods 코드 정의 이름이에요.

  <Type>
    <Name>System.Xml.XmlNode</Name>
    <Members>
      <CodeMethod>
        <Name>ToString</Name>
        <CodeReference>
          <TypeName>Microsoft.PowerShell.ToStringCodeMethods</TypeName>
          <MethodName>XmlNode</MethodName>
        </CodeReference>
      </CodeMethod>
    </Members>
  </Type>

CodeProperty

.NET 클래스의 정적 메서드를 참조해요. <CodeProperty> 태그에는 새 프로퍼티의 이름을 지정하는 <Name> 태그와 프로퍼티가 정의된 코드를 지정하는 <GetCodeReference> 태그가 있어야 해요.

예를 들어 System.IO.DirectoryInfo 객체의 Mode 프로퍼티는 PowerShell FileSystem 공급자에 정의된 코드 프로퍼티(code property)예요.

<Type>
  <Name>System.IO.DirectoryInfo</Name>
  <Members>
    <CodeProperty>
      <Name>Mode</Name>
      <GetCodeReference>
        <TypeName>
          Microsoft.PowerShell.Commands.FileSystemProvider
        </TypeName>
        <MethodName>Mode</MethodName>
      </GetCodeReference>
    </CodeProperty>
  </Members>
</Type>

MemberSet

멤버(프로퍼티와 메서드)의 컬렉션을 정의해요. <MemberSet> 태그는 기본 <Members> 태그 안에 나타나요. 태그는 멤버 집합의 이름을 감싸는 <Name> 태그와, 집합 안의 멤버(프로퍼티와 메서드)를 감싸는 보조 <Members> 태그를 포함해야 해요. 프로퍼티를 만드는 태그(<NoteProperty><ScriptProperty> 같은)나 메서드를 만드는 태그(<Method><ScriptMethod> 같은)는 모두 멤버 집합의 멤버가 될 수 있어요.

Types.ps1xml 파일에서 <MemberSet> 태그는 PowerShell에서 .NET 객체의 기본 보기(default view)를 정의할 때 사용해요. 이 경우 멤버 집합의 이름(<Name> 태그 안의 값)은 항상 PsStandardMembers고, 프로퍼티의 이름(<Name> 태그의 값)은 다음 중 하나예요.

  • DefaultDisplayProperty: 객체의 단일 프로퍼티예요.
  • DefaultDisplayPropertySet: 객체의 하나 이상의 프로퍼티예요.
  • DefaultKeyPropertySet: 객체의 하나 이상의 키 프로퍼티예요. 키 프로퍼티는 프로퍼티 값의 인스턴스를 식별해요. 예를 들어 세션 기록에 있는 항목의 ID 번호가 그렇죠.

예를 들어 다음 XML은 Get-Service cmdlet이 반환하는 서비스(System.ServiceProcess.ServiceController 객체)의 기본 표시를 정의해요. PsStandardMembers라는 멤버 집합을 정의하고, 그 안에 기본 프로퍼티 집합과 기본 표시 프로퍼티를 둬요. 기본 프로퍼티 집합은 Status, Name, DisplayName 프로퍼티로, 기본 표시 프로퍼티는 Name으로 정의해요.

<Type>
  <Name>System.ServiceProcess.ServiceController</Name>
  <Members>
    <MemberSet>
      <Name>PSStandardMembers</Name>
      <Members>
        <PropertySet>
          <Name>DefaultDisplayPropertySet</Name>
          <ReferencedProperties>
            <Name>Status</Name>
            <Name>Name</Name>
            <Name>DisplayName</Name>
          </ReferencedProperties>
        </PropertySet>
        <NoteProperty>
          <Name>DefaultDisplayProperty</Name>
          <Value>Name</Value>
        </NoteProperty>
      </Members>
    </MemberSet>
  </Members>
</Type>

<Method>: 기본 객체의 네이티브 메서드를 참조해요. <Methods>: 객체의 메서드 컬렉션이에요.

NoteProperty

정적 값을 가진 프로퍼티를 정의해요. <NoteProperty> 태그에는 새 프로퍼티의 이름을 지정하는 <Name> 태그와 프로퍼티의 값을 지정하는 <Value> 태그가 있어야 해요.

예를 들어 다음 XML은 System.IO.DirectoryInfo 객체에 Status 프로퍼티를 만들어요. Status 프로퍼티의 값은 항상 Success예요.

<Type>
  <Name>System.IO.DirectoryInfo</Name>
  <Members>
    <NoteProperty>
      <Name>Status</Name>
      <Value>Success</Value>
    </NoteProperty>
  </Members>
</Type>

PropertySet

인수를 받고 값을 반환하는 프로퍼티예요.

<Properties>: 객체의 프로퍼티 컬렉션이에요. <Property>: 기본 객체의 프로퍼티예요. <PropertySet>: 객체의 프로퍼티 컬렉션을 정의해요. <PropertySet> 태그에는 프로퍼티 집합의 이름을 지정하는 <Name> 태그와 프로퍼티를 지정하는 <ReferencedProperty> 태그가 있어야 해요. 프로퍼티의 이름은 <Name> 태그 안에 넣어요.

Types.ps1xml에서 <PropertySet> 태그는 객체의 기본 표시를 위한 프로퍼티 집합을 정의할 때 사용해요. 기본 표시는 <MemberSet> 태그의 <Name> 태그 값 PsStandardMembers로 식별할 수 있어요.

예를 들어 다음 XML은 DefaultDisplayPropertySet이라는 이름의 PropertySet을 만들어요. ReferencedProperties는 3개예요.

<Type>
  <Name>System.ServiceProcess.ServiceController</Name>
  <Members>
    <MemberSet>
      <Name>PSStandardMembers</Name>
      <Members>
        <PropertySet>
          <Name>DefaultDisplayPropertySet</Name>
          <ReferencedProperties>
            <Name>Status</Name>
            <Name>Name</Name>
            <Name>DisplayName</Name>
          </ReferencedProperties>
        </PropertySet>
      </Members>
    </MemberSet>
  </Members>
</Type>

ScriptMethod

스크립트 출력을 값으로 갖는 메서드를 정의해요. <ScriptMethod> 태그에는 새 메서드의 이름을 지정하는 <Name> 태그와 메서드 결과를 반환하는 scriptblock을 감싸는 <Script> 태그가 있어야 해요.

예를 들어 관리 객체(System.System.Management.ManagementObject)의 ConvertToDateTimeConvertFromDateTime 메서드는 System.Management.ManagementDateTimeConverter 클래스의 ToDateTimeToDmtfDateTime 정적 메서드를 사용하는 스크립트 메서드예요.

<Type>
 <Name>System.Management.ManagementObject</Name>
 <Members>
 <ScriptMethod>
   <Name>ConvertToDateTime</Name>
   <Script>
   [System.Management.ManagementDateTimeConverter]::ToDateTime($args[0])
   </Script>
 </ScriptMethod>
 <ScriptMethod>
   <Name>ConvertFromDateTime</Name>
   <Script>
   [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($args[0])
   </Script>
 </ScriptMethod>
 </Members>
</Type>

ScriptProperty

스크립트 출력을 값으로 갖는 프로퍼티를 정의해요. <ScriptProperty> 태그에는 새 프로퍼티의 이름을 지정하는 <Name> 태그와 프로퍼티 값을 반환하는 scriptblock을 감싸는 <GetScriptBlock> 태그가 있어야 해요.

예를 들어 System.IO.FileInfo 객체의 VersionInfo 프로퍼티는 System.Diagnostics.FileVersionInfo 객체의 GetVersionInfo 정적 메서드에 FullName 프로퍼티를 넘겨서 얻는 스크립트 프로퍼티예요.

<Type>
  <Name>System.IO.FileInfo</Name>
  <Members>
    <ScriptProperty>
      <Name>VersionInfo</Name>
      <GetScriptBlock>
      [System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)
      </GetScriptBlock>
    </ScriptProperty>
  </Members>
</Type>

자세한 내용은 Windows PowerShell 소프트웨어 개발 키트(SDK)를 참고해요.

Update-TypeData

Types.ps1xml 파일을 PowerShell 세션에 로드하려면 Update-TypeData cmdlet을 실행해요. 내 파일의 형식이 기본 제공 Types.ps1xml 파일의 형식보다 우선하도록 하려면 Update-TypeData의 PrependData 매개 변수를 추가해요. Update-TypeData는 현재 세션에만 영향을 줘요. 모든 향후 세션에 변경을 적용하려면 세션을 내보내거나 Update-TypeData 명령을 PowerShell 프로필에 추가해요.

프로퍼티에서 발생하는 예외나 Update-TypeData 명령에 프로퍼티를 추가할 때 발생하는 예외는 StdErr로 오류를 보고하지 않아요. 이는 형식화와 출력 중에 흔한 형식들에서 발생할 수 있는 예외를 억제하기 위해서예요. .NET 프로퍼티를 쓰는 경우에는 다음 예시처럼 메서드 구문을 사용해서 예외 억제를 우회할 수 있어요.

"hello".get_Length()

메서드 구문은 .NET 프로퍼티에서만 쓸 수 있다는 점을 유의해요. Update-TypeData cmdlet을 실행해서 추가한 프로퍼티에는 메서드 구문을 쓸 수 없어요.

Types.ps1xml 파일 서명

Types.ps1xml 파일의 사용자를 보호하려면 디지털 서명으로 파일에 서명할 수 있어요. 자세한 내용은 about_Signing을 참고해요.

더 알아보기