您的位置:首页 > 运维架构 > Shell

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

2017-02-10 17:46 447 查看
我们知道我们在定制实现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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Powershell Custom DSC C#
相关文章推荐