<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Saving the World One Line of Code at a Time</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 04:08:13 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Extending Microsoft System Center Configuration Manager 2012 Package Conversion Manager.</title>
      <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/extending-microsoft-system-center-configuration-manager-2012-package-conversion-manager</link>
      <pubDate>Tue, 17 Jan 2012 18:06:00 GMT</pubDate>
      <dc:creator><![CDATA[sperniner]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/one_line_of_code_at_a_time/2012/01/17/extending-microsoft-system-center-configuration-manager-2012-package-conversion-manager/</guid>
      <description><![CDATA[Any great tool should have an extensibility story and System Center Configuration Manager 2012...]]></description>
      <content:encoded><![CDATA[<p><strong>Any great tool should have an extensibility story and System Center Configuration Manager 2012 Package Conversion Manager is no different.</strong></p>
<p>With the release of RC2 of Microsoft System Center Configuration Manager 2012 Package Conversion Manager (PCM) we get to experiment with a new feature; PCM Extensibility. PCM Extensibility is an extensibility point for PCM that provides IT shops with an opportunity to customize the package conversion process with the goal of speeding up the retirement of wrappers commonly used with Classic Software Dist. programs.</p>
<ul>
<li><span style="color: #4f81bd;" color="#4f81bd"><strong>The Why:</strong> </span><span style="color: #000000;" color="#000000">Many Configuration Manager customers have Classic Software Dist. packages with custom logic and wrappers that are unique to their environment. The Application Model in SCCM 2012 addresses many of the reasons customers originally invested in customizations. PCM allows our customers to unwind the extensibility of their program wrappers and to take full advantage of the App Model. Essentially PCM helps them divest in custom wrappers for scenarios that are a 1st class citizen within the new App Model.</span></li>
<li><span style="color: #4f81bd;" color="#4f81bd"><strong>The How:</strong></span><span style="color: #000000;" color="#000000"> Unlock the the full breadth and&nbsp; scope of the App Model SDK during the conversion process by providing a custom executable with access to a copy the XML digest from a converted Application by building a PCM Plugin.</span></li>
<li><span style="color: #4f81bd;" color="#4f81bd"><strong>The What:</strong></span><span style="color: #000000;" color="#000000"> An extensibility option called the PCM Extensibility.</span></li>
</ul>
<p>&nbsp;</p>
<h1>The Basics</h1>
<p>On the high level a PCM plugin is an executable that is launched by the conversion and the analysis process. Below is a diagram that shows the basic interactions. The dashed line represents the process boundary between PCM and the plugin processes. The Application object that is created by PCM is serialized to XML using the SccmSerializer class found within the App Model SDK. In the diagram below the plugin is reading and manipulating the XML. Once the plugin has made all necessary changes it overwrites the original file with the updated XML. Once the plugin process exits PCM deserializes the Application object from the updated XML and continues with the conversion or analysis process. PCM passes three arguments via the command line when launching the Plugin. It passes Package ID, full path to the XML digest of the serialized Application, and the name of the site server that the console is connected to.</p>
<p>It&rsquo;s important to note that the PCM Plugin is ran on a per package basis. Or put differently, is executed within the context of a single package-to-app conversion. So&nbsp; if 5 Automatic packages have been selected for Conversion the plugin will be launched 5 times.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/8666.image_039FC788.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/8666.image_5F00_039FC788.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/6786.image_thumb_025B2EA9.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/6786.image_5F00_thumb_5F00_025B2EA9.png" width="637" height="284" /></a></p>
<p>&nbsp;</p>
<h1>Configuration</h1>
<p>There are several options related to the PCM Plugin. These options are controlled via the Microsoft.ConfigurationManagement.exe.config file for the Admin Console. The Microsoft.ConfigurationManagement.exe.config file found within the &ldquo;bin&rdquo; folder under the Admin Console install location. The sample download at the bottom of this post contains a sample .config file.</p>
<h2><span style="font-size: small;" size="3">Config Sections</span></h2>
<p>The first step in setting up a PCM Plugin is to add a PCM binary to the configSections node. Add the following child node to configSections. </p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">section</span> <span class="attr">name</span><span class="kwrd">="Microsoft.ConfigurationManagement.UserCentric.Workflow.Properties.Settings"</span> 
               <span class="attr">type</span><span class="kwrd">="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"</span> 
               <span class="attr">requirePermission</span><span class="kwrd">="false"</span> <span class="kwrd">/&gt;</span></pre>
<h2><span style="font-size: small;" size="3">Plugin Command Line</span></h2>
<p>PCM launces a command shell process using a command line value specified by the .config file. At run time PCM appends to this command line three arguments. The PackageID of the source package, the full path to the XML digest of the derived Application object, and the site server that the console is connected to are appended in that order. To configure a plugin add the following setting to the Microsoft.ConfigurationManagement.UserCentric.Workflow.Properties.Settings node under applicationSettings similar to the example below.</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">setting</span> <span class="attr">name</span><span class="kwrd">="PcmPlugIn"</span> <span class="attr">serializeAs</span><span class="kwrd">="String"</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">value</span><span class="kwrd">&gt;</span>powershell.exe "C:\sample\PlugInAppModel.ps1"<span class="kwrd">&lt;/</span><span class="html">value</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">setting</span><span class="kwrd">&gt;</span></pre>
<p>Based on the PcmPlugin value specified above the complete command line that will be used to launch the Plugin will look like: <br /><strong>cmd /c powershell.exe &ldquo;c:\sample\PlugInAppModel.ps1&rdquo; ABC00002 %temp%\filename.xml MySiteServer</strong></p>
<p>It&rsquo;s important to note that this is the only required configuration piece to get your plugin up and running within PCM.</p>
<h2><span style="font-size: small;" size="3">Plugin Timeout</span></h2>
<p>PCM has a configurable Plugin Timeout threshold. If the Plugin process runs for longer than the specified duration PCM will consider that an error and skip onto the next package. Below is an example of how to configure the timeout value in milliseconds.</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">setting</span> <span class="attr">name</span><span class="kwrd">="PcmPlugInTimeoutMilliseconds"</span> <span class="attr">serializeAs</span><span class="kwrd">="String"</span><span class="kwrd">&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">value</span><span class="kwrd">&gt;</span>100000<span class="kwrd">&lt;/</span><span class="html">value</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">setting</span><span class="kwrd">&gt;</span></pre>
<h2><span style="font-size: small;" size="3">Plugin Exit Code</span></h2>
<p>The Microsoft.ConfigurationManagement.exe.config also allows us to specify what success is in terms of process exit code. The default is 0 but if your plugin uses a different value to indicate success you can modify the setting as shown below.</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">setting</span> <span class="attr">name</span><span class="kwrd">="PcmPluginExitCode"</span> <span class="attr">serializeAs</span><span class="kwrd">="String"</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">value</span><span class="kwrd">&gt;8</span><span class="kwrd">&lt;/</span><span class="html">value</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">setting</span><span class="kwrd">&gt;</span></pre>
<h1>PowerShell Sample</h1>
<p>To help get the community off and running with building plugins for PCM we created a sample plugin built using PowerShell. In this blog post I will cover the core concepts demonstrated by the sample, however the sample plugin goes further by showing how to achieve more advanced tasks with the App Model SDK.</p>
<h2><span style="font-size: small;" size="3">Arguments</span></h2>
<p>First we need to get our arguments from the command line so we know where our XML digest is.</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; height: 65px; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> $packageId      = $args[0]</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span> $fullFileName   = $args[1]</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum3"> 3:</span> $sccmServerName = $args[2]</pre>
<!--CRLF--></div>
</div>
<h2><span style="font-size: small;" size="3">Loading SDK Assemblies</span></h2>
<p>A plug in can work directly with the XML and use XPath to navigate the digest. This requires an intimate understanding of the schema used by the App Model but it is still a valid approach. In the sample plugin we show how to use the App Model SDK via PowerShell so we don&rsquo;t have to fiddle about with XPath.</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> #Loads Application Model into Application Domain</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span> LoadSccmAssemblies</pre>
<!--CRLF--></div>
</div>
<p>To load the SDK Assemblies for working with the Application class we use the following function from SharedFunctions.ps1</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> #Load Sccm Assemblies</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span> function LoadSccmAssemblies()</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum3"> 3:</span> {</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum4"> 4:</span>     $sccmPath = <span style="color: #006080;">"C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\"</span></pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum5"> 5:</span>     $filesToLoad = "Microsoft.ConfigurationManagement.ApplicationManagement.dll<span style="color: #006080;">","</span>AdminUI.WqlQueryEngine.dll<span style="color: #006080;">", "</span>AdminUI.DcmObjectWrapper.dll<span style="color: #006080;">" </span></pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum6"> 6:</span>     </pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum7"> 7:</span>     Set-Location $sccmPath</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum8"> 8:</span>     [System.IO.Directory]::SetCurrentDirectory($sccmPath)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum9"> 9:</span>     </pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum10"> 10:</span>     foreach($fileName in $filesToLoad)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum11"> 11:</span>     {</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum12"> 12:</span>        $fullAssemblyName = [System.IO.Path]::Combine($sccmPath, $fileName)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum13"> 13:</span>        if([System.IO.File]::Exists($fullAssemblyName ))</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum14"> 14:</span>        {   </pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum15"> 15:</span>            $FileLoaded = [Reflection.Assembly]::LoadFrom($fullAssemblyName )</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum16"> 16:</span>        }</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum17"> 17:</span>        else</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum18"> 18:</span>        {</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum19"> 19:</span>             Write-Host ([System.String]::Format("File not found {0}<span style="color: #006080;">",$fileName )) -backgroundcolor "</span>red"</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum20"> 20:</span>        }</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum21"> 21:</span>     }</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum22"> 22:</span> }</pre>
<!--CRLF--></div>
</div>
<h2><span style="font-size: small;" size="3">Deserialize </span></h2>
<p>Next we need to deserialize the XML digest into an instance of Application.</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; height: 49px; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> #Deserialize XML file</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span> $applicaton = GetApplicationObject $fullFileName</pre>
<!--CRLF--></div>
</div>
<p>This is also handled by a function from SharedFunctions.ps1.</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; height: 122px; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> #Deserialize XML into Application</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span> function GetApplicationObject([<span style="color: #0000ff;">string</span>]$xmlFilePath)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum3"> 3:</span> {</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum4"> 4:</span>    $fileContent = get-content $xmlFilePath -readcount 0   </pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum5"> 5:</span>   [Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer]::DeserializeFromString($fileContent,$<span style="color: #0000ff;">false</span>)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum6"> 6:</span> }</pre>
<!--CRLF--></div>
</div>
<h2><span style="font-size: small;" size="3">Modify</span></h2>
<p>Now that we have an instance of Application to work with we can start to modify it. One easy example is changing the Title of the Application</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; height: 67px; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> #Modifies Application Name</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span> $applicaton.Title = $applicaton.Title + <span style="color: #006080;">"_ModifiedByPlugIn"</span></pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum3"> 3:</span> $applicaton.DisplayInfo.Current.Title = $applicaton.DisplayInfo.Current.Title + <span style="color: #006080;">"_ModifiedByPlugIn"</span></pre>
<!--CRLF--></div>
</div>
<h2><span style="font-size: small;" size="3">Unwinding Your Wrapper</span></h2>
<p>Now that we have modified the title of our Application we need to move on to some more serious work. For example if your programs are currently wrapped with a custom executable or script a key piece to using the PCM Plugin to move away from a wrapper is updating the command line within the Deployment Type to point directly at an MSI. Below we show how one can get to the first DT in the Application and update the InstallCommandLine property to point at the MSI directly. If wrappers are being used to facilitate uninstall scenarios then using the plugin to populate the UninstallCommandLine property will also be valuable.</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> $deploymentType = $applicaton.DeploymentTypes[0]</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span>         </pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum3"> 3:</span> $deploymentType.Installer.InstallCommandLine = <span style="color: #006080;">'MSIExec.exe /i "SimpleMSI.msi" /q'</span></pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum4"> 4:</span> $deploymentType.Installer.UninstallCommandLine = <span style="color: #006080;">'MSIExec.exe /uninstall "SimpleMSI.msi"'</span></pre>
<!--CRLF--></div>
</div>
<p>&nbsp;</p>
<h1>Analysis and the Plugin</h1>
<p>One important point that should be called out is that the Plugin is also invoked during Analysis and the Readiness rule set is applied to the derived Application after the plugin completes. The implication is that the PCM Plugin has an opportunity to modify the Application before readiness rules are applied. This gives the plugin the ability to affect the Readiness state of the package. The example below shows how a plugin can have an impact on Readiness.</p>
<h2><span style="font-size: small;" size="3">Getting More Packages into the Ready State</span></h2>
<p>The PCM Plugin concept is intended to help with moving away from wrappers that are made obsolete by the new Application Model. With that said you can create a plugin for a number of reasons. For example one might create a Plugin to get more packages into the Ready state. The number one blocker to getting your packages into the Ready state will be missing detection methods. PCM is limited in its ability to natively find detection methods. PCM can only find a detection method if an MSI can be located in the program command line. With the plugin we have an opportunity to add the capability to create an enhanced detection method or supply a product code. To determine if a Deployment Type is missing a detection method the plugin will need to examine the ProductCode and EnhancedDetectionMethod properties of the Installer within the DeploymentType instance. If both of these are empty then a detection method will be needed. Below is an example of how to set the ProductCode property to a random GUID. This would be ill-advised in a production&nbsp; environment but gives an example of how to modify the ProductCode value.</p>
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;" id="codeSnippetWrapper">
<div style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;" id="codeSnippet">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum1"> 1:</span> <span style="color: #0000ff;">foreach</span>($i <span style="color: #0000ff;">in</span> $application.DeploymentTypes)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum2"> 2:</span>    {</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum3"> 3:</span>        <span style="color: #0000ff;">if</span>($i.Installer.ProductCode -eq <span style="color: #006080;">" "</span>)</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum4"> 4:</span>        {</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum5"> 5:</span>           $i.Installer.ProductCode = [Guid]::NewGuid().ToString()</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum6"> 6:</span>        }</pre>
<!--CRLF-->
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span style="color: #606060;" id="lnum7"> 7:</span>    }</pre>
<!--CRLF--></div>
</div>
<h1>Sample Code</h1>
<p>Here is a link to the Sample code:</p>
<div style="margin: 0px; display: inline; float: none; padding: 0px;" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:961313a9-0e7a-49d7-97d3-bdce2ffba01d" class="wlWriterEditableSmartContent">
<p>PowerShell <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/5684.Sample-PlugIn_44D8E986.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/5684.Sample_2D00_PlugIn_5F00_44D8E986.zip" target="_blank">Sample</a></p>
</div>]]></content:encoded>
    </item>
    <item>
      <title>How to Create a Basic App using the Configuration Manager 2012 Beta 2 SDK</title>
      <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/how-to-create-a-basic-app-using-the-configuration-manager-2012-beta-2-sdk</link>
      <pubDate>Tue, 14 Jun 2011 15:34:00 GMT</pubDate>
      <dc:creator><![CDATA[sperniner]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/one_line_of_code_at_a_time/2011/06/14/how-to-create-a-basic-app-using-the-configuration-manager-2012-beta-2-sdk/</guid>
      <description><![CDATA[With System Center Configuration Manager 2012 comes a new powerful way to manage apps called the...]]></description>
      <content:encoded><![CDATA[<p>With System Center Configuration Manager 2012 comes a new powerful way to manage apps called the Application Model. The new Application Model (App Model) unlocks the vision of User Centric computing or user targeting. User targeting in Configuration Manager 2007 was technically possible however it was not practical as platform specific issues had to be managed at the collection level. The App Model solves this problem along with many other short comings of what is now called Classic Software Distribution. A.K.A Packages and Programs which we are all familiar with. There are a lot of pieces to the new App Model to discuss. I want to focus on the most basic scenario in this post and show how to create a simple Application with a single deployment type.</p>
<p>Quick note: The App Model SDK is still under development and some of the class referenced below are bound to change between Beta 2 and RTM.</p>
<h1>Start with Application</h1>
<p>To get started you&rsquo;ll need to add a reference to the following assemblies found in the CM 2012 Console install directory:</p>
<ul>
<li>Microsoft.ConfigurationManagement.ApplicationManagement.dll</li>
<li>Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll</li>
</ul>
<p>The first step in creating your first Application in the 2010 App Model is to create an instance of Microsoft.ConfigurationManagement.ApplicationManagement.Application.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span><span style="color: #008000;">//creat an instance of Application</span></span> <br /><span><span style="color: #2b91af;">ObjectId</span></span><span style="color: #000000;"> appId = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ObjectId</span></span><span style="color: #000000;">(</span><span><span style="color: #a31515;">"Authoring_Scope_Id"</span></span><span style="color: #000000;">,<br /></span><span><span style="color: #a31515;"> "Application_"</span></span><span style="color: #000000;">+</span><span><span style="color: #2b91af;">Guid</span></span></span></span><span><span style="font-family: Consolas;"><span style="color: #000000;">.NewGuid().ToString());<br /></span><span><span style="color: #2b91af;">Application</span></span><span style="color: #000000;"> app = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">Application</span></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">(appId);<br /></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">app.Title = </span><span><span style="color: #a31515;">"New App"</span></span><span style="color: #000000;">;<br /></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">app.Version = 1; </span></span></span></pre>
<p>The constructor for Application takes an instance of ObjectId which indicates the Authoring Scope and Logical Name of the Application. These are in the form of &ldquo;ScopeId_5D0545B8-46E1-4F48-B165-B8870DAE1C1C" and &ldquo;Application_b3628303-eeb6-41af-a15c-175c12f3bd6a&rdquo; respectively. The Authoring scope is unique per Primary Site Server and <a href="http://msdn.microsoft.com/en-us/library/cc145534.aspx">you can get that from WMI.</a> Supplying a fake Authoring Scope ID should work just fine for testing purposes. If you plan on deploying this to a client you should do the work to get the actual Site Scope Id. It should also be noted that the &ldquo;Version&rdquo; property does not refer to the version of the Application that your are creating. It indicates the revision of the app in terms of Application revisions which is a new feature in 2012.</p>
<h1>Add Localized Display Info</h1>
<p>The various Application properties such as Title are what we see in the Admin Console. The end user via Software Center or the Software Catalog see different information. The end user sees information contained in an instance of DisplayInfo that can be localized to the language of the end user. This is done by adding an instance of DisplayInfo along with localized metadata for each language you want to support.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span style="color: #008000;"><span>//cerate DisplayInfo</span></span></span><span> <span><span style="color: #008000;">//this is the localizable info that the end user will see in Software Center</span></span> <br /><span><span style="color: #2b91af;">AppDisplayInfo</span></span><span style="color: #000000;"> displayInfo = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">AppDisplayInfo</span></span></span></span><span><span style="font-family: Consolas;"><span style="color: #000000;">(); <br />displayInfo.Title = </span><span><span style="color: #a31515;">"My App"</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">; <br />displayInfo.Language = </span><span><span style="color: #2b91af;">CultureInfo</span></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">.CurrentCulture.Name; <br />displayInfo.Description = </span><span><span style="color: #a31515;">"My first App"</span></span><span style="color: #000000;">; <br />app.DisplayInfo.Add(displayInfo);</span></span></span></pre>
<p>Here I am using the same language as the current executing process &ldquo;en-US&rdquo;, but you could use any language identifier.</p>
<h1>Add a Deployment Type</h1>
<p>For those not familiar with the App Model the Application is the abstract definition of an application and the Deployment Type represents the concrete instance of the app. To make our app work we need to associate an installer and content with the Application instance. This is done with a DeploymentType.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span style="color: #008000;"><span>//Add DT</span></span></span><span> <span><span style="color: #2b91af;">ObjectId</span></span><span style="color: #000000;"> dtId = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ObjectId</span></span><span style="color: #000000;">(</span><span><span style="color: #a31515;">"Authoring_Scope_Id"</span></span></span></span><span><span style="font-family: Consolas;"><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp; <br /></span><span><span style="color: #a31515;"><span style="color: #000000;" color="#000000"> </span>"DeploymentType"</span></span><span style="color: #000000;"> + </span><span><span style="color: #2b91af;">Guid</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">.NewGuid().ToString()); <br /></span><span><span style="color: #2b91af;">DeploymentType</span></span><span style="color: #000000;"> dt = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">DeploymentType</span></span><span style="color: #000000;">(dtId, </span><span><span style="color: #2b91af;">MsiInstaller</span></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">.TechnologyId); <br />app.DeploymentTypes.Add(dt); <br />dt.Title = </span><span><span style="color: #a31515;">"My First DT"</span></span><span style="color: #000000;">;<br />dt.Version = 1; </span></span></span></pre>
<p>Again we see the use of ObjectId but we are using the &ldquo;DeploymentType_&rdquo; prefix for Name. Once we have the DeploymentType created we add it to Application.DeploymentTypes. The TechnologyId paramter in the DT constructor indicates what type of DT we are creating. We are creating an MSI type DT so we use the static property found on Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller that equates to the string &ldquo;MSI&rdquo;.</p>
<h1>Setup the MsiInstaller</h1>
<p>Our new DT has been added to our Application. DeploymentType has a property called &ldquo;Installer&rdquo; that exposes the instance of Installer that we need to work with. The DT constructor was nice enough to supply us with an instance of MsiInstaller so we just need to configure it.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span style="color: #008000;"><span>//configure MSI installer to have a product code detection method</span></span></span><span> <br /><span><span style="color: #2b91af;">MsiInstaller</span></span><span style="color: #000000;"> installer = dt.Installer </span><span><span style="color: #0000ff;">as</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">MsiInstaller</span></span></span></span><span><span style="font-family: Consolas;"><span style="color: #000000;">; <br /></span><span><span style="color: #2b91af;">Guid</span></span><span style="color: #000000;"> fakeProductCode = </span><span><span style="color: #2b91af;">Guid</span></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">.NewGuid(); <br />installer.ProductCode = </span><span><span style="color: #a31515;">"{"</span></span><span style="color: #000000;"> + fakeProductCode.ToString() + </span><span><span style="color: #a31515;">"}"</span></span><span style="color: #000000;">;<br /></span></span></span><span style="font-family: Consolas;"><span><span style="color: #008000;"><span><br />//set commandline</span></span></span><span> <br /><span style="color: #000000;">installer.InstallCommandLine = </span><span><span style="color: #a31515;">"MSIExec /i MyApp.Msi"</span></span><span style="color: #000000;">;</span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;"><br /></span></span></span></pre>
<p>One critical component to any DT is its Detection Method. The Detection Method indicates how the CM Client is suppose to know if the app is installed or not. This is critical as the App Model is state based. If you get the Detection Method wrong the client will think the app is not installed and will attempt to install it every time Global Evaluation runs (every 7 day I believe) even if the app is installed. The nice part about working with MSIs is that we can just specify a Product Code and the rest is handled for us. The Product Code format is a Guid wrapped with { } such as {27aae8e3-e733-4256-a37f-dc1e0287da9f}.</p>
<h1>Add Content</h1>
<p>Next we need to associate our DT and MsiInstaller with actual content so the client has something to install.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span style="color: #008000;"><span>//Add content to the DT</span></span></span><span> <br /><span><span style="color: #2b91af;">Content</span></span><span style="color: #000000;"> installerContent = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">Content</span></span></span></span><span><span style="font-family: Consolas;"><span style="color: #000000;">(); <br />installer.Contents.Add(installerContent); <br />installerContent.Location = </span><span style="color: #a31515;">@\\SomeServer\content\MyAppDir</span></span><span style="font-family: Consolas;"><span style="color: #000000;">; <br /></span><span><span style="color: #008000;">//add MSI file to content</span></span> <br /><span><span style="color: #2b91af;">ContentFile</span></span><span style="color: #000000;"> msiFile = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ContentFile</span></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">(); <br />msiFile.Name = </span><span><span style="color: #a31515;">"MyApp.Msi"</span></span><span style="color: #000000;">; <br />installerContent.Files.Add(msiFile);</span></span></span></pre>
<p>When setting the Name property on ContentFile use a path that is relative to the path specified by &ldquo;Location&rdquo;.</p>
<h1>Serializing the Application</h1>
<p>We are almost ready to send our app to the site to deploy to clients. Before we do that we need to serialize our instance of Application. We use a special serializer found in Microsoft.ConfigurationManagement.ApplicationManagement.Serialization called SccmSerializer. This serializer will do some addition verification for us to check for invalid properties.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span style="color: #008000;"><span>//serialize app.</span></span></span><span> <span><span style="color: #0000ff;">string</span></span><span style="color: #000000;"> appXml = </span><span><span style="color: #2b91af;">SccmSerializer</span></span><span style="color: #000000;">.SerializeToString(app, </span><span><span style="color: #0000ff;">true</span></span><span style="color: #000000;">);&nbsp; </span></span></span></pre>
<h1>Committing the App to the Site</h1>
<p>The last step to creating our app is to use the CM WMI provider to save our serialized data to the site server. To do this we need to create an instance of SMS_Application. I&rsquo;m not going to go into great detail on working with WMI here as there are a ton of articles that cover that subject. But here is a basic method for getting an instance of SMS_Application from the provider.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span><span style="color: #008000;"><span>//serialize app.</span></span></span><span> <br /><span><span style="color: #0000ff;">string</span></span><span style="color: #000000;"> appXml = </span><span><span style="color: #2b91af;">SccmSerializer</span></span><span style="color: #000000;">.SerializeToString(app, </span><span><span style="color: #0000ff;">true</span></span></span></span><span><span style="font-family: Consolas;"><span style="color: #000000;">); <br /></span><span><span style="color: #2b91af;">ManagementObject</span></span><span style="color: #000000;"> appInstance = </span><span><span style="color: #0000ff;">null</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">; <br /></span><span><span style="color: #2b91af;">ManagementPath</span></span><span style="color: #000000;"> path = </span><span><span style="color: #0000ff;">null</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">; <br /></span><span><span style="color: #2b91af;">ObjectGetOptions</span></span><span style="color: #000000;"> options = </span><span><span style="color: #0000ff;">null</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">; <br /></span><span><span style="color: #2b91af;">ManagementClass</span></span><span style="color: #000000;"> appClass = </span><span><span style="color: #0000ff;">null</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">; <br /></span><span><span style="color: #0000ff;">try</span></span> <br /></span><span style="font-family: Consolas;"><span style="color: #000000;">{<br />&nbsp;</span><span><span style="color: #2b91af;">ManagementScope</span></span><span style="color: #000000;"> scope = <br /> </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ManagementScope</span></span><span style="color: #000000;">(</span><span><span style="color: #c0504d;">@&rdquo;</span><a href="file://\\SiteServer\root\Sms\Site_SiteCodeGoesHere"><span style="color: #c0504d;">\\SiteServer\root\Sms\Site_SiteCodeGoesHere</span></a><span style="color: #c0504d;">&rdquo;</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">);&nbsp;&nbsp;&nbsp;&nbsp; <br /> path = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ManagementPath</span></span><span style="color: #000000;">(</span><span><span style="color: #a31515;">"SMS_Application"</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">);&nbsp;&nbsp;&nbsp;&nbsp; <br /> options = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ObjectGetOptions</span></span></span><span style="font-family: Consolas;"><span style="color: #000000;">();&nbsp;&nbsp;&nbsp;&nbsp; <br /> appClass = </span><span><span style="color: #0000ff;">new</span></span><span style="color: #000000;">&nbsp;</span><span><span style="color: #2b91af;">ManagementClass</span></span></span></span><span style="font-family: Consolas;"><span><span style="color: #000000;">(scope, path, options);<br />&nbsp;appInstance = appClass.CreateInstance(); <br />} <br /></span><span><span style="color: #0000ff;">finally</span></span> <br /><span style="color: #000000;">{<br /> appClass.Dispose(); <br />}</span></span></span></pre>
<p>The only property we need to set here is SDMPackageXML. We set SDMPackageXML to the serialzed XML string stored in appXml and call Put() to save our app to the site.</p>
<pre style="line-height: normal; background: silver;"><span style="font-family: Consolas;"><span style="color: #000000;"><span>appInstance.Properties[</span></span><span><span><span style="color: #a31515;">"SDMPackageXML"</span></span><span style="color: #000000;">].Value = appXml; appInstance.Put();</span></span></span></pre>
<p>You should now have an app that is ready to deploy!</p>
<p>There are a lot of other properties associated with the App Model that we did not explore that can impact how an App behaves on the client. This post covers jus the most basic. In upcoming posts I&rsquo;ll cover more advanced topics such as DT dependencies and Enhanced Detection Methods.</p>]]></content:encoded>
    </item>
    <item>
      <title>Leveraging Automated Tests to Tighten up Your Bug Process</title>
      <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/leveraging-automated-tests-to-tighten-up-your-bug-process</link>
      <pubDate>Fri, 03 Jun 2011 11:52:26 GMT</pubDate>
      <dc:creator><![CDATA[sperniner]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/one_line_of_code_at_a_time/2011/06/03/leveraging-automated-tests-to-tighten-up-your-bug-process/</guid>
      <description><![CDATA[The Why: Apart from being expensive in terms of time and effort, every time a bug is handed off...]]></description>
      <content:encoded><![CDATA[<p><strong></strong></p>  <ul>   <li><strong><font color="#4f81bd">The Why:</font></strong> Apart from being expensive in terms of time and effort, every time a bug is handed off between Dev and Test is an opportunity to drop the ball or for confusion to creep in. </li>    <li><font color="#4f81bd"><strong>The How:</strong> </font><font color="#333333">Capture bug repro steps as an automated test that any developer can run without assistance from test.</font></li>    <li><strong><font color="#4f81bd">The What</font><font color="#4f81bd">:</font></strong> Reduce bug hand-offs and interdisciplinary interactions to move a bug to the “Closed” state. </li> </ul>  <p>The cost of finding a defect in test and resolving the issue via a bug is an expensive process in terms 'of time and effort. The ideal solution is to find bugs prior to check-in with TDD or gated check-ins. But we live in a world where that doesn’t always work and the bug is still a part of life. </p>  <p>Within the <a href="http://blogs.technet.com/b/cameronk/archive/2011/04/10/package-conversion-manager-high-level-overview.aspx">Package Conversion Manager 2012 project I am currently engaged in</a> we have put a lot of effort into test automation through TDD and other forms of testing. We’ve essentially implemented the Agile development model that my colleague John Socha-Leialoha has described <a href="http://blogs.msdn.com/b/jsocha/archive/2011/02/11/i-have-a-dream-an-automated-dream.aspx">here.</a> As the project matured we settled on a bug process that I have found to be a bit more efficient than what I have experienced on other more traditional or waterfall projects. It’s this process that I wanted to highlight in this blog post.</p>  <h1>Traditional Bug Process</h1>  <p>If you’ve worked on a traditional waterfall style software project you are probably familiar with a certain bug process. A tester finds an issue then files a bug. Invariably there is some back and forth on the repro steps with the dev. Once the bug is taken and fixed the developer resolves the bug and assigns it back to the originating tester to verify the fix. The tester executes a test or set of tests to ensure that the issues was addressed. If actually fixed it’s resolved as closed. Below is a diagram that shows a typical bug process minus the triage step.&#160; In blue we see the steps taken by a tester and red indicates the steps taken by a developer. In the diagram below we see two transitions or hand-offs. It is these hand-offs that I want to avoid as these are very expensive and each hand off is an opportunity to drop the ball or for confusion to creep in. Keep in mind that the process shown below is a best case scenario for a waterfall style project.</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/8371.image_23974AB3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/8371.image_5F00_23974AB3.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/6646.image_thumb_2A1AA476.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/6646.image_5F00_thumb_5F00_2A1AA476.png" width="550" height="150" /></a></p>  <p>In some cases there can be additional hand-offs. During my testing years I was all to familiar with the “no repro” trick. As a result there was a substantial amount of back and forth with a bug as I attempted to convey the complexities and nuances of the actual issue via a text field in the bug form. In the below diagram we see a less than ideal situation where the number have hand-offs have been doubled.</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/0358.image_69785806.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/0358.image_5F00_69785806.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/3404.image_thumb_6501D73F.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/3404.image_5F00_thumb_5F00_6501D73F.png" width="548" height="197" /></a></p>  <h1>Simplified Bug Process</h1>  <p>Within the PCM project our testers will capture each bug in an automated test that I as a developer can easily run to validate my fix. If the automated test that discovered the bug is a high level acceptance test with a great deal of leverage I will replicate the failure in a unit test that is targeted at that specific area. These tests are created using the Unit Test framework (we use it for all forms of tests) found in Visual Studio / TFS. By having all automated tests be part of the main product solution it is easy for me as a developer to run all tests or a specific test. This process hinges on the ability of the developer to easily run any automation created by a tester. The main benefit here is that once the tester has filed the bug and linked it with an automated test the tester is essentially done with this bug. The automated test serves as clearly defined and very specific repro steps. Gone are the days of a bug being resolved as “No Repro”. The diagram below shows the simplified process that we are using.</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/0755.image_6495A44A.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/0755.image_5F00_6495A44A.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/4075.image_thumb_5D7667D2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-34-metablogapi/4075.image_5F00_thumb_5F00_5D7667D2.png" width="552" height="143" /></a></p>  <p>As you can see we have effectively reduced the number of hand-offs to one greatly reducing the overhead and risk associated with traditional processes shown above. This has had the effect of creating a lighter weight and crisper bug process that keeps the tester focused on expanding test coverage and product quality and not on my dirty laundry.</p>  <h1>Team Dynamics &amp; Culture</h1>  <p>It is technically feasible that any team could use this process, however it is likely that any team that is in a position to be successful with this approach has a certain culture with regard to test. Such a team will probably maintain a culture where the test team is in a position to place the responsibility of running test automation to verify the fix with the development team. Not every team works to put test in the driver seat on such issues which can server as a blocker to implementing the streamlined process described above.</p>]]></content:encoded>
    </item>
    <item>
      <title>Unit Testing Workflow Activities with Moles</title>
      <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/unit-testing-workflow-activities-with-moles</link>
      <pubDate>Mon, 21 Mar 2011 00:35:00 GMT</pubDate>
      <dc:creator><![CDATA[sperniner]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/one_line_of_code_at_a_time/2011/03/21/unit-testing-workflow-activities-with-moles/</guid>
      <description><![CDATA[The Why: True unit testing of Workflow Activities is a pain if not impossible. 
The How: Use...]]></description>
      <content:encoded><![CDATA[<ul>
<li><span style="color: #333333;"><strong><span style="color: #4f81bd;">The Why:</span></strong> True unit testing of Workflow Activities is a pain if not impossible.</span> </li>
<li><strong><span style="color: #4f81bd;">The How:</span></strong> Use Moles CLR Detour technologies developed by Microsoft Research to isolate the system under test. </li>
<li><strong><span style="color: #4f81bd;">The What:</span></strong> A sample C# project that showcases a handful of core Workflow unit test scenarios. </li>
</ul>
<p><span style="color: #333333;">I&rsquo;ve been working with Workflow Foundation for a few year now and I&rsquo;ve become a huge fan of the technology. Working in the enterprise software space I find it to be a natural fit as a solution for a great deal of scenarios. But (there is always a but) if you have ever been charged with the task of unit testing workflow activities or practice TDD you are probably familiar with how frustrating it can be. For what ever reason the Workflow team wasn&rsquo;t overly concerned with unit test-ability and in my&nbsp; opinion were overly aggressive in marking constructors as internal and the like. Unit testing is primarily concerned with testing the smallest unit of functionality possible which is typically a single method. With Workflow Activities this is very difficult. For example you may want to unit test the Method &ldquo;Execute&rdquo; on your CodeActivity which takes an instance of CodeActivityContext, but the constructor is marked internal and it doesn&rsquo;t implement an interface that we can leverage to create Stand-In classes. The usage of interfaces to create and pass in Stand-In classes is my preferred method of isolating the system under test to small testable chunks so I find this especially troublesome. But since that options isn&rsquo;t available to us when we are working with Activities we must do something else.&nbsp; One option I&rsquo;ve found useful is an approach the uses Moles from Microsoft Research that is based on CLR Detours.</span></p>
<h4>Moles</h4>
<p>Moles is part of the <a href="http://research.microsoft.com/en-us/projects/pex/">Pex &amp; Moles project from MSR</a> that leverages a concept called Detours. a Detour is when the memory location for a specific method on a specific instance is updated to point to a mock class with the same method signature. In other words this gives us a back door to wiring in mock functionality. Below is a brief example of how Moles works but a full explanation&nbsp; of Moles is out of scope for this post so if you are new to Moles head on over to MSR and check out their demos and How-Tos.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/3632.y2kbug_64028A1A.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/3632.y2kbug_5F00_64028A1A.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/3718.y2kbug.png" original-url="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/3718.y2kbug.png" alt="y2kbug" title="y2kbug" style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" /></a></p>
<p>&nbsp;</p>
<h4>Moles and Workflow Activities</h4>
<p>Below is a diagram showing the basic architecture of how I&rsquo;ve chosen to unit test activities. Starting from the unit test, Moles and a Test Stand-In classes are used to manipulate and confine the system under test (the Workflow Activity). Moles is used to wire in delegates that allows us to eliminate pieces of typical <span style="color: #809ec2;">Activity</span> execution that are not necessary parts of our test such as getting values from a <span style="color: #809ec2;">InArgument </span><span style="color: #333333;">which normally incorporates complex WF infrastructure</span>. The test Stand-In is a simple component that replaces production classes with simplified test versions that provide test hooks and very predictable behavior. You&rsquo;ll also see the use of test shims that expose protected members or my activities. I&rsquo;ve chosen to use a derived class which uses the <span style="color: #0000ff;">new</span> keyword to create a public version of <span style="color: #809ec2;">Execute</span> which in turn calls the base version of <span style="color: #809ec2;">Execute</span>. You can use shadowing Accessors provided by the unit test wizards but I prefer the more explicit form of a derived class for the sake of a demo. Below is a diagram that shows the architecture of these unit tests and how a combinations of Test Stan-In classes and Moles allows us to focus the tests to a minimal amount of code. </p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/1072.image_781BA6A3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/1072.image_5F00_781BA6A3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/4377.arch.png" original-url="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/4377.arch.png" alt="image" title="image" style="border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" /></a></p>
<p>Let&rsquo;s dig into a Workflow specific use of Moles. Below are a few code samples of unit tests using Moles. You can find a link at the bottom of this post to the complete Visual Studio 2010 solution if you want more details about implementation.</p>
<h4>Testing Execute on SimpleActivity</h4>
<p>In this example we are testing <span style="color: #2b91af">SimpleActivity</span>.<span style="color: #006800">Execute</span>(<span style="color: #2b91af">CodeActivityContext </span><span style="color: #006800">context</span>).&nbsp; As part of <span style="color: #006800">Execute </span>a <span style="color: #2b91af">CustomTrackingRecord </span>is tracked and the same integer that is passed in to the <span style="color: #2b91af">InArgument</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt; </span><span style="color: #006800">SomeInteger </span>is returned. Both of these operations require the <span style="color: #2b91af">CodeActivityContext </span>which we will need Moles to instantiate as Moles has the ability to create instances of classes even when their constructors are marked internal. Below is the code snippet for the entire unit test. After which each section is discussed in detail.</p>
<blockquote>
<pre class="code">        <span style="color: gray">/// &lt;summary&gt;
        ///</span><span style="color: green">A test for Execute
        </span><span style="color: gray">///&lt;/summary&gt;
        </span><span style="color: green">[</span><span style="color: #2b91af">TestMethod</span><span style="color: green">()]
        [</span><span style="color: #2b91af">DeploymentItem</span><span style="color: green">(</span><span style="color: #a31515">"SampleActivities.dll"</span><span style="color: green">)]
        [</span><span style="color: #2b91af">HostType</span><span style="color: green">(</span><span style="color: #a31515">"Moles"</span><span style="color: green">)]
        </span><span style="color: #2222ff">public void </span><span style="color: #006800">ShouldReturnInt_WhenExecute_GivenInteger</span><span style="color: green">()
        {
            </span><span style="color: #23ebaa">// Arrange
            </span><span style="color: #2222ff">int </span><span style="color: #006800">expected </span><span style="color: #627e01">= </span><span style="color: green">10;

            </span><span style="color: gray">/// </span><span style="color: green">we need to create a moled CodeActivityContext so we can <br />            <span style="color: gray">/// </span>get an instance from the </span><span style="color: green">Instance property of the moled <br />            <span style="color: gray">/// <span style="color: #008000;">context </span></span>as all constructors are marked as internal.
            </span><span style="color: #2b91af">MCodeActivityContext </span><span style="color: #006800">moledContext </span><span style="color: #627e01">= </span><span style="color: #2222ff">new </span><span style="color: #2b91af">MCodeActivityContext</span><span style="color: green">();
            </span><span style="color: #006800">moledContext</span><span style="color: #627e01">.</span><span style="color: #006800">TrackCustomTrackingRecord </span><span style="color: #627e01">= </span><span style="color: green">(</span><span style="color: #006800">record</span><span style="color: green">) </span><span style="color: #627e01">=&gt;
            </span><span style="color: green">{
                </span><span style="color: #23ebaa">// do nothing
            </span><span style="color: green">};
            </span><span style="color: gray">/// </span><span style="color: green">We need to create a moled InArgument</span><span style="color: gray">&lt;int&gt; </span><span style="color: green">so we can setup<br />            <span style="color: gray">///</span> a delegate to return our expected value <span style="color: green">without <span style="color: green">using </span></span>
            </span><span style="color: gray">/// </span><span style="color: green">relying on any of the complexities of the WF runtime.
            </span><span style="color: #2b91af">MInArgument01</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt; </span><span style="color: #006800">moledInArg </span><span style="color: #627e01">= </span><span style="color: #2222ff">new </span><span style="color: #2b91af">MInArgument01</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt;</span><span style="color: green">();
            </span><span style="color: #006800">moledInArg</span><span style="color: #627e01">.</span><span style="color: #006800">GetActivityContext </span><span style="color: #627e01">= </span><span style="color: green">(</span><span style="color: #006800">ContextBoundObject </span><span style="color: #627e01">=&gt;
                </span><span style="color: green">{
                    </span><span style="color: #2222ff">return </span><span style="color: #006800">expected</span><span style="color: green">;
                });

            </span><span style="color: #2b91af">TestableSimpleActivity </span><span style="color: #006800">target </span><span style="color: #627e01">= </span><span style="color: #2222ff">new </span><span style="color: #2b91af">TestableSimpleActivity</span><span style="color: green">();
            </span><span style="color: #006800">target</span><span style="color: #627e01">.</span><span style="color: #006800">SomeInteger </span><span style="color: #627e01">= </span><span style="color: #006800">moledInArg</span><span style="color: #627e01">.</span><span style="color: #006800">Instance</span><span style="color: green">;

            </span><span style="color: #23ebaa">// Act
            </span><span style="color: #2222ff">int </span><span style="color: #006800">actual </span><span style="color: #627e01">= </span><span style="color: #006800">target</span><span style="color: #627e01">.</span><span style="color: #006800">Execute</span><span style="color: green">(</span><span style="color: #006800">moledContext</span><span style="color: #627e01">.</span><span style="color: #006800">Instance</span><span style="color: green">);

            </span><span style="color: #23ebaa">//Assert
            </span><span style="color: #2b91af">Assert</span><span style="color: #627e01">.</span><span style="color: #006800">AreEqual</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt;</span><span style="color: green">(</span><span style="color: #006800">expected</span><span style="color: green">, </span><span style="color: #006800">actual</span><span style="color: green">);

        }
</span></pre>
<p>&nbsp;</p>
</blockquote>
<p>In the <span style="color: #23ebaa">// Arrange </span>section of the unit test two moles are created to handle various operations that we can&rsquo;t create test Stand-Ins for. First we create a mole for the <span style="color: #2b91af">CodeActivityContext </span>using <span style="color: #2b91af">MCodeActivityContext </span>. Then we wire in the delegate for <span style="color: #2b91af">MCodeActivityContext </span>.<span style="color: #006800">Track </span>to <span style="color: #2b91af">MCodeActivityContext </span>.<span style="color: #006800">TrackCustomTrackingRecord </span>.<span style="color: #333333;"> This is the delegate that will serve as the Detour for the Track method. In other words this is the code that will be executed when Track is called on CodeActivityContext. In this detour delegate we don&rsquo;t do any asserts but we could verify that the track call is tracking the correct data.</span></p>
<p>Next we wire in a delegate for <span style="color: #2b91af">InArgument</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt;.<span style="color: #006800">Get.<span style="color: #333333;"> We can instantiate an</span><span style="color: #000000;"> <span style="color: #2b91af">InArgument <span style="color: #000000;"><span style="color: #333333;">but the Get call requires additional WF infrastructure that can&rsquo;t reasonably reproduced outside of the WF Runtime so we detour it to get the simple behavior we want which is to just return the value </span><span style="color: #006800">expected<span style="color: #000000;">.</span></span></span></span></span></span></span></p>
<p><span style="color: #627e01"><span style="color: #006800"><span style="color: #2b91af"><span style="color: #006800"><span style="color: #000000;"><span style="color: #333333;">Once our detours are setup we create an instance of the system under test using the Test Shim</span> <span style="color: #2b91af">TestableSimpleActivity<span style="color: #000000;">&nbsp; <span style="color: #333333;">which, as discussed before,&nbsp; is simply a class that exposes protected members. Once we have our target object I set the </span><span style="color: #006800">SomeInteger </span><span style="color: #333333;">property using the <span style="color: #006800">Instance </span>property on our Mole object. We have to use the instance of</span> <span style="color: #2b91af">InArgument</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt; <span style="color: #000000;"><span style="color: #333333;">provided by the moled object as this is the instance that will be associated with our detours. If I just</span> <span style="color: #333333;">created and used another instance of </span><span style="color: #2b91af">InArgument</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">int</span><span style="color: #627e01">&gt;<span style="color: #333333;"> </span></span></span><span style="color: #333333;">our detours would be ignored.</span></span></span></span></span></span></span></span></span></p>
<p><span style="color: #627e01"><span style="color: #006800"><span style="color: #2b91af"><span style="color: #006800"><span style="color: #2b91af"><span style="color: #627e01"><span style="color: #000000;"><span style="color: #333333;">After we have the target object setup <span style="color: #006800">Execute</span> is called using the instance of</span> <span style="color: #2b91af">CodeActivityContext <span style="color: #333333;">that is associated with our detours provided by the mole mole object</span> <span style="color: #006800">moledContext<span style="color: #000000;">.</span></span></span></span></span></span></span></span></span></span></p>
<h4>Testing Asynchronous Execute on ComplexActivity</h4>
<p>In the previous example I showed how to unit test the <span style="color: #006800">Execute </span><span style="color: #333333;">method of a basic</span> <span style="color: #2b91af">CodeActivity<span style="color: #000000;">.&nbsp; <span style="color: #333333;">However the situation is rarely that simple in the real world. To showcase unit testing more complex activities I&rsquo;ve created an activity that uses asynchronous Workflow concepts. There are several ways to create asynchronous activities. I&rsquo;ve chosen to start with</span> <span style="color: #2b91af">NativeActivity<span style="color: #333333;"> as this allows me to cover the use of bookmarks. In this unit test we are testing <span style="color: #006800">Execute<span style="color: #333333;"> again but this time it is an asynchronous operation and it creates a new thread using</span> System.<span style="color: #2b91af">Task<span style="color: #333333;"> so there are a few extra steps. For example an external service is responsible for doing the actual work. </span></span></span></span></span></span></span></p>
<pre class="code"><span style="color: green">        [</span><span style="color: #2b91af">TestMethod</span><span style="color: green">]
        [</span><span style="color: #2b91af">HostType</span><span style="color: green">(</span><span style="color: #a31515">"Moles"</span><span style="color: green">)]
        </span><span style="color: #2222ff">public void </span><span style="color: #006800">ShouldDoWork_WhenExecute_Moled</span><span style="color: green">()
        {
            </span><span style="color: #23ebaa">//Arrange
            //Create test fixture version of target type to expose protected members.
            </span><span style="color: #2b91af">TestableComplexActivity </span><span style="color: #006800">target </span><span style="color: #627e01">= </span><span style="color: #2222ff">new </span><span style="color: #2b91af">TestableComplexActivity</span><span style="color: green">();
            </span><span style="color: #23ebaa">//Create a stand-in version of IWorkerService with my test hooks.
            </span><span style="color: #2b91af">TestWorkerService </span><span style="color: #006800">testSvc </span><span style="color: #627e01">= </span><span style="color: #2222ff">new </span><span style="color: #2b91af">TestWorkerService</span><span style="color: green">();
            </span><span style="color: #2b91af">BookmarkOptions </span><span style="color: #006800">actualBmOptions </span><span style="color: #627e01">= </span><span style="color: #2b91af">BookmarkOptions</span><span style="color: #627e01">.</span><span style="color: #006800">None</span><span style="color: green">; <br /></span><span style="color: #23ebaa">            //Create a moled NativeActivityContext to get access to an instance.
            //And to set a Detour for CreateBookmark
            </span><span style="color: #2b91af">MNativeActivityContext </span><span style="color: #006800">moledContext </span><span style="color: #627e01">= </span><span style="color: #2222ff">new </span><span style="color: #2b91af">MNativeActivityContext</span><span style="color: green">();
            </span><span style="color: #006800">moledContext</span><span style="color: #627e01">.</span><span style="color: #006800">CreateBookmarkStringBookmarkCallbackBookmarkOptions<br />              </span><span style="color: #627e01">= </span><span style="color: green">(</span><span style="color: #006800">bmName</span><span style="color: green">, </span><span style="color: #006800">bmCallback</span><span style="color: green">, </span><span style="color: #006800">bmOptions</span><span style="color: green">) </span><span style="color: #627e01">=&gt;
            </span><span style="color: green">{
                </span><span style="color: #006800">actualBmOptions </span><span style="color: #627e01">= </span><span style="color: #006800">bmOptions</span><span style="color: green">;
                </span><span style="color: #2222ff">return new </span><span style="color: #2b91af">Bookmark</span><span style="color: green">(</span><span style="color: #006800">bmName</span><span style="color: green">);
            };

            </span><span style="color: #23ebaa">//Create a moled ActivityContext to setup a detour for <br />            //</span><span style="color: #23ebaa">GetExtention&lt;T&gt;(Type)
            </span><span style="color: #2b91af">MActivityContext </span><span style="color: #006800">moledActContext </span><span style="color: #627e01">= <br />            </span><span style="color: #2222ff">new </span><span style="color: #2b91af">MActivityContext</span><span style="color: green">(</span><span style="color: #006800">moledContext</span><span style="color: #627e01">.</span><span style="color: #006800">Instance</span><span style="color: green">);
            </span><span style="color: #006800">moledActContext</span><span style="color: #627e01">.</span><span style="color: #006800">GetExtension</span><span style="color: #627e01">&lt;</span><span style="color: #2b91af">IWorkerService</span><span style="color: #627e01">&gt;</span><span style="color: green">(
              </span><span style="color: #2222ff">new </span><span style="color: #2b91af">MolesDelegates</span><span style="color: #627e01">.</span><span style="color: #2b91af">Func</span><span style="color: #627e01">&lt;</span><span style="color: #2b91af">IWorkerService</span><span style="color: #627e01">&gt;</span><span style="color: green">(() </span><span style="color: #627e01">=&gt; </span><span style="color: #006800">testSvc</span><span style="color: green">)
              );

            </span><span style="color: #2222ff">bool </span><span style="color: #006800">actual </span><span style="color: #627e01">= </span><span style="color: #2222ff">false</span><span style="color: green">;



            </span><span style="color: #23ebaa">//Act
            </span><span style="color: #006800">target</span><span style="color: #627e01">.</span><span style="color: #006800">Execute</span><span style="color: green">(</span><span style="color: #006800">moledContext</span><span style="color: green">);
            </span><span style="color: #23ebaa">//blocks until worker thread completes.
            </span><span style="color: #006800">actual </span><span style="color: #627e01">= </span><span style="color: #006800">testSvc</span><span style="color: #627e01">.</span><span style="color: #006800">WaitForWorkToComplete</span><span style="color: green">();

            </span><span style="color: #23ebaa">//Assert
            </span><span style="color: #2b91af">Assert</span><span style="color: #627e01">.</span><span style="color: #006800">AreEqual</span><span style="color: #627e01">&lt;</span><span style="color: #2222ff">bool</span><span style="color: #627e01">&gt;</span><span style="color: green">(</span><span style="color: #2222ff">true</span><span style="color: green">, </span><span style="color: #006800">actual</span><span style="color: green">);
            </span><span style="color: #2b91af">Assert</span><span style="color: #627e01">.</span><span style="color: #006800">AreEqual</span><span style="color: #627e01">&lt;</span><span style="color: #2b91af">BookmarkOptions</span><span style="color: #627e01">&gt;</span><span style="color: green">(</span><span style="color: #2b91af">BookmarkOptions</span><span style="color: #627e01">.</span><span style="color: #006800">MultipleResume</span><span style="color: green">,<br />            </span><span style="color: #006800">actualBmOptions</span><span style="color: green">);
        }
</span></pre>
<p>To help constrain the test to just the <span style="color: #006800">Execute </span>method I&rsquo;ve created a test Stand-In version of the <span style="color: #2b91af">IWorkerService </span>extension service called <span style="color: #2b91af">TestWorkerService </span>to synchronize the threads for me and give me access to the data being passed into the service by <span style="color: #006800">Execute</span>. This is an example of leveraging interfaces for the sake of testability via Stand-Ins. Another aspect that is new to this scenario is working with bookmarks. Bookmarks are a key component to asynchronous activities and are used to indicate where the workflow is suppose to resume execution upon completion of some external process. To accommodate this in our unit test we have to setup a Moles delegate on the Moles version of <span style="color: #2b91af">NativeActivityContext.<span style="color: #006800">CreateBookmark</span><span style="color: #333333;"> method. I use the Moles delegate to&nbsp; capture the <span style="color: #2b91af">BookmarkOptions </span>value so I can validate that against an expected value using an Assert later in the unit test. Another addition to this scenario is providing a <span style="color: #2b91af">MolesDelegates</span><span style="color: #627e01">.</span><span style="color: #2b91af">Func <span style="color: #333333;">to handle access to the test extension service when the Execute method calls <span style="color: #006800">GetExtension</span><span style="color: #627e01">&lt;</span><span style="color: #2b91af">IWorkerService</span><span style="color: #627e01">&gt;</span><span style="color: green">()<span style="color: #333333;">.&nbsp; Finally the last piece that is new to this scenario is the synchronization.</span></span></span></span></span></span></p>
<p><span style="color: #2b91af"><span style="color: #333333;"><span style="color: #2b91af"><span style="color: #333333;"><span style="color: green"><span style="color: #333333;">In the <span style="color: #23ebaa">//Act<span style="color: #333333;"> section of the unit test you will notice a call to</span> <span style="color: #006800">WaitForWorkToComplete</span><span style="color: green"> <span style="color: #333333;">on the instance of</span> <span style="color: #2b91af">TestWorkerService. <span style="color: #333333;">This call blocks until a</span> WaitHandle<span style="color: #333333;"> is signaled by the new thread spawned by</span> <span style="color: #006800">Execute </span><span style="color: #333333;">and returns the value passed into the worker services'</span> <span style="color: #006800">DoWork <span style="color: #333333;">method. Since the behavior of the &ldquo;production&rdquo; worker service is simply to return the value passed in to the</span> DoWork <span style="color: #333333;">method the test Stand-In emulates the same behavior. </span></span></span></span></span></span></span></span></span></span></span><span style="color: #2b91af"><span style="color: #333333;"><span style="color: #2b91af"><span style="color: #333333;"><span style="color: green"><span style="color: #333333;"><span style="color: #23ebaa"><span style="color: green"><span style="color: #2b91af"><span style="color: #006800"><span style="color: #333333;"></span></span></span></span></span></span></span></span></span></span></span></p>
<h4>Sample Solution</h4>
<p>The sample solution contains a few more unit test scenarios not covered here.&nbsp; Below is a list of additional scenarios contained in the sample project.</p>
<ul>
<li>A test for the Abort method </li>
<li>A test for removing MultipleResume bookmarks within bookmark callback methods </li>
<li>A test for not removing MultipleResume bookmarks&nbsp; when asynchronous process fails. </li>
<li>A test that verifies tracking data. </li>
</ul>
<hr />
<div class="wlWriterEditableSmartContent" id="scid:8eb9d37f-1541-4f29-b6f4-1eea890d4876:723c2636-ecfb-4226-82f9-0b2cfa0f4415" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<p>&nbsp;</p>
<div>Complete sample code solution (VS 2010)<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/6281.UnitTestingActivitiesWithMoles.zip" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/6281.UnitTestingActivitiesWithMoles.zip">UnitTestingActivitiesWithMoles.zip</a></div>
<p>&nbsp;</p>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Rapid Prototyping with Workflow Foundation 4.0</title>
      <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/rapid-prototyping-with-workflow-foundation-4-0</link>
      <pubDate>Wed, 05 Jan 2011 23:05:27 GMT</pubDate>
      <dc:creator><![CDATA[sperniner]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/one_line_of_code_at_a_time/2011/01/05/rapid-prototyping-with-workflow-foundation-4-0/</guid>
      <description><![CDATA[While working on various projects within the Configuration Manager ecosystem here in Redmond I’ve...]]></description>
      <content:encoded><![CDATA[<p>While working on various projects within the Configuration Manager ecosystem here in Redmond I’ve had the opportunity to work with Workflow Foundation for a couple years now. Being in the enterprise software space it is not difficult to find a spot for Workflow Foundation within a given problem space or project as it makes for a cozy home for complex business logic routinely found in enterprise software. In a new project that I’m working on related to the upcoming version of Configuration Manager I had the opportunity to swindle the team into using Workflow Foundation as a core component to support all of our business logic. At the time I was in favor of using WF as I was familiar with the benefits of the tracking, persistence, and other features of WF,. all of which already have a multitude of blogs posts dedicated to them. One aspect that I had not explored prior to this project, and which is the subject of this blog post, is ability to rapidly prototype with Workflow Foundation.</p>  <p>While pinning down the vision and high level user stories it became apparent that the crux of this project was getting the business logic right, and doing that would require soliciting input from various subject matter experts from more than one team. Knowing this meant knowing that whatever we use to implement the business logic was going to go through much iteration as we shopped around our current thinking and incorporated feedback.</p>  <h1>It’s all about the Flows</h1>  <p>The nature of the FlowChart activity and its designer allows one to easily rearrange logic and components. But most importantly the Visio-esque FlowChart designer provided two key benefits. The first was that I found it was easy to stay abreast with the changes to our business logic flying out of our design and review meetings. Applying changes were simplified by the literal way in which Visio spec docs translate into a WF workflow definition. I was able to implement core behavior and be confident that it matched what was defined in the spec by simply comparing what I saw in Visio on one monitor with what I saw in the Visual Studio FlowChart designer on the other monitor. </p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/2318.image_117976C5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/2318.image_5F00_117976C5.png"><img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/34/metablogapi/7411.image_thumb_56B1CDEE.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-42-34-metablogapi/7411.image_5F00_thumb_5F00_56B1CDEE.png" width="510" height="510" /></a>     <br />Secondly, it made bridging the technical/nontechnical communication barrier much easier. Since I was working in an environment that was very similar to Visio and to what PMs are comfortable with, we were able to have discussions about the prototype directly. Ergo, non-technical team members were able to contribute to discussions involving the actual implementation or the “code”. This was helpful when the specifics of the implementation inevitably exceeded the detail or fidelity of the spec docs. Or put differently, it increased the relative area of the intersection between PM land and Dev land. The same could easily be achieved while working with Sequence style workflows. The key is to be deliberate about which style you are using in your design discussions and to avoid Visio’s flexible ad hoc nature to create spec diagrams that are some sort of hybrid mash up that won’t translate into some form of Workflow Foundation artifact. This increase in common ground between the disciplines has been a real asset for our team.     </p>]]></content:encoded>
    </item>
    <item>
      <title>Hello Blogosphere</title>
      <link>https://docs.microsoft.com/archive/blogs/one_line_of_code_at_a_time/hello-blogosphere</link>
      <pubDate>Tue, 07 Dec 2010 13:54:04 GMT</pubDate>
      <dc:creator><![CDATA[sperniner]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/one_line_of_code_at_a_time/2010/12/07/hello-blogosphere/</guid>
      <description><![CDATA[My name is Micah Smith and I’m a Dev on the MPSD Client Management Development team which is tasked...]]></description>
      <content:encoded><![CDATA[<p>My name is Micah Smith and I’m a Dev on the MPSD Client Management Development team which is tasked with creating tools and add on components to System Center products. My goal with this blog is to share how our team is solving enterprise management problems using core technologies such as the .Net Framework and infrastructural pieces like System Center SDKs. I also plan on sharing my experiences working within an development team that is pushing to adopt agile practices.</p>]]></content:encoded>
    </item>
  </channel>
</rss>