Creación de puerto de impresora TCPIP VB.net 1.1 con API CreateProcessWithLogon

StackOverflow https://stackoverflow.com/questions/900104

  •  23-08-2019
  •  | 
  •  

Pregunta

Hace unos meses escribí una aplicación de consola VB.net para migrar un grupo de más de 100 impresoras y más de 1800 usuarios que las usan desde algunos dispositivos de impresión HP antiguos a un servidor de impresión mixto y soluciones de impresión directa a IP.La aplicación utiliza una base de datos para comparar impresoras instaladas y eliminar recursos compartidos antiguos/no válidos y reasignarlos al nuevo servidor de impresión basado en Win2K3 O crear un puerto de impresora TCPIP e instalar el controlador para impresión directa a IP.

Funcionó muy bien, pero los usuarios necesitaban derechos de usuario avanzado para crear el puerto de impresora TCPIP.Para el campus principal esto no fue un problema, pero los sitios remotos más pequeños necesitan una solución que permita que la aplicación sea ejecutada por usuarios sin derechos de usuario avanzado.

Mi solución fue tomar la función "CreatePrinterIPPort" y ponerla en su propia aplicación contenedora y luego llamarla según sea necesario desde la aplicación principal usando una cuenta de administrador local codificada para ese propósito, pero tengo problemas al generar el puerto de creación. aplicación.Si ejecuto la aplicación de forma independiente, crea el puerto sin problemas, pero cuando la ejecuto en mi aplicación de prueba para generar el puerto de creación usando la API CreateProcessWithLogon, la creación del puerto falla con un error de "acceso denegado".Estoy limitado a usar .net 1.1 ya que 2.0 no está en nuestro entorno por completo y me dijeron que no se implementaría solo para esta aplicación.

¿Alguna idea?

Fuente que se enumera a continuación.

Aplicación de desove:

Imports System.Runtime.InteropServices

Módulo Módulo1

Región "Estructuras 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

Región final

Región "Constantes 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

Región final

Región "Funciones 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

Región final

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

Función en la aplicación de creación de puertos TCPIP que hace el trabajo y falla cuando se genera en la aplicación anterior.

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

¿Fue útil?

Solución

Parece que WMI no permite el acceso de escritura a una cuenta suplantada, por lo que he pasado a usar el Prnadmin.dll para crear puertos. Esto me obliga a comprobar que la DLL está registrada y registrar si no lo es, pero parece que esta es la única manera que puedo encontrar (y mantener mi cordura) para hacer esto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top