Bagikan melalui


Cara membuat modul biner Perpustakaan Standar

Saya baru-baru ini memiliki ide untuk modul yang ingin saya terapkan sebagai modul biner. Saya belum membuatnya menggunakan Pustaka Standar PowerShell jadi ini terasa seperti kesempatan yang baik. Saya menggunakan panduan Membuat modul biner lintas platform untuk membuat modul ini tanpa hambatan. Kita akan berjalan dengan proses yang sama dan saya akan menambahkan sedikit komentar tambahan di sepanjang jalan.

Nota

Versi asli artikel ini muncul di blog yang ditulis oleh @KevinMarquette. Tim PowerShell berterima kasih kepada Kevin karena telah membagikan konten ini kepada kami. Silakan lihat blognya di PowerShellExplained.com.

Apa itu Pustaka Standar PowerShell?

Pustaka Standar PowerShell memungkinkan kami membuat modul lintas platform yang berfungsi di PowerShell dan Windows PowerShell 5.1.

Mengapa modul biner?

Ketika Anda menulis modul di C# Anda menyerahkan akses mudah ke cmdlet dan fungsi PowerShell. Tetapi jika Anda membuat modul yang tidak bergantung pada banyak perintah PowerShell lainnya, manfaat performanya bisa signifikan. PowerShell dioptimalkan untuk administrator, bukan komputer. Dengan beralih ke C#, Anda dapat mengurangi overhead yang ditambahkan oleh PowerShell.

Misalnya, kami memiliki proses penting yang melakukan banyak pekerjaan dengan JSON dan hashtable. Kami mengoptimalkan PowerShell sebanyak yang kami bisa tetapi prosesnya masih membutuhkan waktu 12 menit untuk diselesaikan. Modul ini sudah berisi banyak powerShell gaya C#. Ini membuat konversi ke modul biner bersih dan sederhana. Dengan mengonversi ke modul biner, kami mengurangi waktu proses dari lebih dari 12 menit menjadi kurang dari empat menit.

Modul hibrid

Anda dapat mencampur cmdlet biner dengan fungsi tingkat lanjut PowerShell. Semua yang Anda ketahui tentang modul skrip menerapkan cara yang sama. File psm1 kosong disertakan sehingga Anda dapat menambahkan fungsi PowerShell lainnya nanti.

Hampir semua cmdlet yang dikompilasi yang telah saya buat dimulai sebagai fungsi PowerShell terlebih dahulu. Semua modul biner kami benar-benar modul hibrid.

Membangun skrip

Saya membuat skrip build sederhana di sini. Saya umumnya menggunakan skrip besar Invoke-Build sebagai bagian dari pipeline CI/CD saya. Ini melakukan lebih banyak tugas ajaib seperti menjalankan tes Pester, menjalankan PSScriptAnalyzer, mengelola pemversian, dan menerbitkan ke PSGallery. Setelah saya mulai menggunakan skrip build untuk modul saya, saya dapat menemukan banyak hal untuk ditambahkan ke dalamnya.

Merencanakan modul

Rencana untuk modul ini adalah membuat folder src untuk kode C# dan menyusun sisanya seperti yang saya lakukan untuk modul skrip. Ini termasuk menggunakan skrip build untuk mengkompilasi semuanya ke dalam folder Output. Struktur folder terlihat seperti ini:

MyModule
├───src
├───Output
│   └───MyModule
├───MyModule
│   ├───Data
│   ├───Private
│   └───Public
└───Tests

Persiapan

Pertama saya perlu membuat folder dan membuat repositori git. Saya menggunakan $module sebagai placeholder untuk nama modul. Ini akan memudahkan Anda untuk menggunakan kembali contoh-contoh ini jika diperlukan.

$module = 'MyModule'
New-Item -Path $module -Type Directory
Set-Location $module
git init

Kemudian buat folder tingkat akar.

New-Item -Path 'src' -Type Directory
New-Item -Path 'Output' -Type Directory
New-Item -Path 'Tests' -Type Directory
New-Item -Path $module -Type Directory

Penyiapan modul biner

Artikel ini difokuskan pada modul biner sehingga di situlah kita akan mulai. Bagian ini mengambil contoh-contoh dari panduan Membuat modul biner lintas platform. Tinjau panduan tersebut jika Anda memerlukan detail lebih lanjut atau memiliki masalah.

Hal pertama yang ingin kita lakukan adalah memeriksa versi SDK inti dotnet yang telah kita instal. Saya menggunakan 2.1.4, tetapi Anda harus memiliki 2.0.0 atau yang lebih baru sebelum melanjutkan.

