Wednesday, March 31, 2010

Using powershell to get ntfs info (such as cluster size)

20100331 - slight update.  Converting the hex items to dec and allowing passing of multiple drives.
20131230 - slight update.  Changed the convert to use an Int64 instead of int32 as I was getting overflow on larger drives

A new function for my library.   Base idea copped from Jacques Barathon [MS] at the bottom of this thread and hashed out to get all the properties.


function get-ntfsinfo {
      param ([char[]]$drive = "c")
     

      $drive | foreach {
            if (test-path "$($_):") {
                  $cs = new-object PSObject
                  $cs | add-member NoteProperty Drive $_
                  $output = (fsutil fsinfo ntfsinfo "$($_):")
                  foreach ($line in $output) {
                        $info = $line.split(':')
                        #if the value is hex, convert to dec and put hex in ()
                        if ($info[1].trim().startswith('0x0')) {
                              $info[1] = [Convert]::ToInt64(($info[1].Trim()),16).toString() + " (" + $info[1].Trim().toString() + ")"
                        }
                        $cs | add-member NoteProperty $info[0].trim().Replace(' ','_') $info[1].trim()
                        $info = $null
                  }
                  $cs
            } else {
                  throw "Drive '$_' not found"
            }
      }
}


A basic run gives you:
PS C:\Windows\system32> get-ntfsinfo e


Drive                           : e
NTFS_Volume_Serial_Number       : 0xeabe7aefbe7ab423
Version                         : 3.1
Number_Sectors                  : 558614527 (0x00000000214bc7ff)
Total_Clusters                  : 69826815 (0x00000000042978ff)
Free_Clusters                   : 36249097 (0x0000000002291e09)
Total_Reserved                  : 0 (0x0000000000000000)
Bytes_Per_Sector                : 512
Bytes_Per_Cluster               : 4096
Bytes_Per_FileRecord_Segment    : 1024
Clusters_Per_FileRecord_Segment : 0
Mft_Valid_Data_Length           : 262144 (0x0000000000040000)
Mft_Start_Lcn                   : 786432 (0x00000000000c0000)
Mft2_Start_Lcn                  : 2 (0x0000000000000002)
Mft_Zone_Start                  : 786496 (0x00000000000c0040)
Mft_Zone_End                    : 837664 (0x00000000000cc820)
RM_Identifier                   : 04E578BF-2D2F-11DF-9782-18A9055883A2


But the nice thing here is being able to say
PS C:\Windows\system32> (get-ntfsinfo e).Bytes_Per_Cluster
4096


I then looped it to check cluster size (what I really wanted) on each drive on the server.

foreach ($drive in Get-PSDrive | where {$_.Provider.name -eq "FileSystem"}) {
      if ($drive.free -ne $null) {
            "$drive - $((get-ntfsinfo $drive.name).bytes_per_cluster)"
      }
}

gives output like:

C - 4096
E - 4096
G - 65536
J - 4096
K - 4096
L - 4096
M - 65536
N - 65536
O - 65536
Q - 4096
S - 65536
T - 65536
Z – 4096


Let me know if you use it…

7 comments:

  1. Good gob Cornasdf! That helped me to make a script to not compress files when size is below cluster size.

    ReplyDelete
  2. Note that "get-ntfsinfo $drive.name).bytes_per_cluster" works only on English OS. Just replace property name by your own words. Example worked on my French OS: "get-ntfsinfo $drive.name).octets_par_cluster"

    Regards

    ReplyDelete
  3. Not sure if both of those are from the same anonymous but they are both good info.
    I especially like the idea to not compress if the file is less than the cluster side.

    Thanks

    ReplyDelete
  4. Hi Conrad, Thanks for this article. It was helpful and I placed a link to your article on our blog ficility.net.

    ReplyDelete
  5. Nice one, especially the NTFS cluster size part!

    ReplyDelete
  6. I've had some drives where I had to change the ToInt32 to a ToInt64 instead due to the larger sizes. Otherwise you get this error:

    "Exception calling "ToInt32" with "2" argument(s): "Value was either too large or too small for a UInt32."
    At C:\scripts\ps\Get-NTFSInfo.ps1:13 char:31
    + $info[1] = [Convert]::ToInt32(($info[1].Trim()),16 ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : OverflowException"

    Change this:
    $info[1] = [Convert]::ToInt32(($info[1].Trim()),16).toString() + " (" + $info[1].Trim().toString() + ")"

    To:
    to $info[1] = [Convert]::ToInt64(($info[1].Trim()),16).toString() + " (" + $info[1].Trim().toString() + ")"

    ReplyDelete
  7. Awesome!!! Great Work! Thanks!

    ReplyDelete

analytics