Erstellen einer DSC-Ressource in C#
Gilt für: Windows PowerShell 4.0, Windows PowerShell 5.0
In der Regel wird eine benutzerdefinierte Windows PowerShell DSC-Ressource in einem PowerShell-Skript implementiert. Allerdings können Sie die Funktionalität einer benutzerdefinierten DSC-Ressource auch durch Schreiben von C#-Cmdlets implementieren. Eine Einführung zum Schreiben von Cmdlets in C# finden Sie unter Schreiben eines Windows PowerShell-Cmdlets.
Abgesehen von der Implementierung der Ressource als Cmdlets in C# entsprechen die Schritte zum Erstellen des MOF-Schemas, zum Erstellen der Ordnerstruktur sowie zum Importieren und Verwenden Ihrer benutzerdefinierten DSC-Ressource dem unter Schreiben einer benutzerdefinierten DSC-Ressource mit MOF beschriebenen Verfahren.
Schreiben einer Cmdlet-basierten Ressource
In diesem Beispiel wird eine einfache Ressource implementiert, die eine Textdatei und deren Inhalt verwaltet.
Schreiben des MOF-Schemas
Im folgenden sehen Sie die Definition der MOF-Ressource.
[ClassVersion("1.0.0"), FriendlyName("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;
};
Einrichten des Visual Studio-Projekts
Einrichten eines Cmdlet-Projekts
- Öffnen Sie Visual Studio.
- Erstellen Sie ein C#-Projekt, und geben Sie diesem einen Namen.
- Wählen Sie -Klassenbibliothek aus den verfügbaren Projektvorlagen aus.
- Klicken Sie auf OK.
- Fügen Sie „System.Automation.Management.dll“ einen Assemblyverweis auf Ihr Projekt hinzu.
- Ändern Sie den Assemblynamen so, dass er dem Namen der Ressource entspricht. In diesem Fall sollte die Assembly MSFT_XDemoFile benannt werden.
Schreiben des Codes des Cmdlets
Mit dem folgenden C#-Code werden die Cmdlets Get-TargetResource
, Set-TargetResource
und Test-TargetResource
implementiert.
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
}
Bereitstellen der Ressource
Die kompilierte DLL-Datei sollte in einer Dateistruktur gespeichert werden, die einer skriptbasierten Ressource ähnelt. Im folgenden finden die Ordnerstruktur für diese Ressource.
$env: psmodulepath (folder)
|- MyDscResources (folder)
|- MyDscResources.psd1 (file, required)
|- DSCResources (folder)
|- MSFT_XDemoFile (folder)
|- MSFT_XDemoFile.psd1 (file, optional)
|- MSFT_XDemoFile.dll (file, required)
|- MSFT_XDemoFile.schema.mof (file, required)
Weitere Informationen
Konzepte
Schreiben einer benutzerdefinierten DSC-Ressource mit MOF