Création de port d'imprimante TCPIP VB.net 1.1 avec l'API CreateProcessWithLogon
-
23-08-2019 - |
Question
Il y a quelques mois, j'ai écrit une application console VB.net pour migrer un groupe d'environ 100+ imprimantes et les 1800+ utilisateurs qui les utilisent de certains anciens appareils d'impression HP vers un serveur d'impression mixte et des solutions d'impression directe vers IP.L'application utilise une base de données pour comparer les imprimantes installées, supprimer les partages anciens/invalides et remapper le nouveau serveur d'impression basé sur Win2K3 OU créer un port d'imprimante TCPIP et installer le pilote pour l'impression directe sur IP.
Cela a très bien fonctionné, mais les utilisateurs avaient besoin de droits d'utilisateur expérimentés pour créer le port d'imprimante TCPIP.Pour le campus principal, cela ne posait pas de problème, mais les sites distants plus petits ont besoin d'une solution permettant à l'application d'être exécutée par des utilisateurs sans droits d'utilisateur expérimenté.
Ma solution consistait à prendre la fonction "CreatePrinterIPPort" et à la placer dans sa propre application wrapper, puis à l'appeler si nécessaire à partir de l'application principale en utilisant un compte d'administrateur local codé en dur à cet effet, mais je rencontre des problèmes lors de la création du createport. application.Si j'exécute l'application de manière autonome, elle crée le port sans problème, mais lorsque je l'exécute dans mon application de test pour générer le createport à l'aide de l'API CreateProcessWithLogon, la création du port échoue avec une erreur "accès refusé".Je suis limité à l'utilisation de .net 1.1 car la version 2.0 n'est pas complètement présente dans notre environnement et on m'a dit qu'elle ne serait pas poussée uniquement pour cette application.
Des pensées?
Source indiquée ci-dessous.
Application de génération :
Imports System.Runtime.InteropServices
ModuleModule1
Région "Structures 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
Région de fin
Région "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
Région de fin
Région "Fonctions 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
Région de fin
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
Fonction dans l'application de création de port TCPIP qui effectue le travail et échoue lorsqu'elle est générée dans l'application ci-dessus.
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
La solution
Il semble que WMI n'autorise pas l'accès en écriture à un compte usurpé, j'ai donc commencé à utiliser prnadmin.dll pour créer des ports.Cela m'oblige à vérifier que la DLL est enregistrée et à l'enregistrer si ce n'est pas le cas, mais il semble que ce soit le seul moyen que je puisse trouver (et garder la raison) pour y parvenir.