{"id":52613,"date":"2009-08-26T03:01:00","date_gmt":"2009-08-26T03:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/08\/26\/hey-scripting-guy-can-i-read-a-text-file-and-use-it-to-query-servers\/"},"modified":"2009-08-26T03:01:00","modified_gmt":"2009-08-26T03:01:00","slug":"hey-scripting-guy-can-i-read-a-text-file-and-use-it-to-query-servers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-can-i-read-a-text-file-and-use-it-to-query-servers\/","title":{"rendered":"Hey, Scripting Guy! Can I Read a Text File and Use It to Query Servers?"},"content":{"rendered":"<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\"><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"><\/p>\n<p class=\"MsoNormal\">Hey Scripting Guy! I need to generate a list of hotfixes that are installed on my servers. I have 100 servers on the network for which I am responsible. Each of the server names is listed in a text file called servers.txt. I need a way to read the text file and then query each of the servers. Can you help me?<\/p>\n<\/p>\n<p class=\"MsoNormal\">&#8212; GM<\/p>\n<p class=\"MsoNormal\">\n<p><span><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><\/span><\/p>\n<\/p>\n<p class=\"MsoNormal\">Hello GM, <\/p>\n<p class=\"MsoNormal\">Microsoft Scripting Guy Ed Wilson here. Today is a special day. For months and months and months we have had a weekly Script Center migration meeting. Today there is not a meeting. That means I have an extra hour to read through e-mail sent to scripter@microsoft.com. It is not that the migration is completed; however, getting the <a href=\"http:\/\/gallery.technet.microsoft.com\/ScriptCenter\/en-us\/\">Script Center Script Gallery<\/a> online was a biggie. It is amazing how much one can get done when meetings get canceled (don&#8217;t get me wrong&mdash;I love meetings; they are a great way to build consensus on projects, an efficient method of disseminating complex information, and a good way to get to know one&rsquo;s team members.) When you work with a large number of different people on a number of different projects, meeting time can rapidly outpace production time. I am very sure you know what I&rsquo;m saying. <\/p>\n<p class=\"MsoNormal\">I looked in the Script Gallery and found the <a href=\"http:\/\/gallery.technet.microsoft.com\/ScriptCenter\/en-us\/96d3ca7c-e8ec-4506-a4af-a53a56ede2c9\"><font face=\"Segoe\">List Installed Hot Fixes<\/font><\/a> script that is seen here. <\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>ListInstalledHotFixes.vbs<\/p>\n<p><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">strComputer = &#8220;.&#8221;<br>Set objWMIService = GetObject(&#8220;winmgmts:&#8221; _<br><span>&nbsp;&nbsp;&nbsp; <\/span>&amp; &#8220;{impersonationLevel=impersonate}!\\&#8221; &amp; strComputer &amp; &#8220;rootcimv2&#8221;)<\/p>\n<p>Set colQuickFixes = objWMIService.ExecQuery _<br><span>&nbsp;&nbsp;&nbsp; <\/span>(&#8220;Select * from Win32_QuickFixEngineering&#8221;)<\/p>\n<p>For Each objQuickFix in colQuickFixes<br><span>&nbsp;&nbsp;&nbsp; <\/span>Wscript.Echo &#8220;Computer: &#8221; &amp; objQuickFix.CSName<br><span>&nbsp; <\/span><span>&nbsp;&nbsp;<\/span>Wscript.Echo &#8220;Description: &#8221; &amp; objQuickFix.Description<br><span>&nbsp;&nbsp;&nbsp; <\/span>Wscript.Echo &#8220;Hot Fix ID: &#8221; &amp; objQuickFix.HotFixID<br><span>&nbsp;&nbsp;&nbsp; <\/span>Wscript.Echo &#8220;Installation Date: &#8221; &amp; objQuickFix.InstallDate<br><span>&nbsp;&nbsp;&nbsp; <\/span>Wscript.Echo &#8220;Installed By: &#8221; &amp; objQuickFix.InstalledBy<br>Next<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">This is not one of those scripts you want to translate into Windows PowerShell. If you did a direct translation, you would end up with a script that looks like the TranslatedHotFixScript.ps1 seen here. <\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>TranslatedHotFixScript.ps1<\/p>\n<p><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">$strComputer = &#8220;.&#8221;<\/p>\n<p>$colItems = get-wmiobject -class &#8220;Win32_QuickFixEngineering&#8221; -namespace &#8220;rootCIMV2&#8221; `<br>-computername $strComputer<\/p>\n<p>foreach ($objItem in $colItems) {<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Caption: &#8221; $objItem.Caption<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;CS Name: &#8221; $objItem.CSName<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Description: &#8221; $objItem.Description<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Fix Comments: &#8221; $objItem.FixComments<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;HotFix ID: &#8221; $objItem.HotFixID<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;InstallationDate: &#8221; $objItem.InstallDate<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Installed By: &#8221; $objItem.InstalledBy<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Installed On: &#8221; $objItem.InstalledOn<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Name: &#8221; $objItem.Name<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Service Pack In Effect: &#8221; $objItem.ServicePackInEffect<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host &#8220;Status: &#8221; $objItem.Status<br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>write-host<br>}<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">There is nothing wrong with the TranslatedHotFixScript.ps1 script. It will work properly, as seen here: <\/p>\n<p class=\"Fig-Graphic\"><img decoding=\"async\" title=\"Image of evidence that TranslatedHotFixScript.ps1 working properly\" alt=\"Image of evidence that TranslatedHotFixScript.ps1 working properly\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/august\/hey0826\/hsg-8-26-09-01.jpg\" width=\"600\" height=\"502\"><\/p>\n<p class=\"MsoNormal\"><br>The script is easy to understand for someone making a transition from VBScript. The bad thing about TranslatedHotFixScript.ps1 is that it does not take advantage of Windows PowerShell objects. The same basic information can be obtained by typing a single line of code. The alias for the <b>Get-WmiObject<\/b> cmdlet is <b>gwmi<\/b>. When you use the alias, the command becomes the one seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">PS C:&gt; gwmi win32_QuickFixEngineering<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The output from the short WMI command is seen here:<\/p>\n<p class=\"Fig-Graphic\"><img decoding=\"async\" title=\"Image of WMI command output\" alt=\"Image of WMI command output\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/august\/hey0826\/hsg-8-26-09-02.jpg\" width=\"600\" height=\"511\"><\/p>\n<p class=\"MsoNormal\"><br>A command-line solution is fine for some short testing, but I prefer to write a script if I am going to be performing a task more than once. The GetServersFromTextGetHotFixesWriteToLog.ps1 is still significantly shorter than the other hotfix scripts (except for the name), yet it does much more. The complete GetServersFromTextGetHotFixesWriteToLog.ps1 is seen here. <\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>GetServersFromTextGetHotFixesWriteToLog.ps1<\/p>\n<p><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">$servers = Get-Content -path c:fsoservers.txt<br>$logfile = &#8220;C:fsohotfixlog.txt&#8221;<br>ForEach ($server in $servers)<br>{<br><span>&nbsp; <\/span>&#8220;Checking hotfixes on $server&#8221; | Out-FIle -filepath $logfile -encoding ASCII -append<br><span>&nbsp; <\/span>Get-WmiObject -class Win32_QuickFixEngineering -Computername $Server |<br><span>&nbsp; <\/span>Format-Table -property HotFixID, InstalledON, Description -autosize |<br><span>&nbsp; <\/span>Out-FIle -filepath $logfile -encoding ASCII -append<br>}<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The GetServersFromTextGetHotFixesWriteToLog.ps1 script begins by creating two variables that are used to point to the log file and to the text file that holds the names of each of the servers. The text file is a simple file that has a computer name on each line of the file. No additional data is required other than the computer name. The <b>Get-Content<\/b> cmdlet reads the text from the servers.txt file. The ForEach statement is used to walk through the array of computer names that is created by using the <b>Get-Content<\/b> cmdlet to read the contents of the servers.txt file. This is seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$servers = Get-Content -path c:fsoservers.txt<br>$logfile = &#8220;C:fsohotfixlog.txt&#8221;<br>ForEach ($server in $servers)<br>{<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Inside the script block for the <b>ForEach<\/b> statement, the first thing we do is write the computer name to the log file. This is done by piping the string directly to the log file. The encoding of the text file is set to ASCII (by default it uses Unicode), and the <b>append<\/b> switch is used to keep the file from overwriting itself. This is seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">&#8220;Checking hotfixes on $server&#8221; | Out-FIle -filepath $logfile -encoding ASCII &ndash;append<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The <b>Get-WmiObject<\/b> cmdlet is used to retrieve the data from WMI. The resulting management object is piped to the <b>Format-Table<\/b> cmdlet. This is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Get-WmiObject -class Win32_QuickFixEngineering -Computername $Server |<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The <b>Format-Table<\/b> cmdlet will create a table. The columns are the order in which the properties are selected. The <b>autosize<\/b> switch is used to remove excess space between columns. The table is piped to the <b>Out-File<\/b> cmdlet. This is seen here: <\/p>\n<p class=\"CodeBlock\"><font face=\"Lucida Sans Typewriter\"><span>Format-Table -property HotFixID, InstalledON, Description -autosize |<br>Out-FIle -filepath $logfile -encoding ASCII -append<\/p>\n<p><\/span><b><\/p>\n<p><\/b><\/font><\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\">When the script is run, the only output is written to the log file:<\/p>\n<p class=\"Fig-Graphic\"><img decoding=\"async\" title=\"Image of script output written to the log file\" alt=\"Image of script output written to the log file\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/august\/hey0826\/hsg-8-26-09-03.jpg\" width=\"600\" height=\"447\"><\/p>\n<p class=\"MsoNormal\"><br>GM, that is about all there is to reading a text file, retrieving hotfix information, and writing it to a log file. We hope you enjoyed our little excursion today. Join us tomorrow as we continue to review scripts we found in the new Script Center Script Gallery. <\/p>\n<p class=\"MsoNormal\">We invite you to follow us on <a href=\"https:\/\/twitter.com\/scriptingguys\/\">Twitter<\/a> or <a href=\"http:\/\/www.facebook.com\/group.php?gid=5901799452\">Facebook<\/a> so that you can keep up to date with the latest Script Center news. If you have a question, you can always post it on the <a href=\"http:\/\/social.technet.microsoft.com\/Forums\/en\/ITCG\/threads\/\"><span><font face=\"Segoe\">Official Scripting Guys Forum<\/font><\/span><\/a>, or send it to us by e-mail at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\"><span><font face=\"Segoe\">scripter@microsoft.com<\/font><\/span><\/a>. <\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p><b><span>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/span><\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey Scripting Guy! I need to generate a list of hotfixes that are installed on my servers. I have 100 servers on the network for which I am responsible. Each of the server names is listed in a text file called servers.txt. I need a way to read the text file and then query [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[31,3,203,45],"class_list":["post-52613","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-operating-system","tag-scripting-guy","tag-service-packs-and-hotfixes","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey Scripting Guy! I need to generate a list of hotfixes that are installed on my servers. I have 100 servers on the network for which I am responsible. Each of the server names is listed in a text file called servers.txt. I need a way to read the text file and then query [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/52613","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\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=52613"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/52613\/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=52613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=52613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=52613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}