كيف أقوم بإنشاء نوع مخصص في PowerShell لاستخدامه في البرامج النصية الخاصة بي؟
-
09-06-2019 - |
سؤال
أود أن أكون قادرًا على تحديد نوع مخصص واستخدامه في بعض نصوص 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.
لدى كيرك مونرو في الواقع منشوران رائعان يعرضان تفاصيل العملية بدقة.
الكتاب Windows PowerShell قيد التنفيذ بواسطة مانينغ يحتوي أيضًا على نموذج تعليمات برمجية لإنشاء لغة خاصة بالمجال لإنشاء أنواع مخصصة.الكتاب ممتاز في كل جوانبه، لذا أنصح به بشدة.
إذا كنت تبحث فقط عن طريقة سريعة للقيام بما ورد أعلاه، فيمكنك إنشاء دالة لإنشاء الكائن المخصص مثل
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
}
نصائح أخرى
قبل PowerShell 3
لم يسمح لك نظام النوع القابل للتوسيع من PowerShell في الأصل بإنشاء أنواع ملموسة يمكنك اختبارها مقابل الطريقة التي اتبعتها في المعلمة الخاصة بك.إذا لم تكن بحاجة إلى هذا الاختبار، فلا بأس باستخدام أي من الطرق الأخرى المذكورة أعلاه.
إذا كنت تريد نوعًا فعليًا يمكنك الإرسال إليه أو التحقق من النوع باستخدامه، كما هو الحال في المثال النصي الخاص بك ...هو - هي لا تستطيع يتم ذلك دون كتابته في 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-Struct Contact @{
First=[string];
Last=[string];
Phone=[string];
}
استخدام Add-Type
أو New-Struct
سيسمح لك بالفعل باختبار الفصل في ملفك param([Contact]$contact)
وصنع أخرى جديدة باستخدام $contact = new-object Contact
وما إلى ذلك وهلم جرا...
في بوويرشيل 3
إذا لم تكن بحاجة إلى فصل دراسي "حقيقي" يمكنك الإرسال إليه، فلن يتعين عليك استخدام طريقة إضافة عضو لقد أثبت ستيفن وآخرون ذلك فوق.
منذ PowerShell 2، يمكنك استخدام المعلمة -Property للكائن الجديد:
$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }
وفي PowerShell 3، حصلنا على القدرة على استخدام PSCustomObject
مسرع لإضافة TypeName:
[PSCustomObject]@{
PSTypeName = "Contact"
First = $First
Last = $Last
Phone = $Phone
}
لا تزال تحصل على كائن واحد فقط، لذا يجب عليك إنشاء ملف New-Contact
وظيفة للتأكد من أن كل كائن يخرج بنفس الشكل، ولكن يمكنك الآن بسهولة التحقق من أن المعلمة "هي" واحدة من تلك الأنواع عن طريق تزيين المعلمة بـ PSTypeName
يصف:
function PrintContact
{
param( [PSTypeName("Contact")]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
في بوويرشيل 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
}
}
لدينا أيضًا طريقة جديدة لإنشاء الأشياء دون استخدامها 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"
}
هذه هي طريقة الاختصار:
$myPerson = "" | Select-Object First,Last,Phone
إجابة ستيفن موراوسكي رائعة، لكنني أحب الإجابة الأقصر (أو بالأحرى كائن التحديد الأكثر دقة بدلاً من استخدام بناء جملة العضو الإضافي):
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.NET وتحميل هذا التجميع إلى 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