{"id":1441,"date":"2014-11-18T12:17:00","date_gmt":"2014-11-18T12:17:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2014\/11\/18\/powershell-dsc-resource-design-and-testing-checklist\/"},"modified":"2019-02-18T13:05:11","modified_gmt":"2019-02-18T20:05:11","slug":"powershell-dsc-resource-design-and-testing-checklist","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/powershell-dsc-resource-design-and-testing-checklist\/","title":{"rendered":"PowerShell DSC Resource Design and Testing Checklist"},"content":{"rendered":"\n<div class=\"WordSection1\">\n<p class=\"MsoTitle\">DSC Resource Design and Testing Checklist<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">Writing Desired State Configuration Resources is not trivial and there\u2019s many things which can go wrong. You should always spend significant amount of time testing resources you create. This task, although critical for quality, is often overlooked or performed carelessly and insufficiently. Below you can find <b>DSC Resource Design and Testing Checklist<\/b> which will help you design the resource and identify critical areas for testing. Follow it the next time you want to verify quality of your resource and check whether it adheres to DSC best practices. <\/p>\n<p class=\"MsoTocHeading\">&#160;<\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056085\">1<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource module contains .psd1 file and schema.mof for every resource<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056086\">2<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource and schema are correct and have been verified using DscResourceDesigner cmdlets<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056087\">3<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource loads without errors<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056106\">4<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource is idempotent in the positive case<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056107\">5<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>User modification scenario was tested<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056114\">6<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Get-TargetResource functionality was verified using Get-DscConfiguration<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056115\">7<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource was verified by calling Get\/Set\/Test-TargetResource functions directly<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056116\">8<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource was verified End to End using Start-DscConfiguration<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056117\">9<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource behaves correctly on all DSC supported platforms (or returns a specific error otherwise)<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056118\">10<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource functionality was verified on Windows Client (if applicable)<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056119\">11<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Get-DSCResource lists the resource<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056121\">12<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource module contains examples<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056122\">13<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Error messages are easy to understand and help users solve problems<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056123\">14<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Log messages are easy to understand and informative (including \u2013verbose, \u2013debug and ETW logs)<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056124\">15<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource implementation does not contain hardcoded paths<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056125\">16<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource implementation does not contain user information<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056126\">17<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource was tested with valid\/invalid credentials<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056127\">18<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource is not using cmdlets requiring interactive input<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056132\">19<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Resource functionality was thoroughly tested<span style=\"text-decoration: none;color: windowtext\">&#160;&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056133\">20<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Best practice: Resource module contains Tests folder with ResourceDesignerTests.ps1 script<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056134\">21<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Best practice: Resource folder contains resource designer script for generating schema<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoToc1\"><a href=\"#_Toc410056135\">22<span style=\"text-decoration: none;color: windowtext\">&#160;&#160;&#160;&#160; <\/span>Best practice: Resource supports -whatif<span style=\"text-decoration: none;color: windowtext\">&#160; <\/span><span style=\"text-decoration: none;color: windowtext\">1<\/span><\/a><\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056085\">1<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource module contains .psd1 file and schema.mof for every resource<\/a> <\/h2>\n<p class=\"MsoNormal\">The first think you should do is to check that your resource has correct structure and contains all required files. Every resource module should contain a .psd1 file and every non-composite resource should have schema.mof file. Resources that do not contain schema will not be listed by Get-DscResource and users will not be able to use the intellisense when writing code against those modules in ISE. <\/p>\n<p class=\"MsoNormal\">The sample directory structure for xRemoteFile resource, which is part of the xPSDesiredStateConfiguration resource module, could look as follows:<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">xPSDesiredStateConfiguration<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DSCResources<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; MSFT_xRemoteFile<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; MSFT_xRemoteFile.psm1<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; MSFT_xRemoteFile.schema.mof<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Examples<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xRemoteFile_DownloadFile.ps1<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ResourceDesignerScripts<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; GenerateXRemoteFileSchema.ps1<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Tests<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ResourceDesignerTests.ps1<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xPSDesiredStateConfiguration.psd1<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">If you don\u2019t quite understand what every single item on this list is for, keep reading \u2013 I\u2019ll explain it in the sections below. <\/p>\n<h2><a name=\"_Toc410056086\">2<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource and schema are correct and have been verified using DscResourceDesigner cmdlets<\/a><\/h2>\n<p class=\"MsoNormal\">Another important aspect is verifying the resource schema (*.schema.mof) file. <\/p>\n<p class=\"MsoNormal\">Make sure that:<\/p>\n<p class=\"MsoListParagraphCxSpFirst\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Property types are correct (e.g. don\u2019t use String for properties which accept numeric values, you should use UInt32 or other numeric types instead)<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Property attributes are specified correctly ([key], [required], [write], [read])<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-left: 1in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>At least one parameter in the schema has to be marked as [key]<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-left: 1in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>[read] property cannot coexist together with any of: [required], [key], [write]<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-left: 1in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>If multiple qualifiers are specified except [read], then [key] takes precedence<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-left: 1in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>If [write] and [required] are specified, then [required] takes precedence<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>ValueMap is specified where appropriate<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-bottom: 0pt;background: white;line-height: normal\">&#160;<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-bottom: 0pt;background: white;line-height: normal\">Example:<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>[Read, ValueMap{&quot;Present&quot;, &quot;Absent&quot;}, Values{&quot;Present&quot;, &quot;Absent&quot;}, Description(&quot;Says whether DestinationPath exists on the machine&quot;)] String Ensure;<\/span><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Friendly name is specified and confirms to DSC naming conventions<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-bottom: 0pt;background: white;line-height: normal\">&#160;<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-bottom: 0pt;background: white;line-height: normal\">Example: <\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>[ClassVersion(&quot;1.0.0.0&quot;), FriendlyName(&quot;xRemoteFile&quot;)]<\/span><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"MsoListParagraphCxSpLast\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Every field has meaningful description<\/p>\n<p class=\"MsoNormal\">Below you can find a good example of the resource schema file (this is the actual schema of xRemoteFile resource from the <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/DSC-Resource-Kit-All-c449312d\">DSC Resource Kit<\/a>)<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>[ClassVersion(&quot;1.0.0.0&quot;), FriendlyName(&quot;xRemoteFile&quot;)]<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>class MSFT_xRemoteFile : OMI_BaseResource<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>{<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; [Key, Description(&quot;Path under which downloaded or copied file should be accessible after operation.&quot;)] String DestinationPath;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; [Required, Description(&quot;Uri of a file which should be copied or downloaded. This parameter supports HTTP and HTTPS values.&quot;)] String Uri;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; [Write, Description(&quot;User agent for the web request.&quot;)] String UserAgent;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; [Write, EmbeddedInstance(&quot;MSFT_KeyValuePair&quot;), Description(&quot;Headers of the web request.&quot;)] String Headers[];<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; [Write, EmbeddedInstance(&quot;MSFT_Credential&quot;), Description(&quot;Specifies a user account that has permission to send the request.&quot;)] String Credential;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; [Read, ValueMap{&quot;Present&quot;, &quot;Absent&quot;}, Values{&quot;Present&quot;, &quot;Absent&quot;}, Description(&quot;Says whether DestinationPath exists on the machine&quot;)] String Ensure;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>}; <\/span><\/p>\n<p class=\"MsoListParagraph\">&#160;<\/p>\n<p class=\"MsoNormal\">Additionally, you should use Test-xDscResource and Test-xDscSchema cmdlets from <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/xDscResourceDesigne-Module-22eddb29\">Dsc Resource Designer<\/a> to automatically verify the resource and schema:<\/p>\n<p class=\"MsoListParagraphCxSpFirst\">Test-xDscResource &lt;Resource_folder&gt;<\/p>\n<p class=\"MsoListParagraphCxSpLast\">Test-xDscSchema &lt;Path_to_resource_schema_file&gt;<\/p>\n<p class=\"MsoNormal\">For example:<\/p>\n<p class=\"MsoNormal\" style=\"text-indent: 0.5in\">Test-xDscResource ..\\DSCResources\\MSFT_xRemoteFile<\/p>\n<p class=\"MsoNormal\" style=\"text-indent: 0.5in\">Test-xDscSchema ..\\DSCResources\\MSFT_xRemoteFile\\MSFT_xRemoteFile.schema.mof<\/p>\n<p class=\"MsoNormal\"><a name=\"_Toc398132608\"><\/a><a name=\"_Toc400031762\"><\/a><a name=\"_Toc400033392\"><\/a><a name=\"_Toc400033425\"><\/a><a name=\"_Toc400092567\"><\/a><a name=\"_Toc400092647\"><\/a><a name=\"_Toc400092827\"><\/a><a name=\"_Toc400092932\"><\/a><a name=\"_Toc400092985\"><\/a><a name=\"_Toc400093120\"><\/a><a name=\"_Toc400960527\"><\/a>&#160;<\/p>\n<h2><a name=\"_Toc410056087\">3<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource loads without errors<\/a><\/h2>\n<p class=\"MsoNormal\" style=\"line-height: 115%\">Once you verified that resource contains all necessary files and verified them using DSC Resource Designer, it\u2019s time to check whether resource module can be successfully loaded.<\/p>\n<p class=\"MsoNormal\" style=\"line-height: 115%\">You can do it either manually, by running <span>Import-Module<\/span><span> <span style=\"color: darkgray\">&lt;<\/span><span style=\"color: blueviolet\">resource_module&gt;<\/span> <span style=\"color: navy\">-force <\/span><\/span>and confirming that no errors occurred, or by writing test automation. In case of the latter, you can follow this structure in your test case:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: 115%\"><span>$error<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$null<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: 115%\"><span>Import-Module<\/span><span> <span style=\"color: darkgray\">&lt;<\/span><span style=\"color: blueviolet\">resource_module&gt; <\/span><span style=\"color: navy\">\u2013force<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: 115%\"><span>If<\/span><span> (<span style=\"color: orangered\">$error<\/span><span style=\"color: darkgray\">.<\/span>count <span style=\"color: darkgray\">\u2013ne<\/span> <span style=\"color: purple\">0<\/span>) {<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: 115%\"><span>&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkblue\">Throw<\/span> <span style=\"color: darkred\">\u201cModule was not imported correctly. Errors returned: <\/span><span style=\"color: orangered\">$error<\/span><span style=\"color: darkred\">\u201d<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/span><\/p>\n<p class=\"MsoNormal\"><a name=\"_Toc389473260\"><\/a><a name=\"_Toc389473658\"><\/a><a name=\"_Toc389473815\"><\/a><a name=\"_Toc389473261\"><\/a><a name=\"_Toc389473659\"><\/a><a name=\"_Toc389473816\"><\/a>&#160;<\/p>\n<h2><a name=\"_Toc410056106\"><\/a><a name=\"_Toc389474067\"><\/a><a name=\"_Toc389474236\"><\/a><a name=\"_Toc391043269\"><\/a><a name=\"_Toc398132612\"><\/a><a name=\"_Toc400031766\"><\/a><a name=\"_Toc400033396\"><\/a><a name=\"_Toc400033429\"><\/a><a name=\"_Toc400092571\"><\/a><a name=\"_Toc400092651\"><\/a><a name=\"_Toc400092831\"><\/a><a name=\"_Toc400092934\"><\/a><a name=\"_Toc400092987\"><\/a><a name=\"_Toc400093122\"><\/a><a name=\"_Toc400960529\"><\/a><a name=\"_Toc401572892\"><\/a><a name=\"_Toc410056088\"><\/a><a name=\"_Toc400092652\"><\/a><a name=\"_Toc400092832\"><\/a><a name=\"_Toc400092935\"><\/a><a name=\"_Toc400092988\"><\/a><a name=\"_Toc400093123\"><\/a><a name=\"_Toc400960530\"><\/a><a name=\"_Toc401572893\"><\/a><a name=\"_Toc410056089\"><\/a><a name=\"_Toc400092653\"><\/a><a name=\"_Toc400092833\"><\/a><a name=\"_Toc400092936\"><\/a><a name=\"_Toc400092989\"><\/a><a name=\"_Toc400093124\"><\/a><a name=\"_Toc400960531\"><\/a><a name=\"_Toc401572894\"><\/a><a name=\"_Toc410056090\"><\/a><a name=\"_Toc400092654\"><\/a><a name=\"_Toc400092834\"><\/a><a name=\"_Toc400092937\"><\/a><a name=\"_Toc400092990\"><\/a><a name=\"_Toc400093125\"><\/a><a name=\"_Toc400960532\"><\/a><a name=\"_Toc401572895\"><\/a><a name=\"_Toc410056091\"><\/a><a name=\"_Toc400092655\"><\/a><a name=\"_Toc400092835\"><\/a><a name=\"_Toc400092938\"><\/a><a name=\"_Toc400092991\"><\/a><a name=\"_Toc400093126\"><\/a><a name=\"_Toc400960533\"><\/a><a name=\"_Toc401572896\"><\/a><a name=\"_Toc410056092\"><\/a><a name=\"_Toc400092656\"><\/a><a name=\"_Toc400092836\"><\/a><a name=\"_Toc400092939\"><\/a><a name=\"_Toc400092992\"><\/a><a name=\"_Toc400093127\"><\/a><a name=\"_Toc400960534\"><\/a><a name=\"_Toc401572897\"><\/a><a name=\"_Toc410056093\"><\/a><a name=\"_Toc400092657\"><\/a><a name=\"_Toc400092837\"><\/a><a name=\"_Toc400092940\"><\/a><a name=\"_Toc400092993\"><\/a><a name=\"_Toc400093128\"><\/a><a name=\"_Toc400960535\"><\/a><a name=\"_Toc401572898\"><\/a><a name=\"_Toc410056094\"><\/a><a name=\"_Toc400092658\"><\/a><a name=\"_Toc400092838\"><\/a><a name=\"_Toc400092941\"><\/a><a name=\"_Toc400092994\"><\/a><a name=\"_Toc400093129\"><\/a><a name=\"_Toc400960536\"><\/a><a name=\"_Toc401572899\"><\/a><a name=\"_Toc410056095\"><\/a><a name=\"_Toc400092659\"><\/a><a name=\"_Toc400092839\"><\/a><a name=\"_Toc400092942\"><\/a><a name=\"_Toc400092995\"><\/a><a name=\"_Toc400093130\"><\/a><a name=\"_Toc400960537\"><\/a><a name=\"_Toc401572900\"><\/a><a name=\"_Toc410056096\"><\/a><a name=\"_Toc400092660\"><\/a><a name=\"_Toc400092840\"><\/a><a name=\"_Toc400092943\"><\/a><a name=\"_Toc400092996\"><\/a><a name=\"_Toc400093131\"><\/a><a name=\"_Toc400960538\"><\/a><a name=\"_Toc401572901\"><\/a><a name=\"_Toc410056097\"><\/a><a name=\"_Toc400092661\"><\/a><a name=\"_Toc400092841\"><\/a><a name=\"_Toc400092944\"><\/a><a name=\"_Toc400092997\"><\/a><a name=\"_Toc400093132\"><\/a><a name=\"_Toc400960539\"><\/a><a name=\"_Toc401572902\"><\/a><a name=\"_Toc410056098\"><\/a><a name=\"_Toc400092662\"><\/a><a name=\"_Toc400092842\"><\/a><a name=\"_Toc400092945\"><\/a><a name=\"_Toc400092998\"><\/a><a name=\"_Toc400093133\"><\/a><a name=\"_Toc400960540\"><\/a><a name=\"_Toc401572903\"><\/a><a name=\"_Toc410056099\"><\/a><a name=\"_Toc400092663\"><\/a><a name=\"_Toc400092843\"><\/a><a name=\"_Toc400092946\"><\/a><a name=\"_Toc400092999\"><\/a><a name=\"_Toc400093134\"><\/a><a name=\"_Toc400960541\"><\/a><a name=\"_Toc401572904\"><\/a><a name=\"_Toc410056100\"><\/a><a name=\"_Toc400092664\"><\/a><a name=\"_Toc400092844\"><\/a><a name=\"_Toc400092947\"><\/a><a name=\"_Toc400093000\"><\/a><a name=\"_Toc400093135\"><\/a><a name=\"_Toc400960542\"><\/a><a name=\"_Toc401572905\"><\/a><a name=\"_Toc410056101\"><\/a><a name=\"_Toc400092668\"><\/a><a name=\"_Toc400092848\"><\/a><a name=\"_Toc400092951\"><\/a><a name=\"_Toc400093004\"><\/a><a name=\"_Toc400093139\"><\/a><a name=\"_Toc400960546\"><\/a><a name=\"_Toc401572909\"><\/a><a name=\"_Toc410056105\"><\/a>4<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource is idempotent in the positive case <\/h2>\n<p class=\"MsoNormal\">One of the fundamental characteristics of every DSC resource should be idempotence. It means that we can apply a DSC configuration containing that resource multiple times without changing the result beyond the initial application. For example, if we create a configuration which contains the following File resource:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>File<\/span><span> <span style=\"color: blueviolet\">file<\/span> {<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160; <span style=\"color: blue\">DestinationPath<\/span> <span style=\"color: blueviolet\">=<\/span> <span style=\"color: darkred\">&quot;C:\\test\\test.txt&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160; <span style=\"color: blue\">Contents<\/span> <span style=\"color: blueviolet\">=<\/span> <span style=\"color: darkred\">&quot;Sample text&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>} <\/span><\/p>\n<p class=\"MsoNormal\">After applying it for the first time, file test.txt should appear in C:\\test folder. However, subsequent runs of the same configuration should not change the state of the machine (e.g. no copies of the test.txt file should be created).<\/p>\n<p class=\"MsoNormal\">To ensure our resource is idempotent we can repeatedly call Set-TargetResource when testing the resource directly, or call Start-DscConfiguration multiple times when doing end to end testing. The result should be the same after every run. <\/p>\n<h2><a name=\"_Toc410056107\">5<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>User modification scenario was tested<\/a><\/h2>\n<p class=\"MsoNormal\">User modification is another common scenario worth testing out. It helps you verify that Set-TargetResource and Test-TargetResource function properly. Here are steps you should take to test it:<\/p>\n<p class=\"MsoListParagraph\" style=\"text-indent: -0.25in\">1.<span>&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Start with the resource not in the desired state.<\/p>\n<ol style=\"margin-top: 0in\" type=\"1\">\n<li class=\"MsoNormal\">Run configuration with your resource <\/li>\n<li class=\"MsoNormal\">Verify Test-DscConfiguration returns True <\/li>\n<li class=\"MsoNormal\">Modify the resource out of the desired state <\/li>\n<li class=\"MsoNormal\">Verify Test-DscConfiguration returns false <\/li>\n<\/ol>\n<p class=\"MsoNormal\">Here\u2019s a more concrete example using Registry resource:<\/p>\n<p class=\"MsoListParagraph\" style=\"text-indent: -0.25in\">1.<span>&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Start with registry key not in the desired state<\/p>\n<ol style=\"margin-top: 0in\" type=\"1\">\n<li class=\"MsoNormal\">Run Start-DscConfiguration with a configuration to put it in the desired state and verify it passes. <\/li>\n<li class=\"MsoNormal\">Run Test-DscConfiguration and verify it returns true <\/li>\n<li class=\"MsoNormal\">Modify the value of the key so that it is not in the desired state <\/li>\n<li class=\"MsoNormal\">Run Test-DscConfiguration and verify it returns false <\/li>\n<\/ol>\n<p class=\"MsoNormal\"><a name=\"_Toc389473265\"><\/a>&#160;<\/p>\n<h2><a name=\"_Toc410056114\"><\/a><a name=\"_Toc389474240\"><\/a><a name=\"_Toc391043273\"><\/a><a name=\"_Toc398132616\"><\/a><a name=\"_Toc400031770\"><\/a><a name=\"_Toc400033400\"><\/a><a name=\"_Toc400033433\"><\/a><a name=\"_Toc400092575\"><\/a><a name=\"_Toc400092671\"><\/a><a name=\"_Toc400092851\"><\/a><a name=\"_Toc400092954\"><\/a><a name=\"_Toc400093007\"><\/a><a name=\"_Toc400093142\"><\/a><a name=\"_Toc400960549\"><\/a><a name=\"_Toc401572912\"><\/a><a name=\"_Toc410056108\"><\/a><a name=\"_Toc388445122\"><\/a><a name=\"_Toc388605141\"><\/a><a name=\"_Toc389474241\"><\/a><a name=\"_Toc391043274\"><\/a><a name=\"_Toc398132617\"><\/a><a name=\"_Toc400031771\"><\/a><a name=\"_Toc400033401\"><\/a><a name=\"_Toc400033434\"><\/a><a name=\"_Toc400092576\"><\/a><a name=\"_Toc400092672\"><\/a><a name=\"_Toc400092852\"><\/a><a name=\"_Toc400092955\"><\/a><a name=\"_Toc400093008\"><\/a><a name=\"_Toc400093143\"><\/a><a name=\"_Toc400960550\"><\/a><a name=\"_Toc401572913\"><\/a><a name=\"_Toc410056109\"><\/a><a name=\"_Toc388445123\"><\/a><a name=\"_Toc388605142\"><\/a><a name=\"_Toc389474242\"><\/a><a name=\"_Toc391043275\"><\/a><a name=\"_Toc398132618\"><\/a><a name=\"_Toc400031772\"><\/a><a name=\"_Toc400033402\"><\/a><a name=\"_Toc400033435\"><\/a><a name=\"_Toc400092577\"><\/a><a name=\"_Toc400092673\"><\/a><a name=\"_Toc400092853\"><\/a><a name=\"_Toc400092956\"><\/a><a name=\"_Toc400093009\"><\/a><a name=\"_Toc400093144\"><\/a><a name=\"_Toc400960551\"><\/a><a name=\"_Toc401572914\"><\/a><a name=\"_Toc410056110\"><\/a><a name=\"_Toc388445124\"><\/a><a name=\"_Toc388605143\"><\/a><a name=\"_Toc389474243\"><\/a><a name=\"_Toc391043276\"><\/a><a name=\"_Toc398132619\"><\/a><a name=\"_Toc400031773\"><\/a><a name=\"_Toc400033403\"><\/a><a name=\"_Toc400033436\"><\/a><a name=\"_Toc400092578\"><\/a><a name=\"_Toc400092674\"><\/a><a name=\"_Toc400092854\"><\/a><a name=\"_Toc400092957\"><\/a><a name=\"_Toc400093010\"><\/a><a name=\"_Toc400093145\"><\/a><a name=\"_Toc400960552\"><\/a><a name=\"_Toc401572915\"><\/a><a name=\"_Toc410056111\"><\/a><a name=\"_Resource_was_verified\"><\/a><a name=\"_Toc389474244\"><\/a><a name=\"_Toc391043277\"><\/a><a name=\"_Toc398132620\"><\/a><a name=\"_Toc400031774\"><\/a><a name=\"_Toc400033404\"><\/a><a name=\"_Toc400033437\"><\/a><a name=\"_Toc400092579\"><\/a><a name=\"_Toc400092675\"><\/a><a name=\"_Toc400092855\"><\/a><a name=\"_Toc400092958\"><\/a><a name=\"_Toc400093011\"><\/a><a name=\"_Toc400093146\"><\/a><a name=\"_Toc400960553\"><\/a><a name=\"_Toc401572916\"><\/a><a name=\"_Toc410056112\"><\/a><a name=\"_Toc389474245\"><\/a><a name=\"_Toc391043278\"><\/a><a name=\"_Toc398132621\"><\/a><a name=\"_Toc400031775\"><\/a><a name=\"_Toc400033405\"><\/a><a name=\"_Toc400033438\"><\/a><a name=\"_Toc400092580\"><\/a><a name=\"_Toc400092676\"><\/a><a name=\"_Toc400092856\"><\/a><a name=\"_Toc400092959\"><\/a><a name=\"_Toc400093012\"><\/a><a name=\"_Toc400093147\"><\/a><a name=\"_Toc400960554\"><\/a><a name=\"_Toc401572917\"><\/a><a name=\"_Toc410056113\"><\/a><a name=\"_Resource_was_verified_1\"><\/a>6<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Get-TargetResource functionality was verified using Get-DscConfiguration<\/h2>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">Get-TargetResource should return details of the current state of the resource. Make sure you test it by calling Get-DscConfiguration after you apply the configuration and verifying that output correctly reflects the current state of the machine. It&#8217;s important to test it separately, since any issues in this area won&#8217;t appear when calling Start-DscConfiguration.<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056115\"><\/a><a name=\"_Resource_was_verified_2\"><\/a>7<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource was verified by calling Get\/Set\/Test-TargetResource functions directly<\/h2>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">Make sure you test the Get\/Set\/Test-TargetResource functions implemented in your resource by calling them directly and verifying that they work as expected.<\/p>\n<h2><a name=\"_Toc410056116\">8<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource was verified End to End using Start-DscConfiguration<\/a><\/h2>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">Testing Get\/Set\/Test-TargetResource functions by calling them directly is important, but not all issues will be discovered this way. You should focus significant part of your testing on using Start-DscConfiguration or the pull server. In fact, this is how users will use the resource, so don\u2019t underestimate the significance of this type of tests. <\/p>\n<p class=\"MsoNormal\">Possible types of issues:<\/p>\n<p class=\"MsoListParagraphCxSpFirst\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Credential\/Session may behave differently because the DSC agent runs as a service.&#160; Be sure to test any features here end to end.<\/p>\n<p class=\"MsoListParagraphCxSpLast\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Verify error messages displayed by the resource make sense. For example, errors outputted by Start-DscConfiguration may be different than those displayed when calling the Set-TargetResource function directly.<\/p>\n<h2><a name=\"_Toc410056117\">9<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Resource behaves correctly on all DSC supported platforms (or returns a specific error otherwise)<\/a><\/h2>\n<p class=\"MsoNormal\">Resource should work on all DSC supported platforms (Windows Server 2008 R2 and newer). Make sure you install latest WMF (Windows Management Framework) on your OS to get the latest version of DSC. If resource by-design does not work on some of these platforms, a specific error message should be returned. Also, make sure your resource checks whether cmdlets you are calling are present on particular machine. Windows Server 2012 added a large number of new cmdlets that are not available on Windows Server 2008R2, even with WMF installed. <\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056118\">10<span>&#160;&#160;&#160; <\/span>Resource functionality was verified on Windows Client (if applicable)<\/a><\/h2>\n<p class=\"MsoNormal\">One very common test gap is verifying the resource only on server versions of Windows. Many resources are also designed to work on Client SKUs, so if that\u2019s true in your case, don\u2019t forget to test it on those platforms as well. <\/p>\n<h2><a name=\"_Toc410056119\">11<span>&#160;&#160;&#160; <\/span>Get-DSCResource lists the resource<\/a><\/h2>\n<p class=\"MsoNormal\">After deploying the module on the machine, calling Get-DscResource should list your resource among others as a result. If you can\u2019t find your resource in the list, make sure that schema.mof file for that resource exists. <\/p>\n<h2><a name=\"_Toc410056121\"><\/a><a name=\"_Toc389473668\"><\/a><a name=\"_Toc389473826\"><\/a><a name=\"_Toc389474077\"><\/a><a name=\"_Toc389474250\"><\/a><a name=\"_Toc391043283\"><\/a><a name=\"_Toc398132626\"><\/a><a name=\"_Toc400031779\"><\/a><a name=\"_Toc400033409\"><\/a><a name=\"_Toc400033442\"><\/a><a name=\"_Toc400092584\"><\/a><a name=\"_Toc400092681\"><\/a><a name=\"_Toc400092863\"><\/a><a name=\"_Toc400092968\"><\/a><a name=\"_Toc400093021\"><\/a><a name=\"_Toc400093156\"><\/a><a name=\"_Toc400960563\"><\/a><a name=\"_Toc401572924\"><\/a><a name=\"_Toc410056120\"><\/a>12<span>&#160;&#160;&#160; <\/span>Resource module contains examples<\/h2>\n<p class=\"MsoNormal\">If you intend to share the resource (which you hopefully do), creating quality examples which will help others understand how to use it. This is crucial, especially since many users treat sample code as documentation. <\/p>\n<p class=\"MsoListParagraph\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>First, you should determine the examples that will be included with the module \u2013 at minimum, you should cover most important use cases for your resource:<\/p>\n<ul type=\"disc\">\n<ul type=\"circle\">\n<li class=\"MsoNormal\" style=\"line-height: normal\">If your module contains several resources that need to work together for an end-to-end scenario, the basic end-to-end example would ideally be first. <\/li>\n<li class=\"MsoNormal\" style=\"line-height: normal\">The initial examples should be very simple &#8212; how to get started with your resources in small manageable chunks (e.g. creating a new VHD) <\/li>\n<li class=\"MsoNormal\" style=\"line-height: normal\">Subsequent examples should build on those examples (e.g. creating a VM from a VHD, removing VM, modifying VM), and show advanced functionality (e.g. creating a VM with dynamic memory) <\/li>\n<\/ul>\n<\/ul>\n<p class=\"MsoListParagraph\" style=\"line-height: normal;text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Example configurations should be parameterized (all values should be passed to the configuration as parameters and there should be no hardcoded values):<\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>configuration<\/span><span> <span style=\"color: blueviolet\">Sample_xRemoteFile_DownloadFile<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>{<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; <span style=\"color: darkblue\">param<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; (<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: teal\">string<\/span><span style=\"color: darkgray\">[]]<\/span> <span style=\"color: orangered\">$nodeName<\/span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: darkred\">&#8216;localhost&#8217;<\/span><span style=\"color: darkgray\">,<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: deepskyblue\">parameter<\/span>(Mandatory <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$true<\/span>)<span style=\"color: darkgray\">]<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: deepskyblue\">ValidateNotNullOrEmpty<\/span>()<span style=\"color: darkgray\">]<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: teal\">String<\/span><span style=\"color: darkgray\">]<\/span> <span style=\"color: orangered\">$destinationPath<\/span><span style=\"color: darkgray\">,<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: deepskyblue\">parameter<\/span>(Mandatory <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$true<\/span>)<span style=\"color: darkgray\">]<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: deepskyblue\">ValidateNotNullOrEmpty<\/span>()<span style=\"color: darkgray\">]<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: teal\">String<\/span><span style=\"color: darkgray\">]<\/span> <span style=\"color: orangered\">$uri<\/span><span style=\"color: darkgray\">,<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: teal\">String<\/span><span style=\"color: darkgray\">]<\/span> <span style=\"color: orangered\">$userAgent<\/span><span style=\"color: darkgray\">,<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: darkgray\">[<\/span><span style=\"color: teal\">Hashtable<\/span><span style=\"color: darkgray\">]<\/span> <span style=\"color: orangered\">$headers<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; )<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; <span style=\"color: blue\">Import-DscResource<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">MSFT_xRemoteFile<\/span> <span style=\"color: navy\">-ModuleName<\/span> <span style=\"color: blueviolet\">xPSDesiredStateConfiguration<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; Node <span style=\"color: orangered\">$nodeName<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; {<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; xRemoteFile <span style=\"color: blueviolet\">DownloadFile<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DestinationPath <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$destinationPath<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Uri <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$uri<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; UserAgent <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$userAgent<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Headers <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$headers<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;&#160;&#160; }<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>} <\/span><\/p>\n<p class=\"MsoListParagraphCxSpFirst\" style=\"line-height: normal;text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>It\u2019s a good practice to include (commented out) example of how to call the configuration with the actual values at the end of the example script. <\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"line-height: normal\">For example, in the configuration above it won\u2019t be obvious for everyone that the best way to specify UserAgent is:<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"line-height: normal\">&#160;<\/p>\n<p class=\"MsoListParagraphCxSpLast\" style=\"margin-bottom: 0pt;background: white;line-height: normal;text-indent: 0.5in\"><span>UserAgent<\/span><span> <span style=\"color: blueviolet\">=<\/span> <span style=\"color: blueviolet\">[Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer<\/span>&#160; <\/span><\/p>\n<p class=\"MsoNormal\" style=\"line-height: normal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; That\u2019s why we should include comment with sample execution of the configuration:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span>&lt;# <\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>Sample use (parameter values need to be changed according to your scenario):<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>Sample_xRemoteFile_DownloadFile -destinationPath &quot;$env:SystemDrive\\fileName.jpg&quot; -uri &quot;http:\/\/www.contoso.com\/image.jpg&quot;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>Sample_xRemoteFile_DownloadFile -destinationPath &quot;$env:SystemDrive\\fileName.jpg&quot; -uri &quot;http:\/\/www.contoso.com\/image.jpg&quot; `<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>-userAgent [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer -headers @{&quot;Accept-Language&quot; = &quot;en-US&quot;}<\/span><\/p>\n<p class=\"MsoNormal\" style=\"background: white;margin: 0in 0in 0pt 1in;line-height: normal\"><span>#&gt;<\/span><span> <\/span>&#160;<\/p>\n<p class=\"MsoListParagraphCxSpFirst\" style=\"line-height: normal;text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>For each example, write a short description which explains what it does, and the meaning of the parameters. <\/p>\n<p class=\"MsoListParagraphCxSpLast\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Make sure examples cover most the important scenarios for your resource and if there\u2019s nothing missing, verify that they all execute and put machine in the desired state.&#160; <\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><a name=\"_Toc400031781\"><\/a><a name=\"_Toc400033411\"><\/a><a name=\"_Toc400033444\"><\/a><a name=\"_Toc400092586\"><\/a><a name=\"_Toc400092683\"><\/a><a name=\"_Toc400092865\"><\/a><a name=\"_Toc400092970\"><\/a><a name=\"_Toc400093023\"><\/a><a name=\"_Toc400093158\"><\/a><a name=\"_Toc400960565\"><\/a><a name=\"_Toc400031782\"><\/a><a name=\"_Toc400033412\"><\/a><a name=\"_Toc400033445\"><\/a><a name=\"_Toc400092587\"><\/a><a name=\"_Toc400092684\"><\/a><a name=\"_Toc400092866\"><\/a><a name=\"_Toc400092971\"><\/a><a name=\"_Toc400093024\"><\/a><a name=\"_Toc400093159\"><\/a><a name=\"_Toc400960566\"><\/a><span>&#160;<\/span><\/p>\n<h2><a name=\"_Toc410056122\">13<span>&#160;&#160;&#160; <\/span>Error messages are easy to understand and help users solve problems<\/a><\/h2>\n<p class=\"MsoNormal\">Good error messages should be:<\/p>\n<p class=\"MsoListParagraphCxSpFirst\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>There: The biggest problem with error messages is that they often don\u2019t exist, so make sure they are there <span style=\"font-family: wingdings\">J<\/span>.<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Easy to understand: Human readable, no obscure error codes<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Precise: Describe what\u2019s exactly the problem<\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Constructive: Advice how to fix the issue<\/p>\n<p class=\"MsoListParagraphCxSpLast\" style=\"text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Polite: Don\u2019t blame user or make them feel stupid<\/p>\n<p class=\"MsoNormal\">Make sure you verify errors in End to End scenarios (using Start-DscConfiguration), because they may differ from those returned when running resource functions directly. <\/p>\n<h2><a name=\"_Toc410056123\">14<span>&#160;&#160;&#160; <\/span>Log messages are easy to understand and informative (including \u2013verbose, \u2013debug and ETW logs)<\/a><\/h2>\n<p class=\"MsoNormal\">Ensure that logs outputted by the resource are easy to understand and provide value to the user. Resource should output all information which might be helpful to the user, but more logs is not always better. You should avoid redundancy and outputting data which does not provide additional value \u2013 don\u2019t make user go through hundreds of log entries in order to find what he\u2019s looking for. Of course, no logs is not an acceptable solution for this problem either ;). <\/p>\n<p class=\"MsoNormal\">When testing, you should also analyze verbose and debug logs (by running Start-DscConfiguration with \u2013verbose and \u2013debug switches appropriately), as well as ETW logs. To see DSC ETW logs, go to event viewer and open the following folder: Applications and Services-Microsoft-Windows-Desired State Configuration.&#160; By default there will be Operational channel, but make sure you enable Analytic and Debug channels (you have to do it before running the configuration). <\/p>\n<p class=\"MsoNormal\">To enable Analytic\/Debug channels, you can execute script below:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$statusEnabled<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">$true<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span># Use &quot;Analytic&quot; to enable Analytic channel<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$eventLogFullName<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: darkred\">&quot;Microsoft-Windows-Dsc\/Debug&quot;<\/span> <\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$commandToExecute<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: darkred\">&quot;wevtutil set-log <\/span><span style=\"color: orangered\">$eventLogFullName<\/span><span style=\"color: darkred\"> \/e:<\/span><span style=\"color: orangered\">$statusEnabled<\/span><span style=\"color: darkred\"> \/q:<\/span><span style=\"color: orangered\">$statusEnabled<\/span><span style=\"color: darkred\">&#160;&#160; &quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$log<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-Object<\/span> <span style=\"color: blueviolet\">System.Diagnostics.Eventing.Reader.EventLogConfiguration<\/span> <span style=\"color: orangered\">$eventLogFullName<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>if<\/span><span>(<span style=\"color: orangered\">$statusEnabled<\/span> <span style=\"color: darkgray\">-eq<\/span> <span style=\"color: orangered\">$log<\/span><span style=\"color: darkgray\">.<\/span>IsEnabled)<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>{<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160; <span style=\"color: blue\">Write-Host<\/span> <span style=\"color: navy\">-Verbose<\/span> <span style=\"color: darkred\">&quot;The channel event log is already enabled&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160; <span style=\"color: darkblue\">return<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>}&#160;&#160;&#160;&#160; <\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>Invoke-Expression<\/span><span> <span style=\"color: orangered\">$commandToExecute <\/span><\/span><\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056124\"><\/a><a name=\"_Toc410055779\">15<span>&#160;&#160;&#160; <\/span>Resource implementation does not contain hardcoded paths<\/a><\/h2>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;line-height: normal\"><span style=\"color: black\">Ensure there are no hardcoded paths in the resource implementation, particularly if they assume language (en-us), or when there are system variables that can be used.<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;line-height: normal\"><span style=\"color: black\">If your resource need to access specific path, use environment variables instead of hardcoding the path, as it may differ on other machines.<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;line-height: normal\"><span style=\"color: black\">&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;line-height: normal\"><span style=\"color: black\">Example:<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;line-height: normal\"><span style=\"color: black\">&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;line-height: normal\"><span style=\"color: black\">Instead of:<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal;text-indent: 0.5in\"><span>$tempPath<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: darkred\">&quot;C:\\Users\\kkaczma\\AppData\\Local\\Temp\\MyResource&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal;text-indent: 0.5in\"><span>$programFilesPath<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: darkred\">&quot;C:\\Program Files (x86)&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span style=\"color: black\">You can write:<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal;text-indent: 0.5in\"><span>$tempPath<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">Join-Path<\/span> <span style=\"color: orangered\">$env:temp<\/span> <span style=\"color: darkred\">&quot;MyResource&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal;text-indent: 0.5in\"><span>$programFilesPath<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: orangered\">${env:ProgramFiles(x86)} <\/span><\/span><\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056125\"><\/a><a name=\"_Toc410055780\">16<span>&#160;&#160;&#160; <\/span>Resource implementation does not contain user information<\/a><\/h2>\n<p class=\"MsoNormal\"><span style=\"color: black\">Make sure there are no email names, account information, or names of people in the code. This is a good practice for any code.<\/span><\/p>\n<h2><a name=\"_Toc410056126\">17<span>&#160;&#160;&#160; <\/span>Resource was tested with valid\/invalid credentials<\/a><\/h2>\n<p class=\"MsoNormal\">If your resource takes a credential as parameter:<\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.25in;text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Verify the resource works when Local System (or the computer account for remote resources) does not have access.<\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.25in;text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>Verify the resource works with a credential specified for Get, Set and Test <\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.25in;text-indent: -0.25in\">&#8211;<span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span>If your resource accesses shares, test all the variants you need to support.&#160; <\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.25in\">For example:<\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.75in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>Standard windows shares.<\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.75in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>DFS shares.<\/p>\n<p class=\"MsoNormal\" style=\"margin-left: 0.75in;text-indent: -0.25in\"><span>o<span>&#160;&#160; <\/span><\/span>SAMBA shares (if you want to support Linux.)<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056127\">18<span>&#160;&#160;&#160; <\/span>Resource is not using cmdlets requiring interactive input<\/a><\/h2>\n<h2>19<span>&#160;&#160;&#160; <\/span>Get\/Set\/Test-TargetResource functions should be executed automatically and must not wait for user\u2019s input at any stage of execution (e.g. you should not use Get-Credential inside these functions). If you need to provide user\u2019s input, you should pass it to the configuration as parameter during the compilation phase. <a name=\"_Toc410056132\"><\/a><a name=\"_Resource_module_contains\"><\/a><a name=\"_Toc400092872\"><\/a><a name=\"_Toc400092977\"><\/a><a name=\"_Toc400093030\"><\/a><a name=\"_Toc400093165\"><\/a><a name=\"_Toc400960572\"><\/a><a name=\"_Toc401572930\"><\/a><a name=\"_Toc410056128\"><\/a><a name=\"_Toc400031789\"><\/a><a name=\"_Toc400033419\"><\/a><a name=\"_Toc400033452\"><\/a><a name=\"_Toc400092594\"><\/a><a name=\"_Toc400092691\"><\/a><a name=\"_Toc400092873\"><\/a><a name=\"_Toc400092978\"><\/a><a name=\"_Toc400093031\"><\/a><a name=\"_Toc400093166\"><\/a><a name=\"_Toc400960573\"><\/a><a name=\"_Toc401572931\"><\/a><a name=\"_Toc410056129\"><\/a><a name=\"_Toc400092874\"><\/a><a name=\"_Toc400092979\"><\/a><a name=\"_Toc400093032\"><\/a><a name=\"_Toc400093167\"><\/a><a name=\"_Toc400960574\"><\/a><a name=\"_Toc401572932\"><\/a><a name=\"_Toc410056130\"><\/a><a name=\"_Toc400092875\"><\/a><a name=\"_Toc400092980\"><\/a><a name=\"_Toc400093033\"><\/a><a name=\"_Toc400093168\"><\/a><a name=\"_Toc400960575\"><\/a><a name=\"_Toc401572933\"><\/a><a name=\"_Toc410056131\"><\/a>Resource functionality was thoroughly tested<\/h2>\n<p class=\"MsoNormal\">You are responsible to make sure the resource is behaving correctly, so test its functionality manually or, better yet, write automation. This checklist contains items which are important to be tested and\/or are often missed. There will be bunch of tests, mainly functional ones which will be specific to the resource you are testing and are not mentioned here. Don\u2019t forget about negative test cases. <b>This will likely be the most time consuming part of the resource testing. <\/b><\/p>\n<h2><a name=\"_Toc410056133\">20<span>&#160;&#160;&#160; <\/span>Best practice: Resource module contains Tests folder with ResourceDesignerTests.ps1 script<\/a><\/h2>\n<p class=\"MsoNormal\">It\u2019s a good practice to create folder \u201cTests\u201d inside resource module, create ResourceDesignerTests.ps1 file and add there tests using Test-xDscResource and Test-xDscSchema for all resources in given module. <\/p>\n<p class=\"MsoNormal\">This way we can quickly validate schemas of all resources from given modules and do sanity check before publishing.<\/p>\n<p class=\"MsoNormal\">For xRemoteFile, ResourceTests.ps1 could look as simple as:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>Test-xDscResource<\/span><span> <span style=\"color: blueviolet\">..\\DSCResources\\MSFT_xRemoteFile<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>Test-xDscSchema<\/span><span> <span style=\"color: blueviolet\">..\\DSCResources\\MSFT_xRemoteFile\\MSFT_xRemoteFile.schema.mof <\/span><\/span><\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<h2><a name=\"_Toc410056134\">21<span>&#160;&#160;&#160; <\/span>Best practice: Resource folder contains resource designer script for generating schema<\/a><\/h2>\n<p class=\"MsoNormal\">Each resource should contain a resource designer script which generates a mof schema of the resource. This file should be placed in &lt;ResourceName&gt;\\ResourceDesignerScripts and be named Generate&lt;ResourceName&gt;Schema.ps1<\/p>\n<p class=\"MsoNormal\">For xRemoteFile resource this file would be called GenerateXRemoteFileSchema.ps1 and contain:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$DestinationPath<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">DestinationPath<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">String<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Key<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;Path under which downloaded or copied file should be accessible after operation.&#8217;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$Uri<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">Uri<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">String<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Required<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;Uri of a file which should be copied or downloaded. This parameter supports HTTP and HTTPS values.&#8217;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$Headers<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">Headers<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">Hashtable[]<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Write<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;Headers of the web request.&#8217;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$UserAgent<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">UserAgent<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">String<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Write<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;User agent for the web request.&#8217;<\/span> <\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$Ensure<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">Ensure<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">String<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Read<\/span> <span style=\"color: navy\">-ValidateSet<\/span> <span style=\"color: darkred\">&quot;Present&quot;<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: darkred\">&quot;Absent&quot;<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;Says whether DestinationPath exists on the machine&#8217;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$Credential<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">Credential<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">PSCredential<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Write<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;Specifies a user account that has permission to send the request.&#8217;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>$CertificateThumbprint<\/span><span> <span style=\"color: darkgray\">=<\/span> <span style=\"color: blue\">New-xDscResourceProperty<\/span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">CertificateThumbprint<\/span> <span style=\"color: navy\">-Type<\/span> <span style=\"color: blueviolet\">String<\/span> <span style=\"color: navy\">-Attribute<\/span> <span style=\"color: blueviolet\">Write<\/span> <span style=\"color: navy\">-Description<\/span> <span style=\"color: darkred\">&#8216;Digital public key certificate that is used to send the request.&#8217;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>New-xDscResource<\/span><span> <span style=\"color: navy\">-Name<\/span> <span style=\"color: blueviolet\">MSFT_xRemoteFile<\/span> <span style=\"color: navy\">-Property<\/span> @(<span style=\"color: orangered\">$DestinationPath<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: orangered\">$Uri<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: orangered\">$Headers<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: orangered\">$UserAgent<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: orangered\">$Ensure<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: orangered\">$Credential<\/span><span style=\"color: darkgray\">,<\/span> <span style=\"color: orangered\">$CertificateThumbprint<\/span>) <span style=\"color: navy\">-ModuleName<\/span> <span style=\"color: blueviolet\">xPSDesiredStateConfiguration2<\/span> <span style=\"color: navy\">-FriendlyName<\/span> <span style=\"color: blueviolet\">xRemoteFile<\/span> <\/span><\/p>\n<h2><a name=\"_Toc410056135\">22<span>&#160;&#160;&#160; <\/span>Best practice: Resource supports -whatif<\/a><\/h2>\n<p class=\"MsoNormal\">If your resource is performing \u201cdangerous\u201d operations, it\u2019s a good practice to implement -whatif functionality. After it\u2019s done, make sure that whatif output correctly describes operations which would happen if command was executed without whatif switch.<\/p>\n<p class=\"MsoNormal\">Also, verify that operations does not execute (no changes to the node\u2019s state are made) when \u2013whatif switch is present. <\/p>\n<p class=\"MsoNormal\">For example, let\u2019s assume we are testing File resource. Below is simple configuration which creates file \u201ctest.txt\u201d with contents \u201ctest\u201d:<\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>configuration<\/span><span> <span style=\"color: blueviolet\">config<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>{<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; node <span style=\"color: blueviolet\">localhost<\/span> <\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; {<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; File file<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Contents<span style=\"color: darkgray\">=<\/span><span style=\"color: darkred\">&quot;test&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DestinationPath<span style=\"color: darkgray\">=<\/span><span style=\"color: darkred\">&quot;C:\\test\\test.txt&quot;<\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>&#160;&#160;&#160;&#160;&#160;&#160; }<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>}<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin-bottom: 0pt;background: white;line-height: normal\"><span>config <\/span><\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">If we compile and then execute the configuration with the \u2013whatif switch, the output is telling us exactly what would happen when we run the configuration. The configuration itself however was not executed (test.txt file was not created).<\/p>\n<p class=\"MsoNormal\">&#160;<\/p>\n<p class=\"MsoNormal\">PS C:\\test&gt; Start-DscConfiguration -path .\\config -ComputerName localhost -wait -verbose -whatif<\/p>\n<p class=\"MsoNormal\">VERBOSE: Perform operation &#8216;Invoke CimMethod&#8217; with following parameters, &#8221;methodName&#8217; =<\/p>\n<p class=\"MsoNormal\">SendConfigurationApply,&#8217;className&#8217; = MSFT_DSCLocalConfigurationManager,&#8217;namespaceName&#8217; =<\/p>\n<p class=\"MsoNormal\">root\/Microsoft\/Windows\/DesiredStateConfiguration&#8217;.<\/p>\n<p class=\"MsoNormal\">VERBOSE: An LCM method call arrived from computer CHARLESX1 with user sid<\/p>\n<p class=\"MsoNormal\">S-1-5-21-397955417-626881126-188441444-5179871.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ Start&#160; Set&#160;&#160;&#160;&#160;&#160; ]<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ Start&#160; Resource ]&#160; [[File]file]<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ Start&#160; Test&#160;&#160;&#160;&#160; ]&#160; [[File]file]<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]:&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [[File]file] The system cannot find the file specified.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]:&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [[File]file] The related file\/directory is: C:\\test\\test.txt.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ End&#160;&#160;&#160; Test&#160;&#160;&#160;&#160; ]&#160; [[File]file]&#160; in 0.0270 seconds.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ Start&#160; Set&#160;&#160;&#160;&#160;&#160; ]&#160; [[File]file]<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]:&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [[File]file] The system cannot find the file specified.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]:&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [[File]file] The related file\/directory is: C:\\test\\test.txt.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]:&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [C:\\test\\test.txt] Creating and writing contents and setting attributes<\/p>\n<p class=\"MsoNormal\">.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ End&#160;&#160;&#160; Set&#160;&#160;&#160;&#160;&#160; ]&#160; [[File]file]&#160; in 0.0180 seconds.<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ End&#160;&#160;&#160; Resource ]&#160; [[File]file]<\/p>\n<p class=\"MsoNormal\">What if: [CHARLESX1]: LCM:&#160; [ End&#160;&#160;&#160; Set&#160;&#160;&#160;&#160;&#160; ]<\/p>\n<p class=\"MsoNormal\">VERBOSE: [CHARLESX1]: LCM:&#160; [ End&#160;&#160;&#160; Set&#160;&#160;&#160;&#160;&#160; ]&#160;&#160;&#160; in&#160; 0.1050 seconds.<\/p>\n<p class=\"MsoNormal\">VERBOSE: Operation &#8216;Invoke CimMethod&#8217; complete.<\/p>\n<p class=\"MsoNormal\" style=\"margin: 12pt 0in 0pt\">&#160;<\/p>\n<p class=\"MsoNormal\" style=\"margin: 12pt 0in 0pt\">&#160;<\/p>\n<p class=\"MsoNormal\">This wraps up our checklist. Please keep in mind that this list is not exhaustive, but it covers many important issues which we encountered while designing, developing and testing DSC resources. Having a checklist helps to ensure we didn\u2019t forget about any of those aspects and in fact, we use it at Microsoft when developing DSC resources ourselves. <\/p>\n<p class=\"MsoNormal\">If you developed guidelines and best practices which you use for writing and testing DSC resources, please share them in a comment.<\/p>\n<p class=\"MsoNormal\" style=\"margin: 12pt 0in 0pt\">&#160;<\/p>\n<p class=\"MsoNoSpacing\">Karol Kaczmarek<\/p>\n<p class=\"MsoNoSpacing\">PowerShell Team<\/p>\n<p class=\"MsoNoSpacing\">Microsoft<\/p>\n<\/p><\/div>\n<p>&#160;<\/p>\n<p>Last updated: January 26, 2015<\/p>\n","protected":false},"excerpt":{"rendered":"<p>DSC Resource Design and Testing Checklist &#160; Writing Desired State Configuration Resources is not trivial and there\u2019s many things which can go wrong. You should always spend significant amount of time testing resources you create. This task, although critical for quality, is often overlooked or performed carelessly and insufficiently. Below you can find DSC Resource [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[142,150,4,248,75,348],"class_list":["post-1441","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-desired-state-configuration","tag-dsc","tag-howto","tag-powershell","tag-testing","tag-windows-powershell-desired-state-configuration"],"acf":[],"blog_post_summary":"<p>DSC Resource Design and Testing Checklist &#160; Writing Desired State Configuration Resources is not trivial and there\u2019s many things which can go wrong. You should always spend significant amount of time testing resources you create. This task, although critical for quality, is often overlooked or performed carelessly and insufficiently. Below you can find DSC Resource [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/1441","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=1441"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/1441\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=1441"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=1441"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=1441"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}