about_Object_Creation — 개체 만들기
about_Object_Creation — 개체 만들기
PowerShell에서 개체(object)를 직접 만드는 방법을 소개해 드릴게요. 커맨드렛이 반환해 주는 개체만 쓰다 보면, 내가 원하는 형태의 개체를 직접 만들고 싶을 때가 있잖아요? 그럴 때 쓸 수 있는 방법들을 차근차근 정리한 문서예요.
본문
짧은 설명 (Short description)
이 문서는 PowerShell에서 개체를 만드는 방법을 설명해요.
자세한 설명 (Long description)
PowerShell에서는 개체를 스스로 만들 수도 있고, 명령이나 스크립트 안에서 그렇게 만든 개체를 바로 사용할 수도 있어요.
개체를 만드는 방법은 여럿 있기 때문에 아래 목록이 전부는 아니에요. 대표적인 방법부터 하나씩 살펴볼게요.
- New-Object: .NET Framework 개체나 COM 개체의 인스턴스를 만들어요.
- Import-Csv / ConvertFrom-Csv: 콤마로 구분된 값(CSV)으로 정의된 항목들로 사용자 지정 개체(PSCustomObject)를 만들어요.
- ConvertFrom-Json: JSON으로 정의된 사용자 지정 개체를 만들어요.
- ConvertFrom-StringData: 키-값 쌍으로 정의된 사용자 지정 개체를 만들어요.
- Add-Type: 현재 세션에서 클래스를 정의하고, 그 클래스를
New-Object로 인스턴스화할 수 있게 해줘요. - New-Module: AsCustomObject 매개 변수로 스크립트 블록을 이용해 정의한 사용자 지정 개체를 만들어요.
- Add-Member: 이미 있는 개체에 속성을 추가해요.
Add-Member를 쓰면[System.Int32]같은 단순한 형식으로도 사용자 지정 개체를 만들 수 있어요. - Select-Object: 개체의 속성을 선택해요. 이미 만들어진 개체에 사용자 지정 속성과 계산된 속성(calculated property)을 만들 때 쓸 수 있어요.
이 문서에서는 그중에서도 다음 두 가지 방법을 더 자세히 다룰 거예요.
- 형식(타입)의 생성자를 정적
new()메서드로 호출하기 - 속성 이름과 속성 값의 해시 테이블을 형변환(typecast)하기
정적 new() 메서드 (Static new() method)
모든 .NET 형식에는 인스턴스를 더 쉽게 만들 수 있는 new() 메서드가 있어요. 특정 형식에 제공되는 생성자 목록도 한눈에 볼 수 있고요.
형식의 생성자를 확인하려면 형식 이름 뒤에 new라는 메서드 이름을 붙이고 <ENTER>를 누르면 돼요.
[System.Uri]::new
OverloadDefinitions
-------------------
uri new(string uriString)
uri new(string uriString, bool dontEscape)
uri new(uri baseUri, string relativeUri, bool dontEscape)
uri new(string uriString, System.UriKind uriKind)
uri new(uri baseUri, string relativeUri)
uri new(uri baseUri, uri relativeUri)
이제 적절한 생성자를 지정해서 System.Uri 개체를 만들 수 있어요.
[System.Uri]::new("https://www.bing.com")
AbsolutePath : /
AbsoluteUri : https://www.bing.com/
LocalPath : /
Authority : www.bing.com
...
지금 로드되어 있는 .NET 형식이 어떤 것들인지 확인해서 인스턴스화하고 싶다면, 다음 샘플을 써볼 수 있어요.
[AppDomain]::CurrentDomain.GetAssemblies() |
ForEach-Object {
$_.GetExportedTypes() |
ForEach-Object { $_.FullName }
}
한 가지 기억해 둘 점이 있어요. new() 메서드로 만든 개체는 같은 형식이라도 PowerShell 커맨드렛이 만든 개체와 속성이 다를 수 있어요. PowerShell 커맨드렛·공급자·확장 형식 시스템(Extended Type System)이 인스턴스에 추가 속성을 붙여 주거든요.
예를 들어 파일 시스템 공급자는 Get-Item이 반환하는 DirectoryInfo 개체에 NoteProperty 값 여섯 개를 추가해요.
$PSDirInfo = Get-Item /
$PSDirInfo | Get-Member | Group-Object MemberType | Select-Object Count, Name
Count Name
----- ----
4 CodeProperty
13 Property
6 NoteProperty
1 ScriptProperty
18 Method
반면 DirectoryInfo 개체를 직접 만들면 그 여섯 개의 NoteProperty 값이 없어요.
$NewDirInfo = [System.IO.DirectoryInfo]::new('/')
$NewDirInfo | Get-Member | Group-Object MemberType | Select-Object Count, Name
Count Name
----- ----
4 CodeProperty
13 Property
1 ScriptProperty
18 Method
확장 형식 시스템에 대해 더 알고 싶다면 about_Types.ps1xml 문서를 참고하세요. 이 기능은 PowerShell 5.0에서 추가되었어요.
해시 테이블로 개체 만들기 (Create objects from hash tables)
속성 이름과 속성 값의 해시 테이블로도 개체를 만들 수 있어요. 문법은 다음과 같아요.
[<class-name>]@{
<property-name>=<property-value>
<property-name>=<property-value>
}
이 방법은 매개 변수 없는 생성자(parameterless constructor)를 가진 클래스에서만 동작해요. 개체의 속성도 public이고 값을 설정할 수 있어야 하고요.
이 기능은 PowerShell 3.0에서 추가되었어요.
해시 테이블로 사용자 지정 개체 만들기 (Create custom objects from hash tables)
사용자 지정 개체(custom object)는 정말 유용한데, 해시 테이블 방식으로 만들기 쉽답니다. PSCustomObject 클래스가 바로 이 목적을 위해 설계된 거예요.
사용자 지정 개체는 함수나 스크립트에서 정돈된 출력을 돌려줄 때 아주 좋아요. 다시 포맷하거나 다른 명령에 파이프하기 어려운, 미리 포맷된 출력을 돌려주는 것보다 훨씬 유용하죠.
Test-Object function은 변수 몇 개에 값을 넣고 그 값으로 사용자 지정 개체를 만드는 함수예요. 이 개체가 쓰이는 모습은 Update-Help 커맨드렛 도움말의 예제 섹션에서도 볼 수 있어요.
function Test-Object {
$ModuleName = "PSScheduledJob"
$HelpCulture = "en-US"
$HelpVersion = "3.1.0.0"
[pscustomobject]@{
"ModuleName"=$ModuleName
"UICulture"=$HelpCulture
"Version"=$HelpVersion
}
$ModuleName = "PSWorkflow"
$HelpCulture = "en-US"
$HelpVersion = "3.0.0.0"
[pscustomobject]@{
"ModuleName"=$ModuleName
"UICulture"=$HelpCulture
"Version"=$HelpVersion
}
}
Test-Object
이 함수의 출력은 기본적으로 표로 포맷된 사용자 지정 개체의 모음이에요.
ModuleName UICulture Version
--------- --------- -------
PSScheduledJob en-US 3.1.0.0
PSWorkflow en-US 3.0.0.0
사용자는 표준 개체를 다루듯이 사용자 지정 개체의 속성을 관리할 수 있어요.
(Test-Object).ModuleName
PSScheduledJob
PSWorkflow
PSObject 형식 개체는 멤버가 추가된 순서대로 멤버 목록을 유지해요. Hashtable 개체는 키-값 쌍의 순서를 보장하지 않지만, 리터럴 해시 테이블을 [pscustomobject]로 형변환하면 순서가 유지돼요.
해시 테이블은 리터럴이어야 해요. 해시 테이블을 괄호로 감싸거나, 해시 테이블이 담긴 변수를 형변환하면 순서가 보존된다는 보장이 없어요.
$hash = @{
Name = "Server30"
System = "Server Core"
PSVersion = "4.0"
}
$Asset = [pscustomobject]$hash
$Asset
System Name PSVersion
------ ---- ---------
Server Core Server30 4.0
해시 테이블로 일반 개체 만들기 (Create non-custom objects from hash tables)
해시 테이블로 사용자 지정 개체가 아닌 클래스의 개체도 만들 수 있어요. 이때는 네임스페이스까지 포함한 형식 이름이 필요해요. 다만 맨 앞의 System 네임스페이스 부분은 생략할 수 있어요.
예를 들어 다음 명령은 세션 옵션 개체를 만들어요.
[System.Management.Automation.Remoting.PSSessionOption]@{
IdleTimeout=43200000
SkipCnCheck=$true
}
해시 테이블 기능의 요구 사항, 특히 매개 변수 없는 생성자 요구 사항 때문에 쓸 수 없는 클래스가 꽤 많아요. 그래도 대부분의 PowerShell 옵션 클래스는 이 기능과 함께 동작하도록 설계되어 있고, ProcessStartInfo 클래스처럼 아주 유용한 클래스도 있어요.
[System.Diagnostics.ProcessStartInfo]@{
CreateNoWindow="$true"
Verb="run as"
}
Arguments :
ArgumentList : {}
CreateNoWindow : True
EnvironmentVariables : {OneDriveConsumer, PROCESSOR_ARCHITECTURE,
CommonProgramFiles(x86), APPDATA...}
Environment : {[OneDriveConsumer, C:\Users\user1\OneDrive],
[PROCESSOR_ARCHITECTURE, AMD64],
[CommonProgramFiles(x86),
C:\Program Files (x86)\Common Files],
[APPDATA, C:\Users\user1\AppData\Roaming]...}
RedirectStandardInput : False
RedirectStandardOutput : False
RedirectStandardError : False
...
해시 테이블 기능은 매개 변수 값을 지정할 때도 쓸 수 있어요. 예를 들어 New-PSSession 커맨드렛의 SessionOption 매개 변수 값으로 해시 테이블을 넘길 수 있답니다.
New-PSSession -ComputerName Server01 -SessionOption @{
IdleTimeout=43200000
SkipCnCheck=$true
}
Register-ScheduledJob -Name Test -FilePath .\Get-Inventory.ps1 -Trigger @{
Frequency="Daily"
At="15:00"
}
제네릭 개체 (Generic objects)
PowerShell에서 제네릭(Generic) 개체도 만들 수 있어요. 제네릭은 저장하거나 사용하는 형식 중 일부를 자리 표시자(형식 매개 변수)로 둔 클래스·구조체·인터페이스·메서드를 말해요.
다음 예제는 Dictionary 개체를 만들어요.
$dict = New-Object 'System.Collections.Generic.Dictionary[String,Int]'
$dict.Add("One", 1)
$dict
Key Value
--- -----
One 1
제네릭에 대해 더 알고 싶다면 .NET의 Generics in .NET 문서를 참고하세요.