NebDaMin
NebDaMin

Reputation: 658

PowerShell display files size as KB, MB, or GB

I have a section of a PowerShell script that gets the file size of a specified directory.

I am able to get the values for different units of measurement into variables, but I don't know a good way to display the appropriate one.

$DirSize = "{0:N2}" -f (($DirArray | Measure-Object -property length -sum).sum)
$DirSizeKB = "{0:N2}" -f (($DirArray | Measure-Object -property length -sum).sum / 1KB)
$DirSizeMB = "{0:N2}" -f (($DirArray | Measure-Object -property length -sum).sum / 1MB)
$DirSizeGB = "{0:N2}" -f (($DirArray | Measure-Object -property length -sum).sum / 1GB)

If the number of bytes is at least 1 KB I want the KB value displayed. If the number of KBs is at least 1 MB I want MBs displayed and so on.

Is there a good way to accomplish this?

Upvotes: 28

Views: 141459

Answers (8)

LeOn - Han Li
LeOn - Han Li

Reputation: 10174

If you have WSL then you can invoke it directly from PWSH:

wsl ls -lh

even better if you use exa:

wsl exa -l /mnt/c

one drawback is the tab completion will give you .\folder1\folder2 which does not work with exa, so I write a custom function replacing the slash:

Function ll { 
  $target = '.' #default to current directory is no command-line arguments supplied
  if($args[0]){
    $target = $args[0] -replace "`\\","`/"
  }
  wsl exa -l --group --icons --sort=modified $target 
}

!!! Put above in your $PROFILE file by notepad.exe $PROFILE, and reload pwsh with . $PROFILE.

Now ll will show info nicely and tab completion will work with sub directories like

ll .\subDir\subSubDir.

Upvotes: 0

PcSi-L
PcSi-L

Reputation: 41

I've added the function DisplayInBytes($num) in the Bill Stewart "d.ps1" script

function DisplayInBytes($num)
{
    $suffix = "oct", "Kib", "Mib", "Gib", "Tib", "Pib", "Eib", "Zib", "Yib"
    $index = 0
    while ($num -gt 1kb) 
    {
        $num = $num / 1kb
        $index++
    }

    $sFmt="{0:N"
    if ($index -eq 0) {$sFmt += "0"} else {$sFmt += "1"}
    $sFmt += "} {1}"
    $sFmt -f $num, $suffix[$index]
}

Replace the block

  # Create the formatted string expression.
   $formatStr = "`"{0,5} {1,10} {2,5} {3,15:N0} ({4,11})"   $formatStr += iif { -not $Q } { " {5}" } { " {5,-22} {6}" }   $formatStr += "`" -f `$_.Mode," +
        "`$_.$TimeField.ToString('d')," +
        "`$_.$TimeField.ToString('t')," +
        "`$_.Length,`$sfSize"