PS> dotnet --version
2.1.4

Saya sedang bekerja di luar folder src untuk bagian ini.

Set-Location 'src'

Dengan menggunakan perintah dotnet, buat pustaka kelas baru.

dotnet new classlib --name $module

Ini membuat proyek pustaka dalam subfolder, tetapi saya tidak ingin tingkat tambahan bersarang tersebut. Aku akan memindahkan file-file itu ke tingkat yang lebih tinggi.

Move-Item -Path .\$module\* -Destination .\
Remove-Item $module -Recurse

Atur versi .NET core SDK untuk proyek. Saya memiliki 2.1 SDK jadi saya akan menentukan 2.1.0. Gunakan 2.0.0 jika Anda menggunakan SDK 2.0.

dotnet new globaljson --sdk-version 2.1.0

Tambahkanpaket PowerShell Standard Library NuGet ke proyek. Pastikan Anda menggunakan versi terbaru yang tersedia untuk tingkat kompatibilitas yang Anda butuhkan. Saya akan default ke versi terbaru tetapi saya tidak berpikir modul ini memanfaatkan fitur apa pun yang lebih baru dari PowerShell 3.0.

dotnet add package PowerShellStandard.Library --version 7.0.0-preview.1

Kita harus memiliki folder src yang terlihat seperti ini:

PS> Get-ChildItem
    Directory: \MyModule\src

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        7/14/2018   9:51 PM                obj
-a----        7/14/2018   9:51 PM             86 Class1.cs
-a----        7/14/2018  10:03 PM            259 MyModule.csproj
-a----        7/14/2018  10:05 PM             45 global.json

Sekarang kita siap untuk menambahkan kode kita sendiri ke proyek.

Membangun cmdlet jenis biner

Kita perlu memperbarui src\Class1.cs agar memuat cmdlet starter ini:

using System;
using System.Management.Automation;

namespace MyModule
{
    [Cmdlet( VerbsDiagnostic.Resolve , "MyCmdlet")]
    public class ResolveMyCmdletCommand : PSCmdlet
    {
        [Parameter(Position=0)]
        public Object InputObject { get; set; }

        protected override void EndProcessing()
        {
            this.WriteObject(this.InputObject);
            base.EndProcessing();
        }
    }
}

Ganti nama file agar sesuai dengan nama kelas.

Rename-Item .\Class1.cs .\ResolveMyCmdletCommand.cs

Kemudian kita dapat membangun modul kita.

PS> dotnet build

Microsoft (R) Build Engine version 15.5.180.51428 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 18.19 ms for C:\workspace\MyModule\src\MyModule.csproj.
MyModule -> C:\workspace\MyModule\src\bin\Debug\netstandard2.0\MyModule.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.19

Kita dapat memanggil Import-Module pada dll baru untuk memuat cmdlet baru kita.

PS> Import-Module .\bin\Debug\netstandard2.0\$module.dll
PS> Get-Command -Module $module

CommandType Name                    Version Source
----------- ----                    ------- ------
Cmdlet      Resolve-MyCmdlet        1.0.0.0 MyModule

Jika impor gagal pada sistem Anda, coba perbarui .NET ke 4.7.1 atau yang lebih baru. Panduan Membuat modul biner lintas platform membahas lebih rinci mengenai dukungan dan kompatibilitas .NET untuk versi .NET yang lebih lama.

Manifest modul

Kerennya kita dapat mengimpor dll dan memiliki modul yang berfungsi. Saya ingin terus menggunakannya dan membuat manifes modul. Kita perlu manifes jika kita ingin menerbitkan ke PSGallery nanti.

Dari akar proyek kami, kita dapat menjalankan perintah ini untuk membuat manifes modul yang kita butuhkan.

$manifestSplat = @{
    Path              = ".\$module\$module.psd1"
    Author            = 'Kevin Marquette'
    NestedModules     = @('bin\MyModule.dll')
    RootModule        = "$module.psm1"
    FunctionsToExport = @('Resolve-MyCmdlet')
}
New-ModuleManifest @manifestSplat

Saya juga akan membuat modul akar kosong untuk fungsi PowerShell di masa mendatang.

Set-Content -Value '' -Path ".\$module\$module.psm1"

Ini memungkinkan saya untuk mencampur fungsi PowerShell normal dan cmdlet biner dalam proyek yang sama.

Membangun modul lengkap

