LocalSystemアカウントで実行されるWindowsサービスからファイルを作成しています。私はファイルが作成されている指定されたフォルダを監視するWindowsアプリケーションがあります。私はFileSystemWatcherを使用していますが、起動しません。 Windowsエクスプローラのファイルアイコンは南京錠のアイコンです。 Windowsサービスからこのファイルを作成すると、Windowsのユーザーアカウントからアクセスできるようになりますか?Windowsサービスから作成されたファイルでFileSystemWatcherが動作しない
答えて
FileWatcherは不安定です。ネットワークドライブ上のフォルダを見ている場合にも問題があります。 FileWatcherを使用するアプリケーションが12個以上あり、そのすべてがファイルの作成時に何度も認識できませんでした。
FileWatcherを新しいファイルや変更されたファイルをチェックするtimedイベントでバックアップします。そうすれば、FileWatcherがイベントを認識できない場合、タイマーはそれを捕捉します。
個人的には、そのサービスのアカウントをLocalSystemに設定することができるので、個人的にそのフォルダを監視するサービスを構築する方が良いと思うし、他のサービスと同じコンピュータ上にあれば問題ありません。ファイルを作成しています。しかし、コードはアプリからのものと似ているはずですが、余分なレイヤーを使用するとします。偽装。 FileSystemWatcher
を使用するかどうかは、実際には関係ありません。パーミッションはパーミッションであり、別個の動物である。
私が構築したサービスで同様のファイルチェックを行った方法は、タイマーで行いました。 File.Exists()
とFile.GetCreationTime()
とFile.GetLastWriteTime()
のようなファイル属性を探して、ファイルが存在するかどうか、ファイルが存在するかどうか、ファイルが最後に変更されたかどうかを判断する組み合わせで使用できます。そのファイルをすでに処理したかどうかは、タイマーが実行される間隔よりも古い場合に分かります。
参考:私にとってhttp://www.csharp-examples.net/file-creation-modification-time/
私はファイルを処理するたびに、私は自分のアプリケーションがそれを削除していたので、私がしなければならないすべては、私は別のものを持っているかどうかを知るFile.Exists()
チェックです。
このコードは、私が定期的にファイルを探していたサービスで、私が説明した偽装のために、あなたがする必要のある次の部分に少し統合しましたその下にあなたは、あなたのアプリケーションにこれを適応することができるかもしれない:
using System;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
namespace MyNamespace
{
public partial class Service1: ServiceBase
{
Thread syncThread = null;
System.Timers.Timer timer1;
string filePath = @"C:\myfile.txt";
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer1 = new System.Timers.Timer();
timer1.Interval = 60000; // 1 min
timer1.Enabled = true;
timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
timer1.Start();
}
protected override void OnStop()
{
syncThread.Abort();
timer1.Stop();
}
protected void timer1_Elapsed(object sender, ElapsedEventArgs e)
{
syncThread = new Thread(new ThreadStart(doThread));
syncThread.Start();
}
protected void doThread()
{
// This will run for each timer interval that elapses
// in its own separate thread, and each thread will
// end when the processing in this function ends
// You'll need to develop a strategy for getting these
// into your app
string username, domainName, password;
// Log the domain service account in, here...
bool returnValue = LogonUser(userName, domainName, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
out safeTokenHandle);
if (!returnValue) return; // not logged in - report this
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
bool fileAbsent = true;
string myFileText = String.Empty;
if (File.Exists(filePath))
{
fileAbsent = false;
FileStream fs = new FileStream(filePath, FileMode.Open);
StreamReader sr = new StreamReader(fs)
myFileText = sr.ReadToEnd();
sr.Close();
fs.Close();
File.Delete(filePath);
}
else
{
// report that file does not exist
}
if (myFileText != String.Empty) // content found
{
// do processing here
}
else
{
//if (fileAbsent == false)
// report file was found, but empty
}
}
}
}
}
}
なお、誰かがあなたのアプリケーションが監視しているファイルを開く権限を持っていない、と彼らはログインしている、と彼らはあなたがしているこのアプリケーションを実行する場合あなたが見つけたように、それを開くことができなくなります。そのファイルへのアクセス権を持つユーザーのためにWindowsImpersonationContext
でコードを実装していない限り、アプリケーションはログインしているユーザーと同じファイルアクセス許可を使用します。しかし、資格情報を持っていないため、アプリケーションでWindows LocalSystemアカウントを偽装することはできません。そのため、余分なアクセス許可が必要な場合はドメインアカウントでサービスを実行することをお勧めします。代わりに、パスワードを知っているファイルへのアクセス許可を持つ新規または既存のドメインサービスアカウントでサービスを実行するように設定する必要があります。次に、そのアカウントで実際にログインしたかのように、そのドメインアカウントをアプリケーション内で偽装することができます。
the MSDN siteからコピーしてフォーマットしたこのクラスは、アプリケーションに適応しなければならないものです。これを上記のタイマーのコードと組み合わせる必要があります。ファイルへのアクセス権を持つドメインアカウントの資格情報を要求するか保存する必要があります。 using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) { ... }
の領域内では、偽装されたユーザーとしてファイルの読み取りと処理を行います。私は上記のコードに、こと、およびLogonUser()
コールを追加したが、あなたは、その機能が含まれるように定数を持つことになり、その下から他のすべての行方不明の言及私は含まれていませんでした:
public class ImpersonationDemo
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
// Test harness.
// If you incorporate this code into a DLL, be sure to demand FullTrust.
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public static void Main(string[] args)
{
SafeTokenHandle safeTokenHandle;
try
{
string userName, domainName;
// Get the user token for the specified user, domain, and password using the
// unmanaged LogonUser method.
// The local machine name can be used for the domain name to impersonate a user on this machine.
Console.Write("Enter the name of the domain on which to log on: ");
domainName = Console.ReadLine();
Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);
userName = Console.ReadLine();
Console.Write("Enter the password for {0}: ", userName);
const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
out safeTokenHandle);
Console.WriteLine("LogonUser called.");
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine("LogonUser failed with error code : {0}", ret);
throw new System.ComponentModel.Win32Exception(ret);
}
using (safeTokenHandle)
{
Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
Console.WriteLine("Value of Windows NT token: " + safeTokenHandle);
// Check the identity.
Console.WriteLine("Before impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// Use the token handle returned by LogonUser.
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
// Check the identity.
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
}
}
// Releasing the context object stops the impersonation
// Check the identity.
Console.WriteLine("After closing the context: " + WindowsIdentity.GetCurrent().Name);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred. " + ex.Message);
}
}
}
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true)
{
}
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
私はファイルシステムウォッチャーにも問題がありました。私が得る問題の1つは、ほとんどの人が単一のイベントとみなす複数のイベントです。たとえば、ファイルの変更をリスンする場合、特定のプログラムに応じて、1つの「保存」アクションで複数のイベントを生成できます。 – Kibbee