And

  if (-not $Bare) {
    $sfSize=DisplayInBytes $_.Length
    invoke-expression $formatStr

And, at the end

  # Output footer information when not using -bare.
  if (-not $Bare) {
    if (($fileCount -gt 0) -or ($dirCount -gt 0)) {
      $sfSize = DisplayInBytes $sizeTotal
      "{0,14:N0} file(s) {1,15:N0} ({3,11})`n{2,15:N0} dir(s)" -f
        $fileCount,$sizeTotal,$dirCount,$sfSize
    }
  }

Upvotes: 1

mjolinor
mjolinor

Reputation: 68263

There are lots of ways to do this. Here's one:

switch -Regex ([math]::truncate([math]::log($bytecount,1024))) {

    '^0' {"$bytecount Bytes"}

    '^1' {"{0:n2} KB" -f ($bytecount / 1KB)}

    '^2' {"{0:n2} MB" -f ($bytecount / 1MB)}

    '^3' {"{0:n2} GB" -f ($bytecount / 1GB)}

    '^4' {"{0:n2} TB" -f ($bytecount / 1TB)}

     Default {"{0:n2} PB" -f ($bytecount / 1pb)}
}

Upvotes: 22

x0n
x0n

Reputation: 52420

Use a switch or a set of "if" statements. Your logic (pseudocode) should look like this:

  1. Is the size at least 1 GB? Yes, display in GB (else...)
  2. Is the size at least 1 MB? Yes, display in MB (else...)
  3. Display in KB.

Note that you should be testing in reverse order from the largest size to the smallest. Yes, I could have written the code for you, but I suspect you know enough to turn the above into a working script. It's just the approach that had you stumped.

Upvotes: 7

zdan
zdan

Reputation: 29450

An alternative to a bunch of if's/switches is to use a while loop until your value is the right size. It scales!

[double] $val = ($DirArray | Measure-Object -property length -sum).sum
while($val -gt 1kb){$val /= 1kb;}
"{0:N2}" -f $val

Upvotes: 0

Mladen Mihajlovic
Mladen Mihajlovic

Reputation: 6435

Mine is similar to @zdan 's one but written as a script function:

function DisplayInBytes($num) 
{
    $suffix = "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
    $index = 0
    while ($num -gt 1kb) 
    {
        $num = $num / 1kb
        $index++
    } 

    "{0:N1} {1}" -f $num, $suffix[$index]
}

Upvotes: 24

Nandha kumar
Nandha kumar

Reputation: 763

I hope the following code will help you...

$file = 'C:\file.txt'
Write-Host((Get-Item $file).length/1KB) // returns file length in KB
Write-Host((Get-Item $file).length/1MB) // returns file length in MB
Write-Host((Get-Item $file).length/1GB) // returns file length in GB

Upvotes: 22

boeprox
boeprox

Reputation: 1868

Here a function that I wrote a while back that utilizes the Win32 API to accomplish what you are looking for.

Function Convert-Size {
    <#
        .SYSNOPSIS
            Converts a size in bytes to its upper most value.

        .DESCRIPTION
            Converts a size in bytes to its upper most value.

        .PARAMETER Size
            The size in bytes to convert

        .NOTES
            Author: Boe Prox
            Date Created: 22AUG2012

        .EXAMPLE
        Convert-Size -Size 568956
        555 KB

        Description
        -----------
        Converts the byte value 568956 to upper most value of 555 KB

        .EXAMPLE
        Get-ChildItem  | ? {! $_.PSIsContainer} | Select -First 5 | Select Name, @{L='Size';E={$_ | Convert-Size}}
        Name                                                           Size                                                          
        ----                                                           ----                                                          
        Data1.cap                                                      14.4 MB                                                       
        Data2.cap                                                      12.5 MB                                                       
        Image.iso                                                      5.72 GB                                                       
        Index.txt                                                      23.9 KB                                                       
        SomeSite.lnk                                                   1.52 KB     
        SomeFile.ini                                                   152 bytes   

        Description
        -----------
        Used with Get-ChildItem and custom formatting with Select-Object to list the uppermost size.          
    #>
    [cmdletbinding()]
    Param (
        [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias("Length")]
        [int64]$Size
    )
    Begin {
        If (-Not $ConvertSize) {
            Write-Verbose ("Creating signature from Win32API")
            $Signature =  @"
                 [DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
                 public static extern long StrFormatByteSize( long fileSize, System.Text.StringBuilder buffer, int bufferSize );
"@
            $Global:ConvertSize = Add-Type -Name SizeConverter -MemberDefinition $Signature -PassThru
        }
        Write-Verbose ("Building buffer for string")
        $stringBuilder = New-Object Text.StringBuilder 1024
    }
    Process {
        Write-Verbose ("Converting {0} to upper most size" -f $Size)
        $ConvertSize::StrFormatByteSize( $Size, $stringBuilder, $stringBuilder.Capacity ) | Out-Null
        $stringBuilder.ToString()
    }
}

Upvotes: 10

Related Questions