문제

I need two simple things, my program asks for the user to enter a directory, I need a way that if nothing is entered a default directory is used.

And secondly, from the directory given find the largest file.

I've been told to use:

Get-ChildItem c:\temp | Sort Length -desc | Select-Object -First 1

But that may as well be Chinese to me. I only know Java. I get what it's supposed to do, but it does nothing in my code:

$a = Read-Host “Enter directory”

function Get-Size {
  param ($Path)
  $Size = 0
  foreach ($Folder in (Get-ChildItem $Path)) {
      if ($Folder.PSIsContainer) {
        Get-Size $Folder.FullName
      } else {
        $Size += $Folder.Length
      }
  }
  New-Object PSObject -Property @{'Size in KB'=$Size/100; 'Folder'=$Path}
}

Write-Host "Disk space use (in KB) for each subdirectory:"
Get-Size $a
도움이 되었습니까?

해결책

Well, there are a few issues with your code, but first I'll answer the questions you asked.

1. Ask the user for a directory, and use a default directory if nothing is entered

To have a function use a default value for any parameter, simply add = defaultvalue at the end of the parameter declaration. In this case,

param (
  $Path = 'C:\My\Default\Directory'
)

If you don't want the function to use a default directory, but want the script to assign the default directory when prompting the user, you can do it this way:

if (! ($a = Read-Host 'Enter directory')) {
  $a = 'C:\My\Default\Directory'
}

The if condition executes $a = Read-Host 'Enter directory', and executes the block that assigns a default value to $a if the user doesn't enter anything (an assignment statement evaluates to the value assigned to the variable, and an empty string is a false value, so (! ($a = Read-Host 'Enter directory')) is true if the user hits Enter without providing a value).

2. Find the largest value in the directory

The command you were given works:

 Get-ChildItem c:\temp | Sort Length -desc | Select-Object -First 1

You say it does nothing in your code, but I don't even see it in your code. If you show where/how you tried to add it, I'll be able to tell you why it appears to do nothing. It probably has something to do with how you're trying to use the results. For now I can explain how it works.

  • Get-ChildItem C:\Temp | lists the contents of C:\Temp, of course, and sends the results (FileInfo objects representing each item in the directory) to the pipeline.
  • Sort Length -desc | sorts the results in descending order, and sends the sorted results down the pipeline. Sort is shorthand for Sort-Object, Length is the property of a FileInfo object that contains the file size in bytes, and -desc is an abbreviation of -Descending.
  • Select-Object -First 1 selects the first item from the results. Since they're sorted by file size in descending order, the first item is a FileInfo object representing the largest file.

Some other issues with your code not directly related to the question

  • PowerShell is designed to work with pipelines. Instead of

    foreach ($Folder in (Get-ChildItem $Path)) {
    

    use

    Get-ChildItem $Path | %{
    

    It's more efficient in terms of both typing and processing. %{} is an abbreviation for ForEach-Object (which is not the same as a foreach loop; it's a filter for use in pipelines, and it generally runs more efficiently).

  • $Size/100 won't give you the size in KB because 1 KB is 1024 bytes, but there's a built-in shorthand for that:

    $Size / 1KB. 
    

    You can also use 1MB, 1GB, 1TB, 1PB (sorry, there is no 1EB yet, but I'm sure in 5-10 years not only will there be one, it will probably be very frequently used). Note that you can change the coefficient, but you can't leave it out (/ 2GB divides by 2 gigabytes, but / GB without the 1 is a syntax error)

  • There's no need to use a recursive function to do this. PowerShell has built-in facilities for recursively walking a directory tree and for summing results. Here's a version showing how to do that, combined with the suggestions made above:

    function Get-Size {
      param (
        $Path  = 'C:\My\Default\Directory'
      )
    
      Get-ChildItem $Path -Recurse | ?{$_.PSIsContainer} | %{
        $Size = (Get-ChildItem $_.FullName | Measure-Object Length -Sum -ea SilentlyContinue).Sum
        New-Object PSObject -Property @{'Size in KB' = ($Size / 1KB); 'Folder' = $_.FullName}
      }
    }
    
  • The output will be rather messy, so you'll probably want to pipe the results to Format-Table. I think it's better practice to do your formatting when you call the function rather than include it in the function definition itself. This will give you the properties in the order you probably want, with the size right-aligned and fixed at a precision of two decimal places:

    Get-Size $a | Format-Table @{Name = 'Size in KB'; Expression = {"{0:N2}" -f $_.'Size in KB'}; Align = 'right'}, ' ', Folder -AutoSize
    

다른 팁

First off, what Frode F. says is right. If you need to use PowerShell, then learn PowerShell. Coming here and stating what you did comes across as 'I'm a java guy, I don't understand PowerShell, fix it for me because I'm either too busy to figure it out, or it's just below me'. Asking us to correct things that you don't seem to have taken the time to try and understand is abusing the services that we offer for free of our own time and good will. I'll get off my soapbox now and help you.

Your request and your code say two very different things. Your script gets the total size for everything in the folder, and also does that for all subfolders recursively. Your request says to just find the largest file in that folder.

Actually, you have 2 requests. The one for a default folder is simple. Setting a default if no path given is a simple matter of setting your parameters correctly. If you set a value for your parameter within the Param section it is considered the default if no value is entered. Doing this will solve that for you:

Function Get-Size{
Param ($Path="$env:USERPROFILE\Desktop")
<code goes here>
}

That sets the default to the current user's Desktop folder.

As for getting the largest file, the code you were given will do that. Let me explain it.

Get-ChildItem $path pulls a directory listing for $path. The pipe (|) sends that information to the next command, which is Sort.

Sort Length -desc sorts the results of the first command by length (effectively the file size), in descending order. That gets piped to Select.

Select-Object -first 1 selects the first 1 result (you could select the first 3 results with -first 3 or what not). Since they are in descending order already it selects the largest file in the path specified.

Note that this does not run recursively. To make it search all folders and return the largest file you add the -recurse switch to the Get-ChildItem command.

As for your script, well, it does what it was intended to do. It gets the full size of every folder and subfolder and reports it back. It's a little clumsy in how it does it, but it's functional. As for me, I'd have done something more like this I think:

Function Get-Size{
Param ([Parameter(ValueFromPipeline=$True)]
    $Path="$env:USERPROFILE\Desktop")
    ForEach ($Folder in (Get-ChildItem $Path -recurse|?{$_.PSIsContainer})) {
        $Size = (Get-ChildItem $Folder.FullName | Measure-Object -property length -sum -ea SilentlyContinue)
        New-Object PSObject -Property @{'Size in KB'="{0:N2}" -f ($Size.sum/1KB) +" KB"; 'Folder'=$Folder.FullName}
    }
}
Read-Host "Enter a path" | Get-Size
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top