构建DSC 资源的"另类写法"
今天我们要说的另类写法并不是什么新鲜东西
而且 这篇博客也迟到了一年甚至更多,
虽然我个人采用这个写法的资源很早之前就在 Gallery发布,并且持续更新,
(有关我个人发布资源 请在 Gallery 搜索 strike 有任何好的建议或者资源bug或者其他问题也请直接联系我)
却总没想起认真的总结这个写法
这个写法并不是我在2014年发布的那个写法 当然新的PS V5 5.1依然支持那个写法
但是更多的资源 都采用这个新的写法,由于我个人并没有找到这个写法的官方的确切的说明 我姑且称之为 "嵌套类",事实上 就是嵌套 一个CIM类的实例中的属性是另外一个类的实例
说着别扭 但是很好理解
首先我们看看以前的MOF中的定义
下图是以前的类的定义 ,
如果你需要多个属性的话你还可以继续添加 当然 你可以硬编码这些 ,
你也可以用工具完成 这里不在多说
废话不多说
下面来看这个 另类的写法
这是MOF 中对资源的定义 看起来就是多了一个类而已
当我们用 (Get-DscResource t_Demo).Properties 查看这资源时候你会发现其中的一个属性不在是你熟悉的那些基本的属性 如下所示
我们发现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版本命令做演示
第一 我们要添加这个属性对应的参数 如下所示
请一定记住 处理这类属性 一定是 ciminstance
首先我们要找出这个实例中 包含用户修改的属性 因为demo中没有定义可选
的属性 所以本例中可以不进行判断 但是实际中可能出现用户未定义的属性这时候就需要判断下了
判断下是否经过用户修改
当然这个办法稍显复杂
我们还是继续说这个判断过后的做法 稍后会有一个更简单的办法来解决他
$haschange.where({$_.Name -eq 'Child_Ensure'}).value 这样我们就获取了Child_Ensure 的值
你还可以如法炮制获取其他的值
下图给出类 $haschange 的 属性结构
其实你完全可以把他当成哈希表来理解
好了 关于筛选取值的笨方法我们说过了
我们来说说简单的办法
$Child.'Child_Ensur' 我们完全可以用这个方法快速获取你要的属性值
好了 test 和set 部分如法炮制 千万记得 如果不是必须属性 在使用前记得判断是否为空 否则抛出异常就不好玩了
代码的强壮型不单靠错误处理 逻辑的严谨性也很重要
现在 我们来说说 get
在这种写法下 我们依然可以采用老套路 get 部分返回一个哈希表
这是一个经典的写法 依然十分有效
但是我想介绍另外一种写法
首先 我们依然还是要返回一个哈希表 用于最外层
也就是返回 t_Demo 这个类的属性 除了嵌套的类的属性 本例中就是除了Child这个属性 当然 Ensure可以不返回 因为没有意义如下所示
此后我们先运行配置 然后get一下 如下所示
然后我们依然 可以新建哈希表用户Child 属性 并且把这个哈希表作为$re的一个属性一起返回
然后我们get 但是结果不尽人意 如下所示 当我们查看Child 时候发现完全不是我们要的结果
所以 第二种方案 采用New-CimInstance 如下图
道理十分简单 由于我们的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 效果如下
至此 这个另类的写法我们已经完成
下面附上 配置
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' } } } }