{"id":2560,"date":"2013-11-15T00:01:00","date_gmt":"2013-11-15T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/11\/15\/use-powershell-to-find-installed-software\/"},"modified":"2013-11-15T00:01:00","modified_gmt":"2013-11-15T00:01:00","slug":"use-powershell-to-find-installed-software","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-find-installed-software\/","title":{"rendered":"Use PowerShell to Find Installed Software"},"content":{"rendered":"<p><strong>Summary<\/strong>: Guest blogger, Marc Carter, reprises his popular blog post about locating installed software.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/tags\/marc+carter\/\" target=\"_blank\">Marc Carter<\/a> is joining us again today with another guest blog post&#8230;<\/p>\n<p>Looking back a couple years ago to my previous post, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/11\/13\/use-powershell-to-quickly-find-installed-software.aspx\" target=\"_blank\">Use PowerShell to Quickly Find Installed Software<\/a>, I find it interesting to reflect on common issues shared amongst the IT pro community. In our underlying goal to control our environment, whether that environment consists of a desktop computer, a development server, or production data center, we must first discover and understand before we can effectively attempt to control. Such is the case for sys admins when determining what software is currently configuring a server.<\/p>\n<p>But first, let&rsquo;s have a quick refresher on what initially prompted this discussion&hellip;<\/p>\n<h2><strong>Win32_Product: The Good, the Bad, and the Ugly<\/strong><\/h2>\n<p><em>&nbsp;[Good]<\/em> The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa394378(v=vs.85).aspx\" target=\"_blank\">Win32_Product WMI class<\/a> represents products as they are installed by Windows Installer.<\/p>\n<p>If you choose to query Win32_Product class by using <strong>Get-WmiObject<\/strong>, you&rsquo;ll find yourself <em>[Bad]<\/em> waiting for your query (or application) to return <em>[Ugly]<\/em> a consistency check of packages that are installed as it attempts to verify and repair installs. (For more information, see <a href=\"http:\/\/support.microsoft.com\/kb\/974524\" target=\"_blank\">Event log message indicates that the Windows Installer reconfigured all installed applications<\/a>).<\/p>\n<h3><strong>Problem #1: Um, is there a problem, officer?<\/strong><\/h3>\n<p>Querying the Win32_Product class to determine installed software is more than likely not your &ldquo;best&rdquo; option. Unfortunately, not everyone knows this.<\/p>\n<p><strong>Solution<\/strong>: (Understanding) Do your part and help spread the word.<\/p>\n<h3><strong>Problem #2: Identify better alternatives <\/strong><\/h3>\n<p>I really like some of the refinements and suggestions within comments that were mentioned by others on my previous post. One of the things I take a lot of pride in is my association with the men and women of US Army and their core values (<a href=\"http:\/\/www.army.mil\/values\" target=\"_blank\">The Army Values<\/a>).<\/p>\n<p>I see that similar mindset and participation reflected in the esprit de corps (or cohesion) of the Windows PowerShell community. As others have pointed out, there are a lot better and easier ways to gather information without invoking the Win32_Product class. One of my favorite alternatives involved suggestions from Knut Johansen and Mike Crowley: use the PS Registry Provider.<\/p>\n<p>The Windows PowerShell Registry provider lets you get, add, change, clear, and delete registry keys, entries, and values in Windows PowerShell. The Registry provider lets you access a hierarchical namespace that consists of registry keys and subkeys. Registry entries and values are not components of that hierarchy. Instead, they are properties of each of the keys. The Registry provider supports all the cmdlets that contain the &ldquo;item&rdquo; noun&mdash;that is, the <strong>Item<\/strong> cmdlets (except <strong>Invoke-Item<\/strong>) such as <strong>Get-Item<\/strong>, <strong>Copy-Item<\/strong>, and <strong>Rename-Item<\/strong>. Use the <strong>Item<\/strong> cmdlets when you work with registry keys and subkeys.<br \/> For more information, see <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh847848.aspx\" target=\"_blank\">Registry Provider<\/a>.<\/p>\n<p>In the following example, I use the <strong>Get-ItemProperty<\/strong> cmdlet to return values from the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa372105(v=vs.85).aspx\" target=\"_blank\">Uninstall Registry Key<\/a> within the HKEY LOCAL MACHINE (HKLM) Registry Provider, selecting specific properties and then formatting output.<\/p>\n<p style=\"padding-left: 30px\">Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | &nbsp;Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | <br \/> Format-Table &ndash;AutoSize<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2541.hsg-11-15-13-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2541.hsg-11-15-13-1.png\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>The <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh849851.aspx\" target=\"_blank\">Get-ItemProperty<\/a> cmdlet is a great tool because it&rsquo;s designed to work with data that is exposed by any provider. To get a better idea of the various providers that are available in your session, simply execute the <strong>Get-PSProvider<\/strong> cmdlet. &nbsp;<\/p>\n<p>And of course, depending on my needs, I could have also used alternative output methods like <strong>Out-GridView<\/strong> or <strong>Export-Csv<\/strong>. Either way, we&rsquo;ve now reduced the process to a one-liner that can be used in 64-bit and 32-bit environments:<\/p>\n<p style=\"padding-left: 30px\">Get-ItemProperty <strong>HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*<\/strong> | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | <br \/> Format-Table &ndash;AutoSize<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5125.hsg-11-15-13-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5125.hsg-11-15-13-2.png\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<h3><strong>Problem #3: Can we make it even more useful?<\/strong><\/h3>\n<p>Absolutely! We are talking Windows PowerShell after all&hellip;<\/p>\n<p>One way that comes to mind (and again, visible within the comments from the previous post), is addressing the issue of how to query multiple remote devices. My solution (or a number of reasons) is to rely on using the <strong>Invoke-Command<\/strong> cmdlet. In the following example, I query both of my SharePoint Web Front End (WFE) servers by using <strong>Invoke-Command<\/strong> to execute the same <strong>Get-ItemProperty<\/strong> on the remote system&rsquo;s HKLM PS Registry Provider:<\/p>\n<p style=\"padding-left: 30px\">Invoke-Command -cn wfe0, wfe1 -ScriptBlock {Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | select DisplayName, Publisher, InstallDate }<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5852.hsg-11-15-13-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5852.hsg-11-15-13-3.png\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>The output now includes the <strong>PSComputerName<\/strong> column, which will help when I want to sort results down the road. And there we have it&hellip;an easy method to report installed software!<\/p>\n<p>I look forward to reading comments from the Windows PowerShell community on other refinements and ways to improve this task. In many ways, I relate our efforts to that of a symphony or band. Each of us plays a different note in that we all hear and see things differently. Put us all together on the same sheet of music, and we have the potential for some awesome melodies.<\/p>\n<p>~Marc<\/p>\n<p>Thank you, Marc, for another awesome blog.<\/p>\n<p>I 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=\"mailto: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.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, Marc Carter, reprises his popular blog post about locating installed software. Microsoft Scripting Guy, Ed Wilson, is here. Marc Carter is joining us again today with another guest blog post&#8230; Looking back a couple years ago to my previous post, Use PowerShell to Quickly Find Installed Software, I find it interesting to [&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":[16,56,296,3,312,45],"class_list":["post-2560","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-desktop-management","tag-guest-blogger","tag-marc-carter","tag-scripting-guy","tag-software","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, Marc Carter, reprises his popular blog post about locating installed software. Microsoft Scripting Guy, Ed Wilson, is here. Marc Carter is joining us again today with another guest blog post&#8230; Looking back a couple years ago to my previous post, Use PowerShell to Quickly Find Installed Software, I find it interesting to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2560","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=2560"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2560\/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=2560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=2560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=2560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}