我正在编写一个管理脚本,我需要计算磁盘上文件的大小.
这些文件位于压缩的NTFS卷上.
我无法使用FileInfo.Length
,因为这是文件大小而不是磁盘上的大小.例如,如果我有一个100MB的文件,但由于NTFS压缩它只使用25MB,我需要我的脚本返回25MB.
有没有办法在Powershell中做到这一点?
(我知道GetCompressedFileSize()
Win32的调用,但我希望这已经在某种程度上受到了影响.)
(编辑)
我想出了如何动态地向Fileobject添加属性(称为"脚本属性"),所以现在,我可以使用语法:$ theFileObject.CompressedSize来读取大小.
(编辑结束)
阅读Goyuix的回复,我想"很酷,但在Powershell中是不是有某种类型扩展功能?".所以我发现这个Scott Hanselman的帖子:http://www.hanselman.com/blog/MakingJunctionsReparsePointsVisibleInPowerShell.aspx
我为FileInfo对象创建了一个Script属性:CompressedSize.
这就是我所做的:(注意:我对Powershell很新,或者至少我没有太多使用它.这可能会更好,但这就是我做的:
首先,我从Goyuix的帖子中编译了Ntfs.ExtendedFileInfo.我把DLL放在我的Powershell配置文件目录中(Documents\WindowsPowershell)
接下来,我在配置文件目录中创建了一个名为My.Types.ps1xml的文件.
我将以下XML放入文件中:
System.IO.FileInfo CompressedSize [Ntfs.ExtendedFileInfo]::GetCompressedFileSize($this.FullName)
该代码(一旦合并到类型系统中)将动态地将名为CompressedSize的属性添加到get-childitem/dir返回的FileInfo对象中.但Powershell还不知道代码,它还不知道我的DLL.我们在下一步处理:
编辑Profile.ps1.在同一目录中.现在,我的配置文件恰好已经包含了一些内容,因为我安装了PowerShell社区扩展.希望我在下一个代码片段中包含您需要的所有内容,以便它甚至可以在没有扩展的机器上运行.将以下代码添加到Profile.ps1:
#This will load the ExtendedfileInfo assembly to enable the GetCompressedFileSize method. this method is used by the #PSCompressedSize Script Property attached to the FileInfo object. $null = [System.Reflection.Assembly]::LoadFile("$ProfileDir\ntfs.extendedfileinfo.dll") #merge in my extended types $profileTypes = $ProfileDir | join-path -childpath "My.Types.ps1xml" Update-TypeData $profileTypes
现在,我引用的$ ProfileDir变量先前在我的Profile.ps1脚本中定义.万一它不在你的身上,这里是定义:
$ProfileDir = split-path $MyInvocation.MyCommand.Path -Parent
而已.下次运行Powershell时,您可以访问FileInfo对象上的CompressedSize属性,就像它是任何其他属性一样.例:
$ myFile = dir c:\ temp\myfile.txt
$ myFile.CompressedSize
这是有效的(无论如何,在我的机器上),但我很想知道它是否符合最佳实践.有一件事我知道我做错了:在Profile.ps1文件中,我将LoadFile的结果返回到一个我不打算使用的变量($ null = blah blah).我这样做是为了禁止将加载文件的结果显示到控制台.可能有更好的方法.
加载托管Windows API(http://mwinapi.sourceforge.net/)并查看ExtendedFileInfo类.有一个方法GetPhysicalFileSize()将返回磁盘上文件所需的大小.
public static ulong GetPhysicalFileSize(string filename)
或者,您可以编译自己的DLL并加载该功能的程序集:
using System; using System.Runtime.InteropServices; namespace NTFS { public class ExtendedFileInfo { [DllImport("kernel32.dll", SetLastError=true, EntryPoint="GetCompressedFileSize")] static extern uint GetCompressedFileSizeAPI(string lpFileName, out uint lpFileSizeHigh); public static ulong GetCompressedFileSize(string filename) { uint high; uint low; low = GetCompressedFileSizeAPI(filename, out high); int error = Marshal.GetLastWin32Error(); if (high == 0 && low == 0xFFFFFFFF && error != 0) { throw new System.ComponentModel.Win32Exception(error); } else { return ((ulong)high << 32) + low; } } } }
然后编译:
csc /target:library /out:ntfs.extendedfileinfo.dll ntfs.extendedfileinfo.cs
最后,在PowerShell中加载并运行:
PS C:\> [System.Reflection.Assembly]::LoadFile("C:\ntfs.extendedfileinfo.dll") PS C:\> [NTFS.ExtendedFileInfo]::GetCompressedFileSize("C:\sample.txt")
使用V2 Add-Type和Pinvoke.NET很容易做到:
add-type -type @' using System; using System.Runtime.InteropServices; using System.ComponentModel; namespace Win32Functions { public class ExtendedFileInfo { [DllImport("kernel32.dll", SetLastError=true, EntryPoint="GetCompressedFileSize")] static extern uint GetCompressedFileSizeAPI(string lpFileName, out uint lpFileSizeHigh); public static ulong GetCompressedFileSize(string filename) { uint high; uint low; low = GetCompressedFileSizeAPI(filename, out high); int error = Marshal.GetLastWin32Error(); if (high == 0 && low == 0xFFFFFFFF && error != 0) throw new Win32Exception(error); else return ((ulong)high << 32) + low; } } } '@ [Win32Functions.ExtendedFileInfo]::GetCompressedFileSize( "C:\autoexec.bat")
实验!请享用!从事!
Jeffrey Snover [MSFT] Windows管理合作伙伴架构师访问Windows PowerShell团队博客:http: //blogs.msdn.com/PowerShell 访问Windows PowerShell ScriptCenter,网址为:http: //www.microsoft.com/technet/scriptcenter/hubs /msh.mspx