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
oricacls
. 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
orfsutil 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
- Alternatively use
-
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 withfsutil 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'sdir
output, and infsutil file layout path\to\file
output under theSize
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
- Last access time (%x):
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