Heads up. Simple repair for pb/win ver 8. If you wish to compile the main program,
then you must add a byval in the function winmain statement for the CmdLine as asciiz ptr.
Cheers,
Frank.
------------------
Announcement
Collapse
RCmd - Remotely login and run commands on NT/2000/XP networked PCs
Collapse
X
-
Instructions to compile:
1.) Compile the service exe: rCmdSvc.bas
2.) Compile the resource file: rCmd.rc
3.) Compile the main program: rCmd.bas
4.) Modify the exe with MakCon. (See program below)
5.) Now you will have a single exe console program
Note: This program was created and compiled with Power Basic 7.2. However it
should have been done in PBCC (but I don't have that yet) So if you want to
convert to PBCC, you will need to change a few things, like replacing DosPrt
with STDOUT, etc.
But to get it working under PBWin7.2, you need to modify the final exe by changing
byte 221 to CHR$(3) which tells windows this is a console app. The following
program (MakCon) is based on a post by Semen. And it will modify the exe for you.
Compile the MakCon.bas program and then type: MakCon rCmd1.exe rCmd.exe
Code:'This will change a PB Win exe program file to a console app 'Makes byte 221 as CHR$(3) which tells windows this is a console app ' #DIM ALL #COMPILE EXE "MakCon" Function PbMain Local sBuff As String Local iFile As Long If ParseCount(Command$," ") <> 2 Then MsgBox "Usage: MakCon myprogram.exe mynewprogram.exe", &H00000000&, "MakCon Usage:" Exit Function End If iFile = FREEFILE Open Parse$(Command$, " ", 1) For Binary Shared As #iFile Get$ #iFile, Lof(iFile), sBuff Close #iFile Mid$(sBuff, 221, 1) = Chr$(3) 'change byte 221 to Chr$(3) iFile = FreeFile Open Parse$(Command$, " ", 2) For Output As #iFile Print #iFile, sBuff; Close #iFile End Function ' 'Then in your programs use a routine like this: DosPrt "This will print in the DOS window." ' 'Function DosPrt(sText AS String) AS Long ' Static hCon As Dword ' Static iTxtDone As Long ' Static isConsole As Long ' If hCon = 0 Then hCon = GetStdHandle(ByVal %STD_OUTPUT_HANDLE) 'try to get console handle first incase this is a console app ' If hCon = %INVALID_HANDLE_VALUE Then 'not current console app, so make console window (for testing phase) ' isConsole = 1 ' Call FreeConsole() ' If AllocConsole() Then hCon = GetStdHandle(ByVal %STD_OUTPUT_HANDLE) 'create one first (used to test run program from the IDE) ' If hCon = %INVALID_HANDLE_VALUE Or hCon = 0 Then MsgBox "Error while allocating console.",,"Console Error" ' End If ' If hCon <> %INVALID_HANDLE_VALUE Then Call WriteConsole(hCon, ByCopy sText, Len(sText), iTxtDone, ByVal %Null) ' Function = isConsole 'used to tell app that this was a created console window, so we can pause before exiting 'End Function ' ' And since the allocconsole will disappear as soon as the program ends you can add this to the end of your program: ' IF DosPrt(" ") THEN SLEEP 5000 'will pause if it is was not already a console app '
"I haven't lost my mind... its backed up on tape... I think??"
Leave a comment:
-
Part 3 is the main program:
Code:'==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' rCmd.bas - by William Burns revised on 09/26/2003 ' Remote command launcher similar to PSEXEC ' ' Notes: Compiled with PB Win 7.2 and then the exe was modified by changing byte 221 to CHR$(3) which ' tells windows that it is a console app. ' Part of this program was based on a C++ program that was based on a program by Zoltan Csizmadia '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' #Compile Exe "rCmd1.exe" #Include "WIN32API.INC" #Resource "rCmd.pbr" 'this resource contains the rCmdSvc service exe %SET_NO_WAIT = 1 'do not wait for program to complete %SET_SYSTEM = 2 'use SYSTEM userid flag %SET_COPY_EXE = 4 'copy our program first (if not program must be accessible to remote PC) %SET_PRI_NORMAL = 8 'runtime priority flag %SET_PRI_IDLE = 16 'runtime priority flag %SET_PRI_HIGH = 32 'runtime priority flag %SET_PRI_REAL = 48 'runtime priority flag %SET_SHOW_WIN = 96 'show window or not flag %BUFFERSIZE = 100 'buffer size for the STD pipes Type rCmdExeInfo 'UDT for comunicating to remote service zPCName AS Asciiz * %MAX_PATH 'the controlling PCs name zStartDir AS Asciiz * %MAX_PATH 'what dir to start program from zCommand As Asciiz * 500 'program command and arguments to run zUserID As Asciiz * 100 'userid to remote PC zPassword As Asciiz * 100 'password to remote PC dTime As Dword '(used to make pipes unique) dFlags As Dword 'options to pass on to remote PC End Type Type rCmdReturn dExit AS Dword 'code returned from running the remote program dError AS Dword 'any error code returned End Type Global gzRemotePC As Asciiz * %MAX_PATH Global ghCommandPipe AS Dword Global giTime As Dword Global ghRemoteStdOutputPipe As Dword Global ghRemoteStdInputPipe AS Dword Global ghRemoteStdErrorPipe AS Dword Global gAbort AS Long '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Translate Error Messages '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function WinErrMsg(ByVal iCode As Long) As String Local zBuffer As Asciiz * 255 Call FormatMessage(%FORMAT_MESSAGE_FROM_SYSTEM, ByVal %NULL, iCode, %NULL, zBuffer, SizeOf(zBuffer), ByVal %NULL) Function = Format$(iCode, "##### ") & Trim$(zBuffer, Any Chr$(0,32,13,10)) End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== 'Send text to console window - This routine is needed if you use PBWin instead of PBCC '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function DosPrt(sText AS String) AS Long Static hCon As Dword Static iTxtDone As Long Static isConsole As Long If hCon = 0 Then hCon = GetStdHandle(ByVal %STD_OUTPUT_HANDLE) 'try to get console handle first incase this is a console app If hCon = %INVALID_HANDLE_VALUE Then 'not current console app, so make console window (for testing phase) isConsole = %TRUE Call FreeConsole() If AllocConsole() Then hCon = GetStdHandle(ByVal %STD_OUTPUT_HANDLE) 'create one first (used to test run program from the IDE) If hCon = %INVALID_HANDLE_VALUE Or hCon = 0 Then MsgBox "Error while allocating console.",,"Console Error" End If If hCon <> %INVALID_HANDLE_VALUE Then Call WriteConsole(hCon, ByCopy sText, Len(sText), iTxtDone, ByVal %NULL) Function = isConsole 'used to tell app that this was a created console window, so we can pause before exiting End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Get command line parameters '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function GetCmdParm(ByVal sParm AS String) AS String Local sCmd AS String Local iRet AS Long Local sText AS String sCmd = UCase$(Command$) iRet = InStr(1,sCmd,sParm) If iRet And (iRet < (Len(sCmd) + 3)) Then sText = Mid$(Command$,iRet + 3) iRet = InStr(1,sText," -") If iRet Then sText = Left$(sText,iRet - 1) Function = Trim$(sText) End If End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' STDIN pipe thread '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function StdInputPipeThread(ByVal iVoid AS Long) AS Long Local hInPut AS Dword Local zBuffer AS Asciiz * %BUFFERSIZE Local dRet AS Dword Local dRead AS Dword Local dWrote AS Dword hInput = GetStdHandle(%STD_INPUT_HANDLE) Do While gAbort = 0 zBuffer = "" If ReadConsole(hInput, zBuffer, %BUFFERSIZE, dRead, ByVal %NULL) = 0 Then 'read console input dRet = GetLastError() If dRet = %ERROR_NO_DATA Then Exit Loop End If If WriteFile(ghRemoteStdInputPipe, zBuffer, dRead, dWrote, ByVal %NULL) = 0 Then Exit Loop 'send it to remote pipe Loop Call CloseHandle(ghRemoteStdInputPipe) ghRemoteStdInputPipe = %INVALID_HANDLE_VALUE End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' STDOUT pipe thread '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function StdOutputPipeThread(ByVal iVoid AS Long) AS Long Local zBuffer AS Asciiz * %BUFFERSIZE Local dRet As Dword Local dRead As Dword Do While gAbort = 0 zBuffer = "" If ReadFile(ghRemoteStdOutputPipe, zBuffer, %BUFFERSIZE, dRead, ByVal %NULL) = 0 Then dRet = GetLastError() If dRet = %ERROR_NO_DATA Or dRet = %ERROR_BROKEN_PIPE Then Exit Loop Else DosPrt "OutPipe dRet = " + Str$(dRet) + $CRLF End If End If zBuffer = Left$(zBuffer,dRead) 'trim If dRead And Len(zBuffer) Then DosPrt ByCopy zBuffer 'display the output Loop CloseHandle(ghRemoteStdOutputPipe) ghRemoteStdOutputPipe = %INVALID_HANDLE_VALUE End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' STDERROR pipe thread '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function StdErrorPipeThread(ByVal iVoid AS Long) AS Long Local zBuffer AS Asciiz * %BUFFERSIZE Local dRet AS Dword Local dRead As Dword Do While gAbort = 0 zBuffer = "" If ReadFile(ghRemoteStdErrorPipe, zBuffer, %BUFFERSIZE, dRead, ByVal %NULL) = 0 Then dRet = GetLastError() If dRet = %ERROR_NO_DATA Or dRet = %ERROR_BROKEN_PIPE Then Exit Loop End If If dRead And Len(zBuffer) Then DosPrt ByCopy zBuffer 'display the err output Loop CloseHandle(ghRemoteStdErrorPipe) ghRemoteStdErrorPipe = %INVALID_HANDLE_VALUE End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Connects to the remote processes stdout, stderr and stdin named pipes '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function ConnectToConsolePipes(dRetryCount AS Dword, dRetryTimeOut AS Dword) AS Long Local iRet As Long Local hThread As Dword Local SECATTRIB As SECURITY_ATTRIBUTES Local SECDESC AS SECURITY_DESCRIPTOR Local zStdOut AS Asciiz * %MAX_PATH Local zStdIn AS Asciiz * %MAX_PATH Local zStdErr AS Asciiz * %MAX_PATH Local zThisPC AS Asciiz * %MAX_PATH Call InitializeSecurityDescriptor(SECDESC, %SECURITY_DESCRIPTOR_REVISION) 'initializes a security descriptor to have no system ACL, no discretionary ACL, no owner, no primary group Call SetSecurityDescriptorDacl(SECDESC, %TRUE, ByVal %NULL, %FALSE) 'sets information in the discretionary ACL in the security descriptor SecAttrib.nLength = SizeOf(SECATTRIB) SecAttrib.lpSecurityDescriptor = VarPtr(SecDesc) SecAttrib.bInheritHandle = %TRUE ghRemoteStdOutputPipe = %INVALID_HANDLE_VALUE ghRemoteStdInputPipe = %INVALID_HANDLE_VALUE ghRemoteStdErrorPipe = %INVALID_HANDLE_VALUE iRet = %MAX_PATH If GetComputerName(zThisPC, iRet) = 0 Then Exit Function zStdOut = gzRemotePC + "\pipe\rCmd_STDOut" + zThisPC + Format$(giTime) zStdErr = gzRemotePC + "\pipe\rCmd_STDErr" + zThisPC + Format$(giTime) zStdIn = gzRemotePC + "\pipe\rCmd_STDIn" + zThisPC + Format$(giTime) Do While (dRetryCount > 0) Decr dRetryCount 'Connects To StdOut pipe If (ghRemoteStdOutputPipe = %INVALID_HANDLE_VALUE) Then If WaitNamedPipe(zStdOut, ByVal %NMPWAIT_USE_DEFAULT_WAIT) Then ghRemoteStdOutputPipe = CreateFile(zStdOut, %GENERIC_READ, 0, SecAttrib, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, ByVal %NULL) End If 'Connects To StdError pipe If (ghRemoteStdErrorPipe = %INVALID_HANDLE_VALUE) Then If WaitNamedPipe(zStdErr, ByVal %NMPWAIT_USE_DEFAULT_WAIT) Then ghRemoteStdErrorPipe = CreateFile(zStdErr, %GENERIC_READ, 0, SecAttrib, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, ByVal %NULL) End If 'Connects To StdIn pipe If (ghRemoteStdInputPipe = %INVALID_HANDLE_VALUE) Then If WaitNamedPipe(zStdIn, ByVal %NMPWAIT_USE_DEFAULT_WAIT) Then ghRemoteStdInputPipe = CreateFile(zStdIn, %GENERIC_WRITE, 0, SecAttrib, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, ByVal %NULL) End If If (ghRemoteStdOutputPipe <> %INVALID_HANDLE_VALUE And ghRemoteStdErrorPipe <> %INVALID_HANDLE_VALUE And ghRemoteStdInputPipe <> %INVALID_HANDLE_VALUE) Then Exit Loop 'at least one of the pipes FAILED, Try it again Sleep(dRetryTimeOut) Loop If (ghRemoteStdOutputPipe = %INVALID_HANDLE_VALUE Or ghRemoteStdErrorPipe = %INVALID_HANDLE_VALUE Or ghRemoteStdInputPipe = %INVALID_HANDLE_VALUE) Then DosPrt "Failed to connect to the remote PCs console handles." + $CRLF Call CloseHandle( ghRemoteStdOutputPipe ) Call CloseHandle( ghRemoteStdErrorPipe ) Call CloseHandle( ghRemoteStdInputPipe ) Else 'Worked so Start listening to these pipes Thread Create StdOutputPipeThread(ByVal %Null) To hThread Thread Close hThread To iRet 'we don't need to keep the thread handles Thread Create StdInputPipeThread(ByVal %Null) To hThread Thread Close hThread To iRet Thread Create StdErrorPipeThread(ByVal %Null) To hThread Thread Close hThread To iRet Function = %TRUE End If End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== 'Sends a message to our remote service to run the command on the remote PC '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Sub ExecuteRemoteCommand(zUserID As Asciiz, zPassword As Asciiz) Local iRet As Long Local dTemp As Dword Local CmdInfo As rCmdExeInfo Local CmdRet As rCmdReturn Local zText AS Asciiz * %MAX_PATH ZeroMemory(ByVal VarPtr(CmdInfo), SizeOf(CmdInfo)) ZeroMemory(ByVal VarPtr(CmdRet), SizeOf(CmdRet)) iRet = %MAX_PATH If GetComputerName(zText, iRet) = 0 Then iRet = GetLastError() DosPrt "Failed to Get PC Name " + WinErrMsg(iRet) + $CRLF Exit Sub End If CmdInfo.dTime = giTime CmdInfo.zPCName = zText CmdInfo.zUserID = zUserID CmdInfo.zPassword = zPassword iRet = InStr(1,UCase$(Command$),"-R:") If iRet And ((iRet + 3) < Len(Command$)) Then CmdInfo.zCommand = Mid$(Command$,InStr(1,UCase$(Command$),"-R:") + 3) Else 'use default command, just run command prompt CmdInfo.zCommand = "CMD.EXE" End If DosPrt "Executing Command " + CmdInfo.zCommand + $CRLF Select Case GetCmdParm("-PRI") Case "0" CmdInfo.dFlags = %SET_PRI_IDLE Case "2" CmdInfo.dFlags = %SET_PRI_HIGH Case "3" CmdInfo.dFlags = %SET_PRI_REAL Case Else CmdInfo.dFlags = %SET_PRI_NORMAL End Select If InStr(1,UCase$(Command$),"-NOWAIT") Then CmdInfo.dFlags = CmdInfo.dFlags Or %SET_NO_WAIT If InStr(1,UCase$(Command$),"-SYSTEM") Then CmdInfo.dFlags = CmdInfo.dFlags Or %SET_SYSTEM If InStr(1,UCase$(Command$),"-COPY") Then CmdInfo.dFlags = CmdInfo.dFlags Or %SET_COPY_EXE If InStr(1,UCase$(Command$),"-SHOW") Then CmdInfo.dFlags = CmdInfo.dFlags Or %SET_SHOW_WIN CmdInfo.zStartDir = GetCmdParm("-D") WriteFile(ghCommandPipe, CmdInfo, SizeOf(CmdInfo), dTemp, ByVal %Null) 'send message to service zText = "Connected to " + gzRemotePC + " (Press Ctr-C to End)" Call SetConsoleTitle(zText) If ConnectToConsolePipes(5, 1000) Then 'connects to remote pipes (stdout, stdin, stderr) DosPrt "Waiting for program to finish..." + $CrLf If ReadFile(ghCommandPipe, CmdRet, SizeOf(CmdRet), dTemp, ByVal %NULL) Then 'wait for response from service If (CmdRet.dError = 0) Then DosPrt "Remote command returned " + Str$(CmdRet.dExit) + " Error =" + Str$(CmdRet.dError) + $CrLf Else DosPrt "Remote command failed. Returned code is " + Str$(CmdRet.dExit) + " Error =" + Str$(CmdRet.dError) + $CrLf End If Else DosPrt "Failed to get program response back from remote PC" End If Else DosPrt "Connection to remote pipes Failed" + $CRLF End If End Sub '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== 'Establish connection (Using a username and pwd) to a resource such as C$ ADMIN$ IPC$ '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function Connect2PC(ByVal sResource As String, zUserID As Asciiz * 100, zPassWord As Asciiz * 100) As Long Local dRet AS Dword Local zText AS Asciiz * %MAX_PATH Local NR AS NETRESOURCE zText = gzRemotePC + "\" + sResource nr.dwType = %RESOURCETYPE_ANY nr.lpLocalName = 0 nr.lpRemoteName = VarPtr(zText) nr.lpProvider = 0 dRet = WNetAddConnection2(NR, zPassWord, zUserID, %FALSE) If dRet = %ERROR_SESSION_CREDENTIAL_CONFLICT Or dRet = %ERROR_INVALID_PASSWORD Then 'invalid userid or pw DosPrt "Invalid userid/password! " + $CrLf ElseIf dRet = %NO_ERROR Then Function = %TRUE Else DosPrt "Error while signing on to remote PC " + zText + " with user " + zUserID + " Err=" + WinErrMsg(dRet) + $CrLf End If End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Connects to remote PCs rCmdSvc service '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function ConnectToRemoteService(ByVal dRetry AS Dword, ByVal dRetryTimeOut AS Dword) AS Dword Local SECATTRIB AS SECURITY_ATTRIBUTES Local SECDESC AS SECURITY_DESCRIPTOR Local zPipeName AS Asciiz * %MAX_PATH Call InitializeSecurityDescriptor(SECDESC, %SECURITY_DESCRIPTOR_REVISION) 'initializes a security descriptor to have no system ACL, no discretionary ACL, no owner, no primary group Call SetSecurityDescriptorDacl(SECDESC, %TRUE, ByVal %NULL, %TRUE) 'sets information in the discretionary ACL in the security descriptor SecAttrib.nLength = SizeOf(SECATTRIB) SecAttrib.lpSecurityDescriptor = VarPtr(SecDesc) SecAttrib.bInheritHandle = %TRUE zPipeName = gzRemotePC + "\pipe\rCmdCommand" Do While (dRetry > 1) 'Connects to the remote service's communication pipe Decr dRetry If WaitNamedPipe(zPipeName, 5000) Then DosPrt "Connected... now sending data." + $CRLF ghCommandPipe = CreateFile(zPipeName, %GENERIC_WRITE Or %GENERIC_READ, 0, ByVal VarPtr(SECATTRIB), %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0) If ghCommandPipe = %INVALID_HANDLE_VALUE Then DosPrt "Remote PC not responding" + $CRLF Function = ghCommandPipe Exit Loop Else Sleep dRetryTimeOut End If Loop End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Copy program to remote PC -COPY option '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function CopyExeToRemotePC() As Long Local iRet As Long Local sDir AS String Local sProg As String Local zProg As Asciiz * %MAX_PATH Local zTarget As Asciiz * %MAX_PATH sDir = GetCmdParm("-D") sProg = Parse$(GetCmdParm("-R")," ",1) If Len(sProg) And (Dir$(sProg) <> "") Then 'make sure a program was listed and is found zProg = sProg If InStr(1,sProg,"\") Then sProg = Mid$(sProg,InStr(-1,sProg,"\") + 1) 'retrieve just filename If Len(sDir) Then 'is their a startup directory in command? If InStr(1,sDir,":") = 0 Then sDir = "c:\" + LTrim$(sDir,"\") Replace ":" With "$" In sDir zTarget = gzRemotePC + "\" + RTrim$(sDir,"\") + "\" + sProg Else zTarget = gzRemotePC + "\ADMIN$\SYSTEM32\" + sProg 'if no startup dir was given use the default system32 dir End If iRet = CopyFile(zProg, zTarget, %FALSE) If iRet Then Function = %TRUE Else iRet = GetLastError() DosPrt "Error copying program to remote PC. " + WinErrMsg(iRet) + $CrLf End If Else DosPrt "Can't find program: " + sProg + $CrLf End If End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Remove the service exe and our copied program from remote PC -CLEANUP option '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Sub CleanUpRemotePC() Local iRet AS Long Local sDir AS String Local sProg AS String Local zTarget AS Asciiz * %MAX_PATH DosPrt "Cleaning up remote files " + $CrLf If InStr(1,UCase$(Command$),"-COPY") Then 'remove our copied exe if we copied one first sDir = GetCmdParm("-D") sProg = Parse$(GetCmdParm("-R")," ",1) If Len(sProg) And (Dir$(sProg) <> "") Then 'make sure a program was listed and is found If InStr(1,sProg,"\") Then sProg = Mid$(sProg,InStr(-1,sProg,"\") + 1) 'retrieve just filename If Len(sDir) Then 'is their a startup directory in command? If InStr(1,sDir,":") = 0 Then sDir = "c:\" + LTrim$(sDir,"\") Replace ":" With "$" In sDir zTarget = gzRemotePC + "\" + RTrim$(sDir,"\") + "\" + sProg Else zTarget = gzRemotePC + "\ADMIN$\SYSTEM32\" + sProg 'if no startup dir was given use the default system32 dir End If If IsFalse DeleteFile(zTarget) Then iRet = GetLastError() DosPrt "Error cleaning up program from remote PC. " + WinErrMsg(iRet) + $CrLf End If Else DosPrt "Can't find program: " + sProg + $CrLf End If End If zTarget = gzRemotePC + "\ADMIN$\SYSTEM32\RCMDSVC.EXE" If IsFalse DeleteFile(zTarget) Then iRet = GetLastError() DosPrt "Error cleaning up service program from remote PC. " + WinErrMsg(iRet) End If End Sub '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Create the Service Manager record for our service and start it '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function StartSvc() AS Long Local hSCM AS Long Local hService AS Long Local dFlags As Dword Local zSvcExe As Asciiz * %MAX_PATH Local zSvcName As Asciiz * %MAX_PATH Local zSvcDsp As Asciiz * %MAX_PATH Local hMod As Dword Local iRet1 As Long Local iRet2 As Long Local dRet1 As Dword Local dRet2 As Dword Local sBuff As String Local zText As Asciiz * 40 Local sText As String Local iFile As Long DosPrt "Copying service exe to remote PC..." + $CRLF 'First extract Service exe from our resource and copy to remote PC zText = "RCMDSVC" hMod = GetModuleHandle(ByVal %NULL) iRet1 = FindResource(hMod, zText, ByVal %RT_RCDATA) If IsFalse iRet1 Then Exit Function dRet1 = SizeofResource(hMod,iRet1) iRet2 = LoadResource(hMod,iRet1) If IsFalse iRet2 Then Exit Function dRet2 = LockResource(iRet2) sBuff = Peek$(dRet2, dRet1) 'load sBuff with the info we just put in memory iFile = FreeFile 'find next open file number sText = gzRemotePC + "\ADMIN$\SYSTEM32\RCMDSVC.EXE" Open sText For Binary As #iFile 'create the new file Put$ #iFile, sBuff 'write the buffer to the file Close #iFile 'close the file dFlags = %SERVICE_WIN32_OWN_PROCESS If InStr(1,UCase$(Command$),"-SHOW") Then dFlags = dFlags Or %SERVICE_INTERACTIVE_PROCESS 'TODO: test %SERVICE_INTERACTIVE_PROCESS DosPrt "Starting remote service..." + $CRLF hSCM = OpenSCManager(gzRemotePC, ByVal %NULL, %SC_MANAGER_CREATE_SERVICE) 'Open the SC Manager If hSCM Then 'Got a handle to SCM. zSvcExe = "%SYSTEMROOT%\SYSTEM32\RCMDSVC.EXE" zSvcName = "rCmdSvc" zSvcDsp = "rCmd Service" hService = OpenService(hSCM, zSvcName, %SERVICE_ALL_ACCESS) 'is it already there? If hService = 0 Then 'nope... so lets install it hService = CreateService(hSCM, zSvcName, zSvcDsp, %SERVICE_ALL_ACCESS Or %SERVICE_USER_DEFINED_CONTROL, _ dFlags, _ %SERVICE_DEMAND_START, %SERVICE_ERROR_NORMAL, zSvcExe, ByVal %NULL, ByVal %NULL, _ ByVal %NULL, ByVal %NULL, ByVal %NULL) Else DosPrt "Failed to OpenService on remote PC " + gzRemotePC + $CRLF End If If StartService(hService, 0, 0) Then Function = %TRUE 'now lets start it up Else DosPrt "Failed to StartService on remote PC " + gzRemotePC + $CRLF End If End If If hService Then CloseServiceHandle hService 'Close all open service If hSCM Then CloseServiceHandle hSCM 'handles before exiting End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Our handler function to catch CTRL-C, CTRL-Break,... '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function ConsoleCtlHandler(ByVal dCode As Dword) As Long Select Case dCode Case %CTRL_C_EVENT, %CTRL_BREAK_EVENT gAbort = 1 DosPrt "Aborting..." + $CRLF End Select Function = %FALSE End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' PbMain: This is the main entry point '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function PbMain() AS Long Local iRet AS Long Local iTimeOut AS Long Local zUserID AS Asciiz * %MAX_PATH Local zPassword As Asciiz * %MAX_PATH Local zText AS Asciiz * %MAX_PATH DosPrt "rCmd - Remote Command ver 1.5 by William" + $CrLf zUserID = GetCmdParm("-U") If (ParseCount(Command$," ") < 2) Or zUserID = "" Then DosPrt " Incorrect parameters! Correct usage:" + $CrLf DosPrt "rCmd remoteHostName [options] -u:userid -p [img]http://www.powerbasic.com/support/forums/tongue.gif[/img]assword -r:Program.exe parms" + $CRLF + $CRLF DosPrt "remoteHostName <-- workstation name of remote PC (required)" + $CrLf DosPrt "-u:userid <-- userid that has access to remote PC (required)" + $CrLf DosPrt "-p [img]http://www.powerbasic.com/support/forums/tongue.gif[/img]assword <-- password for remote PC" + $CRLF DosPrt "-r [img]http://www.powerbasic.com/support/forums/tongue.gif[/img]rogram.exe <-- program and parms to run" + $CRLF DosPrt "-d:c:\path <-- path on remote PC to copy and run program" + $CRLF DosPrt "-copy <-- copy the program to remote PC first" + $CRLF DosPrt "-cleanup <-- remove exes from remote PC when done" + $CRLF DosPrt "-system <-- run program using the SYSTEM userid" + $CrLf DosPrt "-nowait <-- return without waiting for program to complete" + $CRLF DosPrt "-show <-- allow current user to interact with program" + $CrLf DosPrt "-pri:0 <-- run the remote program with IdleTime priority" + $CRLF DosPrt "-pri:1 <-- run the remote program with Normal priority (default)" + $CRLF DosPrt "-pri:2 <-- run the remote program with High priority (caution)" + $CrLf DosPrt "-pri:3 <-- run the remote program with RealTime priority (caution)" + $CrLf DosPrt "Note: Use caution with High and RealTime, they may use all CPU cycles." + $CRLF DosPrt " --- Examples: ---" + $CrLf DosPrt "rCmd WRKSTATION1 -copy -cleanup -system -u:Admin -p:MyPW -r:Setup.exe /q" + $CrLf DosPrt "rCmd WNTMOS36 -system -u:Administrator -p:GuessThis1 -r:cmd.exe /q /c dir" + $CrLf DosPrt "rCmd WRKSTATION2 -u:Administrator" + $CrLf DosPrt "Note: no -r: will run CMD to create a virtual DOS prompt with remote PC" + $CrLf If DosPrt(" ") Then Sleep 5000 'pause if not true console app Exit Function End If giTime = Timer zPassword = GetCmdParm("-P") If zPassword = "" Then zPassword = InputBox$("Type Password for " + zUserID,"Password") If zPassword = "" Then Exit Function gzRemotePC = "\\" + Trim$(Parse$(Command$," ",1),"\") 'set global var for remote workstation name zText = "Connecting to " + gzRemotePC Call SetConsoleTitle(zText) Call SetConsoleCtrlHandler(ByVal CodePtr(ConsoleCtlHandler), %TRUE) DosPrt "Authenticating with remote PC..." + $CRLF iRet = 0 zUserID = Trim$(gzRemotePC,"\") + "\" + zUserID 'add workstation name for domain to userid If Connect2PC("IPC$", zUserID, zPassword) And Connect2PC("ADMIN$", zUserID, zPassword) Then 'authenticate zUserID = GetCmdParm("-U") 'reset userid back to just userid iRet = %TRUE Else 'failed to signon so try with again without workstation name for domain zUserID = GetCmdParm("-U") 'reset userid back to just userid If Connect2PC("IPC$", zUserID, zPassword) And Connect2PC("ADMIN$", zUserID, zPassword) Then iRet = %TRUE End If If iRet Then If InStr(1,UCase$(Command$),"-C") Then DosPrt "Copying program file to remote PC..." + $CRLF If CopyExeToRemotePC() = 0 Then Exit Function End If DosPrt "Trying to connect..." + $CRLF If ConnectToRemoteService(1, 1) = 0 Then 'see if service is already there... don't try real hard [img]http://www.powerbasic.com/support/forums/wink.gif[/img] If StartSvc() Then 'can't connect so install and start the service on the remote PC DosPrt "Trying to connect to service and execute command" + $CrLf If ConnectToRemoteService(5, 1000) Then Call ExecuteRemoteCommand(zUserID,zPassword) 'if we connect send command to launch exe End If Else 'service is already their and running so execute command Call ExecuteRemoteCommand(zUserID,zPassword) End If Else DosPrt "UserID/Password failure." + $CrLf End If gAbort = 1 'done so tell threads to end If iRet Then iTimeOut = 30 DosPrt "Closing connections..." + $CRLF Do While iTimeOut 'now loop here until the threads have closed or we timeout in 3 seconds If ghRemoteStdOutputPipe = %INVALID_HANDLE_VALUE _ And ghRemoteStdInputPipe = %INVALID_HANDLE_VALUE _ And ghRemoteStdErrorPipe = %INVALID_HANDLE_VALUE Then Exit Loop Sleep 100 Decr iTimeOut Loop If InStr(1,UCase$(Command$),"-CLEANUP") Then Call CleanUpRemotePC If DosPrt(" ") Then Sleep 3000 'pause for results if this is not a true console app (see top notes) End Function
"I haven't lost my mind... its backed up on tape... I think??"
[This message has been edited by William Burns (edited October 02, 2003).]
Leave a comment:
-
Part 2 is the resource file that contains the service exe: (rCmd.rc)
Code:#include "resource.h" // Load our service exe so we can save to remote PC RCMDSVC RCDATA DISCARDABLE "rCmdSvc.exe" // Version information VS_VERSION_INFO VERSIONINFO FILEVERSION 1,5,0,0 PRODUCTVERSION 1,5,0,0 FILEFLAGSMASK 0x0 FILEFLAGS 0x0 FILEOS VOS_WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "Comments", "This program can remotely run programs.\0" VALUE "CompanyName", "by William Burns\0" VALUE "FileDescription", "Small utility to remotely launch programs\0" VALUE "FileVersion", "1.5\0" VALUE "InternalName", "rCmd\0" VALUE "LegalCopyright", "Copyright \251 20 BCE (got a chisel?)." "\0" VALUE "LegalTrademarks", "If you can read this, you are too close..., " "Inc.\0" VALUE "OriginalFilename", "rCmd.EXE\0" VALUE "ProductName", "rCmd for Windows\0" VALUE "ProductVersion", "Version 1.5\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END
"I haven't lost my mind... its backed up on tape... I think??"
[This message has been edited by William Burns (edited October 01, 2003).]
Leave a comment:
-
RCmd - Remotely login and run commands on NT/2000/XP networked PCs
This is a program that is very similar to the PSEXEC.EXE found at www.sysinternals.com
It uses the same methods to remotely connect, login, and run a program on the remote PC.
It also has a few extra features that PSEXEC does not have. (like priority options, startup dir...)
Sysinternals makes some great tools, and I would suggest sticking with their proven PSEXEC,
but this gives me the flexibility to customize it as needed. For example, I have some PCs
that use an older admin password than the rest, so I could make my program allow you to give
it multiple username/passwords and have it go down the list until it finds the one that
works.
I compiled this program with Power Basic Win 7.2 (even though it should have been with CC,
see the last post for compiling instructions)
The program has 3 source files.
Part 1 is the Service exe that the main program copy and runs on the remote PC:
Code:'==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' rCmdSvc.bas -by William Burns revised on 09/26/2003 ' Service used in conjunction with rCmd.bas to remotely run programs ' Part of this program was based on a C++ program that was based on a program by Zoltan Csizmadia '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' #Compile Exe #INCLUDE "WIN32API.INC" %SET_NO_WAIT = 1 'do not wait for program to complete %SET_SYSTEM = 2 'use SYSTEM userid %SET_COPY_EXE = 4 'copy our program first (if not program must be accessible to remote PC) %SET_PRI_NORMAL = 8 'runtime priority flag %SET_PRI_IDLE = 16 'runtime priority flag %SET_PRI_HIGH = 32 'runtime priority flag %SET_PRI_REAL = 48 'runtime priority flag %SET_SHOW_WIN = 96 'show window or not... Type rCmdExeInfo 'UDT for comunicating to remote service zPCName AS Asciiz * %MAX_PATH 'the controlling PCs name zStartDir AS Asciiz * %MAX_PATH 'what dir to start program from zCommand As Asciiz * 500 'program command and arguments to run zUserID As Asciiz * 100 'userid to remote PC zPassword As Asciiz * 100 'password to remote PC dTime As Dword '(used to make pipes unique) dFlags As Dword 'options to pass on to remote PC End Type Type rCmdReturn dExit AS Dword 'Code returned from running the remote program dError AS Dword 'any error code returned End Type Declare Sub Handler(ByVal Dword) Declare Sub ServiceMain(ByVal Dword, ByVal Dword) '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' GLOBAL VARIABLES '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Global gzServiceName AS Asciiz * 64 Global ghStopEvent AS Long Global ghServiceStatus AS Dword GLOBAL SS AS Service_Status GLOBAL STE AS Service_Table_Entry Global ghPipe AS Dword Global ghProc AS Dword 'running process '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' LogThis - write to a test log file '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Sub LogThis(ByVal sText As String) Local iFile As Long 'Exit Sub '<-- Un-rem this line to stop log file Try iFile = FreeFile Open "rCmdSvclog.txt" For Append As #iFile 'this file will most likely be in the system32 dir Print #iFile, Date$ + " " + Time$ + " " + sText Catch End Try Close #iFile End Sub '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Start Manually: This function will start the service. Returns %TRUE on success. '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function StartManually() AS Long Local hSCM AS Dword Local hService AS Dword hSCM = OpenSCManager(ByVal %Null, ByVal %Null, %SC_MANAGER_ALL_ACCESS) 'Open the SC Manager If hSCM Then 'Got a handle to SCM. hService = OpenService(hSCM, gzServiceName, %SERVICE_ALL_ACCESS) 'Get the service handle If hService Then If StartService(hService, 0, 0) Then Function = %TRUE 'start the service End If End If CloseServiceHandle(hService) CloseServiceHandle(hSCM) End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Uninstall: This function will uninstall the service. Returns %TRUE (-1) on success. '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function Uninstall() AS Long On Error Resume Next Local hSCM AS Long Local hService AS Long LogThis "Removing service." hSCM = OpenSCManager(ByVal %NULL, ByVal %NULL, %SC_MANAGER_CREATE_SERVICE) If hSCM Then 'Got SCM handle. hService = OpenService(hSCM, gzServiceName, %SERVICE_ALL_ACCESS) 'Get Service handle If hService Then If DeleteService(hService) Then 'Delete the service record Function = %TRUE Else LogThis "DeleteService Failed Err=" + Str$(GetLastError()) End If Else LogThis "Unable to open service Err=" + Str$(GetLastError()) End If End If If hService Then CloseServiceHandle hService 'If any handles open, If hSCM Then CloseServiceHandle hSCM 'close them now End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' ConsolePipes - creates the STDINPUT STDOUTPUT and STDERROR pipes to redirect console to remote PC '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function ConsolePipes(CmdInfo AS rCmdExeInfo, SI AS STARTUPINFO) AS Long Local SECATTRIB AS SECURITY_ATTRIBUTES Local SECDESC AS SECURITY_DESCRIPTOR Local zText AS Asciiz * %MAX_PATH LogThis "ConsolePipes started" Call InitializeSecurityDescriptor(SECDESC, %SECURITY_DESCRIPTOR_REVISION) 'initializes a security descriptor to have no system ACL, no discretionary ACL, no owner, no primary group Call SetSecurityDescriptorDacl(SECDESC, %TRUE, ByVal %Null, %FALSE) 'sets information in the discretionary ACL in the security descriptor SecAttrib.nLength = SizeOf(SECATTRIB) SecAttrib.lpSecurityDescriptor = VarPtr(SecDesc) SecAttrib.bInheritHandle = %TRUE SI.dwFlags = %STARTF_USESTDHANDLES SI.hStdOutput = %INVALID_HANDLE_VALUE SI.hStdInput = %INVALID_HANDLE_VALUE SI.hStdError = %INVALID_HANDLE_VALUE zText = "\\.\pipe\rCmd_STDOut" + CmdInfo.zPCName + Format$(CmdInfo.dTime) SI.hStdOutput = CreateNamedPipe(zText, %PIPE_ACCESS_OUTBOUND, %PIPE_TYPE_MESSAGE Or %PIPE_WAIT, %PIPE_UNLIMITED_INSTANCES, 0, 0, %MAXDWORD, SecAttrib) zText = "\\.\pipe\rCmd_STDIn" + CmdInfo.zPCName + Format$(CmdInfo.dTime) SI.hStdInput = CreateNamedPipe(zText, %PIPE_ACCESS_INBOUND, %PIPE_TYPE_MESSAGE Or %PIPE_WAIT, %PIPE_UNLIMITED_INSTANCES, 0, 0, %MAXDWORD, SecAttrib) zText = "\\.\pipe\rCmd_STDErr" + CmdInfo.zPCName + Format$(CmdInfo.dTime) SI.hStdError = CreateNamedPipe(zText, %PIPE_ACCESS_OUTBOUND, %PIPE_TYPE_MESSAGE Or %PIPE_WAIT, %PIPE_UNLIMITED_INSTANCES, 0, 0, %MAXDWORD, SecAttrib) If SI.hStdOutput = %INVALID_HANDLE_VALUE Or SI.hStdInput = %INVALID_HANDLE_VALUE Or SI.hStdError = %INVALID_HANDLE_VALUE Then CloseHandle(SI.hStdOutput) CloseHandle(SI.hStdError) CloseHandle(SI.hStdInput) LogThis "Failed to create STD pipes" Else LogThis "Waiting for remote PC to connect to Std Pipes" ConnectNamedPipe(SI.hStdOutput, ByVal %NULL) ConnectNamedPipe(SI.hStdInput, ByVal %NULL) ConnectNamedPipe(SI.hStdError, ByVal %Null) LogThis "Remote PC has connected to Std Pipes" Function = %TRUE End If End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Message recieved from remote PC... proccess it '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function StartAction() AS Long Local iRet AS Long Local iWorked AS Long Local CmdInfo As rCmdExeInfo Local CmdRet AS rCmdReturn Local dwWritten AS Dword Local dwRead AS Dword Local hToken AS Dword Local dPriority AS Dword Local zCommand AS Asciiz * %MAX_PATH Local zText AS Asciiz * %MAX_PATH Local zDeskTop As Asciiz * %MAX_PATH Local PI As PROCESS_INFORMATION Local SI AS STARTUPINFO Try LogThis "Trying to Recieve command info from remote PC" If ReadFile(ghPipe, ByVal VarPtr(CmdInfo), SizeOf(CmdInfo), dwRead, ByVal %Null) = 0 Then 'read pipe from remote PC iRet = GetLastError() LogThis "Error while reading remote data ReadFile Error:" + Str$(iRet) Exit Try End If LogThis "Received command from PC " + CmdInfo.zPCName + " cmd=" + CmdInfo.zCommand LogThis "Option dFlags=" + Str$(CmdInfo.dFlags) SI.cb = SizeOf(SI) If IsFalse ConsolePipes(CmdInfo, SI) Then Exit Try 'fill our SI UDT with handles from remote pipes zCommand = CmdInfo.zCommand 'NOTE: use CMD for internal dos commands. ex: CMD /C DIR If CmdInfo.zStartDir = "" Then CmdInfo.zStartDir = Environ$("SystemRoot") + "\system32" 'if no startup dir was given, then use the system32 as default Else zCommand = Trim$(CmdInfo.zStartDir,"\") + "\" + CmdInfo.zCommand'NOTE: use cmd for internal dos commands. ex: CMD /C DIR End If If (CmdInfo.dFlags And %SET_PRI_IDLE) = %SET_PRI_IDLE Then 'setup processing priorities dPriority = dPriority Or %IDLE_PRIORITY_CLASS ElseIf (CmdInfo.dFlags And %SET_PRI_HIGH) = %SET_PRI_HIGH Then dPriority = dPriority Or %HIGH_PRIORITY_CLASS ElseIf (CmdInfo.dFlags And %SET_PRI_REAL) = %SET_PRI_REAL Then dPriority = dPriority Or %REALTIME_PRIORITY_CLASS Else 'default dPriority = dPriority Or %NORMAL_PRIORITY_CLASS End If If (CmdInfo.dFlags And %SET_SHOW_WIN) <> %SET_SHOW_WIN Then dPriority = dPriority Or %CREATE_NO_WINDOW 'hide window Else zDeskTop = "WinSta0\Default" 'show window on default desktop SI.lpDesktop = VarPtr(zDeskTop) End If If (CmdInfo.dFlags And %SET_SYSTEM) = %SET_SYSTEM Then 'do we use the default SYSTEM account or logon as user? LogThis "Now going to CreateProcess for: " + zCommand iWorked = CreateProcess("", zCommand, ByVal %NULL, ByVal %NULL, %TRUE, dPriority, ByVal %NULL, CmdInfo.zStartDir, SI, PI) Else LogThis "Now going to LogonUser " + CmdInfo.zUserID zText = "." iWorked = LogonUser(CmdInfo.zUserID, zText, CmdInfo.zPassword, %LOGON32_LOGON_INTERACTIVE, %LOGON32_PROVIDER_DEFAULT, hToken) If iWorked Then zText = "" LogThis "Now going to CreateProcess for: " + zCommand iWorked = CreateProcessAsUser(hToken, "", zCommand, ByVal %Null, ByVal %Null, %TRUE, dPriority, ByVal %Null, CmdInfo.zStartDir, SI, PI) Else CmdRet.dError = GetLastError() LogThis "LogonUser Error " + Str$(CmdRet.dError) End If End If If iWorked Then ghProc = PI.hProcess LogThis "CreateProcess worked for " + CmdInfo.zCommand If (CmdInfo.dFlags And %SET_NO_WAIT) <> %SET_NO_WAIT Then 'should we wait for process to end? LogThis "Now waiting for program to finish." WaitForSingleObject(PI.hProcess, %INFINITE) 'wait on this line for process to end GetExitCodeProcess(PI.hProcess, CmdRet.dExit) 'get processes exit code LogThis "Program finished with exit code " + Str$(CmdRet.dExit) End If Else If CmdRet.dError = 0 Then CmdRet.dError = GetLastError() LogThis "CreateProcess failed for " + CmdInfo.zCommand + " err=" + Str$(CmdRet.dError) End If 'now send back the results If IsFalse WriteFile(ghPipe, ByVal VarPtr(CmdRet), SizeOf(CmdRet), dwWritten, ByVal %Null) Then LogThis "Failed to send response back to host." CloseHandle(si.hStdOutput) CloseHandle(si.hStdError) CloseHandle(si.hStdInput) Catch LogThis "Error in StartAction sub. " + Error$(Err) End Try DisconnectNamedPipe(ghPipe) 'Done, so close com pipe CloseHandle(ghPipe) 'remove handle Call SetEvent(ghStopEvent) End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' WaitForCommThread - Waits for remote comunication. It stays running until service is shutdown '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function WaitForCommThread(ByVal hName AS Dword) AS Long Local SECATTRIB AS SECURITY_ATTRIBUTES Local SECDESC AS SECURITY_DESCRIPTOR Local zText AS Asciiz * %MAX_PATH LogThis "WaitForCommThread started and waiting for client message" Do Call InitializeSecurityDescriptor(SECDESC, %SECURITY_DESCRIPTOR_REVISION) 'initializes a security descriptor to have no system ACL, no discretionary ACL, no owner, no primary group Call SetSecurityDescriptorDacl(SECDESC, %TRUE, ByVal %Null, %TRUE) 'sets information in the discretionary ACL in the security descriptor SecAttrib.nLength = SizeOf(SECATTRIB) SecAttrib.lpSecurityDescriptor = VarPtr(SecDesc) SecAttrib.bInheritHandle = %TRUE zText = "\\.\pipe\rCmdCommand" ghPipe = CreateNamedPipe(zText, %PIPE_ACCESS_DUPLEX, %PIPE_TYPE_MESSAGE Or %PIPE_WAIT, %PIPE_UNLIMITED_INSTANCES, 0, 0, %MAXDWORD, SecAttrib) If ghPipe <> %INVALID_HANDLE_VALUE Then ConnectNamedPipe(ghPipe, ByVal %Null) 'stays here until remote PC connects Call StartAction() Else LogThis "Timed out waiting for client to talk. looping..." End If Loop End Function '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' ServiceMain - Main code of service, the entry point of the service All service processing takes place here '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== SUB ServiceMain(BYVAL dwArgs AS DWORD, BYVAL lpszArgv AS DWORD) On Error Resume Next Local iRet AS Long Local hComm AS Dword Local iWatch AS Long LogThis "ServiceMain started" SS.dwServiceType = %SERVICE_WIN32_OWN_PROCESS SS.dwCurrentState = %SERVICE_START_PENDING SS.dwControlsAccepted = %SERVICE_ACCEPT_STOP OR %SERVICE_ACCEPT_PAUSE_CONTINUE OR %SERVICE_ACCEPT_SHUTDOWN SS.dwWin32ExitCode = 0 SS.dwServiceSpecificExitCode = 0 SS.dwCheckPoint = 0 SS.dwWaitHint = 0 ghServiceStatus = RegisterServiceCtrlHandler(gzServiceName, CodePtr(Handler)) SS.dwCurrentState = %SERVICE_START_PENDING SetServiceStatus ghServiceStatus, SS ghStopEvent = CreateEvent(ByVal %NULL, ByVal %NULL, ByVal %NULL, "HandlerEvent" + Chr$(0)) SS.dwCurrentState = %SERVICE_RUNNING SetServiceStatus ghServiceStatus, SS Thread Create WaitForCommThread(dwArgs) To hComm 'start the main thread Thread Close hComm To iRet iWatch = Timer Do 'stay here until we stop service iRet = WaitForSingleObject(ByVal ghStopEvent, 50) If iRet = %WAIT_FAILED Or iRet = %WAIT_OBJECT_0 Then Exit Loop Sleep 1000 If Timer > iWatch + 600 Then 'timeout in 10 minutes <--- NOTICE! Might need to adjust this for longer programs LogThis "Watchdog killed service because it was older than 10 mins." Exit Loop End If Loop 'If (CmdInfo.dFlags And %SET_NO_WAIT) <> %SET_NO_WAIT And ghProc Then call TerminateProcess(ByVal ghProc, ByVal %NULL) 'not sure if I want to kill on exit or not??? hmmmm Call UnInstall() 'done so uninstall this service SS.dwCurrentState = %SERVICE_STOP_PENDING 'set status to stopping SetServiceStatus ghServiceStatus, SS 'update status CloseHandle ghStopEvent 'delete the event handle SS.dwCurrentState = %SERVICE_STOPPED 'set status to stopped SetServiceStatus ghServiceStatus, SS 'update status LogThis "Leaving ServiceMain" End Sub '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' Handler: Handles all service requests (only setup to handle STOPs for now '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== SUB Handler(BYVAL pControl AS DWORD) If pControl = %SERVICE_CONTROL_STOP Then SetEvent ghStopEvent Else SetServiceStatus ghServiceStatus, SS 'update status End If End Sub '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== ' WinMain - Main system function (service exe starts here) '==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~==~== Function WinMain(ByVal hCurInst AS Long, ByVal hPrvInst AS Long, CmdLine AS Asciiz Ptr, ByVal CmdShow AS Long) Export AS Long Local iRet AS Long iRet = GetCurrentProcess iRet = SetPriorityClass(iRet,%IDLE_PRIORITY_CLASS) CoUninitialize 'uninitialize COM interfaces (kills the OleThread so service will run without errs when you log off) gzServiceName = "rCmdSvc" 'global var for Service name. If Len(Command$) Then If InStr(1,UCase$(Command$),"UNINSTALL") Then 'just in case we need to manually uninstall [img]http://www.powerbasic.com/support/forums/wink.gif[/img] Call UnInstall ElseIf InStr(1,UCase$(Command$),"START") Then 'or manualy start Call StartManually Else MsgBox "rCmdSvc /UnInstall /Start",,"Usage:" End If Else 'normal execution from service being started Try 'try to remove old log if found Kill "rCmdSvclog.txt" Catch 'do nothing on error... not important End Try Try LogThis "Trying to start service" STE.lpServiceName = VarPtr(gzServiceName) STE.lpServiceProc = CodePtr(ServiceMain) If StartServiceCtrlDispatcher(STE) Then Function = %TRUE Else iRet = GetLastError() LogThis "Error on StartServiceCtrlDispatcher err#" + Str$(iRet) End If ExitProcess 0 Catch ExitProcess Err End Try End If End Function
------------------
"I haven't lost my mind... its backed up on tape... I think??"
[This message has been edited by William Burns (edited October 02, 2003).]Tags: None
Leave a comment: