Contact

Subscribe via Email

Subscribe via RSS/JSON

Categories

Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Elsewhere

Scanning for MS17-010

Was reading about the WannaCrypt attacks. If you have the MS17-010 bulletin patches installed in your estate, you are safe. I wanted to quickly scan our estate to see if the servers are patches with this. Not my job really, but I wanted to do it anyways. 

The security bulletin page lists the actual patch numbers for each version of Windows. We only have Server 2008 – 2016 so that’s all I was interested in. 

Here’s a list of the Server name, internal version, and the patch they should have.

  • Server 2008 | 6.0.6002 | KB4012598
  • Server 2008 R2 | 6.1.7600 | KB4012215 or KB4012212
  • Server 2012 | 6.2.9200 | KB4012214 or KB4012217
  • Server 2012 R2 | 6.3.9600 | KB4012213 or KB4012216
  • Server 2016 | 10.0.14393 | KB4013429

One thing to bear in mind is that it’s possible a server doesn’t have the exact patch installed, but is still not at any risk. That is because since October 2016 Windows patches are cumulative. So if you don’t have the particular March 2017 patch installed, but do have the April 2017 one, you are good to go. The numbers above are from March 2017 – so you will have to update them with patch numbers of subsequent months too to be thorough. 

Another thing – I had one server in my entire estate where the patch above was actually installed but turned up as a false positive in my script. Not sure why. I know it isn’t a script issue. For some reason that patch wasn’t being returned as part of the “Win32_QuickFixEngineering” output. Am assuming it wasn’t installed that way on this particular server.

Without further ado, here’s the script I wrote:

That’s all. Nothing fancy. 

Useful WMIC filters

I have these tabs open in my browser from last month when I was doing some WMI based GPO targeting. Meant to write a blog post but I keep getting side tracked and now it’s been nearly a month so I have lost the flow. But I want to put these in the blog as a reference to my future self. 

That’s all.

Go through a group of servers and find whether a particular patch is installed

Patch Tuesday is upon us. Our pilot group of server was patched via SCCM but there were reports that 2012R2 servers were not picking up one of the patches. I wanted to quickly identify the servers that were missing patches. 

Our pilot servers are in two groups. So I did the following:

The first two lines basically enumerate the two groups. If it was just one group I could have replaced it with Get-ADGroupMember "GroupName"

The remaining code checks whether the server is online, filters out 2012 R2 servers (version number 6.3.9600), and makes a list of the servers along with the installed date of the hotfix I am interested in. If the hotfix is not installed, the date will be blank. Simple. 

Oh, and I wanted to get the output as and when it comes so I went with a Width=20 in the name field. I could have avoided that and gone for an -AutoSize but that would mean I’ll have to patiently wait for PowerShell to generate the entire output and then Format-Table to do an autosize. 

Update: While on the Win32_QuickFixEngineering WMI class I wanted to point out to these posts: [1], [2]

Worth keeping in mind that Win32_QuickFixEngineering (or QFE for short) only returns patches installed via the CBS (Component Based Servicing) – which is what Windows Updates do anyway. What this means, however, is that it does not return patches installed via an MSI/ MSP/ MSU. 

Get a list of services and “Log On As” accounts

Wanted to find what account our NetBackup service is running under on a bunch of servers –

You have to use WMI for this coz Get-Service doesn’t show the Log On As user.

Wheee!! Had a tweet from Jeffrey Snover for this post.

 

 

Following on that tweet I noticed something odd.

The following command works –

Or this –

In the second one I am explicitly casting the arguments as an array.

But this variant doesn’t work –

That generates the following error –

Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:1
+ Get-WmiObject Win32_Service -cn $Servers -Filter ‘Name= “NetBackup Client Service …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:1
+ Get-WmiObject Win32_Service -cn $Servers  -Filter ‘Name= “NetBackup Client Service …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

The error is generated for each entry in the array.

It looks like when I pass the list of servers as an array variable PowerShell uses a different way to connect to each server (PowerShell remoting/ WinRM) while if I specify the list in-line it behaves differently. I didn’t search much on this but found this Reddit thread with the same issue. Something to keep in mind …

 

WMI Access Denied for remote machine etc

This isn’t going to be a coherent post really (unlike my usual posts which are more coherent, I hope!). I came across a bunch of new stuff as I was troubleshooting this WMI issue and thought I should put them all somewhere.

