Notice: The following post was originally published on another website. As the post is no longer accessible, it is being republished here on tommymaynard.com. The post was originally published on January 15, 2019.
As a part of a recent engagement (with a company you’ve likely heard of), we had some code written and provided to us. In my review of what was provided to scan drives using Windows Defender, I noticed that there were some problems. One, there was an assumption that a computer would only ever have a single optical drive, and two, mapped network drives may have ended up being scanned, as well. Now, I’m not sure if Defender would actually scan a network drive, but I assume it would and don’t really care to find out.
We needed a way to filter out optical drives and network mapped drives regardless of the count of either before we started a Windows Defender scan. I’ll start with the code I used, followed by a second option that occurred more recently — it was a would this work idea. It does, so I’ll explain them both and perhaps we’ll all be better off seeing two different options. Before we get deeper into this, take a look at the output provided by Get-PSDrive
(when piped to Format-Table
and the AutoSize
parameter). Clearly, it’s found a good number of drives on my system.
PS> Get-PSDrive | Format-Table -AutoSize
Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- Alias Alias C 698.18 232.15 FileSystem C:\ Users\tommy Cert Certificate \ D FileSystem D:\ E FileSystem E:\ Env Environment Function Function HKCU Registry HKEY_CURRENT_USER HKLM Registry HKEY_LOCAL_MACHINE MDI FileSystem \\mydomain.com\data\in... MDT FileSystem \\mydomain.com\data\to... I 112.80 352.96 FileSystem I:\ P 0.15 465.60 FileSystem P:\ Variable Variable W 676.59 254.92 FileSystem W:\ WSMan WSMan
Now, let’s modify our command and only return our FileSystem drives. Unfortunately, there are a couple of optical drives (although you don’t really know that yet), and two mapped network drives that we don’t want or need in our results.
PS> Get-PSDrive | Format-Table -AutoSize
Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- Alias Alias C 698.18 232.15 FileSystem C:\ Users\tommy Cert Certificate \ D FileSystem D:\ E FileSystem E:\ Env Environment Function Function HKCU Registry HKEY_CURRENT_USER HKLM Registry HKEY_LOCAL_MACHINE MDI FileSystem \\mydomain.com\data\in... MDT FileSystem \\mydomain.com\data\to... I 112.80 352.96 FileSystem I:\ P 0.15 465.60 FileSystem P:\ Variable Variable W 676.59 254.92 FileSystem W:\ WSMan WSMan
In this next example, we’ll remove the mapped drives from our results. In the end, we have our fixed drives and the D:\ and E:\ drives that have no used or free space. Perhaps those are the optical drives and there are no actual disks in either one. Before we move past this example, however, let’s get the results of this command into a variable, as well. The $FixedDrives
variable is assigned toward the bottom of the below example.
PS> Get-PSDrive -PSProvider FileSystem | Where-Object -Property Root -notlike '\\*' | Format-Table -Autosize Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- C 698.18 232.15 FileSystem C:\ Users\tommy D FileSystem D:\ E FileSystem E:\ I 112.80 352.96 FileSystem I:\ P 0.15 465.60 FileSystem P:\ W 676.59 254.92 FileSystem W:\ PS> $FixedDrives = Get-PSDrive -PSProvider FileSystem | Where-Object -Property Root -notlike '\\*' PS> # Noticed we removed Format-Table -- that was _only_ there for the onscreen display.
Now, let’s get a hold of our optical drives. Because we’ll need them in a variable, we’ll go ahead and make that assignment in this next example, as well.
PS> Get-WmiObject -Class Win32_CDROMDrive | Format-Table -AutoSize Caption Drive Manufacturer VolumeName ------- ----- ------------ ---------- ASUS DRW-1814BLT ATA Device D: (Standard CD-ROM drives) ELBY CLONEDRIVE SCSI CdRom Device E: (Standard CD-ROM drives) PS> $OpticalDrives = Get-WmiObject -Class Win32_CDROMDrive
Now that that’s done — oh look, it is the D:\ and E:\ drives — let’s run a comparison against the fixed drives and optical drives we’ve returned. Again, this first example is how I rewrote the code that was provided to us. Once we’ve seen this, then we’ll try the comparison I considered over some recent weekend. This example compares the Get-PSDrive
‘s Root property (with the backslash removed) against the Get-WmiObject
‘s Drive property. If they don’t match, it stays. Otherwise, it’s filtered out. As you’ll see, when we assign and return our new $DrivesToTest
variable, we can see that our D:\ and E:\ drives — our optical drives — have been removed. Perfect.
PS> $DrivesToTest = ($FixedDrives.Root).TrimEnd('\') | Where-Object {$OpticalDrives.Drive -notcontains $_} PS> $DrivesToTest C: I: P: W:
Let’s use our $FixedDrives
and $OpticalDrives
variables again, but this time with the Compare-Object
cmdlet. This was the additional idea I had to determine if we can simplify things even more. As some have noticed — I have not shied away from the fact that I tend to do things the hard way, the first time. In case it makes a difference, and I hope it doesn’t, Compare-Object
was first introduced in PowerShell 3.0.
PS> (Compare-Object -ReferenceObject ($FixedDrives.Root).TrimEnd('\') -DifferenceObject $OpticalDrives.Drive).InputObject C: I: P: W:
Just like that, we’ve got the same results, with less work. Now, I can get back to doing whatever it was before I began reviewing this code. That and our users can safely get to work scanning machines with Windows Defender, without the concern anyone will scan against any number of optical drives, or mapped network drives.