I’ve recently completed my first DSC deployment. Whilst I was testing DSC in a lab, I wrote a primer for my colleages. Here is that primer, with some edits. It’s a rough guide but it features links to a number of useful resources.

Note: This is an old article which may contain some out of date content.

This article concentrates on using DSC in a push configuration. That means that the configuration is applied when a system administrator manually starts DSC from their own workstation. In the coming weeks I’ll be implementing a pull configuration for a development environments. This relies on a pull server from which the DSC clients are configured to fetch and apply DSC configuration.

What is DSC?

Desired State Configuration is a feature that first shipped with Windows Management Framework 4, which is in-turn closely coupled to Powershell 4.0. DSC provides an idempotent mechanism for deploying configuration changes to a target host or a group of target hosts.

Which version of Windows Work with DSC

  • Windows 7 (PowerShellGet functionality doesn’t seem to work)
  • Windows 8.1 (Professional Upwards)
  • Server 2008 R2
  • Server 2012
  • Server 2012 R2

What do you need for DSC Administration?

Prerequisites

A pc for pushing your DSC configuration which must be running any version for Windows post Windows 7/Server 2008 r2 At least one host which you can provision with DSC.

Prepare your Environment

  • If you are using Windows 7, then you will need to install Windows Management Framework 4.0 or higher. Windows 8.1 Professional/Server 2012r2 ship with WMF 4.0 in the tin. PowerShell WMF 4.0 (includes Powershell 4.0).
  • Although WMF ships with a small set of resources, you might want to add some more. If you’re not using WMF5.0 I would recommend installing the DSC Resource Kit “Wave 10”.

Getting Started

The Powershell ISE can be used to author scripts and compile them into MOFs (Managed Object Files). Be aware that the MOFs will be generated in the ISE’s current folder, so before starting work use the console pane to change directory (e.g. Set-Location E:\DSC)

Writing a simple DSC Script is quite a trivial business. For example, the following PowerShell script will create a DSC MOF to provision an IIS Server with the base IIS role:

Configuration IisWebServerSample1
{
    Import-DscResource –ModuleName ’PSDesiredStateConfiguration’

    Node "MyWebServer"
    {
        WindowsFeature IIS
	{
        Ensure="Present"
        Name="Web-Server"
	}
    }
}

Set-Location $env:UserProfile\Documents\ManagedObjectFiles
IisWebServerSample1

The DSC Script defines what to all intents and purposes, is a PowerShell function. The penultimate statement in the script sets our location so that executing the “function” (final step) produces a MOF in ‘‘‘C:\Users<UserName>\Dcouments\ManagedObjectFiles\MyWebServer’'’.

We can now apply our compiled MOF to a target host called “MyWebServer” with the following command:

Start-DscConfiguration -Path .\IisWebServerSample1 -Wait -Verbose

You can be a bit more flexible around applying DSC configuration to different hosts. Use a parameter for your target host (node) name and then leave compiling the MOF until it’s actually used, as per the following example:

Configuration IisWebServerSample2
{
    # Parameters are optional
    param($TargetNodeName)

    Import-DscResource –ModuleName ’PSDesiredStateConfiguration’
 
    Node $TargetNodeName
    {
        WindowsFeature IIS
	{
        Ensure="Present"
        Name="Web-Server"
	}
    }
}

To apply this configuration to Server001, use the following statements:

Set-Location -Path $env:UserProfile\Documents\ManagedObjectFiles
. $env:UserProfile\Documents\ManagedObjectFiles\DscScripts\IisWebServerSample2.ps1 -TargetNodeName Server001
Start-DscConfiguration -Path $env:UserProfile\Documents\ManagedObjectFiles\IisWebServerSample2 -Wait

Resources

DSC is all about resources. In the examples above, the resource “WindowsFeature” is used to install IIS. In short, resources enable you to “do stuff” using DSC. With WMF 4.0, Microsoft started releasing resources in waves, the latest being Wave 10. With the advent of WMF 5.0, Microsoft has introduced a NuGet Style repository type system.

You can read more about resources here.

Resource Kits and Repositories

Installing and using a Module

DSC resources are incorporated into modules. These very much resemble traditional PowerShell modules - it’s only their content and use that differs slightly.

If using WMF 5.0 (not on Windows 7), installing a new module is as simple as: Install-Module -Name xSmbShare