The issue is that we are trying to get Solarwinds to monitor one of our DMZ servers via WMI but it keeps failing.

solarwinds

Other servers in the DMZ work, it’s just this one that fails. WMI ports aren’t fixed like I had mentioned earlier but I don’t think that matters coz they aren’t fixed for the other servers either. Firewall configuration is the same between both servers.

I thought of running Microsoft Network Monitor but realized that it’s been replaced with Microsoft Message Analyzer. That looks nice and seems to do a lot more than just network monitoring – I must explore it sometime. For now I ran it on the DMZ and applied a filter to see traffic from our Solarwinds server to it. The results showed that access was being denied, so may not a port issue after all.

analyzer message

Reading up more on this pointed me to a couple of suggestions. None of them helped but I’d like to mention them here for future reference.

First up is the command wbemtest. Run this from the local machine (the DMZ server in my case), click “Connect”, and then “Connect” again.

wbemtest1

If all is well with WMI you should get no error.

wbemtest2

Now try the same from the Solarwinds server, but this time try connecting to the DMZ server and enter credentials if any.

wbemtest3

That worked with the local administrator account but failed with the account I was using from Solarwinds to monitor the server. Error 0x80070005.

wbemtest4

So now I know the issue is one of permissions and not ports.

Another tool that can be used is WmiMgmt. Just type wmimgmt.msc somewhere to launch it. I tried this on the DMZ machine to confirm WMI works fine. I also tried it from SolarWinds machine to the DMZ machine. (Right click to connect to a remote computer).

wmimgmt

Problem with WmiMgmt is that unlike wbemtest you can’t a different account to use. If the two machines are domain joined or have the same local accounts, then it’s fine – you can run as from one machine and connect to the other – but otherwise there’s nothing much you can do. WmiMgmt is good to double check the permissions though. Click “Properties” in the screenshot above, go to the “Security” tab, select the “Root” namespace and click the “Security” button. The resulting window should show the permissions.

wmimgmt2

In my case the Administrators group members had full permissions as expected. The account I was using from the Solarwinds server was a member of this group too yet had access denied.

Another place to look at is Component Services > Computers > My Computer > DCOM Config > “Windows Management and Instrumentation” – right click and “Properties”.

componentservices

Make sure “Authentication Level” is “Default”. Then go to the “Security” tab and make sure the account/ group you want has permissions.

componentservices2

 

Also right click on “My Computer” and go to “Properties”.

componentservices3

Under the “COM Security” tab go to the “Edit Limits” of both access & launch and activation permissions and ensure the permissions are correct. My understanding is that the limits you specify here over-ride everything else.

componentservices4

In my case none of the above helped as they were all identical between both servers and at the correct setting. What finally helped was this Serverfault post.

Being DMZ servers these were on a workgroup and the Solarwinds server was connecting via a local account. Turns out that:

In a workgroup, the account connecting to the remote computer is a local user on that computer. Even if the account is in the Administrators group, UAC filtering means that a script runs as a standard user.

That is a good link to refer to. It is about Remote UAC and WMI. The solution is to go to the following registry key – HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System – and create a new name called LocalAccountTokenFilterPolicy (of type DWORD_32) with a value of 1. (Check the Serverfault post for one more solution if you are using a Server 2012).

Remote UAC. Ah! Am surprised I didn’t think of that in the beginning itself. If the LocalAccountTokenFilterPolicy has a value of 0 (the default) then whenever a member of the Administrators group connects remotely, the security tokens of that account and filtered to remove admin access. This is only for local admin accounts, not domain admin accounts – mind you. If LocalAccountTokenFilterPolicy has a value of 1, then no filtering happens and the account connects with full admin rights. I have encountered Remote UAC in the past when accessing admin shares (e.g. \\computer\drive$) in my home workgroup, never thought it would be playing a role here with WMI!

Hope this helps someone. :)

Notes on WMI ports & monitoring

Trying to set up monitoring for some of our Windows DMZ servers via SolarWinds and came across a few interesting links. At the same time I noticed that my carefully organized bookmarks folders seem to be corrupt. Many folders are empty. This happened a few days ago too, but that time it was just one folder (well one folder that I knew of, could be more who knows) and so I was able to view and older copy of my bookmarks via Xmarks and add the missing entries back.

But this time it’s a whole bunch of folders and the only option Xmarks has it to either export the older copy or overwrite your current copy with this older set. I don’t want the latter as that would mean losing all my newer bookmarks. Wish there was some way of merging the current and older copies! Anyhow, what’s happened is happened, I think I’ll stick to using this blog for bookmarks. I keep referring to this blog over my bookmarks anyway, so this is a sign to stop with the unnecessary filing.

To start off, this is a must read on WMI ports and how to allow firewall exceptions for WMI. Gist of the matter is that WMI uses dynamic ports via the RPC Portmapper. When the Solarwinds server (for example) wants to talk to WMI on a target server, it contacts the RPC Portmapper service on the target server on port 135 (which is the standard port for the Portmapper service) and gets a dynamic port to use for WMI. This port can be anywhere between 1024 – 65535.

The fix for this is to give the Portmapper service a specific set of ports to use. One method is to use the registry (see the previous link or this KB article). Add a key called Internet under HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc. To this add values  Ports (MULTI_SZ), PortsInternetAvailable (REG_SZ), and UseInternetPorts (REG_SZ). Set a value of Y for the latter two, and a range like 5000-5100 to the former. Restart the server after this.

Although I haven’t tried it, I think a similar effect as the above can be achieved via Component Services (type dcomcnfg.exe in a command prompt). Expand the “Computers” folder here, right click on “My Computer”, go to “Default Protocols”, click “Properties” of “Conenction-oriented TCP/IP”, and add a port range.

dcomcnfg

Another method is to use Group Policies.

Yet another method seems to be to get WMI to not use the RPC Portmapper for dynamic ports. By default WMI runs as a shared service, which is why it uses the RPC Portmapper. It is possible to make it run as a standalone service so it doesn’t use the Portmapper and instead defaults to port 24158. (This port number too can be changed via dcomcnfg.exe but I am not sure how).


These two links didn’t make much sense to me, but I know they are of use so linking them here as a reference to myself for later:

 

How to undo changes made by winrm quickconfig

Here’s what happens when you do a winrm quickconfig:

In my case the Windows Remote Management (WS-Management) service was already running, so its startup type was merely changed to “Automatic (Delayed)”, but if it wasn’t already running then it would have been started too.

So what all happens here?

  1. The service is started and type changed to “Automatic (Delayed)”.
  2. Starting the service in itself does not do anything as it does not listen for anything. So a listener is created. This listener listens for messages sent via HTTP on all IP addresses of the machine.
  3. A firewall exception is created for Windows Remote Management.
  4. A configuration change is made such that when a remote user connects with admin rights to this machine, the admin rights are not stripped via User Account Control (UAC). (See this & this blog post for what this means). Basically, this configuration change involves modifying a registry entry.

Thus, to undo the effect of winrm quickconfig one must undo each of these changes.

1. Disabling the service

Either go via the Services MMC console and (1) stop the service and (2) change its type to disabled; or use PowerShell (running as administrator of course):

That’s disabled.

2. Delete the listener

You can see the listener thus:

And delete it thus:

The command has no output, so enumerate the listeners again if you want to confirm.

3. Delete the firewall exceptions

Either go via the GUI and disable the highlighted rule:

winrm-firewall

Or use PowerShell:

That’s disabled.

4. Disable Remote UAC

Either open the Registry Editor and navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System, then set the value of LocalAccountTokenFilterPolicy to 0 (zero).

Or via PowerShell:

That’s it!

Hyper-V between Windows 10 & Windows 8.1 in a workgroup

My laptop’s running Windows 10, desktop’s running Windows 8.1. Since both have client Hyper-V I thought it would be cool to install Hyper-V manager on the laptop and use it to manage Hyper-V running on the desktop. Did that and came across the following error –

Hyper-V error

DOGBERT is the Windows 8.1 desktop. The error is from my Windows 10 laptop.

First I followed the steps in this blog post. Actually, I didn’t have to do much as the account I was using on the desktop was already in the local Administrators group and so I didn’t have to do anything in terms of COM (step 3) & WMI (step 4) permissions. But I did enable the firewall rules for the Windows Management Instruction (WMI) group (step 2).

Additionally, I noticed that the Windows Remote Management (WS-Man) service was not running on the desktop so I enabled that. For this I used the winrm command.

 

Then I had to enable the Windows Remote Management (WS-Man) service on the laptop and add the desktop as a trusted host. Remember the error message above? It said that either I must use HTTPS or add the remote computer to the TrustedHosts list. I add that thus (from my laptop):

Probably a good idea to see what your existing trusted hosts are before you run this command (so you can append to the list instead of removing existing entries). You can do that thus:

After this Hyper-V manager from the laptop was able to connect to the desktop, but in the Virtual Machines section I had the following error:

Access denied. Unable to establish communication between ‘Hyper-V Server’ and ‘Hyper-V Manager’

The solution for that (thanks to this blog post) is to open “Component Services” on the laptop. Alternatively open a run window/ command prompt and type dcomcnfg.

In the windows that opens expand to Component Services > Computers > My Computer, right click and go to Properties, then the COM Security tab, and click “Edit Limits” under Access Permissions. Select the ANONYMOUS LOGIN username here and tick the box to allow Remote Access.

Component Services

That’s it! After this Hyper-V on my laptop was able to talk to the desktop.

Get a list of recently installed Windows updates via the command line

In a previous post I gave a DISM command to get a list of installed Windows Updates:

While useful that command has no option of filtering results based on some criteria. 

If you are on Windows 8 or above the Get-WindowsPackage cmdlet can be of use:

This gets me all updates installed in the last 15 days. 

Another alternative (on pre-Windows 8 machines) is good ol’ WMIC:

The above gives output similar to this:

For more details more switches can be used:

Result is:

This output also gives an idea of the criteria available. 

So how can I filter this output like I did with PowerShell? Easy – use WQL (WMIC Query Language). Inspired by a blog post I found (which I am sure I have referred to in the past too) either of the following will do the trick:

-or- 

And if you want to format the output with specific fields:

Which results in something along these lines:

This includes Updates, Hotfixes, and Security Updates. If you want to filter down further, that too is possible (just mentioning these as a reference to my future self). Do a specific match:

Or a wildcard:

Or a negation:

These two links (WQL and WHERE clauses) were of use in picking up the WQL syntax. They are not very explanatory but you get an idea by trial and error. Once I had picked up the syntax I came across this about_WQL page that’s part of the PowerShell documentation and explains WQL operators. Linking to it here as a reference to myself and others. 

Unlike PowerShell I don’t know how to make WMIC use a greater than operator and simply specify the date. I tried something like this (updates installed after 12th May 2015):

But the results include some updates from 2013 & 2014 too. Not sure what’s wrong and I am not in the mood to troubleshoot at the moment. The like operator does the trick well for me currently. 

Notes of PowerShell DSC course, OneGet & Chocolatey

Spent the past hour and half attending this course – Getting started with PowerShell Desired State Configuration (DSC) Jump Start, by Jeffrey Snover (inventor of PowerShell) and Jason Helmick. Had to give up coz my connection quality is so poor it kept freezing every now and then. Better to wait 2-3 weeks for the recorded version to be released so I can download and view. It’s a pity I couldn’t watch this though. I was looking forward to this course very much (and also its sequel Advanced PowerShell Desired State Configuration (DSC) and Custom Resources same time tomm which I will now have to skip).

From the little bit that I did attend, here are some notes.

Desired State Configuration (DSC)

  • Desired State Configuration (DSC) is meant to be a platform. You have tools that can manage configuration changes. And you have the actual items which you configure. Usually the tools are written specifically for the item you wish to configure. So, a certain tool might be good at managing certain aspects of your environment but not that great at managing other aspects. What Microsoft’s goal here is to offer a platform for configuration tools. Jeffrey likens it to Word Processors and printers in the past. Whereas once upon a time Word Processors were tied to printers in that certain Word Processors only worked with certain printers, once Windows OS came along and it had the concept of print drivers, all that was required was for printer manufacturers to provide drivers for their model and Word Processors to target this driver model and soon all Word Processors could print to all printers. DSC has a similar aim. 
  • DSC tends to get compared to GPOs a lot because they do similar things. But, (1) GPOs require domain joined machines – which DSC does not require – and (2) with a GPO you don’t have a way of knowing whether the policy applied successfully and/ or what failed, while with DSC you have insight into that. Other differences are that GPOs are tied to Windows whereas DSC is standards based so works with Linux and *nix (and even network switches!). 
  • DSC is Distributed & Heterogeneous. Meaning it’s meant to scale across a large number of devices or various types. 
  • Local Configuration Manager (LCM) is a WMI agent that’s built into PowerShell 4 and above. It is the engine behind DSC? (The presenters were starting to explain LCM in Module 2 which is when I finally gave up coz of the jerkiness).
  • Windows Management Infrastructure (WMI) has an open source counterpart (created by Microsoft?) called Open Management Infrastructure (OMI) for Linux and *nix machines. This is based on DMTF standards and protocols. Since LCM is based on WMI whose open source counterpart is OMI, LCM can work with Linux and *nix machines too. 
  • DevOps model is the future. Release a minimal viable product (i.e. release a product that works with the minimum requirements and then quickly keep releasing improvements to it). Respect reality (i.e. release what you have in mind, collect customer feedback (reality), improve the product). Jeffrey Snover recommends The Phoenix Project, a novel on the DevOps style. 
    • Windows Management Framework (WMF) – which contains PowerShell, WMI, etc – now follows a DevOps style. New releases happen every few months in order to get feedback. 

OneGet and friends

  • NuGet is a package manager for Visual Studio (and other Windows development platforms?). Developers use it to pull in development libraries. It is similar to the package managers for Perl, Ruby, Python, etc. I think.
  • Chocolatey is a binary package manager, built on NuGet infrastructure, but for Windows. It is similar to apt-get, yum, etc. Chocolatey is what you would use as an end-user to install Chrome, for instance.
  • OneGet is a package manager’s manager. It exposes APIs for package managers (such as Chocolatey) to tap into, as well as APIs for packages to utilize. OneGet is available in Windows 10 Technical Preview as well as in the WMF 5.0 Preview. Here’s the blog post introducing OneGet. Basically, you can use a set of common cmdlets to install/ uninstall packages, add/ remove/ query package repositories regardless of the installation technology.

To my mind, an analogy would be that OneGet is something that can work with deb and rpm repositories (as well as repositories maintained by multiple entities such as say Ubuntu deb repositories, Debian deb repositories) and as long as these repositories have a hook into OneGet. You, the end user, can then add repositories containing such packages and use a common set of cmdlets to manage it. This is my understanding, I could be way off track here … 

Installing WMF 5.0 preview on my Windows 8.1 machine, for instance, gets me a new module called OneGet. Here are the commands available to it:

As part of the course Jeffrey mentioned the PowerShell Gallery which is a repository of PowerShell and DSC stuff. He mentioned two modules – MVA_DSC_2015_DAY1 and MVA_DSC_2015_DAY2 – which would be worth installing to practice what is taught during the course. The PowerShell Gallery has its own package manager called PowerShellGet which has its own set of cmdlets. 

Notice there are cmdlets to find modules, install modules, and even publish modules to the repository. One way of installing modules from PowerShell Gallery would be to use the PowerShellGet cmdlets. 

Notice that it depends on NuGet to proceed. My guess is that NuGet is where the actual dependency resolution and other logic happens. I can install the modules using another cmdlet from PowerShellGet:

Now, the interesting thing is that you can do these operations via OneGet too. Because remember, OneGet provides a common set of cmdlets for all these operations. You use the OneGet provided cmdlets and behind the scenes it will get the actual providers (like PowerShellGet) to do the work. (Update: Turns out it’s actually the reverse. Sort of. Install-Module from PowerShellGet actually invokes Install-Package -Provider PSModule from OneGet. This works because PowerShellGet hooks into OneGet with so OneGet knows how to use the PowerShellGet repository). 

Remember, the find-* cmdlets are for searching the remote repository. The get-* cmdlets are for searching the installed packages. PowerShellGet is about modules, hence these cmdlets have the noun as module. OneGet is about packages (generic), so the noun has package

Very oddly, there seems to be no way to uninstall the modules installed from the PowerShell Gallery. As you can see below Uninstall-Module does nothing. That’s because there’s no uninstall cmdlet from PowerShellGet

I installed the xFirefox module above. Again, from the course I learnt that “x” stands for experimental. To know more about this module one can visit the page on PowerShell Gallery and from there go to the actual module DSC resource page. (I have no idea what I can do with this module. From the module page I understand it should now appear as a DSC resource, but when I do a Get-DSCResource it does not appear. Tried this for the xChrome module too – same result. Other modules, e.g. xComputer, appear fine so it seems to be an issue with the xFirefox and xChrome modules.)

Notice I have two repositories/ sources on my system now: Chocolatey, which came by default, and PowerShell Gallery. I can search for packages available in either repository. 

OneGet is working with Chocolatey developers to make this happen. Currently OneGet ships with a prototype plugin for Chocolatey, which work with packages from the Chocolatey repository (note: this plugin is a rewrite, not a wrapper around the original Chocolatey). For instance, here’s how I install Firefox from Chocolatey:

OneGet & Chocolatey – still WIP

Even though Firefox appeared as installed above, it did not actually install. This is because Chocolatey support was removed in the latest WMF 5.0 preview I had installed. To get it back I had to install the experimental version of OneGet. Here’s me installing PeaZip:

For comparison here’s the same output with the non-experimental version of OneGet:

As you can see it doesn’t really download anything …

Here’s a list of providers OneGet is aware of:

ARP stands for Add/ Remove Programs. With the experimental version one can list the programs in Add/ Remove programs:

The MSI and MSU providers are what you think they are (for installing MSI, MSP (patch) and MSU (update) packages). You can install & uninstall MSI packages via OneGet. (But can you specify additional parameters while installing MSI? Not yet, I think …)

That’s it then! 

Find removable drive letter from label

Been a while since I posted here, and while the following is something trivial it is nevertheless something I had to Google a bit to find out, so here goes.

I have a lot of micro SD cards to which I sync my music. The cards are labelled “Card1”, “Card2”, and so on. Corresponding to these I have folders called “Card1”, “Card2”, and so on. I have a batch file that runs robocopy to copy from the folder to card. I have to specify the drive letter of the card to the batch file, but now I am being lazy and want to just double click the batch file and get it to figure out the drive letter. After all the drive with a label “CardX” will be the one I want to use.

How can I get the drive letter from the label? There are many ways probably, since I like WMIC here’s how I will do it:

This command will list all the volumes on the computer. There’s a lot of output, so a better way is to use the /format:list switch to get a listed output:

Here’s an example output for my micro SD card:

It’s easy to see that the Label property can be used to check the label. The DriveLetter property gives me the drive name. If I want to target removable disks only (as is my case) the DriveType property can be used.

Thus for instance, to filter by the label I can do:

Or to filter by both label and type I can do:

To output only the drive letter, I can use the get verb of WMIC:

The second command is what I will use further as it returns the output in a way I know how to use.

In batch files the FOR loop can be used to parse output and do things with it. The best place to get start with is by typing help for in a command prompt to get the help text. Here’s the bit that caught my attention:

Finally, you can use the FOR /F command to parse the output of a
command. You do this by making the file-set between the
parenthesis a back quoted string. It will be treated as a command
line, which is passed to a child CMD.EXE and the output is captured
into memory and parsed as if it was a file. So the following
example:

FOR /F “usebackq delims==” %i IN (set) DO @echo %i

would enumerate the environment variable names in the current
environment.

This looks like what I want. The usebackq option tells FOR that the text between the back-ticks – set in the example above – is to be treated like a command and the output of that is to be parsed. The delims== option tells FOR that the delimiter between parts of the output is the = character. In case of the example above, since the output of set is a series of text of the form VARIABLE=VALUE, this text will be split along the = character and the %i variable will be assigned the part on the left. So the snippet above will output a list of VARIABLEs.

If I adapt that command to my command above, I have the following:

Output from the above code looks like this:

As expected, the picks the DriveLetter part. What I want instead is the bit on the right hand side, so I use the tokens option for that. I want the second token, so I use tokens=2. I learnt about this from the FOR help page.

Here’s the final command:

That’s it! Now to assign this to a variable I do change the echo to a variable assignment:

Here’s the final result in a batch file:

Using WMIC to find RAM info

The “Win32_PhysicalMemory” class is your friend here.

And to get the total number of slots in the machine as well as the maximum supported RAM, “Win32_PhysicalMemoryArray” is your friend.

Both classes have more properties than the ones I filtered for above.

Using WMIC to find machine info

I needed to find the model number of my Compaq Presario laptop today. The machine’s right next to me so it’s just a matter of lifting it up to look at the model number, but what’s the fun in that aye? Enter WMIC (via PowerShell).

The following WMI classes are useful in finding details of your hardware:

Win32_ComputerSystemProduct For manufacturer, serial number, UUID, etc. Does not contain the model number.
Win32_ComputerSystem For manufacturer, model, physical memory, and details such as the owner name, whether it’s part of a domain, etc.
Win32_OperatingSystem For OS specific information such as language, architecture, OS, registered user, etc.
Win32_Bios For BIOS info such as the name, version, etc.

