Windows equivalent to the unix "stat" command?

Solution 1:

I just threw together a PowerShell script. It includes pretty much everything that makes sense for Windows, except the access controls, which are usually too large to fit in a summary. You can see them with the icacls utility.

$obj = $args[0]
If ($obj.GetType().Name -eq 'String') {$obj = gi $obj}
'File: ' + $obj.FullName
'Size: ' + $obj.Length
$extents = [string](fsutil file queryextents "$($obj.FullName)")
If (-$extents.StartsWith('i')) {
  'Clusters: ' + ($extents.Substring(26) -split 'LCN')[0]
  'LCN: ' + $extents.Substring(42)
} Else {
  'Clusters: stored in file table'
}
'Attributes: ' + $obj.Attributes
$volumeinfo = (fsutil fsinfo volumeinfo "$([System.IO.Path]::GetPathRoot($obj.FullName)[0] + ':')")
$volumeinfo | ? {$_.StartsWith('Volume Serial')} | % {$_.Replace(' :', ':')}
$fileid = (fsutil file queryfileid "$($obj.FullName)")
'File ID: ' + $fileid.Substring(11)
$links = (fsutil hardlink list "$($obj.FullName)")
'Links: ' + ([string[]]$links).Length
'Owner: ' + $obj.GetAccessControl().Owner
''
'Access: ' + $obj.LastAccessTime
'Modify: ' + $obj.LastWriteTime
'Create: ' + $obj.CreationTime
'' # Extra blank line for readability

It uses the normal .NET/PowerShell file system entry properties and calls out to the fsutil utility for the tricky stuff. Since that utility isn't a PowerShell cmdlet, I had to do some messy string chopping to get the right information.

To use it, save it as a .ps1 file and see the Enabling Scripts section of the PowerShell tag wiki. Example of output:

File: C:\Users\Ben\test\blank.ps1
Size: 8
Clusters: stored in file table
Attributes: Archive
Volume Serial Number: 0x9c67b42c
File ID: 0x0000000000000000000700000014428b
Links: 1
Owner: POWERSHELL\Ben

Access: 07/29/2016 20:01:25
Modify: 07/29/2016 20:02:43
Create: 07/29/2016 20:01:25

Solution 2:

Get-Item /path/to/file | Format-List should get you what you need using only native Cmdlets.

Get-Item gets the details about whatever file you are interested in. Format-List will, somewhat unintuitively, expose more parameters to the PowerShell host than would be seen otherwise. It also formats it as a list, as you would expect.

 ~> Get-Item ./temp.txt | Format-List


    Directory: /Users/brianshacklett


Name           : temp.txt
Length         : 989
CreationTime   : 4/5/18 9:52:04 PM
LastWriteTime  : 4/5/18 9:52:04 PM
LastAccessTime : 6/26/18 7:58:18 PM
Mode           : ------
LinkType       :
Target         :
VersionInfo    : File:             /Users/brianshacklett/temp.txt
                 InternalName:
                 OriginalFilename:
                 FileVersion:
                 FileDescription:
                 Product:
                 ProductVersion:
                 Debug:            False
                 Patched:          False
                 PreRelease:       False
                 PrivateBuild:     False
                 SpecialBuild:     False
                 Language:

If the verbosity bothers you, you can use aliases to shorten this to gi /path to file | fl

Solution 3:

There are no exact equivalent but the closest you can get with Windows built-in utilities is with the fsutil command. It'll give you most of the things stat provides, along with more detailed information about the underlying file system structure. But unlike stat it needs to be run under administrator rights. You can also use wmic (or the Get-WmiObject (gwmi alias) PowerShell version) for a lot of useful data. For a few other options you need to get with other commands

