我正在进行文件服务器迁移,并且正在编写一个小型 C# 应用程序来帮助我映射用户权限,以便我们可以将它们放入用户组中。
我目前正在使用
Directory.GetAccessControl(path);
但是,当它到达这个 263 字符文件路径时它会失败。
名称无效。
参数名称:名称
我使用时遇到同样的错误DirectoryInfo.GetAccessControl();
这种方法是否有解决方法或替代方法?
谢谢!
我正在进行文件服务器迁移,并且正在编写一个小型 C# 应用程序来帮助我映射用户权限,以便我们可以将它们放入用户组中。
我目前正在使用
Directory.GetAccessControl(path);
但是,当它到达这个 263 字符文件路径时它会失败。
名称无效。
参数名称:名称
我使用时遇到同样的错误DirectoryInfo.GetAccessControl();
这种方法是否有解决方法或替代方法?
谢谢!
在路径前加上“\?\”以指定“扩展长度路径”。我无法测试 Directory.GetAccessControl()` 是否适用于扩展长度路径,但值得一试:
来自http://msdn.microsoft.com/en-us/library/aa365247.aspx:
最大路径长度限制
在 Windows API(以下段落中讨论的一些例外情况)中,路径的最大长度为
MAX_PATH
,定义为 260 个字符。本地路径按以下顺序构造:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止空字符。例如,驱动器 D 上的最大路径是"D:\<some 256-character path string><NUL>"
表示"<NUL>"
当前系统代码页的不可见终止空字符的位置。(此处使用的字符< >
是为了清晰起见,不能作为有效路径字符串的一部分。)注意 Windows API 中的文件 I/O 函数转换
"/"
为"\"
将名称转换为 NT 样式名称的一部分,除非使用"\\?\"
以下部分中详述的前缀。Windows API 有许多函数也有 Unicode 版本,以允许最大总路径长度为 32,767 个字符的扩展长度路径。这种类型的路径由由反斜杠分隔的组件组成,每个组件都达到 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用
"\\?\"
前缀。例如,"\\?\D:\<very long path>"
。(此处使用的字符< >
是为了清晰起见,不能作为有效路径字符串的一部分。)
一种替代方法是使用subst
. 在命令提示符下,您可以执行
subst X: "D:\really really really\long path\that you can shorten"
然后在 X: 驱动器上执行您的操作,整个开始部分将不计入您的 260 字符限制。
您应该使用 DirectoryInfo 递归处理您的目录树 - 这样做可以避免传递完整路径。
如果它是库中的任意限制,那么您可以尝试使用 8 个字符的目录名称。要确定这些名称是什么,请使用 /X 选项运行 dir:
C:\>dir /x
29/12/2009 23:33 PROGRA~1 Program Files
23/02/2010 21:26 PROGRA~2 Program Files (x86
05/12/2009 20:57 Users
02/02/2010 09:23 Windows
短名称是带有波浪线的名称。尝试将它们传递给函数以减少字符串长度。请注意,不保证这会起作用。
使用我上面提到的库可以很好地解决问题。我想我应该根据需要获取更多映射的驱动器号,但我的最大目录长度只有 300 个字符长。
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security;
using System.Security.AccessControl;
using aejw.Network;
namespace SecurityScanner
{
class Program
{
static void Main(string[] args)
{
string path = @"\\mynetworkdir";
DirectoryInfo di = new DirectoryInfo(path);
List<DirSec> dirs = new List<DirSec>();
RecordSecurityData(di, dirs, path, path);
//Grouping up my users
List<List<DirSec>> groups = new List<List<DirSec>>();
foreach (DirSec d in dirs)
{
bool IsNew = true;
foreach (List<DirSec> group in groups)
{
if (d.IsSameUserList(group[0]))
{
group.Add(d);
IsNew = false;
break;
}
}
if (IsNew)
{
List<DirSec> newGroup = new List<DirSec>();
newGroup.Add(d);
groups.Add(newGroup);
}
}
//Outputting my potential user groups
StringBuilder sb = new StringBuilder();
foreach (List<DirSec> group in groups)
{
foreach (DirSec d in group)
{
sb.AppendLine(d.DirectoryName);
}
foreach (string s in group[0].UserList)
{
sb.AppendLine("\t" + s);
}
sb.AppendLine();
}
File.WriteAllText(@"c:\security.txt", sb.ToString());
}
public static void RecordSecurityData(DirectoryInfo di, List<DirSec> dirs, string path, string fullPath)
{
DirSec me = new DirSec(fullPath);
DirectorySecurity ds;
NetworkDrive nd = null;
if(path.Length <= 248)
ds = Directory.GetAccessControl(path);
else
{
nd = new NetworkDrive();
nd.LocalDrive = "X:";
nd.ShareName = path;
nd.MapDrive();
path = @"X:\";
di = new DirectoryInfo(path);
ds = Directory.GetAccessControl(path);
}
foreach (AuthorizationRule ar in ds.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
{
me.AddUser(ar.IdentityReference.Value);
}
dirs.Add(me);
foreach (DirectoryInfo child in di.GetDirectories())
{
RecordSecurityData(child, dirs, path + @"\" + child.Name, fullPath + @"\" + child.Name);
}
if (nd != null)
nd.UnMapDrive();
}
public struct DirSec
{
public string DirectoryName;
public List<string> UserList;
public DirSec(string directoryName)
{
DirectoryName = directoryName;
UserList = new List<string>();
}
public void AddUser(string UserName)
{
UserList.Add(UserName);
}
public bool IsSameUserList(DirSec other)
{
bool isSame = false;
if (this.UserList.Count == other.UserList.Count)
{
isSame = true;
foreach (string myUser in this.UserList)
{
if (!other.UserList.Contains(myUser))
{
isSame = false;
break;
}
}
}
return isSame;
}
}
}
}