In my case WMI didn’t have the exact model number. But thankfully HP has a way of giving you the model number from serial number, and since I had the serial number via WMI I was able to get the model number without lifting a finger.

How to get a list of COM objects via WMI & PowerShell

Let’s see what WMI can tell us about COM objects on the system.

Get a list of all WMI classes with the word “COM” in them (doing a case sensitive match to avoid entries like “computer”).

Win32_COMApplication gives me about 386 results. It includes the AppID of the application associated with the COM object.

I am not a programmer so I won’t be going further into AppIDs and such, but it’s worth knowing about this and related COM terminology so here’s a quick rundown:

  1. All COM objects have a CLSID which is basically a 128-bit hexadecimal Globally Unique IDentifier (GUID) for the COM object. This way COM objects can be referred to independent of their installation path. The CLSID is unique across network computers too (relevant, when used with DCOM).

    WMI objects refer to this as ComponentID. They can also be found in the registry under HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID. For example, the CLSID for WordPad is {73FDDC80-AEA9-101A-98A7-00AA00374959}

  2. CLSIDs are not easy to remember, and sometimes COM objects with different CLSIDs can be used interchangeably (for instance: different versions of Internet Explorer will have different CLSIDs but you need some way of referring to the Internet Explorer COM object such that whatever version is installed on the system is used). For this reason you have ProgIDs (Programmatic IDentifier).

    ProgIDs can be found in the registry under HKEY_LOCAL_MACHINE\SOFTWARE\Classes. The format of a ProgID is <Program>.<Component>.<Version>, separated by periods and with no spaces. For example, the ProgID for WordPad is WordPad.Document.1.

    PowerShell’s New-Object cmdlet uses ProgID when creating new objects that refer to COM objects so ProgIDs are relevant to us.

  3. While not relevant to the current topic, there’s also an AppID which is yet another 128-bit hexadecimal GUID. You can read more about it here.

Now let’s get a list of how many objects are returned by each WMI class.

The biggest results are from the Win32_COMSetting class. Let’s compare the results of this with the Win32_ClassicCOMClassSetting class (which has the second largest number of results) to see what’s different. Since the ProgID property is what’s relevant to PowerShell, let’s filter the results to objects where ProgID is not $null.

There’s no difference. So in terms of ProgID both classes contain the same number of objects. Now let’s recreate the above table to only consider results where ProgID is not $null.

The interesting thing to note is that all the other classes have 0 objects now. In fact, we can see that the number of objects returned by the Win32_COMSetting class is equal to the number returned by Win32_ClassicCOMClassSetting plus Win32_COMApplication or Win32_DCOMApplication or Win32_DCOMApplicationSetting or Win32_COMApplicationSettings. Something to investigate later?

So, the best way to get COM objects via WMI & PowerShell is to use the Win32_COMSetting class. And to get the ProgID or any application (such as Internet Explorer in the previous post) something along the following lines will do:

If there’s only one version, the version number can be skipped in ProgID which is why InternetExplorer.Application too works.

Update: In fact, only the Win32_COMSetting and Win32_ClassicCOMClassSetting classes contain ProgID in their output. So these are the only two classes one can use. And since the only difference them is that Win32_COMSetting contains objects without any ProgID (of no use in our case!) it’s ok to use either class.

Update2: Turns out WMI is not a good way to get the list of COM objects. A better approach is to query the registry. See my next post.

WMI queries

A useful link to refer to later: WMI Query language examples.

PowerShell can access WMI via Get-WMIObject. And while it’s easier to just pull all WMI objects and then filter, it’s faster if you do the filtering while pulling itself.

Case in hand: getting a list of installed drivers. The Win32_PnpSignedDriver WMI class is what you need to tap into for this. Like thus:

This gives a bucket-load of output. If you want to filter out just a particular driver, the easy way is this:

The better way, though, is to use WMI queries and filter while running WMI itself. Like this:

Both return the same number of results:

But the latter is faster.

The difference isn’t much in the example above, but when you run this across the network for multiple computers it adds up quickly.

So when in doubt filter at the WMI level. And to make filter queries like the above, the link at the start of this post helps. It gives you the keywords you can use. Like, for instance, to do wildcard matches use the like keyword as above. And like * is the wildcard symbol usually, for WMI queries % is the wildcard symbol. Similarly, to do exact matches use the = keyword; to do relational matches (greater than, less than) use the < and > keywords; and so on.

Special shout-out to this blog post where I first came across the like keyword.