If using WMF 4.0 you may need to find the module on GitHub, download it, and extract the contents to C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources. Once it is installed, it should be immediately available to use in DSC scripts. You can check by running Get-DscResource and searching for the resource/module name, e.g.

> Get-DscResource

ImplementedAs   Name                      ModuleName                     Version    Properties                                        
-------------   ----                      ----------                     -------    ----------                                        
Binary          File                                                                {DestinationPath, Attributes, Checksum, Content...
PowerShell      Archive                   PSDesiredStateConfiguration    1.1        {Destination, Path, Checksum, Credential...}      
PowerShell      Environment               PSDesiredStateConfiguration    1.1        {Name, DependsOn, Ensure, Path...}                
PowerShell      Group                     PSDesiredStateConfiguration    1.1        {GroupName, Credential, DependsOn, Description...}
Binary          Log                       PSDesiredStateConfiguration    1.1        {Message, DependsOn, PsDscRunAsCredential}        
PowerShell      Package                   PSDesiredStateConfiguration    1.1        {Name, Path, ProductId, Arguments...}             
PowerShell      Registry                  PSDesiredStateConfiguration    1.1        {Key, ValueName, DependsOn, Ensure...}            
PowerShell      Script                    PSDesiredStateConfiguration    1.1        {GetScript, SetScript, TestScript, Credential...} 
PowerShell      Service                   PSDesiredStateConfiguration    1.1        {Name, BuiltInAccount, Credential, Dependencies...
PowerShell      User                      PSDesiredStateConfiguration    1.1        {UserName, DependsOn, Description, Disabled...}   
PowerShell      WaitForAll                PSDesiredStateConfiguration    1.1        {NodeName, ResourceName, DependsOn, PsDscRunAsC...
PowerShell      WaitForAny                PSDesiredStateConfiguration    1.1        {NodeName, ResourceName, DependsOn, PsDscRunAsC...
PowerShell      WaitForSome               PSDesiredStateConfiguration    1.1        {NodeCount, NodeName, ResourceName, DependsOn...} 
PowerShell      WindowsFeature            PSDesiredStateConfiguration    1.1        {Name, Credential, DependsOn, Ensure...}          
PowerShell      WindowsOptionalFeature    PSDesiredStateConfiguration    1.1        {Name, DependsOn, Ensure, LogLevel...}            
PowerShell      WindowsProcess            PSDesiredStateConfiguration    1.1        {Arguments, Path, Credential, DependsOn...}       
PowerShell      xSmbShare                 xSmbShare                      1.1.0.0    {Name, Path, ChangeAccess, ConcurrentUserLimit...}

If you experience problems installing resources, have a read of the MSDN Powershell Blog on How to Deploy and Discover Windows Powershell Desired State Configuration Resources.

Finding out about a Resource

List Installed DSC Resources

Get-DscResource

Get the properties for a resource

(Get-DscResource -Name File).Properties

Creating Resources

Sometimes it’s necessary to create your own resources.

Please note that I couldn’t get PowerShellGet working under Windows 7, which is used in the following example to install the xDSCResourceDesigner. It is possible to download it from GitHub and ensure the files are extracted to the appropriate path, e.g. *C:\Program Files\WindowsPowerShell\Modules\xDSCResourceDesigner\1.5.0.0*.

Set-Up

Before you can begin creating your own resources, you will need to install the xDSCResourceDesigner module.

Installing xDSCResourceDesigner with WMF 4.0

  1. Download xDSCResourceDesigner from GitHub
  2. Extract the contents of the folder contained within the zip file to C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources\xDSCResourceDesigner.

Once the module is installed, you can confirm it using Get-ChildItem:

> Get-ChildItem C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources\xDSCResourceDesigner


    Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources\xDSCResourceDesigner


Mode                LastWriteTime         Length Name                                                                                                                                                                                                                                                            
----                -------------         ------ ----                                                                                                                                                                                                                                                            
-a----       17/12/2014     18:09          17204 TechNetDocumentation-xDscResourceDesigner.html                                                                                                                                                                                                                  
-ar---       11/12/2014     14:13           1275 xDSCResourceDesigner.psd1                                                                                                                                                                                                                                       
-ar---       11/12/2014     14:13         103520 xDSCResourceDesigner.psm1                                                                                                                                                                                                                                       
-ar---       27/03/2014     09:33           8022 xDSCResourceDesigner.strings.psd1                                                                                                                                                                                                                               

And also check using Get-Module:

> Get-Module -listavailable | Select-String "xDSCResourceDesigner"

Installing xDSCResourceDesigner with WMF 5.0

Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module -Name xDSCResourceDesigner

Building Your New Resource

  • Create a new module, if we don’t already have one for our DSC Resources

      New-Item -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\" -Name myDSCResources -ItemType Directory
    
  • Create the manifest for our new module

      New-ModuleManifest -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\myDSCResources\myDSCResources.psd1" -Guid (([guid]::NewGuid()).Guid) -Author "Codeweavers Ltd." -CompanyName "Codeweavers Ltd." -ModuleVersion 1.0 -Description "Codeweavers DSC Resources" -PowerShellVersion 4.0 -FunctionsToExport '*.TargetResource'
    
  • Define properties, e.g.

       $ServiceName = New-xDscResourceProperty -Name ServiceName -Type String -Attribute key
       $ServicePath = New-xDscResourceProperty -Name ServicePath -Type String -Attribute Write
       $ServiceAdditionalArgs = New-xDscResourceProperty -Name ServiceAdditionalArgs -Type String -Attribute Write
       $ServiceStartCondition = New-xDscResourceProperty -Name ServiceStartCondition -Type String -Attribute Write
       $ServiceStopAction = New-xDscResourceProperty -Name ServiceStopAction -Type String -Attribute Write
       $NssmPath = New-xDscResourceProperty -Name NssmPath -Type String -Attribute Write
       $Ensure = New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -ValidateSet "Present","Absent"
    
  • Create the resource:

      New-xDscResource -Name bnNssmService -Property $ServiceName,$ServicePath,$ServiceAdditionalArgs,$ServiceStartCondition,$ServiceStopAction,$NssmPath,$Ensure `
          -Path $env:windir\System32\WindowsPowerShell\v1.0\Modules\myDSCResources
    
  • Add logic to the resultant PowerShell Script Module, e.g. “C:\Windows\System32\WindowsPowerShell\v1.0\Modules\bnDCSResources\DSCResources\bnNssmService\bnNssmService.psm1”. This is what the module looks like before any additional logic is included:

      function Get-TargetResource
      {
          [CmdletBinding()]
          [OutputType([System.Collections.Hashtable])]
          param
          (
              [parameter(Mandatory = $true)]
              [System.String]
              $ServiceName
          )
    
          #Write-Verbose "Use this cmdlet to deliver information about command processing."
    
          #Write-Debug "Use this cmdlet to write debug information while troubleshooting."
    
    
          <#
          $returnValue = @{
              ServiceName = [System.String]
              ServicePath = [System.String]
              ServiceAdditionalArgs = [System.String]
              ServiceStartCondition = [System.String]
              ServiceStopAction = [System.String]
              NssmPath = [System.String]
              Ensure = [System.String]
          }
    
          $returnValue
          #>
      }
    
    
      function Set-TargetResource
      {
          [CmdletBinding()]
          param
          (
              [parameter(Mandatory = $true)]
              [System.String]
              $ServiceName,
    
              [System.String]
              $ServicePath,
    
              [System.String]
              $ServiceAdditionalArgs,
    
              [System.String]
              $ServiceStartCondition,
    
              [System.String]
              $ServiceStopAction,
    
              [System.String]
              $NssmPath,
    
              [ValidateSet("Present","Absent")]
              [System.String]
              $Ensure
          )
    
          #Write-Verbose "Use this cmdlet to deliver information about command processing."
    
          #Write-Debug "Use this cmdlet to write debug information while troubleshooting."
    
          #Include this line if the resource requires a system reboot.
          #$global:DSCMachineStatus = 1
    
    
      }
    
    
      function Test-TargetResource
      {
          [CmdletBinding()]
          [OutputType([System.Boolean])]
          param
          (
              [parameter(Mandatory = $true)]
              [System.String]
              $ServiceName,
    
              [System.String]
              $ServicePath,
    
              [System.String]
              $ServiceAdditionalArgs,
    
              [System.String]
              $ServiceStartCondition,
    
              [System.String]
              $ServiceStopAction,
    
              [System.String]
              $NssmPath,
    
              [ValidateSet("Present","Absent")]
              [System.String]
              $Ensure
          )
    
          #Write-Verbose "Use this cmdlet to deliver information about command processing."
    
          #Write-Debug "Use this cmdlet to write debug information while troubleshooting."
    
    
          <#
          $result = [System.Boolean]
    
          $result
          #>
      }
    
    
      Export-ModuleMember -Function *-TargetResource
    
  • This is what the module looks like after we have added some logic:

      function Get-TargetResource
      {
          [CmdletBinding()]
          [OutputType([System.Collections.Hashtable])]
          param
          (
              [parameter(Mandatory = $true)]
              [System.String]
              $ServiceName,
              [parameter(Mandatory = $true)]
              [System.String]
              $NssmPath
      )
      Write-Verbose "Verbose: Checking $NssmPath"
      Write-Debug "Debug: Test-Path -Path $NssmPath"
      $nssmInstalled = Test-Path -Path $NssmPath
      if($nssmInstalled){
          Write-Verbose "Verbose: $NssmPath is installed - retrieving details"
          Write-Debug "Debug: GetPath: & $NssmPath get $ServiceName Application"
          $ServicePath =& $NssmPath get $ServiceName Application
          Write-Debug "Debug: GetArgs: & $NssmPath get $ServiceName AppParameters"
          $ServiceAdditionalArgs = & $NssmPath get $ServiceName AppParameters
          Write-Debug "Debug: GetStartCondition: & $NssmPath get `"$ServiceName`" Start"
          $ServiceStartCondition = & $NssmPath get "$ServiceName" Start
          Write-Debug "Debug: GetStopAction: & $NssmPath set `"$ServiceName`" Appexit Default"
          $ServiceStopAction = & $NssmPath set "$ServiceName" Appexit Default
      } else {
          Write-Verbose "Verbose: $NssmPath is not installed"
      }
      Write-Debug "Debug: Set return value"
      $returnValue = @{
          ServiceName = $ServiceName
          ServicePath = $ServicePath
          ServiceAdditionalArgs = $ServiceAdditionalArgs
          ServiceStartCondition = $ServiceStartCondition
          ServiceStopAction = $ServiceStopAction
          NssmPath = $NssmPath
          Ensure = $ensureResult
      }
      $returnValue
      }
    
      function Set-TargetResource
      {
          [CmdletBinding()]
          param
          (
              [parameter(Mandatory = $true)]
              [System.String]
              $ServiceName,
              [System.String]
              $ServicePath,
              [System.String]
              $ServiceAdditionalArgs,
              [System.String]
              $ServiceStartCondition,
              [System.String]
              $ServiceStopAction,
              [parameter(Mandatory = $true)]
              [System.String]
              $NssmPath,
              [ValidateSet("Present","Absent")]
              [System.String]
              $Ensure
          )
          Write-Verbose "Verbose: Checking $NssmPath"
          Write-Debug "Debug: Test-Path -Path $NssmPath"
          $nssmInstalled = Test-Path -Path $NssmPath
          if(!$nssmInstalled) {
              Write-Verbose "Verbose: $NssmPath is not installed"
              Write-Debug "Debug: Throwing Exception"
              throw [System.IO.FileNotFoundException]"$NssmPath not found. Hint: Use File resource to copy NSSM to appropriate location on target host"
          }
          Write-Verbose "Verbose: Remove $ServiceName Service - ignore any errors"
          if($PSCmdlet.ShouldProcess("Removing existing installation of $ServiceName")){
              Write-Debug "Debug: ErrorActionPreference = `"SilentlyContinue`""
              $_ErrorActionPreference = $ErrorActionPreference ; $ErrorActionPreference = "SilentlyContinue"
              Write-Debug "Debug: & $NssmPath remove `"$ServiceName`" confirm"
              & $NssmPath remove "$ServiceName" confirm
              Write-Debug "Debug: ErrorActionPreference = $_ErrorActionPreference"
              $ErrorActionPreference = $_ErrorActionPreference
          }
          Write-Verbose "Verbose: Testing `"Ensure`" property: $Ensure"
          if($Ensure -eq "Present") {
              Write-Verbose "Verbose: Property `"Ensure`" equals `"Present`"; Proceed with installation/configuration"
              if($PSCmdlet.ShouldProcess("Installing $ServiceName")){
                  Write-Debug "Debug: & $NssmPath install `"$ServiceName`" `"$ServicePath`" $ServiceAdditionalArgs"
                  & $NssmPath install "$ServiceName" "$ServicePath" $ServiceAdditionalArgs    
                  if($LastExitCode -ne 0){
                      Write-Debug "Debug: LastExitCode not 0: $LastExitCode`nDebug: Throwing Exception"
                      throw [System.Exception]"Return Code: $LastExitCode `n Failed Nssm Service Install"
                  }
              }
              if($PSCmdlet.ShouldProcess("Applying the Start Condition `"$ServiceStartCondition`" to $ServiceName")){
                  Write-Debug "Debug: & $NssmPath set `"$ServiceName`" Start $ServiceStartCondition"
                  & $NssmPath set "$ServiceName" Start $ServiceStartCondition
                  if($LastExitCode -ne 0){
                      Write-Debug "Debug: LastExitCode not 0: $LastExitCode`nDebug: Throwing Exception"
                      throw [System.Exception]"Return Code: $LastExitCode `n Failed Nssm Set Parameter"
                  }
              }
              if($PSCmdlet.ShouldProcess("Applying the Service Stop Action `"$ServiceStopAction`" to $ServiceName")){
                  Write-Debug "Debug: & $NssmPath set `"$ServiceName`" Appexit Default $ServiceStopAction"
                  & $NssmPath set "$ServiceName" Appexit Default $ServiceStopAction
                  if($LastExitCode -ne 0){
                      Write-Debug "Debug: LastExitCode not 0: $LastExitCode`nDebug: Throwing Exception"
                      throw [System.Exception]"Return Code: $LastExitCode `n Failed Nssm Set Parameter"
                  }
              }
          } else {
              Write-Verbose "Verbose: Property `"Ensure`" equals `"Absent`"; No further work to do"
          }
          #Include this line if the resource requires a system reboot.
          #$global:DSCMachineStatus = 1
      }
    
      function Test-TargetResource
      {
          [CmdletBinding()]
          [OutputType([System.Boolean])]
          param
          (
              [parameter(Mandatory = $true)]
              [System.String]
              $ServiceName,
              [System.String]
              $ServicePath,
              [System.String]
              $ServiceAdditionalArgs,
              [System.String]
              $ServiceStartCondition,
              [System.String]
              $ServiceStopAction,
              [parameter(Mandatory = $true)]
              [System.String]
              $NssmPath,
              [ValidateSet("Present","Absent")]
              [System.String]
              $Ensure
          )
          Write-Verbose "Verbose: Checking path $NssmPath"
          Write-Debug "Debug: Test-Path -Path $NssmPath"
          $nssmInstalled = Test-Path -Path $NssmPath
          if($nssmInstalled) {
              Write-Verbose "Verbose: $NssmPath is installed - proceed to next check"
          } else {
              Write-Verbose "Verbose: $NssmPath is not installed. Terminate here"
              $returnValue = ($false -eq ($Ensure -eq "Present"))
              return $returnValue         
          }
    
          Write-Verbose "Verbose: Checking whether $ServiceName is installed and configured with correct start condition/stop action"
          Write-Debug "Debug: ErrorActionPreference = `"SilentlyContinue`""
          $_ErrorActionPreference = $ErrorActionPreference ; $ErrorActionPreference = "SilentlyContinue"
                Write-Debug "Debug: if(((& $NssmPath get `"$ServiceName`" Start) -eq $ServiceStartCondition) -and`n`t((& $NssmPath get `"$ServiceName`" Appexit Default) -eq $ServiceStopAction))"
    
          $serviceInstalledConfigged = ((& $NssmPath get "$ServiceName" Start) -eq $ServiceStartCondition) -and`
                                              ((& $NssmPath get "$ServiceName" Appexit Default) -eq $ServiceStopAction)
    
          Write-Debug "Debug: ErrorActionPreference = $_ErrorActionPreference"
          $ErrorActionPreference = $_ErrorActionPreference
    
          if($serviceInstalledConfigged) {
              Write-Verbose "Verbose: $ServiceName is installed and correctly configured"
              $returnValue = ($true -eq ($Ensure -eq "Present")) 
          } else {
              Write-Verbose "Verbose: $ServiceName is either not installed or incorrectly configured"
              $returnValue = ($false -eq ($Ensure -eq "Present")) 
          }
          Write-Verbose "Verbose: Returning $returnValue"
          return $returnValue
      }
      Export-ModuleMember -Function *-TargetResource
    
  • You can test your new resource is recognised as a DSC resource

      > Get-Module -name myDSCResources
    
      ModuleType Version    Name                                ExportedCommands                                                                                                                    
      ---------- -------    ----                                ----------------                                                                                                                    
      Manifest   1.0        myDSCResources               
    
      > (Get-DscResource -Name bnNssmService).Properties
    
      Name                  PropertyType   IsMandatory Values           
      ----                  ------------   ----------- ------           
      NssmPath              [string]              True {}               
      ServiceName           [string]              True {}               
      DependsOn             [string[]]           False {}               
      Ensure                [string]             False {Absent, Present}
      PsDscRunAsCredential  [PSCredential]       False {}               
      ServiceAdditionalArgs [string]             False {}               
      ServicePath           [string]             False {}               
      ServiceStartCondition [string]             False {}               
      ServiceStopAction     [string]             False {}  
    

Using Your New Resource

Import the module containing your new resource into a DSC script and then simply use the new resource within the “Node” section.

Import-DscResource -ModuleName 'myDSCResources'

bnNssmService Unison
{
    NssmPath="C:\Unison\nssm-2.23\win64\nssm.exe"
    ServiceName="Unison"
    Ensure="Present"
    ServiceAdditionalArgs="-socket 874"
    ServicePath="C:\Unison\unison.exe"
    ServiceStartCondition="SERVICE_DEMAND_START"
    ServiceStopAction="Exit"
}

Further Info

Some of the references used in building my first resource:

Gotchas

Resources Not On Target Node

A DSC resource needs to be copied to a target host before it can be used. If you are using WMF 5.0 (Windows 8.1/Server 2012 r2 have WMF 4.0 pre-installed by default) and you use a library available from the PowerShell Gallery, then PowerShellGet should retrieve any PowerShell Gallery modules that you use almost automagically. Why ‘almost’? That’s because you need to install ‘‘‘nuget-anycpu.exe’’’ on the target node first. That can be accomplished by

Get-PackageProvider -Name NuGet -ForceBootstrap

If you are using WMF 4.0 or a custom resource, then you will need to copy the module to the target host manually. We are using Group Policy to pre-stage everything needed for our DSC configuration to the ‘‘‘C:\DSC’’’ folder on each target node. But you could, for example use a DSC script to pre-stage a target host, for example: Configuration PreStageIisWebServer { Import-DscResource –ModuleName ’PSDesiredStateConfiguration’

    Node "MyWebServer"
    {
     
        File bnDSCModuleReplace
        {
            SourcePath = "\\win2k12r2-dc1\dsc$\myDSCResources"
            DestinationPath = "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\myDSCResources"
            Recurse = $true
            Type = "Directory"
            Force= $true
            Ensure="Present"
        }        
    }
}
Set-Location -Path "D:\Code\infrastructure\Scripts\DesiredStateConfiguration\ManagedObjectFiles"
PreStageIisWebServer

Note that the source path needs to be a network share that the machine account on the target host has access too. See the “DSC Runs Under Local System Account” gotcha.

DSC Runs Under Local System Account

When DSC is applied to a target host, it runs on the target host under the local system account. This can make things like accessing network shares problematic without some pre-configuration. In order for DSC running on a target node to access a network share, you will need need to give the target hosts machine account the relevant permissions on that share. You can accomplish this from the command line on the server (or remotely via winrs or PsExec) as follows:

net share MyFolder=d:\dsc\staging /GRANT:&gt;domain name&lt;\&gt;machine name&lt;$,READ

Where >domain name< and >machine name< are subsituted for your Domain and your DSC target computer name.

The PSDesiredStateConfiguration File Resource

Does not copy files from source to destination when the source files already exist at the target location. Even if the source files have changed.

Exception Handling

In my experience so far, non-terminating powershell errors can turn into fugly uncaught exceptions. Especially when using Test-TargetResource within a custom resource and the test involves an unavoidable exception when the test fails. Either use $ErrorActionPreference="Stop" and handle the logic within a try-catch or use $ErrorActionPreference="SilentlyContinue" (N.B. once you have executed the potentially failing statements, you may want to set $ErrorActionPreference back to it’s original value.

References