كيف أقوم بإنشاء نوع مخصص في PowerShell لاستخدامه في البرامج النصية الخاصة بي؟

StackOverflow https://stackoverflow.com/questions/59819

  •  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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top