en-us/Writing_DSC_Resources_with_cFg.walkthru.help.txt

<#
One of the many ways you can use cFg is to help you write a DSC resource.
 
DSC Resources are most commonly implemented in a combination of a .MOF file and 3 PowerShell functions:
 
* Get-TargetResource <span style='font-size:.7em'>(which optionally returns a hashtable of data)</span>
* Set-TargetResource <span style='font-size:.7em'>(which does the bulk of the configuration)</span>
* Test-TargetResource <span style='font-size:.7em'>(which determines if the configuration should be applied)</span>
 
These functions are fairly tedious to write, and the .MOF can be difficult to understand.
cFg radically simplifies the process of writing a DSC resource by providing you with a function to generate it's code - [Write-DSCResource](/Write-DSCResource).
 
Here's a simple DSC resource that mirrors two directories with RoboCopy:
 
#>
 
Write-DSCResource -ResourceName cRoboCopyMirror -ModuleRoot $env:ProgramFiles\WindowsPowerShell\cFg -Property @{
    Source = 'The source directory'
    Destination = 'The destination directory'
} -Set {
    robocopy $Source $Destination /MIR
} -KeyProperty Source, Destination
 
 
<#
 
There's a few things to notice about the previous simple example:
 
1. Set-TargetResource is the only function you actually need to implement. <br/><span style='font-size:.7em'>( Test-TargetResource is also useful, as it can be used to skip you to skip the Set )</span>
2. You can have more than one KeyProperty.<br/><span style='font-size:.7em'>(This is very useful, and not just because it allows you to require multiple values. The ability to have multiple keys is part of the ability to write DSC resources that do persistent monitoring. )</span>
3. You don't need to specify types in the -Property parameter <br/><span style='font-size:.7em'>(though you can, just add a typename after the description)</span>
 
As you can see, cFg radically simplifies writing a DSC resource while allowing for new possibilities. Here's another sample, this time showing a fully custom Get,Set, and Test.
 
#>
 
Write-DSCResource -Property @{
    TimerId = 'An identifier for the timer'
    IntervalBetweenEvents = 'The number of milliseconds between each event', [Uint64]
    SkipIfPassed = 'Indicates if the event should fire after the event has passed', [bool]
} -Test {
    $existingTimer = Get-WmiObject -Namespace root\cimv2 -Class __IntervalTimerInstruction -Filter "TimerID = '$TimerID'"
 
    $existingTimer -and
        $existingTimer.IntervalBetweenEvents -eq $IntervalBetweenEvents -and
        $existingTimer.TimerID -eq $TimerID -and
        $existingTimer.SkipIfPassed -eq $SkipIfPassed
} -Get {
    $existingTimer = Get-WmiObject -Namespace root\cimv2 -Class __IntervalTimerInstruction -Filter "TimerID = '$TimerID'"
    if (-not $existingTimer) { return @{} }
 
    return @{
        TimerID = $existingTimer.TimerID
        SkipIfPassed = $existingTimer.SkipIfPassed
        IntervalBetweenEvents = $existingTimer.IntervalBetweenEvents
    }
} -Set {
    $wmiClass = [wmiclass]'__IntervalTimerInstruction'
    $newInstance = $wmiClass.CreateInstance()
    $newInstance.TimerID = $timerID
    $newInstance.IntervalBetweenEvents = $intervalBetweenEvents
    $newInstance.SkipIfPassed = $SkipIfPassed
    $null = $newInstance.Put()
} -KeyProperty TimerID -MandatoryProperty IntervalBetweenEvents
  
<#
 
In this example, you might notice how easy it is to provide a property type. With the -Property parameter, the key is the name of the property, the first value is the property's description, and the second (optional) value is the property's type.
 
What you might not notice is that it's missing the -ResourceName and -ModuleRoot parameter. This is because cFg provides another pair of functions to help automatically generate the DSC resources for a module, [Initialize-DSCResource](/Initialize-DSCResource) and [Reset-DSCResource](/Reset-DSCResource).
 
Initialize-DSCResource will find all files named *.resource.version.ps1 (i.e. cRoboCopyMirror.0.1.resource.ps1) within a module, and will run those files and provide the default parameter values for -ResourceName, -Version, and -ModuleRoot. Reset-DSCResource will find the same set of files, but will delete the corresponding files. By using Initalize-DSCResource and Reset-DSCResource, it's easy to author DSC resources with cFg without requiring cFg.
 
One other capability of Write-DSCResource is worth noting. You might notice that DSC resources end up being somewhat similar to commands within a PowerShell module. You can use the -SetCommand parameter of Write-DSCResource to wrap the resource.
 
This example creates a DSC resource based off of Stop-Process:
 
#>
 
Write-DSCResource "StopProcess" -TestCommand (Get-Command Get-Process) -SetCommand (Get-Command Stop-Process) -SetParameterBlacklist Id, InputObject, WhatIf, Confirm, PassThru, Force -KeyProperty Name -SetDefaultParameter @{
    Force = $true
}
 
 
 
<#
     
In this last example, a few things are happening:
 
1. -SetParameterBlackList is used to prevent the StopProcess resource from using the -Id, -InputObject, -WhatIf, -Confirm, or -PassThru from Stop-Process.
2. -KeyProperty is still required, because DSC requires all resources to have a key (and there's no way to know which mandatory parameter of the command you should use).
3. -SetDefaultParameter is used to always supply the -Force parameter to Stop-Process
4. The Test is also a command, in this case, Get-Process. If any results are returned from this command, the Test-TargetResource function will return $true, and the SetCommand will run.
 
As with the other examples, cFg saves writing hundreds of lines of tedious code.
#>