Below are how to get the analogous information to the format options in stat (in PowerShell, with cmd version if available) that you can use to customize the output. Otherwise just dump the fsutil file layout, fsutil fsinfo sectorinfo and fsutil fsinfo ntfsinfo output directly

  • Access rights: Windows access rights are very different from POSIX ones. Therefore there are no analog to %a. However there does exist similar information

    • If you want to get file permissions then use Get-Acl or icacls. See more in Windows: List files and their permissions (access) in command line

    • If you just want the file mode then either of these will suffice and is the closest to %A

        (ls path\to\file).Mode
        for %i in (path\to\file) do echo %~ai in cmd
      
  • Number of blocks allocated (%b): Run fsutil file layout path\to\file or fsutil volume filelayout path\to\file and count the total number of clusters allocated in the $DATA stream.

    For example for the below output we have 4 extents allocated, each is 82, 432.419, 259 and 155.076-cluster long respectively. As a result the number of blocks allocated is 82 + 432419 + 259 + 155076 = 587836. A quick trick is to add the VCN number of the last cluster with it's length: 432760 + 155076 = 587836

      Stream                  : 0x080  ::$DATA
          Attributes          : 0x00000000: *NONE*
          Flags               : 0x00000000: *NONE*
          Size                : 2.407.772.410
          Allocated Size      : 2.407.776.256
          Extents             : 4 Extents
                              : 1: VCN: 0 Clusters: 82 LCN: 1.620.482
                              : 2: VCN: 82 Clusters: 432.419 LCN: 5.331.392
                              : 3: VCN: 432.501 Clusters: 259 LCN: 3.230.067
                              : 4: VCN: 432.760 Clusters: 155.076 LCN: 9.299.239
    
  • The size in bytes of each block reported by %b (%B):

      fsutil fsinfo ntfsinfo <drive> | findstr /c:"Bytes Per Cluster"`
    
  • SELinux security context string (%C): No comparable feature

  • Device number (%d, %D): No similar counterpart. But you can use the following command if you want to get the device ID

      (Get-WmiObject win32_volume | where { $_.driveletter -eq '<drive>' }).deviceid
    
  • Raw mode in hex (%f): No equivalent form. See %a/%A above

  • File type (%F): No direct equivalent, since Windows file and driver models are very different and there are no such things like character devices on Windows so you won't get "character special file". However generally you can use (ls path\to\file).Mode to get the file mode like %A above, and (ls path\to\file).LinkType to get link type

  • Group name of owner (%G):

      (Get-Acl file.ext).Group
    
  • Group ID of owner (%g):

      (gwmi win32_useraccount | where { $_.caption -eq "$((Get-Acl file.ext).Group)" }).SID
    
  • Number of hard links (%h): There are no similar information. However fsutil hardlink list path\to\file prints all the hard links of a file, so we can easily count them with

      (fsutil hardlink list path\to\file | Measure-Object).Count
    
    • Alternatively use (fsutil file layout path\to\file | sls -CaseSensitive -Pattern '^Link.+\s+:\s+0x[0-9a-f]+:\s*HLINK Name\s+:' | Measure-Object).Count
  • Inode number (%i): There's no inode in Windows, but NTFS (and possibly newer file systems like ReFS) has an equivalent called file ID that can be extracted from fsutil file layout output or directly with

      fsutil file queryfileid path\to\file
    
  • File name (%n): This is quite obvious

  • Quoted file name with dereference if symbolic link (%N):

    • (ls path\to\file | ?{$_.LinkType} | select FullName,LinkType,Target
    • or dir path\to\file in cmd, with the symbolic name in square brackets
  • I/O block size (%o): see %s for file systems below

  • Total size, in bytes (%s): (ls path\to\file).Length. Or can be easily seen in cmd's dir output, and in fsutil file layout path\to\file output under the Size field like above

  • Device type (%t, %T): See %T for file system type below

  • User name of owner (%U):

      (Get-Acl path\to\file).Owner
    
  • User ID of owner (%u): You can get the user SID with the below command

      (gwmi win32_useraccount | where { $_.caption -eq "$((Get-Acl D:\zz.bat).owner)" }).SID
    
  • File time:

    • Last access time (%x): (ls path\to\file).LastAccessTime
    • To get the last access time since Epoch (%X): (ls path\to\file).LastAccessTime.Ticks or (ls path\to\file).LastAccessTime.ToFileTime() (depending on which Epoch you want: 1/1/0001 or 1/1/1601) to get the file time in 100ns resolution
    • Similarly last modification time (%y, %Y) can be retrived with LastWriteTime
    • Getting last metadata change time (%z, %Z) is trickier and you may need to call win32 APIs from PowerShell

For file systems generally you can use fsutil fsinfo ntfsinfo <drive> or fsutil fsinfo sectorinfo <drive> to find detailed information

  • Free blocks available to non-superuser (%a): No equivalent. But I think you can check it with fsutil quota query

  • Total data blocks in file system (%b):

      fsutil fsinfo ntfsinfo <drive> | findstr /c:"Number Sectors"
    
  • Total file nodes in file system (%c): If it's about the number of inodes then there's no MFT record limit on NTFS as well as many newer Linux filesystems like Btrfs or XFS. The MFT file size will be increased to store more file records. The total number of MFT records can be checked with fsutil fsinfo ntfsinfo <drive>

  • Free file nodes in file system (%d): Not sure what this is. If it's about the number of unused inodes then as said above, there's generally no upper limit. Possibly fsutil volume allocationreport <drive> will work

  • Free blocks in file system (%f):

    • fsutil fsinfo ntfsinfo <drive> | findstr /c:"Free Clusters"
    • More detailed information can be found with fsutil volume allocationreport <drive>
  • File System ID in hex (%i): I don't know what's the exact synonymous on Windows but these may provide that information

      fsutil fsinfo ntfsinfo <drive> | findstr /c:"Resource Manager Identifier" /c:"NTFS Volume Serial Number"
      (gwmi win32_volume | where { $_.driveletter -eq 'd:' }).serialnumber`
    
  • Maximum length of filenames (%l):

      (gwmi win32_volume | where { $_.driveletter -eq <drive>  }).maximumfilenamelength
    
  • Block size (for faster transfers) (%s):

      fsutil fsinfo sectorinfo <drive> | findstr /c:"Performance"
    
  • Fundamental block size (for block counts) (%S):

      fsutil fsinfo sectorinfo <drive> | sls physical
      fsutil fsinfo ntfsinfo <drive> | sls physical
      (gwmi win32_volume | where { $_.driveletter -eq 'd:' }).blocksize
    
  • Type: For %T you can use fsutil fsinfo volumeinfo <drive> | findstr /c:"File System Name". I'm not sure what %t is but it seems that's the magic number of the partition

The (Get-WmiObject win32_ALIAS | where { $_.FILTERFIELD -eq 'VALUE' }).GETFIELD commands above can be changed to wmic ALIAS where FILTERFIELD='VALUE' get GETFIELD /value. However wmic was deprecated so in the future it may be removed