PSBasicInfo.psm1

$script:memberDefinition =  @'
 
    public struct FILE_BASIC_INFO
    {
        [MarshalAs(UnmanagedType.I8)]
        public Int64 CreationTime;
        [MarshalAs(UnmanagedType.I8)]
        public Int64 LastAccessTime;
        [MarshalAs(UnmanagedType.I8)]
        public Int64 LastWriteTime;
        [MarshalAs(UnmanagedType.I8)]
        public Int64 ChangeTime;
        [MarshalAs(UnmanagedType.U4)]
        public UInt32 FileAttributes;
    }
 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateFile(
        [MarshalAs(UnmanagedType.LPTStr)] string filename,
        [MarshalAs(UnmanagedType.U4)] UInt32 access,
        [MarshalAs(UnmanagedType.U4)] UInt32 share,
        IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
        [MarshalAs(UnmanagedType.U4)] UInt32 creationDisposition,
        [MarshalAs(UnmanagedType.U4)] UInt32 flagsAndAttributes,
        IntPtr templateFile);
 
    [DllImport("kernel32.dll", SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
 
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool GetFileInformationByHandleEx(
        IntPtr hFile,
        int infoClass,
        out FILE_BASIC_INFO fileInfo,
        uint dwBufferSize);
 
'@
 

function Get-ItemBasicInfo 
{
    [CmdletBinding()]
    param(
        # Path to file or directory
        [Parameter(Mandatory = $true,
                Position = 0, 
                ValueFromPipeline = $true,
                ValueFromPipelineByPropertyName = $true)]
        [ValidateScript({Test-Path -Path $_.FullName})]
        [System.IO.FileSystemInfo]
        $Path
    )
    
    begin 
    {
        Add-Type -MemberDefinition $script:memberDefinition -Name File -Namespace Kernel32
    }
    
    process
    {
        $currentPath = $Path.FullName
        
        try
        {
            Write-Verbose "CreateFile: Open file $currentPath"
            $fileHandle = [Kernel32.File]::CreateFile($currentPath,
                [System.IO.FileAccess]::Read,
                [System.IO.FileShare]::ReadWrite,
                [System.IntPtr]::Zero,
                [System.IO.FileMode]::Open,
                [System.UInt32]0x02000000,
                [System.IntPtr]::Zero)
            
            if($fileHandle -eq -1)
            {
                throw "CreateFile: Error opening file $Path"
            }
            
            # Output object
            $fileBasicInfo = New-Object -TypeName Kernel32.File+FILE_BASIC_INFO
            
            Write-Verbose "GetFileInformationByHandleEx: Get basic info"
            $bRetrieved = [Kernel32.File]::GetFileInformationByHandleEx($fileHandle,0,
                [ref]$fileBasicInfo,
                [System.Runtime.InteropServices.Marshal]::SizeOf($fileBasicInfo))
            
            if(!$bRetrieved)
            {
                throw "GetFileInformationByHandleEx: Error retrieving item information"
            }
            
            # Return result
            [PSCustomObject]@{
                Item = $Path
                CreationTime = [System.DateTime]::FromFileTime($fileBasicInfo.CreationTime)
                LastAccessTime = [System.DateTime]::FromFileTime($fileBasicInfo.LastAccessTime)
                LastWriteTime  = [System.DateTime]::FromFileTime($fileBasicInfo.LastWriteTime)
                ChangeTime     = [System.DateTime]::FromFileTime($fileBasicInfo.ChangeTime)
                FileAttributes = $fileBasicInfo.FileAttributes
            }
        }
        catch 
        {
            throw $_
        }
        finally
        {
            Write-Verbose "CloseHandle: Close file $currentPath"
            $bClosed = [Kernel32.File]::CloseHandle($fileHandle)
            
            if(!$bClosed)
            {
                Write-Warning "CloseHandle: Error closing handle $fileHandle of $Path"
            }
        }
    }
}