问题:
通过 LoadUserProfile API 为漫游用户登录和加载配置文件未创建正确的配置文件。这只发生在 Windows 2008(UAC 关闭和打开)下。使用标准 Windows 登录的登录工作正常,相同的代码在 Windows 2003 上工作正常。
日志:
环境:
重现:
ETL 可能是到达此处的最佳方式,并将提供最快的诊断。用户配置文件服务 svchost 实例的 Procmon 和系统级别的跟踪登录并没有透露太多关于出了什么问题(如有必要,我可以提供更多信息,但这是一个死胡同)。 Windows 2003 上的 userenv.log 会有所帮助,但 ETL 只能由 MSFT 的人员进行分析。
有什么想法吗?
谢谢, 亚历克斯
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace consoleLogon {
class Program {
#region Helpers for setting privilegies functionality
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct LUID_AND_ATTRIBUTES {
public long Luid;
public int Attributes;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct TOKEN_PRIVILEGES {
public int PrivilegeCount;
public LUID_AND_ATTRIBUTES Privileges;
}
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool AdjustTokenPrivileges(
IntPtr TokenHandle,
bool DisableAllPrivileges,
ref TOKEN_PRIVILEGES NewState,
int BufferLength,
IntPtr PreviousState,
IntPtr ReturnLength
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LookupPrivilegeValue(
string lpSystemName,
string lpName,
ref long lpLuid
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool OpenProcessToken(
IntPtr ProcessHandle,
int DesiredAccess,
ref IntPtr TokenHandle
);
public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const int TOKEN_QUERY = 0x00000008;
public const int TOKEN_DUPLICATE = 0x00000002;
public const int TOKEN_IMPERSONATE = 0x00000004;
public const int SE_PRIVILEGE_ENABLED = 0x00000002;
public const string SE_RESTORE_NAME = "SeRestorePrivilege";
public const string SE_BACKUP_NAME = "SeBackupPrivilege";
[DllImport("advapi32.dll", SetLastError = true)]
static public extern bool LogonUser(String lpszUsername, String lpszDomain,
String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool LoadUserProfile(
IntPtr hToken, // user token
ref PROFILEINFO lpProfileInfo // profile
);
[DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool UnloadUserProfile(
IntPtr hToken, // user token
IntPtr hProfile // handle to registry key
);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private extern static bool DuplicateToken(
IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL,
ref IntPtr DuplicateTokenHandle
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PROFILEINFO {
public static readonly int SizeOf = Marshal.SizeOf(typeof(PROFILEINFO));
public int dwSize; // Set to sizeof(PROFILEINFO) before calling
public int dwFlags; // See PI_ flags defined in userenv.h
public string lpUserName; // User name (required)
public string lpProfilePath; // Roaming profile path (optional, can be NULL)
public string lpDefaultPath; // Default user profile path (optional, can be NULL)
public string lpServerName; // Validating domain controller name in netbios format (optional, can be NULL but group NT4 style policy won't be applied)
public string lpPolicyPath; // Path to the NT4 style policy file (optional, can be NULL)
public IntPtr hProfile; // Filled in by the function. Registry key handle open to the root.
}
#endregion
static void Main(string[] args) {
string domain = "dev1";
string userName = "tuser1";
string password = "asd!234";
string profilePath = @"\\fs001\TestProfiles\tuser9\profile";
bool retVal = false;
IntPtr primaryToken = IntPtr.Zero;
IntPtr dupeToken = IntPtr.Zero;
PROFILEINFO profileInfo = new PROFILEINFO();
try {
// Add RESTORE AND BACUP privileges to process primary token, this is needed for LoadUserProfile function
IntPtr processToken = IntPtr.Zero;
OpenProcessToken(System.Diagnostics.Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref processToken);
long luidRestore = 0;
long luidBackup = 0;
retVal = LookupPrivilegeValue(null, SE_RESTORE_NAME, ref luidRestore);
retVal = LookupPrivilegeValue(null, SE_BACKUP_NAME, ref luidBackup);
TOKEN_PRIVILEGES tpRestore = new TOKEN_PRIVILEGES();
TOKEN_PRIVILEGES tpBackup = new TOKEN_PRIVILEGES();
tpRestore.PrivilegeCount = 1;
tpRestore.Privileges = new LUID_AND_ATTRIBUTES();
tpRestore.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
tpRestore.Privileges.Luid = luidRestore;
tpBackup.PrivilegeCount = 1;
tpBackup.Privileges = new LUID_AND_ATTRIBUTES();
tpBackup.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
tpBackup.Privileges.Luid = luidBackup;
retVal = AdjustTokenPrivileges(processToken, false, ref tpRestore, 0, IntPtr.Zero, IntPtr.Zero);
if (false == retVal) {
throw new Win32Exception();
}
retVal = AdjustTokenPrivileges(processToken, false, ref tpBackup, 0, IntPtr.Zero, IntPtr.Zero);
if (false == retVal) {
throw new Win32Exception();
}
// Logon as user + password in clear text for sake of simple sample (protocol transitioning is better).
retVal = LogonUser(userName, domain, password, 3 /* LOGON32_LOGON_NETWORK */, 0 /*LOGON32_PROVIDER_DEFAULT */, ref primaryToken);
if (false == retVal) {
throw new Win32Exception();
}
// Duplicate primary token.
// LoadUserProfile needs a token with TOKEN_IMPERSONATE and TOKEN_DUPLICATE access flags.
retVal = DuplicateToken(primaryToken, 2 /* securityimpersonation */, ref dupeToken);
if (false == retVal) {
throw new Win32Exception();
}
// Load user profile for roaming profile
profileInfo.dwSize = PROFILEINFO.SizeOf;
profileInfo.lpUserName = domain + @"\" + userName;
profileInfo.lpProfilePath = profilePath;
Console.WriteLine("UserName: {0}", profileInfo.lpUserName);
Console.WriteLine("ProfilePath: {0}", profileInfo.lpProfilePath);
retVal = LoadUserProfile(dupeToken, ref profileInfo);
if (false == retVal) {
throw new Win32Exception();
}
// What should happen
// 1. Local new profile in c:\users\tuser1.dev1 folder with copy from default.
// 2. Valid user registry hive ntuser.dat
// 3. Loaded profile session entry in the registry entry
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\SID of tuser1\
// State bit mask should have new local profile (x004), new central profile (x008),
// update the central profile (0010).
//
// "State"=dword:0000021c
// "CentralProfile"="\\fs001\Share\tuser1\profile.V2"
// "ProfileImagePath"="C:\Users\tuser1"
//
// See http://technet.microsoft.com/en-us/library/cc775560(WS.10).aspx fpr more info
// Roaming Profile - New User section.
//
// What actually happens:
// 1. Temp profile is loaded in c:\users\temp
// 2. Registry entry ProfieList/SID is showing temporary profile
// "State"=dword:00000a04
// "CentralProfile"="\\fs001\Share\tuser1\profile.V2"
// "ProfileImagePath"="C:\Users\TEMP"
Console.WriteLine("Profile loaded, hit enter to unload profile");
Console.ReadLine();
}
catch (Exception e) {
Console.WriteLine(e.ToString());
Console.ReadLine();
}
finally {
// Unload profile properly.
if (IntPtr.Zero != dupeToken) {
retVal = UnloadUserProfile(dupeToken, profileInfo.hProfile);
if (false == retVal) {
throw new Win32Exception();
}
}
}
}
}
最佳答案
几个月来我一直在追寻同一个问题,终于找到了答案。我在互联网上的其他任何地方都没有看到这个答案。它还从 LoadUserProfile 的处理中删除了 5 到 10 秒。这些评论仅适用于使用漫游配置文件的情况。
至少在 Windows 2008 R2 中,PROFILEINFO 中的 lpUserName 字段不仅仅用于事件目录用户验证。它用于构建漫游配置文件路径和本地配置文件路径。如果 lpUserName 包含域名 (mydomain\myusername),则使用的路径包含此名称。但是,如果您更改 lpUserName 以排除域,则 LoadUserProfile 调用将失败。
但是,如果您只在 lpUserName 中使用用户名并在 lpServerName 中提供 NetBIOS 域名,它就可以工作。 NetBIOS 名称通常是最高级别的域名(mydomain.parent.com,例如名称为 mydomain),在第 16 个字符中填充或修剪为 15 个字符加上十六进制 1B(C# 字符串中为\u001B)。
问题可以自己看HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList{sid}中的CentralProfile字符串。 CentralProfile 仅在您尝试将 LoadUserProfile 用于漫游配置文件时出现。
关于c# - 在 Windows 2008 上以编程方式创建漫游用户配置文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2015103/
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123