{"id":9311,"date":"2012-05-26T00:01:00","date_gmt":"2012-05-26T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/05\/26\/weekend-scripter-the-mission-for-true-up-data-via-get-wmiobject\/"},"modified":"2012-05-26T00:01:00","modified_gmt":"2012-05-26T00:01:00","slug":"weekend-scripter-the-mission-for-true-up-data-via-get-wmiobject","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-the-mission-for-true-up-data-via-get-wmiobject\/","title":{"rendered":"Weekend Scripter: The Mission for &#8220;True-Up&#8221; Data Via Get-WmiObject"},"content":{"rendered":"<p><b>Summary<\/b>: Guest blogger, Brian Wilhite, shares his experience using Windows PowerShell jobs to speed up collecting information from WMI.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. This weekend, we will start with guest blogger, Brian Wilhite.<\/p>\n<p style=\"padding-left: 30px\">Brian Wilhite works as a Windows system administrator for a large health-care provider in North Carolina. He has over 15 years of experience in IT. In his current capacity as a Windows system administrator, he leads a team of individuals who have responsibilities for Microsoft Exchange Server, Windows Server builds, and management and system performance. Brian also supports and participates in the <a href=\"http:\/\/powershellgroup.org\/charlotte.nc\" target=\"_blank\">Charlotte PowerShell Users Group<\/a>. <br \/> Twitter: <a href=\"https:\/\/twitter.com\/bwilhite1979\" target=\"_blank\">Brian Wilhite<\/a><\/p>\n<p>Take it away Brian&hellip;<\/p>\n<p>Here in North Carolina, it&rsquo;s getting warmer, the rain is falling, flowers are blooming, and nature is giving us a blast of pollen to last a lifetime&mdash;yes, spring is in full swing. Like most things that are common with this time of year, so is my organization&rsquo;s Microsoft Enterprise Agreement &ldquo;True-Up.&rdquo; If you are like us, we gather information from various data sources, such as SCCM, Active Directory and\/or a CMDB. I was on a mission, given to me by my manager, to track down all Windows Server installations in my organization&rsquo;s domain. I began by querying Active Directory for computer objects that have a server operating system by using the Active Directory module in Windows PowerShell. To import the Active Directory module, I will have to, <i>you guessed it<\/i>, use <b>Import-Module<\/b>. It looks like this:<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/prod.evol.blogs.technet.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/00\/76\/18\/6710.Fig1.JPG\"><img decoding=\"async\" src=\"https:\/\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/prod.evol.blogs.technet.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/00\/76\/18\/6710.Fig1.JPG\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p><b>Note<\/b>&nbsp;&nbsp;&nbsp;Prior to running this cmdlet, to ensure that you have the Active Directory module available for import, you can run the following Windows PowerShell code:<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Get-Module &#8211; ListAvailable<\/p>\n<p>If you do not have the Active Directory module available, you need to download and install the<b> <\/b><a href=\"http:\/\/www.microsoft.com\/en-us\/download\/details.aspx?displaylang=en&amp;id=7887\" target=\"_blank\">Remote Server Administration Tools<\/a><b> <\/b>from the Microsoft Download Center. In addition, for them to work on any domain earlier than Windows Server&nbsp;2008, you need to install <a href=\"http:\/\/blogs.msdn.com\/b\/adpowershell\/archive\/2009\/09\/18\/active-directory-management-gateway-service-released-to-web-manage-your-windows-2003-2008-dcs-using-ad-powershell.aspx\" target=\"_blank\">Active Directory Management Gateway Service<\/a>.<b><\/b><\/p>\n<p>Next, I use <b>Get-ADComputer<\/b> to query Active Directory for all computer objects that have &ldquo;Server&rdquo; in the <b>OperatingSystem<\/b> property, and I stored it as <b>$AllServers<\/b>. I also wanted to export this to a CSV file for review. Notice that I use the <i>NoTypeInformation<\/i> parameter. In my opinion, this should be the default; however, this parameter will not display the object data at the top of the CSV.<\/p>\n<p style=\"padding-left: 30px\">$AllServers = Get-ADComputer -Filter {OperatingSystem -like &#8220;*Server*&#8221;} -Properties OperatingSystem | Select Name, OperatingSystem<\/p>\n<p style=\"padding-left: 30px\">$AllServers | Export-Csv -Path C:\\Users\\Brian\\Desktop\\AllServers.csv -NoTypeInformation<\/p>\n<p>When reviewing the data shown in the following image, I realized that Windows Server&nbsp;2008 populates the Standard, Enterprise, and Datacenter versions correctly within Active Directory. However, Windows Server&nbsp;2003 does not:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3808.wes-5-26-12-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3808.wes-5-26-12-2.png\" alt=\"Image of menu\" title=\"Image of menu\" \/><\/a><\/p>\n<p>Because the &ldquo;True-Up&rdquo; requires us to count what specific versions we&rsquo;re running, I need to go one step further to gather that information. When I thought about how I was going to gather this data, I pondered for a bit, and then I decided that I would use my good old friend WMI. Because I already had the counts for the servers running Windows Server&nbsp;2008, and I had the data filtering in Excel, I would shift my focus and effort to the servers running Windows Server&nbsp;2003. To isolate them from the <b>$AllServers<\/b> variable that I created earlier, I ran the following code, selecting only the <b>Name<\/b> property:<\/p>\n<p style=\"padding-left: 30px\">$2003ServersOnly = $AllServers | Where-Object {$_.OperatingSystem -eq &ldquo;Windows Server 2003&rdquo;} | Select -ExpandProperty Name<\/p>\n<p>Now that I had all the names of servers running Windows Server&nbsp;2003 in a variable to itself, I ran the following code &ldquo;trying&rdquo; to export the data to a CSV file:<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject -Class Win32_OperatingSystem -ComputerName $2003ServersOnly | Select CSName, Caption | Export-Csv -Path C:\\Users\\Brian\\Desktop\\2003Servers.csv -NoTypeInformation<\/p>\n<p>This should work because the <i>ComputerName<\/i> parameter will accept an array of computer names. It is also quicker than piping to a <b>Foreach-Object<\/b>. However, about 20 minutes later, I noticed that the CSV file was not growing in size like it had earlier, so I terminated the one-liner. I gave it more thought, and I decided that I would try the <b>Foreach-Object<\/b> route to see where that would take me. That code follows:<\/p>\n<p style=\"padding-left: 30px\">$2003ServersOnly | ForEach-Object {Get-WmiObject -Class Win32_OperatingSystem -ComputerName $_} | Select CSName, Caption | Export-Csv -Path C:\\Users\\Brian\\Desktop\\2003Servers.csv -NoTypeInformation<\/p>\n<p>That didn&rsquo;t work either. About 20 minutes later, I noticed that it stalled once again. Back to the drawing board&hellip;<\/p>\n<p>I gave it further thought, and I remembered a conversation that I had with a good friend of mine about the <b>AsJob<\/b> parameter for <b>Get-WmiObject<\/b>. It came about because of a function I wrote, <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Get-ComputerInfo-Query-23dd6042\">Get-ComputerInfo<\/a>, which serially queries a set of 8 or 9 WMI classes. He said that he made some modifications specifically around running <b>Get-WmiObject -AsJob<\/b>, so that the queries would run asynchronously, making the function execute faster. So I put that method into practice for the mission at hand. Instead of running the objects one at a time through the pipeline, why not create a job for each server and see if my one-liner continues to stall? Boy, was I in for a surprise on this one. I ran the following code:<\/p>\n<p style=\"padding-left: 30px\">$2003ServersOnly | ForEach-Object {Get-WmiObject -Class Win32_OperatingSystem -ComputerName $_ -AsJob}<\/p>\n<p>With the snap of my fingers the job creation was off and running on over 1100 servers. It took maybe 30 seconds to create all the jobs. &ldquo;Oh my&hellip;,&rdquo; I thought in disbelief, &ldquo;Did that just happen that fast? No<i> <\/i>way!&rdquo; As it turns out, it most certainly did.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0083.wes-5-26-12-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0083.wes-5-26-12-3.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>After the jobs finished scrolling by, I ran <b>Get-Job<\/b> to check the status. To my surprise, other than a few &ldquo;Running&rdquo; and &ldquo;Failed&rdquo; jobs, all were &ldquo;Completed&rdquo;:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1526.wes-5-26-12-4.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1526.wes-5-26-12-4.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Because all the jobs completed, I ran the following code to capture the data from the jobs and then exported the data to a CSV file:&nbsp;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Jobs = Get-Job | Receive-Job | Select CSName, Caption<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Jobs | Export-Csv -Path C:\\Users\\Brian\\Desktop\\2003Servers.csv -NoTypeInformation<\/p>\n<p>Later I went back to find out exactly how long it took to kick the jobs off, and it appears that it ran in <b>17.267<\/b> seconds:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8270.wes-5-26-12-5.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8270.wes-5-26-12-5.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Now keep in mind that after &nbsp;the jobs finished scrolling by within Windows PowerShell, I ran <b>Get-Job<\/b> and most had finished. So the total time taken to query that many servers was less than 25 to 30 seconds, that is AWESOME!<\/p>\n<p>With this information, I was able to complete the &ldquo;True-Up&rdquo; mission that my manager had given me in a timely manner. I was so happy with the sheer &ldquo;Power&rdquo; of Windows PowerShell that I reached out to my friend and shared the story. And now I have the privilege of sharing it with the community. I enjoy working daily in Windows PowerShell, and I hope you do too. Thanks for taking the time to listen to me ramble on about the &ldquo;Shell.&rdquo;<\/p>\n<p>~Brian<\/p>\n<p>I don&rsquo;t think you are rambling, Brian. In fact, I appreciate your enthusiasm. I can also tell you that the longer you work with Windows PowerShell, the greater that enthusiasm grows. I am constantly shouting out loud, &ldquo;Dude, that is awesome!&rdquo; So much so that the Scripting Wife simply ignores me&mdash;at least I think that is why she ignores me sometimes. Anyway, Brian, thank you so very much for taking the time to share your experience with the Windows PowerShell scripting community. Join me tomorrow for more Windows PowerShell goodness.<\/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><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, Brian Wilhite, shares his experience using Windows PowerShell jobs to speed up collecting information from WMI. Microsoft Scripting Guy, Ed Wilson, is here. This weekend, we will start with guest blogger, Brian Wilhite. Brian Wilhite works as a Windows system administrator for a large health-care provider in North Carolina. He has over [&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":[327,56,3,61,45],"class_list":["post-9311","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-brian-wilhite","tag-guest-blogger","tag-scripting-guy","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, Brian Wilhite, shares his experience using Windows PowerShell jobs to speed up collecting information from WMI. Microsoft Scripting Guy, Ed Wilson, is here. This weekend, we will start with guest blogger, Brian Wilhite. Brian Wilhite works as a Windows system administrator for a large health-care provider in North Carolina. He has over [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/9311","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=9311"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/9311\/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=9311"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=9311"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=9311"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}