PowerShell to get Size on Disk of files

Last updated on 10th February 2017

If you right click a file or folder in windows and look at it properties you will find there are two size properties - Size and Size on Disk. Size is the actual size of the file in bytes and Size on disk is the disk space required to store that file. The two sizes can be the same in some cases or it could be hugely different especially if its a sparse file or if its a compressed file that is stored in a volume that supports compression.

To get the size of a file in PowerShell you just have to run the Get-Item command

PS C:\Users\> Get-Item export.sql

    Directory: C:\Users

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        23/01/2017     15:25     177331 export.sql

There isn't any single command or cmdlets that gives you the size on disk of a file, however we could achieve this with .Net Platform Invoke (P/Invoke) feature and the PowerShell Add-Type cmdlet.

First you create a .NET class that finds the actual size on disk of a file. Inside this class you will use the Win32 function GetCompressedFileSizeW to which returns the size in bytes used to store a file.

The Add-Type cmdlet is used to add the class to your PowerShell session. Finally get each file from the specfied directory and call the function in .Net class you created with full file name as paramater.

Here is the full script:

Script: Get-FileSizeOnDisk.ps1


<#

.SYNOPSIS
  Powershell script to get file size and size on disk of all files
  in a directory.
  
.DESCRIPTION
  This PowerShell script gets file size and size on disk in bytes
  of all files in a directory.
  
.PARAMETER <path>
   Directory path of the files to check. If this parameter is not
   specified the default value is current directory.
 
.NOTES
  Version:        1.0
  Author:         Open Tech Guides
  Creation Date:  06-Feb-2017
 
.LINK
    www.opentechguides.com
    
.EXAMPLE
  Get-FileSizeOnDisk c:\myfolder

#>
   

param (
 [string]$path='.'
)


$source = @"
 using System;
 using System.Runtime.InteropServices;
 using System.ComponentModel;
 using System.IO;

 namespace Win32
  {
    
    public class Disk {
	
    [DllImport("kernel32.dll")]
    static extern uint GetCompressedFileSizeW([In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
    [Out, MarshalAs(UnmanagedType.U4)] out uint lpFileSizeHigh);	
        
    public static ulong GetSizeOnDisk(string filename)
    {
      uint HighOrderSize;
      uint LowOrderSize;
      ulong size;

      FileInfo file = new FileInfo(filename);
      LowOrderSize = GetCompressedFileSizeW(file.FullName, out HighOrderSize);

      if (HighOrderSize == 0 && LowOrderSize == 0xffffffff)
       {
	 throw new Win32Exception(Marshal.GetLastWin32Error());
      }
      else { 
	 size = ((ulong)HighOrderSize << 32) + LowOrderSize;
	 return size;
       }
    }
  }
}

"@

Add-Type -TypeDefinition $source

$result = @()

Get-ChildItem $path | Where-Object { ! $_.PSIsContainer} | Foreach-Object { 
  
    $size = [Win32.Disk]::GetSizeOnDisk($_.FullName)
    $obj = New-Object PSObject
    Add-Member -InputObject $obj -MemberType NoteProperty -Name "File Name" -Value $_.Name
    Add-Member -InputObject $obj -MemberType NoteProperty -Name "Size" -Value $_.Length
    Add-Member -InputObject $obj -MemberType NoteProperty -Name "Size on Disk" -Value $size
    $result += $obj
}

write-output $result 

Sample output

PS C:\> Get-FileSizeOnDisk.ps1 C:\Users

File Name          Size        Size on Disk
---------          ----        ------------
export.sql       177331               45056

PS C:\>

Post a comment

Comments

Subrahmanyam | September 22, 2022 12:28 PM |

I want to know c drive size and free size in all my servers is there any script for that

Suresh | September 24, 2022 10:01 PM |

Try Get-PSDisk or Get-Volume cmdlets
Get-Volume | Format-Table DriveLetter, Size, SizeRemaining

Bryan | June 13, 2019 7:14 PM |

This is awesome. But I have a huge directory structure, where I want to find all files that have 0 size on disk (revealing files that have been "stubbed out" by an archiving process). How might I tweak this code to do this? (Looks like Trevor would be interested too!)

Adrian Dcosta | September 7, 2021 9:14 AM |

param (
 [string]$path='.'
)


$source = @"
 using System;
 using System.Runtime.InteropServices;
 using System.ComponentModel;
 using System.IO;

 namespace Win32
  {
    
    public class Disk {
	
    [DllImport("kernel32.dll")]
    static extern uint GetCompressedFileSizeW([In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
    [Out, MarshalAs(UnmanagedType.U4)] out uint lpFileSizeHigh);	

DelphicOracle | March 17, 2020 4:07 AM |

The code used to get 'size' returns the same information as (get-childitem -path [yourPathHere]).length.
The *Disk size* is the rounded up number of clusters used to store the bytes in the file. A cluster on a 4K NTFS formatted disk is 4096 bytes. A file of 6000 bytes needs 2 clusters to store the file, a disk size of 8192 bytes.

Oscar Nieves | November 1, 2018 4:59 PM |

First off, this is incredile, thanks!! Is there a way to get the Folder Size and Size on Disk?

Trevor | January 29, 2018 6:35 PM |

Works a treat! Thanks so much. Best solution I could find on web for getting the file attribute showing 'size on disk'. Useful for hunting down IBM Tivoli Storage Manager HSM files with 0 bytes because they are 'archived' to media