构建DSC 资源的"另类写法"


今天我们要说的另类写法并不是什么新鲜东西

而且 这篇博客也迟到了一年甚至更多,

虽然我个人采用这个写法的资源很早之前就在 Gallery发布,并且持续更新,

(有关我个人发布资源 请在 Gallery 搜索 strike 有任何好的建议或者资源bug或者其他问题也请直接联系我)

却总没想起认真的总结这个写法


这个写法并不是我在2014年发布的那个写法 当然新的PS V5 5.1依然支持那个写法

但是更多的资源 都采用这个新的写法,由于我个人并没有找到这个写法的官方的确切的说明 我姑且称之为 "嵌套类",事实上 就是嵌套 一个CIM类的实例中的属性是另外一个类的实例

说着别扭 但是很好理解

首先我们看看以前的MOF中的定义

下图是以前的类的定义 ,

如果你需要多个属性的话你还可以继续添加  当然 你可以硬编码这些 ,

你也可以用工具完成 这里不在多说


构建DSC 资源的”另类写法”_第1张图片


废话不多说

下面来看这个 另类的写法

构建DSC 资源的”另类写法”_第2张图片

这是MOF 中对资源的定义 看起来就是多了一个类而已

当我们用 (Get-DscResource t_Demo).Properties 查看这资源时候你会发现其中的一个属性不在是你熟悉的那些基本的属性 如下所示

构建DSC 资源的”另类写法”_第3张图片


我们发现Child 属性是一个叫 t_Demo_Child 的属性

这个就是我们说的 CIM类的实例的属性是其他cim类的实例

这时候你可以看见 Child 属性只接受一个值  如果我要多个值呢

那么我们去更改mof中的

[Write,EmbeddedInstance("t_Demo_Child")] String Child[这部分为


[Write,EmbeddedInstance("t_Demo_Child")] String Child[];

就是在Child 之后加上 [] 来标记这个属性有多个值

那么问题来了 这个t_Demo_Child类定义和以前一样么 答案是完全一样 以前怎么定义还怎么定义 Key 该要还是得要不得省略


好了 我们说完架构的问题 然后我们要来说说怎么在资源里处理这个属性

我们首先用Test-TargetResource 的PS版本命令做演示

第一 我们要添加这个属性对应的参数 如下所示

构建DSC 资源的”另类写法”_第4张图片

请一定记住 处理这类属性 一定是 ciminstance

首先我们要找出这个实例中  包含用户修改的属性 因为demo中没有定义可选

的属性 所以本例中可以不进行判断 但是实际中可能出现用户未定义的属性这时候就需要判断下了

判断下是否经过用户修改

当然这个办法稍显复杂

我们还是继续说这个判断过后的做法 稍后会有一个更简单的办法来解决他

$haschange.where({$_.Name -eq 'Child_Ensure'}).value 这样我们就获取了Child_Ensure 的值

你还可以如法炮制获取其他的值


下图给出类 $haschange 的 属性结构

构建DSC 资源的”另类写法”_第5张图片

其实你完全可以把他当成哈希表来理解

好了 关于筛选取值的笨方法我们说过了

我们来说说简单的办法


$Child.'Child_Ensur' 我们完全可以用这个方法快速获取你要的属性值

好了 test 和set 部分如法炮制 千万记得  如果不是必须属性 在使用前记得判断是否为空 否则抛出异常就不好玩了

代码的强壮型不单靠错误处理 逻辑的严谨性也很重要

现在  我们来说说 get

在这种写法下 我们依然可以采用老套路 get 部分返回一个哈希表

这是一个经典的写法 依然十分有效

但是我想介绍另外一种写法

首先 我们依然还是要返回一个哈希表 用于最外层

也就是返回 t_Demo 这个类的属性 除了嵌套的类的属性 本例中就是除了Child这个属性 当然 Ensure可以不返回 因为没有意义如下所示

此后我们先运行配置 然后get一下 如下所示


构建DSC 资源的”另类写法”_第6张图片

然后我们依然 可以新建哈希表用户Child 属性 并且把这个哈希表作为$re的一个属性一起返回

构建DSC 资源的”另类写法”_第7张图片

然后我们get  但是结果不尽人意 如下所示 当我们查看Child 时候发现完全不是我们要的结果

构建DSC 资源的”另类写法”_第8张图片


所以  第二种方案  采用New-CimInstance 如下图

构建DSC 资源的”另类写法”_第9张图片

道理十分简单 由于我们的MOF中定义了child 属性是多个值 那么 我们理应返回一个数组

这就是$re_child 要提前声明数组的原因

(New-CimInstance -Namespace "root/Microsoft/Windows/DesiredStateConfiguration" `

-ClassName t_Demo_Child -Property @{Child_Name = "T_name"} -ClientOnly)


至于这段代码 则是new 一个新的实例 由于我们经过 test set 传入的是 CimInstance 那么我们一样返回 一个CimInstance  而-Property @{Child_Name = "T_name"} 这部分则是 该类中定义的key 作为初始化该CimInstance必须的属性 所以我们必须写Child_Name

由于本例中并没有定义任何 dsc资源属性为Required 否则 标记为 Required 的属性一样需要返回,

此后我们再次get 效果如下

构建DSC 资源的”另类写法”_第10张图片

至此 这个另类的写法我们已经完成

下面附上 配置

Configuration T
{
Import-DscResource -ModuleName t_demo
Node localhost
{
t_Demo d
{
Ensure = 'Present'
Name = "T_name"
Child =  t_Demo_Child
{
Child_Name = "Child"
Child_Ensure = 'Present'
}
}
}
}