使用F#编写PowerShell模块

▲F#和PowerShell模块
作为可能是人类世界最强大的Shell,PowerShell最大的特点是能够直接在命令间传递.NET对象,而支持这种能力的命令被称作cmdlet。自己编写PowerShell模块,就能给PowerShell扩展更多的cmdlet。
为何要写本文
通常来讲,PowerShell模块有两种:脚本模块和二进制模块。顾名思义,脚本模块基本上就是一组PowerShell脚本,而二进制模块,实质上是一个.NET类库。微软对于二进制模块的官方文档中,只提供了C#的范例;但鉴于F#和C#几乎是同等强大的,我在想,使用F#也能编写出可以工作的PowerShell模块。经过一小段时间的研究和整理,我决定将可行的方案分享给之家的朋友们。
任务目标
使用F#编写一个PowerShell模块,提供一个名为Get-Sum的cmdlet,完成对一个整数数组求和的功能。至于为什么选择“求和”,是因为递归求和函数通常是F#这类函数式编程语言第一课必学的例子,这种递归的思想也算是函数式语言的特色之一。
正式开始
1、建立项目
开始上手操作之前,确保你安装了.NET Core SDK,并经过适当配置,可以在任意位置使用“dotnet”命令。
打开PowerShell,在你通常保存项目代码的地方创建一个目录,作为整个项目的根。在这个目录下,使用dotnet new命令创建一个F#的类库项目和一个解决方案文件,并将项目添加进解决方案中。

如此,我们便建立了解决方案fsharp-module和F#类库工程testmodule。
2、添加用于编写/生成PowerShell模块的组装件
使用dotnet add package为工程testmodule添加名为PowerShellStandard.Library的组装件,这个组装件由微软提供,并将为工程提供System.Management.Automation名称空间和必要的类型。

如此,我们建立的F#类库已经可以用于编写PowerShell模块了。
3、编写代码
使用自己喜爱的代码编辑器修改testmodule\Library.fs,代码内容如下,我将在代码的下方解释一些要点。

注0:代码中的向右的箭头是->两个字符,向右的三角形是|>两个字符。这种连体字由著名字体FiraCode提供。灰色注释是VSCode相关插件自动生成的;
注1:此名称空间包含了编写PowerShell模块必须的类型;
注2:任何作cmdlet存在的类型必须加上Cmdlet属性(Attribute)。任何cmdlet的名称都由两部分组成:动词(Verb)和名词(Noun),最终形成“Verb-Noun”形式的名称。在这里,我们定义VerbName为Get,NounName为Sum,即得到最终的cmdlet名称Get-Sum。需要注意的是,Verb的选择需要遵守微软的规范。如果你执意要使用奇怪的Verb,构建代码时和导入模块时就会产生警告。任何cmdlet类都必须继承于PSCmdlet类;
注3:一个很经典的递归求和函数。我知道这功能可以干脆使用Array.sum方法来实现,但作为函数式语言的标志性操作之一,展示出来可以展现函数式语言和命令式语言的某种区别;
注4:Parameter属性(Attribute)标记的InputArray属性(Property)用来接收传递过来的参数对象。可以在Parameter属性(Attribute)中指定关于这个参数的更多细节,比如参数的位置、能否从管道中接收等等;
注5:重写基类(部分Java程序员会称作父类,其实都一样)的EndProcessing方法(命令处理完成后)执行求和操作并输出结果。类似的可供重写的虚函数还有BeginProcessing、ProcessRecord和StopProcessing,它们分别表示命令开始执行之前、命令执行的主体和命令中断时的过程。原则上求和应放在ProcessRecord中执行,但由于我们命令的功能很简单,干脆直接在EndProcessing里直接输出求和的结果。
4、编译模块并测试
使用dotnet publish命令发布这个类库。之所以使用publish而不是build,是因为F#程序还依赖另一个组装件:FSharp.Core来运行,而build默认不包含该组装件,该模块将不能被导入PowerShell中。
发布完成后,使用Import-Module命令导入我们编写的模块,并测试功能。

其实,别看这个cmdlet输出的是看似文本的5050,其实它输出的是一个System.Int32,你可以使用GetType()函数来证明这一点:

