[15]Windows PowerShell DSC学习系列---基于.NET DLL(C#) 定制DSC资源?

原创 2017年02月10日 17:46:20

我们知道我们在定制实现DSC的时候,其实现方式,既可以通过写PowerShell脚本实现,也可以通过写C#实现(DLL库),还可以通过类似于写Class风格的PowerShell脚本实现。本文笔者主要给大家介绍一下,如果通过C#代码来写实现。

@第1步:通过xDscResourceDesigner生成模板框架

首先通过x-DscResourceDesigner 模块中提供的cmdlet来自动生成MOF文件和相应的模板目录。

New-xDscResource -ModuleName xCustomDemo -Name MSFT_XDemoFile -Path 'C:\Program Files\WindowsPowerShell\Modules' -FriendlyName 'MSFT_XDemoFile' -ClassVersion '0.9.0.0' -Property @(
  New-xDscResourceProperty -Name 'Path' -Type String -Attribute Key  -Description 'path'
  New-xDscResourceProperty -Name 'Ensure' -Type String -Attribute Write   -ValidateSet 'Present','Absent' -Description 'Should the file be present' 
  New-xDscResourceProperty -Name 'Content' -Type String -Attribute Write  -Description 'Contentof file.'
) -Force


生成后的MOF Schema(C:\Program Files\WindowsPowerShell\Modules\xSPAV\DSCResources\MSFT_XDemoFile\MSFT_XDemoFile.

schema.mof)的文件如下:

[ClassVersion("0.9.0.0"), FriendlyName("MSFT_XDemoFile")]
class MSFT_XDemoFile : OMI_BaseResource
{
    [Key, Description("path")] String Path;
    [Write, Description("Should the file be present"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure;
    [Write, Description("Contentof file.")] String Content;
};



@第2步:删除其生成的MSFT_XDemoFile.psm1

在下面的目录下:C:\Program Files\WindowsPowerShell\Modules\xSPAV\DSCResources\MSFT_XDemoFile\

找到MSFT_XDemoFile.psm1文件并删除。


@第3步:写C#的实现代码

打开Visual Studio,然后新建一个Class Library的项目,其目录结构如下:



注意,我们需要引入System.Automation.Management.dll 这个DLL到项目中来。那么如何找到这个包呢?
在PowerShell的界面中执行下面的命令:Copy([PSObject].Assembly.Location) c:\Users\Admin\Desktop



就能把System.Automation.Management.dll 复制到桌面上,然后在Visutal Stuido导入进来即可。
打开MSFT_XDemoFile.cs文件,输入下面的内容。
namespace cSharpDSCResourceExample
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Management.Automation;  // Windows PowerShell assembly.

    #region Get-TargetResource

    [OutputType(typeof(System.Collections.Hashtable))]
    [Cmdlet(VerbsCommon.Get, "TargetResource")]
    public class GetTargetResource : PSCmdlet
    {
        [Parameter(Mandatory = true)]
        public string Path { get; set; }

        /// <summary>
        /// Implement the logic to return the current state of the resource as a hashtable with keys being the resource properties 
        /// and the values are the corresponding current value on the machine.
        /// </summary>
        protected override void ProcessRecord()
        {
            var currentResourceState = new Dictionary<string, string>();
            if (File.Exists(Path))
            {
                currentResourceState.Add("Ensure", "Present");

                // read current content 
                string CurrentContent = "";
                using (var reader = new StreamReader(Path))
                {
                    CurrentContent = reader.ReadToEnd();
                }
                currentResourceState.Add("Content", CurrentContent);
            }
            else
            {
                currentResourceState.Add("Ensure", "Absent");
                currentResourceState.Add("Content", "");
            }
            // write the hashtable in the PS console.
            WriteObject(currentResourceState);
        }
    }

    # endregion

    #region Set-TargetResource
    [OutputType(typeof(void))]
    [Cmdlet(VerbsCommon.Set, "TargetResource")]
    public class SetTargetResource : PSCmdlet
    {
        [Parameter(Mandatory = true)]
        public string Path { get; set; }

        [Parameter(Mandatory = false)]

        [ValidateSet("Present", "Absent", IgnoreCase = true)]
        public string Ensure
        {
            get
            {
                // set the default to present.
                return (this._ensure ?? "Present");
            }
            set
            {
                this._ensure = value;
            }
        }

        [Parameter(Mandatory = false)]
        public string Content
        {
            get { return (string.IsNullOrEmpty(this._content) ? "" : this._content); }
            set { this._content = value; }
        }

        private string _ensure;
        private string _content;

        /// <summary>
        /// Implement the logic to set the state of the machine to the desired state.
        /// </summary>
        protected override void ProcessRecord()
        {
            WriteVerbose(string.Format("Running set with parameters {0}{1}{2}", Path, Ensure, Content));
            if (File.Exists(Path))
            {
                if (Ensure.Equals("absent", StringComparison.InvariantCultureIgnoreCase))
                {
                    File.Delete(Path);
                }
                else
                {
                    // file already exist and ensure "present" is specified. start writing the content to a file
                    if (!string.IsNullOrEmpty(Content))
                    {
                        string existingContent = null;
                        using (var reader = new StreamReader(Path))
                        {
                            existingContent = reader.ReadToEnd();
                        }
                        // check if the content of the file mathes the content passed 
                        if (!existingContent.Equals(Content, StringComparison.InvariantCultureIgnoreCase))
                        {
                            WriteVerbose("Existing content did not match with desired content updating the content of the file");
                            using (var writer = new StreamWriter(Path))
                            {
                                writer.Write(Content);
                                writer.Flush();
                            }
                        }
                    }
                }

            }
            else
            {
                if (Ensure.Equals("present", StringComparison.InvariantCultureIgnoreCase))
                {
                    // if nothing is passed for content just write "" otherwise write the content passed.
                    using (var writer = new StreamWriter(Path))
                    {
                        WriteVerbose(string.Format("Creating a file under path {0} with content {1}", Path, Content));
                        writer.Write(Content);
                    }
                }

            }

            /* if you need to reboot the VM. please add the following two line of code.
            PSVariable DscMachineStatus = new PSVariable("DSCMachineStatus", 1, ScopedItemOptions.AllScope);
            this.SessionState.PSVariable.Set(DscMachineStatus);
             */

        }

    }

    # endregion

    #region Test-TargetResource

    [Cmdlet("Test", "TargetResource")]
    [OutputType(typeof(Boolean))]
    public class TestTargetResource : PSCmdlet
    {
        [Parameter(Mandatory = true)]
        public string Path { get; set; }

        [Parameter(Mandatory = false)]

        [ValidateSet("Present", "Absent", IgnoreCase = true)]
        public string Ensure
        {
            get
            {
                // set the default to present.
                return (this._ensure ?? "Present");
            }
            set
            {
                this._ensure = value;
            }
        }

        [Parameter(Mandatory = false)]
        public string Content
        {
            get { return (string.IsNullOrEmpty(this._content) ? "" : this._content); }
            set { this._content = value; }
        }

        private string _ensure;
        private string _content;

        /// <summary>
        /// Return a boolean value which indicates wheather the current machine is in desired state or not.
        /// </summary>
        protected override void ProcessRecord()
        {
            if (File.Exists(Path))
            {
                if (Ensure.Equals("absent", StringComparison.InvariantCultureIgnoreCase))
                {
                    WriteObject(false);
                }
                else
                {
                    // check if the content matches
                    string existingContent = null;
                    using (var stream = new StreamReader(Path))
                    {
                        existingContent = stream.ReadToEnd();
                    }

                    WriteObject(Content.Equals(existingContent, StringComparison.InvariantCultureIgnoreCase));
                }
            }
            else
            {
                WriteObject(Ensure.Equals("Absent", StringComparison.InvariantCultureIgnoreCase));
            }
        }
    }

    # endregion

}

编译成一个名字为MSFT_XDemoFile.dll类库;注意这个名字必须和MOF的名字保持一致。

@第4步:部署MSFT_XDemoFile.dll

把MSFT_XDemoFile.dll类库拷贝到C:\Program Files\WindowsPowerShell\Modules\xCustomDemo\DSCResources\
MSFT_XDemoFile 目录下,下面是最终的相对目录结构。
$env: psmodulepath (folder)
    |- xCustomDemo (folder)
        |- xCustomDemo.psd1 (file, required)        
        |- DSCResources (folder)
            |- MSFT_XDemoFile (folder)
                |- MSFT_XDemoFile.psd1 (file, optional)
                |- MSFT_XDemoFile.dll (file, required)
                |- MSFT_XDemoFile.schema.mof (file, required)

@第5步:单元测试MSFT_XDemoFile DSC Resource

我们现在就可以测试MSFT_XDemoFile DSC资源中的Set和get方法了。
测试脚本如下:
$result = Invoke-DscResource -Name MSFT_xDemoFile -Method Set -Property @{path="d:\DSC\test.txt"
     Ensure="Present"
     Content="Hello ggggg"} -Verbose

$result| ft

$result = Invoke-DscResource -Name MSFT_xDemoFile -Method Get -Property @{path="d:\DSC\test.txt"
     Ensure="Present"
     Content="Hello ggggg"} -Verbose
$result| ft

@第6步:测试MSFT_XDemoFile配置是否生效

Configuration Test_CSharp_XDemo{
   Import-DscResource -ModuleName xSPAV
   MSFT_xDemoFile test-xdemoFile{
     path="d:\DSC\test.txt"
     Ensure="Present"
     Content="Hello World!!!!"
   }
}
Test_CSharp_XDemo
Start-DscConfiguration -path .\Test_CSharp_XDemo -Wait -Force



执行上面的脚本后,我们发现d:\DSC\test.txt文件里面的内容已经写成功。


参考文献:

https://msdn.microsoft.com/en-us/powershell/dsc/authoringresourcemofcs



版权声明:本文为博主原创文章,未经博主允许不得转载。

[1] Window PowerShell DSC 学习系列----DSC的定义和2种架构模式

PowerShell DSC是PowerShell的一部分,是一个新的管理平台,英文全称为,PowerShell Desired Status Configuration,翻译成中文就是理想管理配置状...
  • chancein007
  • chancein007
  • 2017年01月09日 23:09
  • 1587

[16]Windows PowerShell DSC学习系列---基于Class风格定制DSC资源?

前面的章节介绍了,[15]Windows PowerShell DSC学习系列---基于.NET DLL(C#) 定制DSC资源?和 [11] Windows PowerShell DSC学习系列--...
  • chancein007
  • chancein007
  • 2017年02月13日 13:57
  • 1694

DSC模块之Modbus通讯(以PLC为例)

http://digital.ni.com/public.nsf/allkb/F716ABC0F75705ED86257AF5002E1451 主要软件: LabVIEW...
  • leonliufeng
  • leonliufeng
  • 2016年06月21日 10:02
  • 1839

UEFI原理与编程(七):包及.dsc、.dec、.fdf文件

包及.dsc、.dec、.fdf文件  前面的文章中比较详细介绍了UEFI工程文件即.inf。UEFI的包中一般都会包含一个.dsc文件和一个dec文件。在包生成固件Image、Option Rom ...
  • sevensevensevenday
  • sevensevensevenday
  • 2017年04月27日 15:27
  • 2129

[22]Window PowerShell DSC学习系列---- 如何用PowerShell脚本查看DSC服务器的执行报表(Report)

本文只适合DSC 5.x的版本。我们知道在DSC 5.x的版本中,Pull服务器和Report是安装在一起的。那么当目标节点注册成功到Pull和Report服务器之后,且Pull服务器上的MOF和Re...
  • chancein007
  • chancein007
  • 2017年02月14日 13:45
  • 1716

使用AO往MDB和SDE写数据的一些经验之谈

http://blog.163.com/1234_wangmin/blog/static/1276550200923115753767/    往PersonalGDB或SDEGDB中写入要素记...
  • zzh_my
  • zzh_my
  • 2013年12月10日 21:19
  • 829

[5] Window PowerShell DSC 学习系列----如何生成一个DSC MOF文件?

在前面的四个章节,笔者介绍了一些PowerShell基础的知识,包括PowerShell DSC的基本架构,DSC的资源以及配置格式,已经在PowerShell DSC 如何安装扩展的DSC Modu...
  • chancein007
  • chancein007
  • 2017年01月23日 16:07
  • 1447

[25]Window PowerShell DSC学习系列----如何更换DSC Pull服务器数据库为Access数据库?

我们知道,PowerShell DSC的默认数据库为ESENT文件数据库;或者oleDB形式的Access数据库(数据库文件后缀名为:mdb). 默认安装方式下,如果用xDscWebService D...
  • chancein007
  • chancein007
  • 2017年04月10日 22:24
  • 1968

linux/ubuntu中制作deb安装包

linux/ubuntu中如何制作deb安装包由于要制作一个在arm平台上运行的xorg-server-1.12.4版本的安装包,所以需要学习如何制作deb安装包。这里以一个非常小的工程为例,记录制作...
  • mountzf
  • mountzf
  • 2016年07月08日 20:58
  • 4246

c# 工程加入 win32 资源文件

这种事情就是一个字烦人,蛋疼,特别蛋疼。 搞了我一天。方法有几种,都特别烦,一个是 build event , 一个是 msbuild今天说 build event1.在 Build Events 中...
  • norsd
  • norsd
  • 2013年04月23日 17:33
  • 1503
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[15]Windows PowerShell DSC学习系列---基于.NET DLL(C#) 定制DSC资源?
举报原因:
原因补充:

(最多只允许输入30个字)