首页 > 解决方案 > Skip Drive during Powershell Iteration

问题描述

I'm currently listing all the lists of drives in my computer. However, I want to skip the C:\ drive from the output:

This is my code:

# Iterates over all drives found
$SortedDrives = $Drives | Sort-Object -Property Used -Descending

foreach ($Drive in $SortedDrives) {
    if ($Drive.Name -eq "C") {
        continue
    }

    Write-Output $Drive.Root
    $newSortedDrives = $newSortedDrives += $Drive.Root
}

And this is the output:

Name           Used (GB)     Free (GB) Provider      Root                                                                                      ---------     --------- --------      ----                                                                           ---------------
C                 150.62        688.78 FileSystem    C:\                                                                                           
I                   2.42         65.94 FileSystem    I:\                                                                                           
F                   0.09          2.96 FileSystem    F:\                                                                                           
G                   0.05         16.43 FileSystem    G:\                                                                                           
D                   0.05         15.67 FileSystem    D:\                                                                                           
H                   0.03          9.73 FileSystem    H:\                                                                                           

Ideally, I want the C drive to be skipped and only display drives I F G D H.

What am I doing wrong? It looks like this instruction:

if ($Drive.Name -eq "C") {
    continue
}

Is not doing what it's supposed to do.

标签: powershell

解决方案


(Aside from missing initialization $newSortedDrives = @() before the loop), the code in your question now works correctly and as expected, because you later edited your question to fix the original problem, which was using the wrong variable as the enumeration source in the foreach loop.

A more concise, PowerShell-idiomatic formulation of your code is (PSv3+):

# Collects just the .Root property values; omit the (...).Root to get drive objects.
[array] $newSortedDrives = (Get-PSDrive -PSProvider FileSystem | 
                              Where-Object Name -ne C | 
                                Sort-Object -Property Used -Descending).Root

This avoids the inefficient iterative construction of your output array $newSortedDrives, because using += to "append" to an array actually creates a new array with the new element appended behind the scenes.

Note how (...).Root is used to provide the array of .Root property values automatically collected by accessing that property on the individual elements of the input collection, a feature called member enumeration.

It also shows that filtering a collection is a natural fit for PowerShell's pipeline via the Where-Object cmdlet.

In the realm of expressions (things already collected in memory) there is also the faster PSv4+ .Where() array (collection) method; e.g.:

PS> ('C', 'A', 'B').Where({ $_ -ne 'C' })
A
B

推荐阅读