VB.NET 1.1 إنشاء منفذ طابعة TCPIP مع CreateProcessWithlogon API
-
23-08-2019 - |
سؤال
ظهرت بضعة أشهر، لقد كتبت تطبيق وحدة التحكم VB.NET لترحيل مجموعة من حوالي 100 طابع، و 1800+ المستخدمين الذين يستخدمونها من بعض الأجهزة الطباعة HP القديمة إلى خادم طباعة مختلط وتوجيه حلول طباعة IP. يستخدم التطبيق قاعدة بيانات للمقارنة بين الطابعات المثبتة وإزالة المشاركات القديمة / غير الصحيحة و REMAP إلى خادم الطباعة المستند إلى WIN2K3 الجديد أو إنشاء منفذ طابعة TCPIP وتثبيت برنامج التشغيل المباشر إلى طباعة IP.
لقد عملت بشكل جيد حقا، لكن المستخدمين بحاجة إلى حقوق مستخدمي الطاقة لإنشاء منفذ طابعة TCPIP. بالنسبة للحرم الجامعي الرئيسي، لم تكن هذه مشكلة، لكن المواقع البعيدة الأصغر تحتاج إلى حل يسمح بتشغيل التطبيق من قبل المستخدمين دون حقوق مستخدم الطاقة.
كان الحل الخاص بي هو أخذ وظيفة "CreatePrinteripport" ووضعها في تطبيق Wrapper الخاص به الأمر ثم اتصل به حسب الحاجة من التطبيق الرئيسي باستخدام حساب مسؤول محلي مشفرة بجد للغرض، لكنني أعمل في مشكلات عند التفريغ تطبيق. إذا قمت بتشغيل التطبيق المستقل، فهو يخلق المنفذ بدون مشكلة، ولكن عندما أقوم بتشغيله في تطبيق الاختبار الخاص بي لتفرخ ReadPort باستخدام CreateProcessWithlogon API فشل إنشاء المنفذ مع خطأ "تم رفض الوصول". أقتصر على استخدام .NET 1.1 ك 2.0 ليس في بيئتنا، وقيل لي لن يتم دفعها فقط لهذا التطبيق.
أي أفكار؟
مصدر مدرج أدناه.
Spawning التطبيق:
Imports System.Runtime.InteropServices
الوحدة النمطية 1.
منطقة "بنية API"
<StructLayout(LayoutKind.Sequential)> _
Public Structure PROCESS_INFORMATION
Dim hProcess As System.IntPtr
Dim hThread As System.IntPtr
Dim dwProcessId As Integer
Dim dwThreadId As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure STARTUPINFO
Dim cb As Integer
Dim lpReserved As System.IntPtr
Dim lpDesktop As System.IntPtr
Dim lpTitle As System.IntPtr
Dim dwX As Integer
Dim dwY As Integer
Dim dwXSize As Integer
Dim dwYSize As Integer
Dim dwXCountChars As Integer
Dim dwYCountChars As Integer
Dim dwFillAttribute As Integer
Dim dwFlags As Integer
Dim wShowWindow As Short
Dim cbReserved2 As Short
Dim lpReserved2 As System.IntPtr
Dim hStdInput As System.IntPtr
Dim hStdOutput As System.IntPtr
Dim hStdError As System.IntPtr
End Structure
نهاية المنطقة
المنطقة "ثوابت API"
Private Const LOGON_NETCREDENTIALS_ONLY As Integer = &H2
Private Const NORMAL_PRIORITY_CLASS As Integer = &H20
Private Const CREATE_DEFAULT_ERROR_MODE As Integer = &H4000000
Private Const CREATE_NEW_CONSOLE As Integer = &H10
Private Const CREATE_NEW_PROCESS_GROUP As Integer = &H200
Private Const LOGON_WITH_PROFILE As Integer = &H1
نهاية المنطقة
المنطقة "وظائف API"
Private Declare Unicode Function CreateProcessWithLogon Lib "Advapi32" Alias "CreateProcessWithLogonW" _
(ByVal lpUsername As String, _
ByVal lpDomain As String, _
ByVal lpPassword As String, _
ByVal dwLogonFlags As Integer, _
ByVal lpApplicationName As String, _
ByVal lpCommandLine As String, _
ByVal dwCreationFlags As Integer, _
ByVal lpEnvironment As System.IntPtr, _
ByVal lpCurrentDirectory As System.IntPtr, _
ByRef lpStartupInfo As STARTUPINFO, _
ByRef lpProcessInfo As PROCESS_INFORMATION) As Integer
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As System.IntPtr) As Integer
نهاية المنطقة
Public Sub RunProgram(ByVal UserName As String, ByVal Password As String, ByVal Domain As String, ByVal Application As String, ByVal CommandLine As String)
Dim siStartup As STARTUPINFO
Dim piProcess As PROCESS_INFORMATION
Dim intReturn As Integer
If CommandLine Is Nothing OrElse CommandLine = "" Then CommandLine = String.Empty
siStartup.cb = Marshal.SizeOf(siStartup)
siStartup.dwFlags = 0
intReturn = CreateProcessWithLogon(UserName, Domain, Password, LOGON_WITH_PROFILE, Application, CommandLine, _
NORMAL_PRIORITY_CLASS Or CREATE_DEFAULT_ERROR_MODE Or CREATE_NEW_CONSOLE Or CREATE_NEW_PROCESS_GROUP, _
IntPtr.Zero, IntPtr.Zero, siStartup, piProcess)
If intReturn = 0 Then
Throw New System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())
End If
CloseHandle(piProcess.hProcess)
CloseHandle(piProcess.hThread)
End Sub
Overloads Sub Main(ByVal args() As String)
Dim command As String = "C:\Program Files\Printer Server Update Utility\CreatePrinterPort.exe"
Dim arguments As String = Chr(34) & "C:\Program Files\Printer Server Update Utility\CreatePrinterPort.exe" & Chr(34) & " /I:138.90.1.3"
Dim user As String = "PrintAdmin"
Dim domain As String = System.Environment.MachineName
Dim password As String = "Pa$$word" '<---- No not really
Dim currentDirectory As String = System.IO.Directory.GetCurrentDirectory()
RunProgram(user, password, domain, command, arguments)
System.Console.WriteLine("Please press the ENTER key to close window.")
System.Console.WriteLine("")
System.Console.Read()
End Sub
End Module
وظيفة في تطبيق إنشاء منفذ Tcpip الذي يقوم بالعمل وفشل عند طرحه في التطبيق أعلاه.
Function CreatePrinterIPPort(ByVal strPrinterIPAddress As String, Optional ByVal Protocol As Short = 1, Optional ByVal QueueName As String = "Dummy", _
Optional ByVal ByteCount As Boolean = False) As Boolean
' Protocal 1 = RAW (Default) 2 = LPR
System.Console.WriteLine("Attempting to create port at IP Address: " & strPrinterIPAddress)
Dim options As New ConnectionOptions
options.Impersonation = ImpersonationLevel.Impersonate
Dim mpBasePath As New ManagementPath("\.\ROOT\CIMV2")
Dim mpTCPIPPort As New ManagementPath("Win32_TCPIPPrinterPort")
Dim msLocalMachine As New ManagementScope(mpBasePath, options)
msLocalMachine.Connect()
Dim mcNetworkPorts As New ManagementClass(msLocalMachine, mpTCPIPPort, New ObjectGetOptions)
Dim moNewPort As ManagementObject = mcNetworkPorts.CreateInstance()
moNewPort.Properties("Name").Value = "IP_" & strPrinterIPAddress
moNewPort.Properties("Protocol").Value = Protocol
moNewPort.Properties("HostAddress").Value = strPrinterIPAddress
If Protocol = 1 Then
moNewPort.Properties("PortNumber").Value = "9100"
ElseIf Protocol = 2 Then
moNewPort.Properties("ByteCount").Value = ByteCount
moNewPort.Properties("Queue").Value = QueueName
End If
Try
moNewPort.Put()
Catch ex As Exception
System.Console.WriteLine("Port creation failed.")
System.Console.WriteLine(ex.Message.ToString)
Return False
End Try
System.Console.WriteLine("Created port at IP Address: " & strPrinterIPAddress)
Return True
End Function
المحلول
يبدو أن WMI لا يسمح بالكتابة الوصول إلى حساب منذر، لذلك انتقلت إلى استخدام PRNADMIN.DLL لإنشاء منافذ. هذا يتطلب مني التحقق من أن DLL مسجلا وتسجيلا إذا لم يكن الأمر كذلك، ولكن يبدو أن هذه هي الطريقة الوحيدة التي يمكنني العثور عليها (والحفاظ على عقلي) للحصول على هذا.