不确定这是否对你有帮助,考虑到你有这么多文件要处理。如果你确实需要像 Mehrdad 解释的那样直接调用 Windows API ,你可以尝试合并下面的代码并使用它而不是get-ntfsowner
to看看它是否工作得更快。
另外我建议把这部分代码
$Properties = @{
Path = $Path
Owner = $Owner
}
一行下来,所以就在
If ($Owner -ne "BUILTIN\Administrators" -and $Owner -ne $null-and $Owner -ne "Domain\Domain Admins" -and $Owner -notlike "S-1*")
当然,它不会做太多事情,但它可以让您在不需要时避免创建散列。也许测试本身可以整理一下,例如:
If (($Owner) -and $Owner -notmatch '^(BUILTIN\\|NT AUTHORITY\\|S-1).+|(.+\\Domain Admins)$')
无论如何,这是使用 Win32 api 克服 Get-Ace 的 260 个字符限制的代码
if (-not ([System.Management.Automation.PSTypeName]'Win32Api.LongFileName').Type) {
Add-Type -Language CSharp -TypeDefinition @"
using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Security.Principal;
namespace Win32Api {
public static class LongFileName
{
internal const uint ERROR_SUCCESS = 0;
internal const int INVALID_FILE_ATTRIBUTES = -1;
internal const int FILE_ATTRIBUTE_READONLY = 0x1; // A file that is read-only. This attribute is not honored on directories.
internal const int FILE_ATTRIBUTE_HIDDEN = 0x2; // The file or directory is hidden. It is not included in an ordinary directory listing.
internal const int FILE_ATTRIBUTE_SYSTEM = 0x4; // A file or directory that the operating system uses a part of, or uses exclusively.
internal const int FILE_ATTRIBUTE_NORMAL = 0x80; // A file that does not have other attributes set. This attribute is valid only when used alone.
internal const int FILE_ATTRIBUTE_DIRECTORY = 0x10; // The handle that identifies a directory.
internal const int FILE_ATTRIBUTE_ARCHIVE = 0x20; // A file or directory that is an archive file or directory.
internal const int FILE_READ_ATTRIBUTES = 0x0080;
internal const int FILE_WRITE_ATTRIBUTES = 0x0100;
internal const int FILE_READ_DATA = 0x0001;
internal const int FILE_WRITE_DATA = 0x0002;
internal const int FILE_APPEND_DATA = 0x0004;
internal const int FILE_READ_EA = 0x0008;
internal const int FILE_WRITE_EA = 0x0010;
internal const int FILE_SHARE_NONE = 0x00000000;
internal const int FILE_SHARE_READ = 0x00000001;
internal const long READ_CONTROL = 0x00020000L;
internal const long STANDARD_RIGHTS_READ = READ_CONTROL;
internal const long STANDARD_RIGHTS_WRITE = READ_CONTROL;
internal const long SYNCHRONIZE = 0x00100000L;
internal const long FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
SYNCHRONIZE;
internal const long FILE_GENERIC_READ = STANDARD_RIGHTS_READ |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
SYNCHRONIZE;
internal const int CREATE_NEW = 1;
internal const int CREATE_ALWAYS = 2;
internal const int OPEN_EXISTING = 3;
internal const int MAX_PATH = 260;
internal const int MAX_ALTERNATE = 14;
enum SE_OBJECT_TYPE
{
SE_UNKNOWN_OBJECT_TYPE,
SE_FILE_OBJECT,
SE_SERVICE,
SE_PRINTER,
SE_REGISTRY_KEY,
SE_LMSHARE,
SE_KERNEL_OBJECT,
SE_WINDOW_OBJECT,
SE_DS_OBJECT,
SE_DS_OBJECT_ALL,
SE_PROVIDER_DEFINED_OBJECT,
SE_WMIGUID_OBJECT,
SE_REGISTRY_WOW64_32KEY
}
enum SECURITY_INFORMATION
{
OWNER_SECURITY_INFORMATION = 1,
GROUP_SECURITY_INFORMATION = 2,
DACL_SECURITY_INFORMATION = 4,
SACL_SECURITY_INFORMATION = 8,
}
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint GetSecurityInfo(IntPtr handle, SE_OBJECT_TYPE objectType, SECURITY_INFORMATION securityInfo, out IntPtr sidOwner, out IntPtr sidGroup, out IntPtr dacl, out IntPtr sacl, out IntPtr securityDescriptor);
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool ConvertSidToStringSid(IntPtr sid, out IntPtr sidString);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int GetFileAttributesW(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr handle);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool CloseHandle(IntPtr handle);
public static string GetFileOwner(string filename)
{
IntPtr fileHandle;
IntPtr ownerSid;
IntPtr groupSid;
IntPtr dacl;
IntPtr sacl;
IntPtr securityDescriptor = IntPtr.Zero;
uint result = 0;
try
{
fileHandle = GetFileHandle(filename);
result = GetSecurityInfo(fileHandle, SE_OBJECT_TYPE.SE_FILE_OBJECT, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, out ownerSid, out groupSid, out dacl, out sacl, out securityDescriptor);
IntPtr ptrString = IntPtr.Zero;
bool success = ConvertSidToStringSid(ownerSid, out ptrString);
string strSid = Marshal.PtrToStringAuto(ptrString);
Marshal.FreeHGlobal(ptrString);
// convert the user sid string to a domain\name. Needs .NET 2.0 or better
string account = new SecurityIdentifier(strSid).Translate(typeof(NTAccount)).ToString();
if (!string.IsNullOrEmpty(account))
{
return account; // domain\user
}
else
{
// Console.WriteLine("Could not translate SID to username. User may have been deleted.");
return strSid;
}
}
finally
{
LocalFree(securityDescriptor);
// If you use a SafeFileHandle, do not call CloseHandle as the CLR will close it for you (even if it's already closed).
// CloseHandle(fileHandle);
}
}
public static IntPtr GetFileHandle(string filename)
{
if (filename.Length >= MAX_PATH) filename = AddLongPathPrefix(filename);
SafeFileHandle hfile = CreateFile(filename, (int)FILE_GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (hfile.IsInvalid) ThrowWin32Exception();
return hfile.DangerousGetHandle();
}
public static string AddLongPathPrefix(string path)
{
if (path.StartsWith(@"\\?\")) return path;
var newpath = path;
if (newpath.StartsWith("\\"))
{
newpath = @"\\?\UNC\" + newpath.Substring(2);
}
else if (newpath.Contains(":"))
{
newpath = @"\\?\" + newpath;
}
else
{
var currdir = Environment.CurrentDirectory;
newpath = CombinePath(currdir, newpath);
while (newpath.Contains("\\.\\")) newpath = newpath.Replace("\\.\\", "\\");
newpath = @"\\?\" + newpath;
}
return newpath.TrimEnd('.');
}
public static string CombinePath(string path1, string path2)
{
return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.');
}
public static bool Exists(string path)
{
if (path.Length < MAX_PATH) return System.IO.File.Exists(path);
var attr = GetFileAttributesW(AddLongPathPrefix(path));
return (attr != INVALID_FILE_ATTRIBUTES && (((attr & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE) ||
((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)));
}
private static void ThrowWin32Exception()
{
int code = Marshal.GetLastWin32Error();
if (code != 0)
{
throw new System.ComponentModel.Win32Exception(code);
}
}
}
}
"@
}
function Get-FileOwner {
# Returns the owner of a file as string.
# The script can handle both 'normal' path lengths aswell as Long paths (up to approx. 32760 characters)
# The returned string MAY contain names such as "NT AUTHORITY\SYSTEM", "NT AUTHORITY\IUSR" or "BUILTIN\Administrators"
# so you will have to exclude those afterwards if need be. When a string in the form of a SID string like
# "S-1-5-21-3623811015-3361044348-30300820-1013" is returned, it usually means the user has already been deleted.
[CmdletBinding()]
param(
[ValidateNotNullOrEmpty()]
[string]$Path
)
if ([Win32Api.LongFileName]::Exists($Path)) {
return [Win32Api.LongFileName]::GetFileOwner($Path)
}
Write-Warning "Path not found '$Path'"
}
该脚本是基于从多个地方收集的信息构建的,特别是通过改编Wolf5的代码