Saya mengkompilasi semuanya bersama-sama ke dalam folder output. Kita perlu membuat skrip build untuk melakukannya. Saya biasanya akan menambahkan ini ke skrip Invoke-Build, tetapi kita dapat membuatnya sederhana untuk contoh ini. Tambahkan ini ke build.ps1 di akar proyek.

$module = 'MyModule'
Push-Location $PSScriptRoot

dotnet build $PSScriptRoot\src -o $PSScriptRoot\output\$module\bin
Copy-Item "$PSScriptRoot\$module\*" "$PSScriptRoot\output\$module" -Recurse -Force

Import-Module "$PSScriptRoot\Output\$module\$module.psd1"
Invoke-Pester "$PSScriptRoot\Tests"

Perintah ini membangun DLL kami dan menempatkannya ke folder output\$module\bin kami. Kemudian menyalin file-file modul lainnya ke tempatnya.

Output
└───MyModule
    ├───MyModule.psd1
    ├───MyModule.psm1
    └───bin
        ├───MyModule.deps.json
        ├───MyModule.dll
        └───MyModule.pdb

Pada titik ini, kita dapat mengimpor modul kita dengan file psd1.

Import-Module ".\Output\$module\$module.psd1"

Dari sini, kita dapat menjatuhkan folder .\Output\$module ke direktori $Env:PSModulePath kita dan memuat otomatis perintah kita setiap kali kita membutuhkannya.

Pembaruan: dotnet new PSModule

Saya belajar bahwa alat dotnet memiliki templat PSModule.

Semua langkah yang saya uraikan di atas masih valid, tetapi templat ini memotong banyak langkah tersebut. Ini merupakan templat yang cukup baru dan sedang dalam proses pemolesan. Harapkan untuk terus semakin membaik dari sini.

Ini adalah cara Anda menginstal dan menggunakan templat PSModule.

dotnet new -i Microsoft.PowerShell.Standard.Module.Template
dotnet new psmodule
dotnet build
Import-Module "bin\Debug\netstandard2.0\$module.dll"
Get-Module $module

Templat yang minimal layak ini mengurus penambahan .NET SDK, PowerShell Standard Library, dan membuat kelas contoh dalam proyek. Anda dapat membangunnya dan menjalankannya segera.

Detail penting

Sebelum kami mengakhiri artikel ini, berikut adalah beberapa detail lain yang layak disebutkan.

Membongkar DLL

Setelah modul biner dimuat, Anda tidak dapat benar-benar membongkarnya. File DLL dikunci hingga Anda membongkarnya. Ini bisa mengganggu saat pengembangan karena setiap kali Anda membuat perubahan dan ingin membangunnya, file sering dikunci. Satu-satunya cara yang dapat diandalkan untuk mengatasinya adalah dengan menutup sesi PowerShell yang memuat DLL.

Perintah muat ulang jendela VS Code

Saya melakukan sebagian besar pekerjaan dev PowerShell saya di VS Code. Ketika saya mengerjakan modul biner (atau modul dengan kelas), saya terbiasa memuat ulang Visual Studio Code setiap kali saya membangun. Ctrl+Shift+P memunculkan jendela perintah dan Reload Window selalu berada di bagian atas daftar saya.

Sesi PowerShell berlapis

Salah satu pilihan lainnya adalah memiliki cakupan uji Pester yang baik. Kemudian Anda dapat menyesuaikan skrip build.ps1 untuk memulai sesi PowerShell baru, melakukan build, menjalankan pengujian, dan menutup sesi.

Memperbarui modul yang terinstal

Penguncian ini dapat mengganggu saat mencoba memperbarui modul yang diinstal secara lokal. Jika ada sesi yang memilikinya, Anda harus mencarinya dan menutupnya. Ini tidak menjadi masalah besar saat menginstal dari PSGallery karena versi modul menempatkan yang baru di folder yang berbeda.

Anda dapat menyiapkan PSGallery lokal dan menerbitkannya ke dalam PSGallery tersebut sebagai bagian dari proses build Anda. Kemudian lakukan penginstalan lokal Anda dari PSGallery tersebut. Ini terdengar seperti banyak pekerjaan, tetapi ini bisa sesederhana memulai docker kontainer. Saya membahas cara melakukan hal tersebut di artikel saya di Menggunakan server NuGet untuk PSRepository.

Pemikiran akhir

Saya tidak menyentuh sintaks C# untuk membuat cmdlet, tetapi ada banyak dokumentasi di Windows PowerShell SDK. Ini jelas sesuatu yang layak bereksperimen dengan sebagai batu loncatan ke C#yang lebih serius.