一个查看谁在网络服务器上打开文件的应用程序
一个查看网络服务器上谁打开了文件的应用程序。
引言
这是系列文章的第三部分。在网络共享上存储 .NET 应用程序存在一个问题。当您想发布新版本时,需要确保每个人都已退出应用程序。本文介绍了我提出的一种解决方案,用于弄清楚谁在使用该应用程序,以便您可以请他们退出。您可能需要阅读前两篇文章
背景
即使 .NET 应用程序在用户 PC 上本地运行,网络共享上的 .net 应用程序仍然对其具有打开的文件锁。因此,您实际上有两个选项来发现谁打开了应用程序。第一个是您需要成为网络管理员,并且在共享文件夹所在的网络服务器上拥有权限。如果您满足这些要求,则可以打开计算机管理(右键单击“我的电脑”然后选择“管理”)。然后单击“共享文件夹”。最后单击“打开文件”。如果您是自己 PC 的管理员,可以尝试一下,看看我在说什么。请注意,我没有管理员权限,这就是为什么我提出了这个解决方案。第二个选项是使用我编写的程序,以便帮助台或发布协调员或其他任何人都可以看到谁打开了什么应用程序/文件。
解决方案概述
首先,您需要知道没有神奇的解决方案。此解决方案需要进行一些设置才能工作。以下是解决方案的布局。您有一个 Windows 服务,它调用一个名为 openfiles.exe 的现有程序。openfiles.exe 可以在 c:\windows\system32\openfiles.exe 找到。如果您找不到此程序,那就无能为力了。Windows 服务以一个已添加到您要查看其打开文件的网络服务器的“Power Users”组中的域用户的身份登录。Windows 服务将打开文件列表写入网络共享上的一个 XML 文件。然后有一个 Windows 客户端读取 XML 文件并显示服务器和打开的文件。注意,Windows 服务可以在任何安装了 openfiles.exe 的网络服务器上运行。Windows 服务使用 XML INI 文件来了解它应该查询哪些网络服务器。此 XML INI 文件默认为 c:\。写入 XML 文件的网络共享也可以在任何地方,只要 Windows 服务和 Windows 客户端都指向同一个位置。注意,openfiles.exe 是 Microsoft 提供的。它允许您查询网络服务器上的打开文件,前提是您在服务器上拥有正确的权限。Windows 服务每分钟为每个服务器写入一个文件。Windows 客户端将始终尝试读取上一分钟的 XML 文件。所以,是的,这意味着您每个服务器会有 60 个文件。如果您有很多打开的文件,XML 文件可能会变得很大。注意,源代码已提供,您可以做得更好。
解决方案
首先,您需要一个属于您感兴趣的任何网络服务器的“Power Users”组的域用户。此域用户用于 Windows 服务的登录。接下来,您需要安装 Windows 服务。您需要使用 .NET 框架附带的 installutil 程序。它通常可以在 c:\windows\microsoft.net\framework\v1.1.4322\installutil.exe 中找到(注意,v1.1.4322 应替换为您正在运行的 .NET 框架版本)。因此,将 Windows 服务复制到网络服务器上的本地驱动器。通常创建一个 services 目录是个好主意。打开命令提示符。更改目录以到达您保存 Windows 服务的位置。运行 installUtil(c:\windows...\installutil openfilesServer.exe)。系统将提示您输入域用户名和密码。然后进入计算机管理。然后是服务和应用程序,然后是服务。您应该会看到 OpenfilesServer。启动服务。将创建一个 OpenFilesini.xml 文件。停止服务。找到 Openfilesini.xml 文件并编辑它,以便输出目录和您想要的网络服务器/服务器正确。不要忘记将域用户添加到您要查看打开文件的网络服务器的 Power Users 组中。一旦 OpenFilesini.xml 文件设置正确,就启动 Windows 服务。注意,服务加载 INI XML 文件的默认位置是 c:\。您应该启动服务以查看 XML 文件正在创建。现在我们可以使用客户端了。第一次运行客户端 Windows 应用程序时,您猜对了,也会创建一个 Openfilesini.xml 文件。关闭应用程序并编辑 Openfilesini.xml 文件,使其指向 Windows 服务正在写入的正确输出目录。它应该位于某个网络共享上。启动 Windows 客户端,您应该会看到网络服务器的列表。一旦您选择了一个,您将看到所有打开文件的列表视图。请注意,客户端会进行检查以确保文件是最新的,而不是昨天的。
一些代码
这是调用 openfiles.exe 的一些代码
'VB.NET
Dim myprocess As New Process
'Program you want to launch execute etc.
myprocess.StartInfo.FileName = "c:\windows\system32\openfiles.exe"
myprocess.StartInfo.Arguments = "/query /s " + infileserver + " /v"
'This is important. Since this is a windows service it will run
'even though no one is logged in.
'Therefore there is not desktop available so you better
'not show any windows dialogs
myprocess.StartInfo.UseShellExecute = False
myprocess.StartInfo.CreateNoWindow = True
'We want to redirect the output from the openfiles call to the program
'Since there won't be any window to display it in
myprocess.StartInfo.RedirectStandardOutput = True
'Create the shell and execute the command
Try
myprocess.Start()
If Not (myprocess.StandardOutput Is Nothing) Then
'This string is used to contain what openfiles program returns
Dim tmpstr2 As String = String.Empty
DSFileData.Tables(0).Clear()
DSFileData.Tables(1).Clear()
Dim values(6) As Object 'This storeds the fields from openfiles
Dim values2(0) As Object 'This is the current date
values2(0) = DateTime.Now
Dim cnt As Integer = 0
Do
tmpstr2 = myprocess.StandardOutput.ReadLine
' Add some text to the file.
If Not (tmpstr2 Is Nothing) Then
cnt += 1
'The output is fixed length
If cnt > 5 Then
values(0) = tmpstr2.Substring(0, 15).Trim 'Host name
values(1) = tmpstr2.Substring(16, 8).Trim 'ID
values(2) = tmpstr2.Substring(25, 20).Trim 'accessed by
values(3) = tmpstr2.Substring(46, 10).Trim 'type
values(4) = tmpstr2.Substring(57, 10).Trim 'locks
values(5) = tmpstr2.Substring(68, 15).Trim 'open mode
values(6) = tmpstr2.Substring(84) 'open file
DSFileData.Tables(0).LoadDataRow(values, True)
End If
End If
Loop Until tmpstr2 Is Nothing
...
//C#
Process myprocess = new Process();
//Program you want to launch execute etc.
myprocess.StartInfo.FileName = "c:\\windows\\system32\\openfiles.exe";
myprocess.StartInfo.Arguments = "/query /s " + infileserver + " /v";
//This is important. Since this is a windows service it will run
//even though no one is logged in.
//Therefore there is not desktop available so you better
//not show any windows dialogs
myprocess.StartInfo.UseShellExecute = false;
myprocess.StartInfo.CreateNoWindow = true;
//We want to redirect the output from the openfiles call to the program
//Since there won't be any window to display it in
myprocess.StartInfo.RedirectStandardOutput = true;
//Create the shell and execute the command
try
{
myprocess.Start();
if ((myprocess.StandardOutput != null))
{
//This string is used to contain what openfiles program returns
string tmpstr2 = String.Empty;
DSFileData.Tables[0].Clear();
DSFileData.Tables[1].Clear();
object[] values = new object[6]; //This storeds the fields from openfiles
//This is the current date
object[] values2 = new object[1] {DateTime.Now};
int cnt = 0;
while (myprocess.StandardOutput.Peek() >= 0)
{
tmpstr2 = myprocess.StandardOutput.ReadLine();
// Add some text to the file.
cnt += 1;
//The output is fixed length
if (cnt > 5)
{
values[0] = tmpstr2.Substring(0, 15).Trim(); //Host name
values[1] = tmpstr2.Substring(16, 8).Trim() ;//ID
values[2] = tmpstr2.Substring(25, 20).Trim();//accessed by
values[3] = tmpstr2.Substring(46, 10).Trim ();//type
values[4] = tmpstr2.Substring(57, 10).Trim();//locks
values[5] = tmpstr2.Substring(68, 15).Trim();//open mode
values[6] = tmpstr2.Substring(84);//open file
DSFileData.Tables[0].LoadDataRow(values, true);
}
} //end while
...
结论
所以这只是一个程序员用来绕过我缺乏权限的解决方法。使用 Openfiles.exe 是一个强大的工具,可以查看谁在使用文件。请注意,openfiles.exe 也允许您中断打开的文件连接。我没有将此功能包含在此应用程序中,但可以做到。所以希望您喜欢这个,如果您的网络管理员允许的话。