PowerShell cmd-let with F#

PS Cmd-let สามารถสร้างได้ 4 แบบ[1] แบบที่เขียนด้วย .NET Language (C#,F#,etc.) เรียกว่า Binary Module ทำได้โดยการ publish .NET class library แล้ว copy ไปไว้ใน directory ของ PowerShell Module Path ($env:PSModulePath)[2]

Build Cmd-let solution

  1. สร้าง .NET project file ด้วย dotnet new classlib -lang F# <module name>
  2. Reference Nuget PowerShellStandard.Library และต้อง mark PackageReference ใน project file ให้เป็น PrivateAssets="all" ด้วย!
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <RootNamespace>ps_hello</RootNamespace>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Library.fs" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="PowerShellStandard.Library" Version="5.1.0" PrivateAssets="all" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Update="FSharp.Core" Version="5.0.1" />
  </ItemGroup>

</Project>
ตัวอย่าง project file
  1. Derive class with Cmdlet และ mark class ด้วย attribute Cmdlet และ OutputType
    • Parameter จะต้องทำเป็น get/set property และ mark ด้วย attribute Parameter
namespace RZ.PowerShell

open System
open System.Management.Automation

[<Cmdlet(VerbsCommunications.Write, "Word")>]
[<OutputType(typeof<string>)>]
type SayAWord() as this =
    inherit Cmdlet()

    [<Parameter(Position=0, Mandatory=true, ValueFromPipeline=true, ValueFromPipelineByPropertyName=true)>]
    [<ValidateNotNullOrEmpty>]
    member val Word = String.Empty with get,set

    override _.ProcessRecord() =
        base.ProcessRecord()

        this.WriteObject $"Hello, {this.Word}"
Sample code
  1. Publish project
dotnet publish -c Release -o <module name>

Copy publish project ไปไว้ใน PS module path

เราสามารถใช้ user module path ซึ่งปกติ PowerShell จะ set ไว้ที่ $Home\Documents\PowerShell\Modules สำหรับ PowerShell .NET Core (หรือ $Home\Documents\WindowsPowerShell\Modules ถ้าเป็น PowerShell for Windows)

เมื่อ copy ไปใน folder ดังกล่าวแล้ว ให้ run คำสั่ง Import-Module <module name> แล้วจะสามารถใช้คำสั่ง Write-Word ได้ โดยครั้งหน้าไม่ต้องสั่งคำสั่งนี้อีก[3]

** สิ่งสำคัญคือ ชื่อ module name ที่ PowerShell คือชื่อของ directory ที่เรา copy ไปวาง และต้องเป็นชื่อเดียวกันกับ dll ในนั้นด้วย เช่น ถ้าเราตั้งชื่อ project เราว่า PsHello เวลา compile ออกมาจะได้ PsHello.dll และเวลาเรา publish ก็ควรใช้ชื่อ PsHello จึงจะทำให้เราสามารถใช้คำสั่ง Import-Module PsHello ได้

More examples

See: https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/examples-of-cmdlet-code?view=powershell-7.1

References


  1. PowerShell Module ↩︎

  2. Install PowerShell Module ↩︎

  3. Module Auto-Loading ↩︎