{"id":10177,"date":"2015-11-10T09:00:51","date_gmt":"2015-11-10T17:00:51","guid":{"rendered":"https:\/\/www.sapien.com\/blog\/?p=10177"},"modified":"2015-11-10T09:04:53","modified_gmt":"2015-11-10T17:04:53","slug":"powershellget-gui-part-1","status":"publish","type":"post","link":"https:\/\/dev.sapien.com\/blog\/2015\/11\/10\/powershellget-gui-part-1\/","title":{"rendered":"PowerShellGet-GUI Part 1"},"content":{"rendered":"<p>Back in mid-September, I presented a talk on &#8220;Building PowerShell GUI Tool Solutions&#8221; at the PowerShell Conference Asia in Singapore. The talk centered around GUI application design and development using PowerShell as the core language. During that talk , I developed an application that used PowerShell&#8217;s PSGet module to communicate with the PowerShell Gallery. Finishing\u00a0work was done by Devin Leaman of SAPIEN Technologies. The recorded talk should be available at some point on the <a href=\"http:\/\/psconf.azurewebsites.net\/Asia2015.html\">PowerShell Conference Asia Website<\/a>.<\/p>\n<p>The application creates an interface that displays gallery module information and allows the user to easily add and remove modules from their system. The complete source code can be found on the SAPIEN github repository here.<\/p>\n<p>The github\u00a0repository\u00a0contains the complete PowerShell Studio source code as well as a packaged .EXE of the final project and an .MSI ready for deployment. For those without PowerShell Studio, we have exported the complete project into a .PS1 file that can be run from the PowerShell console. We have also taken the .PS1 file and &#8220;modularized&#8221; it and posted it to the PowerShell Gallery <a href=\"https:\/\/www.powershellgallery.com\/packages\/PowerShellGetGUI\/\" target=\"_blank\">here<\/a>.<\/p>\n<p><strong>So let&#8217;s take a look at the project&#8230;<\/strong><\/p>\n<div id=\"attachment_10178\" style=\"width: 1047px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.19.43-AM.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-10178\" class=\"wp-image-10178 size-full\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.19.43-AM.png\" alt=\"PowerShellGet-GUI Interface\" width=\"1037\" height=\"744\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.19.43-AM.png 1037w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.19.43-AM-300x215.png 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.19.43-AM-1024x735.png 1024w\" sizes=\"auto, (max-width: 1037px) 100vw, 1037px\" \/><\/a><p id=\"caption-attachment-10178\" class=\"wp-caption-text\">Figure 1<\/p><\/div>\n<p>Figure 1 shows the completed application interface. The top left pane displays a sorted list of the modules found on the PowerShell Gallery. The top right pane shows details for the module selected from\u00a0the module list. The bottom pane is basically a dump of all the actions that are taken by the user and PowerShell cmdlet responses.<\/p>\n<p><strong>The Details<\/strong><\/p>\n<p>At the top of our file we start off with two calls to Import-Module: the first to import PowerShellGet and the second to import PackageManagement. (Actually, these are inserted automatically by PowerShell Studio when we include the appropriate cmdlet in our code.)<\/p>\n<p>Since GUI applications are event driven, most of our operational code goes into event-handlers. These are functions that are called by the application when a specific event occurs. For instance, when a user clicks on a button, that button&#8217;s &#8220;click&#8221; event handler is called. Default\u00a0event handlers are automatically\u00a0generated by PowerShell Studio when you double-click on an object in the designer. Event handlers are named using the following formula:<\/p>\n<p>$&lt;objectType&gt;&lt;objectName&gt;_&lt;eventName&gt;<\/p>\n<p>So for a BUTTON named MyButton, the CLICK event handler would be named:<\/p>\n<p>$buttonMyButton_Click<\/p>\n<p>For the purposes of this blog article, we are only going to examine the actual code that gets executed when an event occurs. Bear in mind that many object properties have been manipulated in the object &#8216;s Property list to help create a working UI. These are not being discussed here.<\/p>\n<p>&nbsp;<\/p>\n<div id=\"attachment_10188\" style=\"width: 1232px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.56.24-AM.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-10188\" class=\"wp-image-10188 size-full\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.56.24-AM.png\" alt=\"Screen Shot 2015-10-30 at 10.56.24 AM\" width=\"1222\" height=\"596\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.56.24-AM.png 1222w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.56.24-AM-300x146.png 300w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-10.56.24-AM-1024x499.png 1024w\" sizes=\"auto, (max-width: 1222px) 100vw, 1222px\" \/><\/a><p id=\"caption-attachment-10188\" class=\"wp-caption-text\">Figure 2<\/p><\/div>\n<p>The first event handler that we are concerned with is the form_load event ($formPowerShellGet_Load), seen at the top of\u00a0Figure 2. This event gets fired when the form is first loaded (as the name implies.) Our form_load event handler calls a user defined\u00a0function called Check-NuGet which verifies the availability of NuGet on the system. If NuGet is not available it prompts the user to download and install it. \u00a0Add-TextToOutputWindow is the\u00a0helper function that writes to the output pane at the bottom of the application.<\/p>\n<p>With NuGet installed, we can then implement our menu selection File-&gt;Get Modules. Besides enabling some menu options which the reader can explore on their own, this event handler calls a user defined function called Update-ListView as seen in Figure 3.<\/p>\n<div id=\"attachment_10207\" style=\"width: 675px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-1.48.20-PM.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-10207\" class=\"wp-image-10207 size-full\" src=\"https:\/\/www.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-1.48.20-PM.png\" alt=\"Screen Shot 2015-10-30 at 1.48.20 PM\" width=\"665\" height=\"1077\" srcset=\"https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-1.48.20-PM.png 665w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-1.48.20-PM-185x300.png 185w, https:\/\/dev.sapien.com\/blog\/wp-content\/uploads\/2015\/10\/Screen-Shot-2015-10-30-at-1.48.20-PM-632x1024.png 632w\" sizes=\"auto, (max-width: 665px) 100vw, 665px\" \/><\/a><p id=\"caption-attachment-10207\" class=\"wp-caption-text\">Figure 3<\/p><\/div>\n<p>This is a fairly long function so let&#8217;s go through it a step at a time.<\/p>\n<p>First, because we know that this function will take a bit of time (as it needs to communicate across the internet), we change the cursor to a wait cursor on line 22. We also could have put this code in a separate thread so as not to impact the UI. In lines 24-29, we store the top item&#8217;s index so that when we refresh the list we can return it to the same position. In lines 31-34, we check to see if there is an item selected, and if so, we store that item&#8217;s index.<\/p>\n<p>Using the Find-Module cmdlet (line 40), we connect to the PSGallery and store the result in a local variable, $psgModules. Then in line 43 we use Get-InstalledModule to get a list of the currently installed modules and store that as well ($instModules).<\/p>\n<p>In lines 46-65, we populate our list. By enclosing all the work between .BeginUpdate and .EndUpdate calls, we delay drawing the list until all the work has been done, thereby eliminating flashing of the list control. \u00a0For each module\u00a0in $psgModules, we get the name and the version and place those items into the list control. We also store the module itself in the listItems&#8217;s TAG property for easy access to the module later. <a href=\"https:\/\/www.sapien.com\/blog\/2013\/05\/23\/spotlight-on-controls-the-versatile-tag-property\/\">See this article <\/a>for more detailed information about the TAG property.<\/p>\n<p>In lines 55-63 we check to see if the module we just added is included in our installed modules ($instModules) array and if it is, we add a checkmark image to the list control.<\/p>\n<p>Remember when we stored the current selection above in line 33? Well, next we use that to check to see if an item had previously been selected and if so, we select it in the list. Then we scroll the list to the same location we stored ($topIndex) in line 26 to restore the list to the same state it was in previously (assuming that it had been scrolled and had an item selected.)<\/p>\n<p>Finally, we restore the cursor to an arrow cursor.<\/p>\n<p>Whew! Quite a lot of work there. I think that is enough for this post. We&#8217;ll look at the rest of the code in <a href=\"https:\/\/wp.me\/p3tXTf-2ES\">part 2<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Back in mid-September, I presented a talk on &#8220;Building PowerShell GUI Tool Solutions&#8221; at the PowerShell Conference Asia in Singapore. The talk centered around GUI application design and development using PowerShell as the core language. During that talk , I developed an application that used PowerShell&#8217;s PSGet module to communicate with the PowerShell Gallery. Finishing\u00a0work [&hellip;]<\/p>\n","protected":false},"author":4,"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":[22,2,946,723,25],"tags":[313,41,28,1016,1039,312],"class_list":["post-10177","post","type-post","status-publish","format-standard","hentry","category-events","category-general","category-guiprogramming","category-user-interface-design-for-administrators","category-windows-powershell","tag-forms","tag-gui","tag-powershell","tag-powershell-studio","tag-ui-design","tag-winforms"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/10177","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\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/comments?post=10177"}],"version-history":[{"count":19,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/10177\/revisions"}],"predecessor-version":[{"id":10296,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/10177\/revisions\/10296"}],"wp:attachment":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/media?parent=10177"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/categories?post=10177"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/tags?post=10177"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}