{"id":15677,"date":"2018-08-07T06:00:51","date_gmt":"2018-08-07T13:00:51","guid":{"rendered":"https:\/\/www.sapien.com\/blog\/?p=15677"},"modified":"2018-08-06T15:03:26","modified_gmt":"2018-08-06T22:03:26","slug":"powershell-studio-azure-background-jobs-in-gui-application-with-helper-functions","status":"publish","type":"post","link":"https:\/\/dev.sapien.com\/blog\/2018\/08\/07\/powershell-studio-azure-background-jobs-in-gui-application-with-helper-functions\/","title":{"rendered":"PowerShell Studio: Azure Background Jobs in GUI application with Helper Functions"},"content":{"rendered":"<p>PowerShell Studio provides application templates and helper functions to help you speed up your development process.<\/p>\n<p>The <a href=\"https:\/\/www.sapien.com\/blog\/2018\/07\/19\/new-video-powershell-studio-working-with-azure-cmdlets-in-background-jobs\/\">recent blog post series<\/a>\u00a0on creating an Azure application shows the evolution of an Azure solution from a console script to a Windows application. In the <a href=\"https:\/\/www.sapien.com\/blog\/2018\/07\/31\/new-video-powershell-studio-working-with-azure-cmdlets-in-background-jobs-in-a-gui-app\/\">previous post<\/a> I used an empty form with two controls (Button &amp; RichTextBox), and then started building from an existing console script. Then I added code with logic to handle the background job process.<\/p>\n<p>Now I&#8217;m going to take it a little further with the help of PowerShell Studio&#8217;s ready-to-use templates.<\/p>\n<h3>Using &#8220;Grid Job&#8221; Template<\/h3>\n<p>I am going to use the GUI Form &#8220;<strong>Grid Job<\/strong>&#8221; template (File\u00a0&gt; New\u00a0&gt; New\u00a0 Form\u00a0&gt; Forms &gt; Grid Job).<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15681\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39-300x175.jpg\" alt=\"\" width=\"835\" height=\"487\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39-300x175.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39-768x449.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39-1024x598.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39-848x496.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_01_2018-07-31_9-26-39.jpg 1790w\" sizes=\"auto, (max-width: 835px) 100vw, 835px\" \/><\/a><\/p>\n<p>This is a PowerShell Studio single form file which includes some of SAPIEN&#8217;s Helper Functions\u00a0 to assist with your GUI application development.<\/p>\n<p>Below is a list of the Helper Functions available when using the &#8220;<strong>Grid Job<\/strong>&#8221; template:<\/p>\n<ul>\n<li><strong>Add-JobTracker<\/strong><\/li>\n<li>Update-JobTracker<\/li>\n<li>Stop-JobTracker<\/li>\n<li><strong>ConvertTo-DataTable<\/strong><\/li>\n<li><strong>Update-DataGridView<\/strong><\/li>\n<li>SearchGrid<\/li>\n<\/ul>\n<p>In this article I will cover the JobTracker\u00a0<strong>Add-JobTracker<\/strong>\u00a0helper function and the DataGridView <strong>ConvertTo-DataTable<\/strong> and <strong>Update-DataGridView<\/strong> helper functions.<\/p>\n<p>First I will change the Button control text property from &#8220;<em>Query<\/em>&#8221; to &#8220;<em>StartJob<\/em>&#8220;. Then I will add a Label control and change the label text property to &#8220;<em>Time:<\/em>&#8220;. Finally, I will save the file as &#8220;<em>JobTracker_AzureRM_Sample.psf<\/em>&#8220;.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15682\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39-300x201.jpg\" alt=\"\" width=\"828\" height=\"555\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39-300x201.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39-768x515.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39-1024x687.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39-848x569.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_02_2018-07-31_9-26-39.jpg 1314w\" sizes=\"auto, (max-width: 828px) 100vw, 828px\" \/><\/a><\/p>\n<h3>Understanding JobTracker Function<\/h3>\n<p>Before I start to implement my code, let&#8217;s take a look at the main function used for background job processing: <strong>Add-JobTracker<\/strong>.<\/p>\n<pre>Basic usage syntax:\r\nAdd-JobTracker [-Name] &lt;String&gt; [-JobScript] &lt;ScriptBlock&gt; [[-ArgumentList] &lt;Object&gt;] [[-CompletedScript] &lt;ScriptBlock&gt;] [[-UpdateScript] &lt;ScriptBlock&gt;] [&lt;CommonParameters&gt;]<\/pre>\n<p>The following parameters can be used:<\/p>\n<ul>\n<li><em>Name<\/em> &#8211; This is the name of the background job.<\/li>\n<li><em>JobScript<\/em> &#8211; This is the code to executed in the background job.<\/li>\n<li><em>CompletedScript<\/em> &#8211; This is the code to execute at the completion of the background job.<\/li>\n<li><em>UpdateScript<\/em> &#8211; This code executes while the background job is running.<\/li>\n<li><em>ArgumentList<\/em> &#8211; (Optional) Only used if there is a need to pass a value to the ScriptBlock.<\/li>\n<\/ul>\n<p>The JobTracker functions can be found in a custom Control Set labeled &#8220;<em>Button &#8211; Start Job<\/em>&#8221; which is part of the &#8220;<strong>Grid Job<\/strong>&#8221; template.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15685\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39-300x183.jpg\" alt=\"\" width=\"836\" height=\"510\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39-300x183.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39-768x469.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39-1024x625.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39-848x518.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_03_2018-07-31_9-26-39.jpg 1063w\" sizes=\"auto, (max-width: 836px) 100vw, 836px\" \/><\/a><\/p>\n<p>The JobTracker helper functions are highlighted below:<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_10_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15702\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_10_2018-07-31_9-26-39-231x300.jpg\" alt=\"\" width=\"302\" height=\"393\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_10_2018-07-31_9-26-39-231x300.jpg 231w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_10_2018-07-31_9-26-39.jpg 323w\" sizes=\"auto, (max-width: 302px) 100vw, 302px\" \/><\/a><\/p>\n<p>The\u00a0&#8220;<strong>Grid Job<\/strong>&#8221; template also has a DataGridView component, with helper functions that convert and display the receive-job result in a simple format.<\/p>\n<h3>Understanding DataGridView Functions<\/h3>\n<p>Here&#8217;s where I can use the following helper functions:<\/p>\n<p><strong>ConvertTo-DataTable<\/strong> &#8211; This function converts the result object into a data table object.<br \/>\n<strong>Update-DataGridView<\/strong> &#8211; This function reads the data type object to be displayed in the DataGridView component.<\/p>\n<pre>Basic usage syntax:\r\nConvertTo-DataTable [[-InputObject] &lt;Object&gt;] [[-Table] &lt;DataTable&gt;] [-RetainColumns] [-FilterWMIProperties] [&lt;CommonParameters&gt;]\r\n\r\nUpdate-DataGridView [-DataGridView] &lt;DataGridView&gt; [-Item] &lt;Object&gt; [[-DataMember] &lt;String&gt;] `\r\n[[-AutoSizeColumns] {None | ColumnHeader | AllCellsExceptHeader | AllCells | DisplayedCellsExceptHeader | DisplayedCells | Fill} ] [&lt;CommonParameters&gt;]<\/pre>\n<p>Array objects created in PowerShell can be displayed in a DataGridView component. The benefit of using a DataTable is that it allows you to use sorting. This can be accomplished with the following two lines of code:<\/p>\n<pre>## - Sample Code to display converted data table object results into a Databgridview component:\r\n$dgvResults = ConvertTo-DataTable -InputObject $results -FilterWMIProperties;\r\nUpdate-DataGridView -DataGridView $datagridviewResults -Item $dgvResults -AutoSizeColumns DisplayedCells;<\/pre>\n<p>Note that &#8220;<em>$datagridviewResults<\/em>&#8221; is the name on the DataGridView component in the form:<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15693\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39-300x144.jpg\" alt=\"\" width=\"832\" height=\"399\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39-300x144.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39-768x368.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39-1024x491.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39-848x407.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_05_2018-07-31_9-26-39.jpg 1055w\" sizes=\"auto, (max-width: 832px) 100vw, 832px\" \/><\/a><\/p>\n<p>The DataGridView helper functions are highlighted below:<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_11_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15703\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_11_2018-07-31_9-26-39-231x300.jpg\" alt=\"\" width=\"315\" height=\"409\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_11_2018-07-31_9-26-39-231x300.jpg 231w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_11_2018-07-31_9-26-39.jpg 330w\" sizes=\"auto, (max-width: 315px) 100vw, 315px\" \/><\/a><\/p>\n<h3>Some Additional Changes<\/h3>\n<p>I also made the following additional changes:<\/p>\n<p>In the <em>$formMain_Load<\/em>\u00a0form event, I added a global variable for the job name: <em>$global:JobName<\/em>. For now, this is a hard-coded constant string.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_06_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15694\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_06_2018-07-31_9-26-39-300x160.jpg\" alt=\"\" width=\"564\" height=\"301\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_06_2018-07-31_9-26-39-300x160.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_06_2018-07-31_9-26-39.jpg 728w\" sizes=\"auto, (max-width: 564px) 100vw, 564px\" \/><\/a><\/p>\n<p>In the <em>$buttonStartJob_Click<\/em>\u00a0button event, I added the Timer code which updates the label &#8220;<em>Timer:<\/em>&#8221; text property with the recurring execution time.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_07_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15695\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_07_2018-07-31_9-26-39-300x133.jpg\" alt=\"\" width=\"564\" height=\"250\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_07_2018-07-31_9-26-39-300x133.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_07_2018-07-31_9-26-39-768x340.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_07_2018-07-31_9-26-39-848x375.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_07_2018-07-31_9-26-39.jpg 929w\" sizes=\"auto, (max-width: 564px) 100vw, 564px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_08_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15696\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_08_2018-07-31_9-26-39-300x205.jpg\" alt=\"\" width=\"562\" height=\"384\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_08_2018-07-31_9-26-39-300x205.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_08_2018-07-31_9-26-39-768x525.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_08_2018-07-31_9-26-39-848x580.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_08_2018-07-31_9-26-39.jpg 932w\" sizes=\"auto, (max-width: 562px) 100vw, 562px\" \/><\/a><\/p>\n<p>In the <strong>Add-JobTracker<\/strong>\u00a0function I added the &#8220;<em>-ArgumentList<\/em>&#8221; parameter to pass the hard-coded system name value. In the &#8220;-JobScript&#8221; parameter, values can be passed through the Param($Argument1).<\/p>\n<p>Note that you can rename this variable to suit your needs\u2014with a descriptive name that describes the purpose of the argument.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_09_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15699\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_09_2018-07-31_9-26-39-300x126.jpg\" alt=\"\" width=\"562\" height=\"236\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_09_2018-07-31_9-26-39-300x126.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_09_2018-07-31_9-26-39-768x322.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_09_2018-07-31_9-26-39-848x355.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_09_2018-07-31_9-26-39.jpg 924w\" sizes=\"auto, (max-width: 562px) 100vw, 562px\" \/><\/a><\/p>\n<p>Remember, any hard-coded variable is a prospect for automation. It is up to the developer to improve the application.<\/p>\n<h3>Working with Add-JobTracker function<\/h3>\n<p>Next I start adding the code in the <strong>Add-JobTracker<\/strong> function. All of this is happening in the <em>$buttonStartJob_Click<\/em> button event.<\/p>\n<p>The following image shows the areas where the code can be added and follows the process after the ScriptBlock has been submitted to the background for processing:<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_04_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15728\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_04_2018-07-31_9-26-39-300x264.jpg\" alt=\"\" width=\"557\" height=\"490\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_04_2018-07-31_9-26-39-300x264.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_04_2018-07-31_9-26-39-768x676.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_04_2018-07-31_9-26-39-848x746.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_04_2018-07-31_9-26-39.jpg 957w\" sizes=\"auto, (max-width: 557px) 100vw, 557px\" \/><\/a><\/p>\n<p>In this Azure GUI form sample I am using the following <strong>Add-JobTracker<\/strong> function parameters in the <em>$buttonStartJob_Click<\/em>\u00a0button event:<\/p>\n<p>1. &#8216;<em>-Name<\/em>&#8216; and the &#8216;<em>-ArgumentList<\/em>&#8216;:<\/p>\n<pre> Add-JobTracker -Name $global:JobName -ArgumentList 'Win2K16VM1' `...<\/pre>\n<p>2. &#8216;<em>-JobScript<\/em>&#8216;:<\/p>\n<pre>#region AddScriptBlockJob\r\n\r\n#--------------------------------------------------\r\n# Add Script Code below\r\n# -------------------------------------------------\r\n\r\n## - Automatic Sign-On to Azure:\r\nImport-AzureRmContext -Path 'c:\\Temp\\WinPS_AsubRMprofile.json' | Out-Null;\r\n\r\nWrite-Host \"Stopping Azure VM - $Argument1\";\r\n\r\n## - Run Azure cmdlet with AsJob parameter:\r\nStop-AzureRMVM -ResourceGroupName \"GlobalAzureBootCampResources\" `\r\n-Name $Argument1 `\r\n-Force;\r\n\r\n#--------------------------------------------------\r\n# End of Script Code\r\n# -------------------------------------------------\r\n\r\n#endregion AddScriptBlockJob<\/pre>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15705\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39-300x141.jpg\" alt=\"\" width=\"709\" height=\"333\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39-300x141.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39-768x361.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39-1024x481.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39-848x399.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_12_2018-07-31_9-26-39.jpg 1219w\" sizes=\"auto, (max-width: 709px) 100vw, 709px\" \/><\/a><\/p>\n<p>3. &#8216;<em>-CompletedScript<\/em>&#8216;:<\/p>\n<pre>#region EndOfJopScript\r\n\r\n#--------------------------------------------------\r\n# Add Script Code below\r\n# -------------------------------------------------\r\n \r\n## - Popup messagebox:\r\n[System.Windows.Forms.MessageBox]::Show('Background Task Completed!','CompletedScript Event Message')\r\n## - CompletedScript will only show data if there are any:\r\n$results = Receive-Job -Job $Job -Keep;\r\n\r\n## - Add code display Receive-Job results in the Databgridview:\r\n$dgvResults = ConvertTo-DataTable -InputObject $results -FilterWMIProperties;\r\nUpdate-DataGridView -DataGridView $datagridviewResults -Item $dgvResults -AutoSizeColumns DisplayedCells;\r\n\r\n#--------------------------------------------------\r\n# End of Script Code\r\n# -------------------------------------------------\r\n\r\n#endregion EndOfJopScript<\/pre>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15719\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39-300x157.jpg\" alt=\"\" width=\"686\" height=\"359\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39-300x157.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39-768x402.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39-1024x537.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39-848x444.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_13_2018-07-31_9-26-39.jpg 1225w\" sizes=\"auto, (max-width: 686px) 100vw, 686px\" \/><\/a><\/p>\n<p>4. &#8216;<em>-UpdateScript<\/em>&#8216; &#8211; There are two added code blocks: &#8220;<em>UpdateJobResults<\/em>&#8221; and the &#8220;<em>TimerUpdateCode<\/em>&#8220;.<\/p>\n<pre>#region UpdateJobResults\r\n\r\n#--------------------------------------------------\r\n# Add Script Code below\r\n# -------------------------------------------------\r\n\r\n## - Commented out line below, enabled if needed:\r\n$results = Get-Job -Name $global:JobName `\r\n| Select-Object -property State, Name, PSBeginTime, PSEndTime, PSJobTypeName, Command, location;\r\n\r\n$dgvResults = ConvertTo-DataTable -InputObject $results -FilterWMIProperties;\r\nUpdate-DataGridView -DataGridView $datagridviewResults -Item $dgvResults -AutoSizeColumns DisplayedCells\r\n\r\n#--------------------------------------------------\r\n# End of Script Code\r\n# -------------------------------------------------\r\n\r\n#endregion UpdateJobResults<\/pre>\n<pre>#region TimerUpdateCode\r\n\r\n#--------------------------------------------------\r\n#\t\t\tScript Code Added for timer\r\n# -------------------------------------------------\r\n\r\n## - To Display Time Elapsed and update datagridviewGetJob:\r\n$CurrentTime = $global:Time.Elapsed;\r\n$DisplayTime = $([string]::Format(\"Time: {0:d2}:{1:d2}:{2:d2}\",\r\n\t       $CurrentTime.hours,\r\n\t       $CurrentTime.minutes,\r\n\t       $CurrentTime.seconds))\r\n$labelTime.Text = $DisplayTime;\r\n\r\n#--------------------------------------------------\r\n#\t\t\tEnd of Script Code\r\n# -------------------------------------------------\r\n\r\n#endregion TimerUpdateCode<\/pre>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15730\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39-300x208.jpg\" alt=\"\" width=\"699\" height=\"484\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39-300x208.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39-768x532.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39-1024x710.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39-848x588.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_14a_2018-07-31_9-26-39.jpg 1221w\" sizes=\"auto, (max-width: 699px) 100vw, 699px\" \/><\/a><\/p>\n<p>You can use both the &#8216;<em>-UpdateScript<\/em>&#8216; and &#8216;<em>-CompletedScript<\/em>&#8216; parameter section to update the information on the DataGridView component.<\/p>\n<p>In this Azure GUI form application I am using the <strong>Get-Job<\/strong> cmdlet results to display the progress of the background job in the DataGridView component during the &#8220;<em>-UpdateScript<\/em>&#8221; process. When the job completes, the &#8220;<em>-CompletedScript<\/em>&#8221; section gets the result from the <strong>Receive-Job<\/strong> cmdlet that is sent to the DataGridView component.<\/p>\n<p><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-15723\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39-300x147.jpg\" alt=\"\" width=\"747\" height=\"366\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39-300x147.jpg 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39-768x377.jpg 768w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39-1024x503.jpg 1024w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39-848x417.jpg 848w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureBJ_15_2018-07-31_9-26-39.jpg 1412w\" sizes=\"auto, (max-width: 747px) 100vw, 747px\" \/><\/a><\/p>\n<h3>Summary<\/h3>\n<p>This &#8220;<strong>Grid job<\/strong>&#8221; sample shows how to integrate Azure scripts into a GUI application to take advantage of background processing.<\/p>\n<p>Remember to submit Azure scripts as background jobs to prevent the GUI form from freezing.<\/p>\n<p>This article covered two main topics:<br \/>\n1. Use the JobTracker <strong>Add-JobTracker<\/strong> helper function to submit the Azure code as a background job.<br \/>\n2. Use the DataGridView helper functions (<strong>ConvertTo-DataTable<\/strong>\u00a0and\u00a0<strong>Update-DataGridView<\/strong>) to display the results during and after the background process.<\/p>\n<p>I also covered the parameters used in the <strong>Add-JobTracker<\/strong> function which is enough to get you started.<\/p>\n<p>PowerShell Studio template can cut down time in development. Specially when taking time to understand these helper functions.<\/p>\n<p>You can download the updated sample Windows GUI here:\u00a0<a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/JobTracker_AzureRM_Sample.zip\" target=\"_blank\" rel=\"noopener\">JobTracker_AzureRM_Sample.zip<\/a><br \/>\nCheckout this short two minute video showing the GUI form in action: <a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2018\/08\/AzureGUIHelperFunctions_06.mp4\" target=\"_blank\" rel=\"noopener\">Sample_AzureGUI_HelperFunctions<\/a><\/p>\n<h3>Related Articles<\/h3>\n<ul>\n<li><a href=\"https:\/\/info.sapien.com\/index.php\/guis\/gui-scripting\/powershell-gui-apps-why-think-in-events\">PowerShell GUI Apps: Why think in events?<\/a><\/li>\n<li><a href=\"https:\/\/info.sapien.com\/index.php\/guis\/gui-advanced-tips\/powershell-studio-creating-responsive-forms\">PowerShell Studio: Creating Responsive Forms<\/a><\/li>\n<li><a href=\"https:\/\/www.sapien.com\/blog\/2018\/07\/12\/powershell-studio-how-to-prevent-powershell-cmdlets-from-hanging-in-gui-apps\/\">PowerShell Studio: How to prevent Powershell cmdlets from hanging in GUI apps<\/a><\/li>\n<li><a href=\"https:\/\/www.sapien.com\/blog\/2018\/07\/19\/new-video-powershell-studio-working-with-azure-cmdlets-in-background-jobs\/\">New Video \u2013 PowerShell Studio: Working with Azure cmdlets in Background Jobs<\/a><\/li>\n<li><a href=\"https:\/\/www.sapien.com\/blog\/2018\/07\/31\/new-video-powershell-studio-working-with-azure-cmdlets-in-background-jobs-in-a-gui-app\/\">New Video \u2013 PowerShell Studio: Working with Azure cmdlets in Background Jobs in a GUI app<\/a><\/li>\n<\/ul>\n<h3>Feedback<\/h3>\n<p>As always, if you have any ideas, comments, or feedback, please\u00a0<a href=\"https:\/\/www.sapien.com\/forums\/viewforum.php?f=23\" target=\"_blank\" rel=\"noopener\">visit our feedback forum<\/a>\u00a0and reference this post.<\/p>\n<p>&nbsp;<\/p>\n<p><em>Max Trinidad is a Technology Evangelist at SAPIEN Technologies Inc., and a Microsoft PowerShell MVP. You can reach him at\u00a0<a href=\"mailto:maxt@sapien.com\">maxt@sapien.com<\/a><\/em><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PowerShell Studio provides application templates and helper functions to help you speed up your development process. The recent blog post series\u00a0on creating an Azure application shows the evolution of an Azure solution from a console script to a Windows application. In the previous post I used an empty form with two controls (Button &amp; RichTextBox), [&hellip;]<\/p>\n","protected":false},"author":47,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1143,941,703,25],"tags":[28,961,1016,997],"class_list":["post-15677","post","type-post","status-publish","format-standard","hentry","category-powershell","category-powershell-5-0","category-powershell-studio","category-windows-powershell","tag-powershell","tag-powershell-5-0","tag-powershell-studio","tag-windows-powershell"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/15677","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/users\/47"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/comments?post=15677"}],"version-history":[{"count":38,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/15677\/revisions"}],"predecessor-version":[{"id":15746,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/15677\/revisions\/15746"}],"wp:attachment":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/media?parent=15677"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/categories?post=15677"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/tags?post=15677"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}