{"id":4205,"date":"2013-02-06T00:01:00","date_gmt":"2013-02-06T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/02\/06\/powershell-workflows-design-considerations\/"},"modified":"2013-02-06T00:01:00","modified_gmt":"2013-02-06T00:01:00","slug":"powershell-workflows-design-considerations","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/powershell-workflows-design-considerations\/","title":{"rendered":"PowerShell Workflows: Design Considerations"},"content":{"rendered":"<p><span style=\"font-size: 12px\"><strong>Summary:<\/strong>&nbsp;Windows PowerShell MVP and Honorary Scripting Guy Richard Siddaway talks about design considerations for Windows PowerShell workflows.<\/span>\nMicrosoft Scripting Guy, Ed Wilson, is here. Today, we have the seventh article in the most excellent Richard Siddaway workflow series.&nbsp;<\/p>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong> The first article, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/12\/26\/powershell-workflows-the-basics.aspx\" target=\"_blank\">PowerShell Workflows: The Basics<\/a><em>, <\/em>introduced the basic concepts of Windows PowerShell workflow. The second article, <a href=\"http:\/\/blogs.technet.comhttps:\/\/devblogs.microsoft.com\/scripting\/powershell-workflows-restrictions\/\" target=\"_blank\">PowerShell Workflows: Restrictions<\/a><em>, <\/em>discussed the restrictions encountered with working with Windows PowerShell workflows. The third article was <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2013\/01\/09\/powershell-workflows-nesting.aspx\" target=\"_blank\">PowerShell Workflows: Nesting<\/a>. The fourth article talked about <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2013\/01\/16\/powershell-workflows-job-engine.aspx\" target=\"_blank\">PowerShell Workflows: Job Engine<\/a>. The fifth article talked about <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2013\/01\/23\/powershell-workflows-restarting-the-computer.aspx\" target=\"_blank\">PowerShell Workflows: Restarting the Computer<\/a>. Next, was&nbsp;<a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2013\/01\/30\/powershell-workflows-using-parameters.aspx\" target=\"_blank\">PowerShell Workflow: Using Parameters<\/a>. You should read these articles before getting into today&rsquo;s article.\nTake it away, Richard &hellip;\nThe first big question you need to ask yourself is: &ldquo;Should this be a workflow or a normal Windows PowerShell script?&rdquo;\nMy fellow MVP Don Jones produced an excellent review of <a href=\"http:\/\/powershell.org\/wp\/2012\/08\/30\/powershell-workflow-when-should-you-use-it\/\" target=\"_blank\">when you should use workflows<\/a>:\nTo summarize Don&rsquo;s conclusions, you should use workflows when:<\/p>\n<ul>\n<li>You need to interrupt and restart tasks.<\/li>\n<li>You need to checkpoint the task (persistence).<\/li>\n<li>You have a mixture of sequential and parallel tasks.<\/li>\n<\/ul>\n<p>&nbsp;Some of the other potential reasons for using a workflow include:<\/p>\n<ul>\n<li>You need to perform a long-running task that combines multiple steps in a sequence.<\/li>\n<li>You need to perform a task that runs on multiple devices.<\/li>\n<li>You need to perform a long-running task that is asynchronous.<\/li>\n<li>You need to perform a long-running task that is parallelizable.<\/li>\n<\/ul>\n<p>In reality, these requirements can be met by Windows PowerShell scripts or background Jobs. One of the essentials for being regarded as an expert in a technology is being able to state when it shouldn&rsquo;t be used, so don&rsquo;t be afraid to say no to using a workflow!\nParallelization needs to be considered as having two aspects:<\/p>\n<ol>\n<li>Simultaneously running the same tasks on a number of machines.<\/li>\n<li>Simultaneously running a number of tasks on a single machine.<\/li>\n<\/ol>\n<p>In the first case, you could use Jobs or workflows. In the second case, you are definitely in workflow territory. There is a grey area. Imagine the case when you need to run a task on a large scale, or in high availability environments, that potentially requires throttling and connection pooling. This situation may be best suited to a Windows PowerShell Job or a workflow. There is no definitive answer either way. I know of organizations that have run Windows PowerShell Jobs that touched thousands of machines. Workflows are still too new for us to have a body of evidence to produce guidelines&mdash;if you&rsquo;ve run large-scale workflows, I&rsquo;d be interested in hearing your experiences, if you can share them.\nOne last thought before we start to look at some examples&mdash;even given that you could use a Windows PowerShell Job&mdash;<em>there is nothing wrong with using a workflow to get experience<\/em>. The only way to learn these techniques is to use them.\nLet&rsquo;s have a look at some examples. One common scenario is to add a registry key to a number of remote computers. Many organizations have a heterogeneous environment. I&rsquo;ll simulate that by using these machines.<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"133\">  <strong>Machine<\/strong><\/p>\n<\/td>\n<td valign=\"top\" width=\"210\">\n<p><strong>Operating system<\/strong><\/p>\n<\/td>\n<td valign=\"top\" width=\"258\">\n<p><strong>Windows PowerShell version<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"133\">\n<p>W12SUS<\/p>\n<\/td>\n<td valign=\"top\" width=\"210\">\n<p>Windows Server 2012<\/p>\n<\/td>\n<td valign=\"top\" width=\"258\">\n<p>Windows PowerShell 3.0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"133\">\n<p>Server02<\/p>\n<\/td>\n<td valign=\"top\" width=\"210\">\n<p>Windows Server 2012<\/p>\n<\/td>\n<td valign=\"top\" width=\"258\">\n<p>Windows PowerShell 3.0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"133\">\n<p>WebR201<\/p>\n<\/td>\n<td valign=\"top\" width=\"210\">\n<p>Windows Server 2008 R2<\/p>\n<\/td>\n<td valign=\"top\" width=\"258\">\n<p>Windows PowerShell 2.0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"133\">\n<p>Win7test<\/p>\n<\/td>\n<td valign=\"top\" width=\"210\">\n<p>Windows 7<\/p>\n<\/td>\n<td valign=\"top\" width=\"258\">\n<p>Windows PowerShell 3.0<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Creating a registry key and value is a job for WMI&mdash;you didn&rsquo;t think I wouldn&rsquo;t touch on it, did you? One of my machines uses Windows PowerShell 2.0, so I need to use the WMI cmdlets rather than the CIM cmdlets from Windows PowerShell 3.0, because the default connection for CIM cmdlets is WSMAN, but it has to be WSMAN v3.\nAdding the key involves these steps:<\/p>\n<p style=\"padding-left: 30px\">$hklm =&nbsp; 2147483650<\/p>\n<p style=\"padding-left: 30px\">$key = &#8220;SOFTWAREHSGworkflowDEMO&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key\nYou need these extra steps to add a value:<\/p>\n<p style=\"padding-left: 30px\">$value = &#8220;AreYouThere&#8221;<\/p>\n<p style=\"padding-left: 30px\">$data = &#8220;Yes&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value\nIn case you are wondering about the order of the parameters, I checked this with <strong>Get-CimClass<\/strong>:<\/p>\n<p style=\"padding-left: 30px\">$class = Get-CimClass -ClassName StdRegProv<\/p>\n<p style=\"padding-left: 30px\">$class.CimClassMethods[&#8220;SetStringValue&#8221;]<\/p>\n<p style=\"padding-left: 30px\">$class.CimClassMethods[&#8220;SetStringValue&#8221;].Parameters\nThis is what was returned:<\/p>\n<p style=\"padding-left: 30px\">Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CimType Qualifiers<\/p>\n<p style=\"padding-left: 30px\">&#8212;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;- &#8212;&#8212;&#8212;-<\/p>\n<p style=\"padding-left: 30px\">hDefKey&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UInt32 {ID, IN}<\/p>\n<p style=\"padding-left: 30px\">sSubKeyName&nbsp; String {ID, IN}<\/p>\n<p style=\"padding-left: 30px\">sValue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String {ID, in}<\/p>\n<p style=\"padding-left: 30px\">sValueName&nbsp;&nbsp; String {ID, in}\nIf you look at the documentation, it states the <strong>sValueName<\/strong> should occur <em>before<\/em> <strong>sValue<\/strong>, which makes sense, but <strong>Invoke-WmiMethod<\/strong> has an issue with parameters and seems to expect them in alphabetical order! If in doubt, use the order that <strong>Get-CimClass<\/strong> reports.\nThis demonstrates what is, probably, the most important point regarding the creation of workflows: <em>test your code outside of the workflow<\/em>. If you know your code works, it makes testing the workflow easier. Using this for a local machine is a simple script. If you want to run it remotely, you have a couple options:<\/p>\n<ol>\n<li>Use the <strong>&ndash;ComputerName<\/strong> parameter with <strong>Invoke-WmiMethod<\/strong> for each call.<\/li>\n<li>Wrap the commands in a script block and run remotely through <strong>Invoke-Command<\/strong>.<\/li>\n<\/ol>\n<p>In either case, you can use the <strong>&ndash;AsJob<\/strong> parameter.\nWe&rsquo;ll go with option 2.<\/p>\n<p style=\"padding-left: 30px\">$sb = {<\/p>\n<p style=\"padding-left: 30px\">$hklm =&nbsp; 2147483650<\/p>\n<p style=\"padding-left: 30px\">$key = &#8220;SOFTWAREHSGworkflowDEMO&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key<\/p>\n<p style=\"padding-left: 30px\">$value = &#8220;AreYouThere&#8221;<\/p>\n<p style=\"padding-left: 30px\">$data = &#8220;Yes&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Invoke-Command -ComputerName server02, w12sus, win7test, webr201 -ScriptBlock $sb\nThis could be run as a Windows PowerShell Job by adding the <strong>&ndash;AsJob<\/strong> parameter, which changes the last line to the following:<\/p>\n<p style=\"padding-left: 30px\">Invoke-Command -ComputerName server02, w12sus, win7test, webr201 -ScriptBlock $sb -AsJob\nAs a side note, I noticed that the commands on machines with Windows PowerShell 3.0 executed more quickly than the machine with Windows PowerShell 2.0.\nTo turn this into a workflow involves changing the code to look like this:<\/p>\n<p style=\"padding-left: 30px\">workflow new-regkey {<\/p>\n<p style=\"padding-left: 30px\">$hklm =&nbsp; 2147483650<\/p>\n<p style=\"padding-left: 30px\">$key = &#8220;SOFTWAREHSGworkflowDEMO&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key&nbsp;<\/p>\n<p style=\"padding-left: 30px\">$value = &#8220;AreYouThere&#8221;<\/p>\n<p style=\"padding-left: 30px\">$data = &#8220;Yes&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value<\/p>\n<p style=\"padding-left: 30px\">}\nAnd we run the workflow by using the <strong>&ndash;PSComputerName<\/strong> parameter:<\/p>\n<p style=\"padding-left: 30px\">new-regkey -PSComputerName server02, w12sus, win7test, webr201\nSo far, we have a simple task that could be accomplished in a number of ways. Let&rsquo;s complicate things a bit. Your task becomes:<\/p>\n<ul>\n<li>Create a registry key:&nbsp; HKLM:SOFTWAREHSGworkflowDEMO<\/li>\n<li>Create three values in that key and populate each with a given value:  \n<ul>\n<li>AreYouThere = Yes<\/li>\n<li>AreWeThereYet = No<\/li>\n<li>PowerShell = 1<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>This gives you a mixture of parallel and sequential tasks. You have to create the key before the values, but you can create the values in parallel. You could code this as a Windows PowerShell script, and it would work perfectly but sequentially. Using a workflow means you can do things in parallel, which may be more efficient. One solution to creating a workflow to solve this problem looks like this:<\/p>\n<p style=\"padding-left: 30px\">workflow new-regkey {<\/p>\n<p style=\"padding-left: 30px\">$hklm =&nbsp; 2147483650<\/p>\n<p style=\"padding-left: 30px\">$key = &#8220;SOFTWAREHSGworkflowDEMO&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key<\/p>\n<p style=\"padding-left: 30px\">parallel {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;sequence {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $value = &#8220;AreYouThere&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $data = &#8220;Yes&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;} # end of sequence<\/p>\n<p style=\"padding-left: 30px\">&nbsp;sequence {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $value = &#8220;PowerShell&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $data = 1<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Invoke-WmiMethod -Class StdRegProv -Name SetDwordValue -ArgumentList $hklm, $key, $value, $data<\/p>\n<p style=\"padding-left: 30px\">&nbsp;} # end of sequence<\/p>\n<p style=\"padding-left: 30px\">&nbsp;sequence {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $value = &#8220;AreWeThereYet&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $data = &#8220;No&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;}# end of sequence<\/p>\n<p style=\"padding-left: 30px\">}# end of parallel<\/p>\n<p style=\"padding-left: 30px\">}\nRun the workflow:<\/p>\n<p style=\"padding-left: 30px\">new-regkey -PSComputerName server02, w12sus, win7test, webr201\nNotice the order of arguments changes for <strong>Invoke-WmiMethod<\/strong> in the second sequence block. One of the joys of WMI. I really like the way you can use the <strong>&ndash;PSComputername<\/strong> parameter in the workflow, and it automatically passes the computer names to the workflow activities.\nThe workflow breaks down like this:<\/p>\n<ul>\n<li>Sequentially:  \n<ul>\n<li>Create the registry key<\/li>\n<li>In parallel create three registry values&mdash;two strings and one integer  \n<ul>\n<li>The creation of each value consists of three sequential steps<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>This is where the fun, headaches, and skill come into designing your workflows&mdash;deciding what can run in parallel, what has to run sequentially, what variables are needed, and identifying any scope issues.\nAs with any major piece of work, I recommend sitting down and designing your workflow before you start coding. I covered how I go about creating a script to solve a problem in <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/04\/20\/expert-commentary-2012-scripting-games-advanced-event-5.aspx\" target=\"_blank\">my commentary on the 2012 Scripting Games<\/a>.\nFor workflows, your decision making needs to cover:<\/p>\n<ul>\n<li>What tasks is the workflow performing?<\/li>\n<li>In what order do those tasks occur?<\/li>\n<li>What can be performed in parallel?<\/li>\n<li>Do I need any InLineScript blocks?<\/li>\n<li>What variables do I need and where are they defined?<\/li>\n<ul>\n<li>What is the impact of workflow scope?<\/li>\n<\/ul>\n<li>Does the workflow run against remote computers?<\/li>\n<ul>\n<li>Does it run on the local machine and access remote computers or run through remoting so that it is running on the remote computer?<\/li>\n<li>Where do I define the computer name parameters&mdash;workflow or activity or cmdlet?<\/li>\n<\/ul>\n<li>What do I want returned by the workflow?<\/li>\n<li>Is there a computer restart involved in the workflow?<\/li>\n<li>Do I need to checkpoint the workflow?<\/li>\n<ul>\n<li>If so, how often?<\/li>\n<\/ul>\n<li>Do I need to store output data outside the workflow?<\/li>\n<li>Will the workflow run as a Job?<\/li>\n<\/ul>\n<p>You&rsquo;ve seen how to perform these tasks in previous workflows. How the pieces go together depends on the problem you are trying to solve.\nIn case you were wondering how to remove the registry keys you&rsquo;ve created:<\/p>\n<p style=\"padding-left: 30px\">$sb = {<\/p>\n<p style=\"padding-left: 30px\">$hklm =&nbsp; 2147483650<\/p>\n<p style=\"padding-left: 30px\">$key = &#8220;SOFTWAREHSGworkflowDEMO&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-WmiMethod -Class StdRegProv -Name DeleteKey -ArgumentList $hklm, $key<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">Invoke-Command -ComputerName server02, w12sus, win7test, webr201 -ScriptBlock $sb\nDeleting the key removes the key, any sub-keys, and any values.\nThis installment has been a bit wordier than the others, but normal service will be resumed next time when you get a big workflow to consider, which incorporates a lot of what we&rsquo;ve covered in the series.\n~Richard\nThank you, Richard. This series is most excellent, and I really appreciate you taking the time to share your knowledge with the Windows PowerShell scripting community.\nJoin me tomorrow when I will talk about more cool Windows PowerShell stuff.\nI invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.\n<strong>Ed Wilson, Microsoft Scripting Guy<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary:&nbsp;Windows PowerShell MVP and Honorary Scripting Guy Richard Siddaway talks about design considerations for Windows PowerShell workflows. Microsoft Scripting Guy, Ed Wilson, is here. Today, we have the seventh article in the most excellent Richard Siddaway workflow series.&nbsp; Note The first article, PowerShell Workflows: The Basics, introduced the basic concepts of Windows PowerShell workflow. The [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[56,362,189,3,45,382],"class_list":["post-4205","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-guest-blogger","tag-powershell-3","tag-richard-siddaway","tag-scripting-guy","tag-windows-powershell","tag-workflow"],"acf":[],"blog_post_summary":"<p>Summary:&nbsp;Windows PowerShell MVP and Honorary Scripting Guy Richard Siddaway talks about design considerations for Windows PowerShell workflows. Microsoft Scripting Guy, Ed Wilson, is here. Today, we have the seventh article in the most excellent Richard Siddaway workflow series.&nbsp; Note The first article, PowerShell Workflows: The Basics, introduced the basic concepts of Windows PowerShell workflow. The [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/4205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=4205"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/4205\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=4205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=4205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=4205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}