几个月前,我编写了一个 VB.net 控制台应用程序,用于将一组大约 100 多台打印机和 1800 多位使用它们的用户从一些旧的 HP 打印设备迁移到混合打印服务器和直接 IP 打印解决方案。该应用程序使用数据库来比较已安装的打印机,删除旧的/无效的共享,并重新映射到新的基于 Win2K3 的打印服务器,或者创建 TCPIP 打印机端口并安装直接 IP 打印的驱动程序。

它运行得非常好,但用户需要高级用户权限才能创建 TCPIP 打印机端口。对于主校区来说这不是问题,但较小的远程站点需要一个解决方案,允许没有高级用户权限的用户运行应用程序。

我的解决方案是采用“CreatePrinterIPPort”函数并将其放入它自己的包装应用程序中,然后使用硬编码的本地管理帐户根据需要从主应用程序中调用它,但我在生成 createport 时遇到了问题应用程序。如果我独立运行该应用程序,它会毫无问题地创建端口,但是当我在测试应用程序中运行它以使用 CreateProcessWithLogon API 生成 createport 时,端口创建会失败并出现“访问被拒绝”错误。我仅限于使用 .net 1.1,因为 2.0 并不完全存在于我们的环境中,而且我被告知不会仅针对此应用程序推送它。

有什么想法吗?

下面列出了来源。

生成应用程序:

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 是否已注册,如果没有注册,但似乎这是我能找到(并保持理智)完成此操作的唯一方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top