構建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' } } } }