In previous blog, we learned how one can use their PowerShell skills to author DSC resources very easily. Still there are folks (we met some at TechEd NA) who want to author their DSC resources using C# because they are more productive with it than PowerShell language. Well, you can fully leverage the power of DSC by writing your resources in C#. In this blog, we will explore how you can write a C# based DSC resource and later seamlessly consume it from your DSC Configurations.
Authoring DSC resources in C#
For the purpose of this blog, we will write a DSC resource named “xDemoFile”. This resource will be used to assert the existence of a file and its contents. It is similar to a File resource but with limited functionalities.
I) Project Setup:-
a) Open visual studio
b) Create a C# project and provide the name (such as “cSharpDSCResourceExample”)
c) Select “Class Library” from the available project templates
d) Hit “Ok”
e) Add assembly reference to system.automation.management.dll preferably from PowerShell SDK [but you can add assembly reference to your project from the windows assembly cache, GAC (<systemDrive>\ Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll)].
f) *Update the assembly name to match the DSC resource name. (write right click on the project then hit properties and change the Assembly Name to MSFT_xDemoFile)
II) Resource Definition
Similar to script based DSC resource. You will need to define the input and output parameters of your resources in <ResourceName>.schema.mof. You can generate the schema of your resource using the Resource Designer Tool.
Save the following in to a file named MSFT_xDemoFile.Schema.mof
[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;
};
III) Resource Implementation
In order to write DSC Resources in C#, you need to implement three PowerShell cmdlets. PowerShell cmdlets are written by inheriting from PSCmdlet or Cmdlet. Detail on how to write PowerShell Cmdlet in C# can be found in this MSDN documentation.
See below for the signature of the cmdlets:-
Get-TargetResource
[OutputType(typeof(System.Collections.Hashtable))]
[Cmdlet(VerbsCommon.Get, "TargetResource")]
publicclassGetTargetResource : PSCmdlet
{
[Parameter(Mandatory = true)]
publicstring Path { get; set; }
///<summary>
/// Implement the logic to write 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>
protectedoverridevoid ProcessRecord()
{
// download the zip file at the end of this blog to see sample implementation
}
}
Set-TargetResouce
[OutputType(typeof(void))]
[Cmdlet(VerbsCommon.Set, "TargetResource")]
publicclassSetTargetResource : PSCmdlet
{
privatestring _ensure;
privatestring _content;
[Parameter(Mandatory = true)]
publicstring Path { get; set; }
[Parameter(Mandatory = false)]
[ValidateSet("Present", "Absent", IgnoreCase = true)]
publicstring Ensure {
get
{
// set the default to present.
return (this._ensure ?? "Present");
}
set
{
this._ensure = value;
}
}
publicstring Content {
get { return (string.IsNullOrEmpty(this._content) ? "" : this._content); }
set { this._content = value; }
}
///<summary>
/// Implement the logic to set the state of the machine to the desired state.
///</summary>
protectedoverridevoid ProcessRecord()
{
//Implement the set method of the resource
/* Uncomment this section if your resource needs a machine reboot.
PSVariable DscMachineStatus = new PSVariable("DSCMachineStatus", 1, ScopedItemOptions.AllScope);
this.SessionState.PSVariable.Set(DscMachineStatus);
*/
}
}
Test-TargetResource
[Cmdlet("Test", "TargetResource")]
[OutputType(typeof(Boolean))]
publicclassTestTargetResource : PSCmdlet
{
privatestring _ensure;
privatestring _content;
[Parameter(Mandatory = true)]
publicstring Path { get; set; }
[Parameter(Mandatory = false)]
[ValidateSet("Present", "Absent", IgnoreCase = true)]
publicstring Ensure
{
get
{
// set the default to present.
return (this._ensure ?? "Present");
}
set
{
this._ensure = value;
}
}
[Parameter(Mandatory = false)]
publicstring Content
{
get { return (string.IsNullOrEmpty(this._content) ? "“:this._content);}
set { this._content = value; }
}
///<summary>
/// Write a Boolean value which indicates whether the current machine is in /// desired state or not.
///</summary>
protectedoverridevoid ProcessRecord()
{
// Implement the test method of the resource.
}
}
IV) How to handle Machine reboot in C# based DSC Resources.
If your resource needs a machine reboot. The way to indicate that in script-based DSC resource is setting the global variable $global:DSCMachineStatus to 1 in the Set-TargetResource function of the resource. To do similar in C#-based DSC resource, you will need to set the same variable in the runspace where the Set Cmdlet of the resource will be executed.
Adding the following two lines will signal a machine reboot to the DSC engine.
PSVariable DSCMachineStatus = new PSVariable("DSCMachineStatus", 1, ScopedItemOptions.AllScope);
this.SessionState.PSVariable.Set(DSCMachineStatus);
Consume C# based resources
I) How to deploy C# based DSC Resource
The folder structure of C# based DSC resource is the same as the script based resource. Please refer to this blog to see how DSC resources should be deployed in your machine.
The output binaries from your project and the schema mof of the resource should be deployed to the correct path before you can use it to author or apply configurations.
Example: - if you deploy the resource under a module “CSharpDSCResource” inside $env:programfiles, the folder structure would look like:-
$env:ProgramFiles\WindowsPowerShell\Modules\CSharpDSCResource\DSCResources\MSFT_XDemoFile\MSFT_XDemoFile.dll
$env:ProgramFiles\WindowsPowerShell\Modules\CSharpDSCResource\DSCResources\MSFT_XDemoFile\MSFT_XDemoFile.Shema.mof
II) Create Configuration:-
ConfigurationCsharpExample
{
Import-DSCResource-ModuleCSharpDSCResource
Node("localhost")
{
xDemoFile fileLog
{
Path ="c:\foo.txt"
Content ="content example"
Ensure =“Present"
}
}
}
III) Run the configuration:-
Start-DSCConfiguration -ComputerName localhost -Path .\CsharpExample\ -Verbose -Wait
Berhe Abrha
Windows PowerShell Team