也正是这种在管道中传递对象的能力,使PowerShell比别的一些Shell拥有更高的潜力。
使用F#编写PowerShell模块的更多相关文章
- 【转】PowerShell入门(十一):编写脚本模块
转至:http://www.cnblogs.com/ceachy/archive/2013/03/08/PowerShell_Script_Module.html 现在通过编写模块就可以在PowerS ...
- 【转】PowerShell入门(十二):编写PowerShell管理单元和二进制模块
转至:http://www.cnblogs.com/ceachy/archive/2013/03/13/PowerShell_SnapIn.html PowerShell一开始就提出利用管理单元来实现 ...
- 使用 Azure PowerShell 模块创建和管理 Windows VM
Azure 虚拟机提供完全可配置的灵活计算环境. 本教程介绍 Azure 虚拟机的基本部署项目,例如选择 VM 大小.选择 VM 映像和部署 VM. 你将学习如何执行以下操作: 创建并连接到 VM 选 ...
- [转]使用 C 编写 Lua 模块
Lua 作为一种小巧的语言,一般都是嵌入到 C/C++ 中作为扩展语言,但是也可以作为独立的脚本语言使用,并且可以使用 C/C++ 编写扩展模块.在参考资料 [1] 中有怎样用 C/C++ 编写模块的 ...
- 用Perl编写Apache模块续二 - SVN动态鉴权实现SVNAuth 禅道版
代码地址:https://code.csdn.net/x3dcn/svnauth 以禅道项目管理系统的数据库结构为标准,实现了可用的svn authz验证功能. 以用户名.密码.项目的acl开发程度o ...
- 用Perl编写Apache模块
前言 Apache被许多大流量网站所嫌弃,但很多企业级的场景则更为适用. Apache httpd 从 2.0 之后,已经不仅仅局限于一个 http 的服务器,更是一个完善而强大.灵活而健壮且容易扩展 ...
- 为Lua5.3编写C模块简单示例
为Lua5.3编写C模块简单示例 一.编译安装Lua5.3 MSVC 命令行安装脚本: @echo off md bin md lib md include cd src cl /c /nologo ...
- 支持国内版Office 365的PowerShell模块现已发布
作者:陈希章 发表于2017年5月12日 上一篇文章我详细介绍了如何在PowerShell中访问到Office 365的Graph API,在文章结尾处我留了一个问题,希望有朋友可以根据那个思路,尝试 ...
- 新版Azure Automation Account 浅析(二) --- 更新Powershell模块和创建Runbook
前篇我们讲了怎样创建一个自动化账户以及创建时候"Run As Account"选项背后的奥秘.这一篇针对在Azure自动化账户中使用Powershell Runbook的用户讲一下 ...
随机推荐
- 「AGC029C」Lexicographic constraints
「AGC029C」Lexicographic constraints 传送门 好像这个题非常 easy. 首先这个答案显然具有可二分性,所以问题转化为如何判定给定的 \(k\) 是否可行. 如果 \( ...
- C++11标准特性的一些理解
(1)auto 和 decltype 关键字 在C++11之前,auto关键字用来指定存储期(C++98中指的是自动生命周期).在新标准中,它的功能变为类型推断.C++11引入auto关键词与之前C语 ...
- Pandas高级教程之:自定义选项
目录 简介 常用选项 get/set 选项 经常使用的选项 最大展示行数 超出数据展示 最大列的宽度 显示精度 零转换的门槛 列头的对齐方向 简介 pandas有一个option系统可以控制panda ...
- linux系统安装+windows系统安装
linux 1.格式化U盘 打开管理员命令提示符 diskpart list disk select disk 2 clean create partition primary format fs=f ...
- P1447能量采集
P1447能量采集 定义:(i,j)表示处于(i,j)的植物的贡献 我们发现,点(i,j)与(0,0)的连线所过整点的数目为\(\gcd(i,j)\) 发现要是想记录每个点的答案并不好算.那么怎么好算 ...
- 【递归+树】FBI树
题目描述 我们可以把由"0"和"1"组成的字符串分为三类:全"0"串称为BB串,全"1"串称为I串,既含"0& ...
- U盘启动盘安装win10出现cdboot:couldn't find ntldr
格式化硬盘后出现:cdboot:couldn't find ntldr 解决方法: 分区时格式选择:硬盘格式导致的,一般出现在win10装win7时,需要用pe系统里的分区工具重新给为硬盘分区,并将 ...
- a = input(a, yymmdd10.)引发的问题
在数据清理过程中,经常会遇到以文本储存的日期型数据,这种数据不能直接进行分析,需要先将其转化为以数值存储的格式. 首先准备数据集: data data1; input a :$10. b :$10. ...
- Mac卸载软件真不省心啊
最近看看磁盘觉得有点小, 就整理了一下, 经过一番折腾, 发现MacOS卸载软件可真是不省心啊. 从应用里移到垃圾桶仅仅是第一步, 当然对于不读写任何文件的应用也许就可以了. 咱们看看赶紧卸载一个软件 ...
- 3D网页小实验-基于多线程和精灵动画实现RTS式单位行为
一.实验目的: 1.在上一篇的"RTS式单位控制"的基础上添加逻辑线程,为每个单位实现ai计算: 2.用精灵动画为单位的行为显示对应的动作效果. 二.运行效果: 1.场景中的单位分 ...