Jump to content

Offer Remote Assistance


Zinthose
 Share

Recommended Posts

History

Did you know that since Windows XP, Microsoft has included a remote desktop support system? Most people don't as it is well hidden in the Help and Support and doesn't have a direct executable to start it. Anyone who has used the MSN Messenger remote desktop has seen it but probably thought it was built into MSN Messenger.

I decided to see if I can use AutoIt to connect to a remote system and remote assist the user for HelpDesk use. The easy part was identifying the registry values to allow for unsolicited Remote Assistance. I had this part of the code working within a few hours. the hard part was automating the connection to the remote system. At first I was very disappointed with the lack of documentation and was even surprised just how few people attempted this. I found some attempts that involved hacking some of the "htm" files in the %Windows%\PCHealth folder and in my opinion that is too much of a hack and is asking for trouble.

I finally identified the com object used, "PCH.HelpService". The remainder of my script is derived from the VBScript posted at LOGINternet Forum and my own touches. :)

Requirments

  • Tested on Windows XP Pro and Windows XP x64. It should work on Server 2003/2008. I know Vista changed somethings so it will likely not work but I haven't tested it yet.
  • Script must be run with an account that has administrative privileges on the remote system
  • Third party firewalls might block the connection and will need an exception added or to be disabled entirely for this demo
  • Target system's user must accept the request before the remote session is allowed. ** There is a way to bypass this but I WILL NOT disclose how due to ethical issues **

I hope everyone finds it useful. :o

#Include <File.au3>
#include <ButtonConstants.au3>
#include <ComboConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <ListboxConstants.au3>

Global $__RegistryConnectFailed, $__HelpServiceFailed

Exit _Main()

Func _Main()
    Local $HostName = InputBox("ORA", "Enter Hostname to connect to:")
    
    ;## Connect to the remote system's Registry hive
        $Reg = _RegistryConnect($HostName)
        If @error Then Return 1
       
    ;## Enable Unsolicited Remote Assistance on remote system
        _EnableRemoteAssist($Reg)
        If @error Then Return 2
   
    ;## Start Remote Assistance Session
        _OfferRemoteAssistance($HostName)
        If @error Then Return 3
       
    ;## Enable Unsolicited Remote Assistance on remote system and close Remote registry connection
        _DisableRemoteAssist($Reg)
        If @error Then Return 4
        $Reg = Default
       
    Return 0
EndFunc

#Region ;**** Offer Remote Assistance Functions
    Func _OfferRemoteAssistance($HostName, $UserID = Default, $UserDomain = Default, $EnablePingTest = True)
        Local Const $IncidentFileFormat = '<?xml version="1.0" encoding="Unicode" ?><UPLOADINFO TYPE="Escalated"><UPLOADDATA USERNAME="%s" ' & _
            'RCTICKET="%s" RCTICKETENCRYPTED="0" DtStart="0" DtLength="0" IP="%s" Status="Active" URA="1" /></UPLOADINFO>'
        Local $Ticket, $HelpService, $Session, $Sessions, $i
        Local $IncidentFile, $Command, $Users = ""
       
        ;## Define the Temporary Incident Ticket File and the command to initialize the Remote Assistance Application
            $IncidentFile = _TempFile()
            $Command = '"' & @WindowsDir & '\pchealth\helpctr\binaries\helpctr.exe" -Mode "hcp://system/Remote Assistance/raura.xml" ' & _
                '-url "hcp://system/Remote Assistance/Interaction/Client/RcToolscreen1.htm" -ExtraArgument "IncidentFile=' & $IncidentFile & '"'

        ;## Perform a quick ping test to verify the system is online
            If $EnablePingTest And Ping($HostName) = 0 Then Return SetError(1, 0, False)

        ;## Connect to Remote system's Help Service
            $__HelpServiceFailed = ObjEvent("AutoIt.Error", "__HelpServiceFailed")
            $HelpService = ObjCreate("PCH.HelpService", $HostName)
            $__HelpServiceFailed = Default
           
        ;## Validate
            If Not IsObj($HelpService) Then Return SetError(2, 0, False)

        ;## Identify Active User Sessions
            $Sessions = $HelpService.RemoteUserSessionInfo

            Select
                Case $Sessions.Count = 0
                    $UserID = ""
                    $UserDomain = ""
                Case $Sessions.Count = 1
                    $Session = $Sessions.Item(1)
                    $UserID = $Session.UserName
                    $UserDomain = $Session.DomainName
                Case $Sessions.Count > 1
                    ;## Get list of Active Users for prompt dropdown list
                        For $i = 1 to $Sessions.Count
                            $Session = $Sessions.Item($i)
                            $Users &= $Session.DomainName & "/" &$Session.UserName & "|"
                        Next
                       
                        $Users = StringTrimRight($Users, 1)
                       
                    ;## Prompt for UserID
                        $SelectedUser = _PromptForUser($Users)
                        If @error Then Return SetError(3, @error, False)
                       
                    ;## Split Domain/User and save for latter use
                        $SelectedUser   = StringSplit($SelectedUser, "/")
                        $UserDomain     = $SelectedUser[1]
                        $UserID         = $SelectedUser[2]
                       
                Case Else
                    ;## Error! / Unexpected
                    Return SetError(4, 0, False)
            EndSelect
       
        ;## Create Incident Ticket File
            $Ticket = $HelpService.RemoteConnectionParms($UserID, $UserDomain, -1, "")
            $IncidentFileXML = StringFormat($IncidentFileFormat, $UserID, $Ticket, $UserDomain)
           
            $File = FileOpen($IncidentFile, 42)
            $RC = FileWrite($File, $IncidentFileXML)
            FileClose($File)
           
            If $RC = 0 Then Return SetError(5, 0, False);   <-- ## Bad Unable to create Incident Ticket File
               
        ;## Execute / Offer Remote Assistance to the target system
            $RC = RunWait($Command)
            If $RC <> 0 Then SetError(6, $RC, False)
            Return True
    EndFunc
       
    Func __HelpServiceFailed()
       
        MsgBox(4096 + 48, @ScriptName, "Unable to connect to the remote system."  & @CRLF & @CRLF & _
            "Description: "      & @TAB & $__HelpServiceFailed.description    & @CRLF & _
            "Windows description:"  & @TAB & $__HelpServiceFailed.windescription & @CRLF & _
            "Number: "        & @TAB & Hex($__HelpServiceFailed.number,8)  & @CRLF & _
            "Last DLL Error: "    & @TAB & $__HelpServiceFailed.lastdllerror   & @CRLF & _
            "Scriptline: "      & @TAB & $__HelpServiceFailed.scriptline     & @CRLF & _
            "Source: "        & @TAB & $__HelpServiceFailed.source         & @CRLF & _
            "Help file: "         & @TAB & $__HelpServiceFailed.helpfile       & @CRLF & _
            "Help context: "        & @TAB & $__HelpServiceFailed.helpcontext _
        )
    EndFunc
   
    Func _PromptForUser($Users)
        Local $frmSelectUser, $cmbUser, $lblSelectUser, $cmdCancel, $cmdOK, $msg, $FirstUser, $SelectedUser = Default
        Local $PrevGUICloseOnESC, $PrevGUIOnEventMode
       
        ;## Define dialog Box
            $PrevGUICloseOnESC = Opt("GUICloseOnESC", 1)
            $PrevGUIOnEventMode = Opt("GUIOnEventMode", 0)
            $frmSelectUser = GUICreate("Offer Remote Assistance", 326, 118, -1, -1, _
                BitOR($WS_SYSMENU,$WS_CAPTION,$WS_POPUP,$WS_POPUPWINDOW,$WS_BORDER,$WS_CLIPSIBLINGS), _
                BitOR($WS_EX_TOPMOST,$WS_EX_WINDOWEDGE))
               
            $cmbUser = GUICtrlCreateCombo("", 12, 48, 301, 25, $CBS_DROPDOWNLIST, $LBS_NOSEL)
            GUICtrlCreateLabel("Please Select the user you want to offer remote assistance:", 12, 30, 283, 17)
            GUICtrlCreateLabel("Target system detected to have multiple active user's ", 0, 0, 325, 17, $SS_CENTER)
            GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
            $cmdCancel = GUICtrlCreateButton("Cancel", 156, 84, 75, 25, 0)
            $cmdOK = GUICtrlCreateButton("OK", 240, 84, 75, 25, $BS_DEFPUSHBUTTON)
            GUISetState(@SW_SHOW)
       
        ;## Add users to the ComboBox list
            $Length = StringInStr($Users, "|") - 1
           
            If $Length > 0 Then
                $FirstUser = StringLeft($Users, $Length)
            Else
                $FirstUser = $Users
            EndIf
           
            GUICtrlSetData($cmbUser, $Users, $FirstUser)

        ;## Wait for it.....
            While True
                Switch GUIGetMsg()
                    Case $GUI_EVENT_CLOSE, $cmdCancel
                        ExitLoop
                    Case $cmdOK
                        $SelectedUser = GUICtrlRead($cmbUser)
                        ExitLoop
                EndSwitch
            WEnd
       
        ;## Clean Up GUI
            GUIDelete($frmSelectUser)
            Opt("GUICloseOnESC", $PrevGUICloseOnESC)
            Opt("GUIOnEventMode", $PrevGUIOnEventMode)
           
        ;## Do some value checking and Return
            If $SelectedUser = Default Then Return SetError(1, 0, False)
            Return $SelectedUser
    EndFunc
#EndRegion

#Region ;**** General Functions
    Func _Echo($Msg)
        ConsoleWrite("+ Echo:" & @CRLF & "+  " & $Msg & @CRLF)
    EndFunc
#EndRegion

#Region ;**** Registry Functions
    Func _RegistryConnect($HostName, $EnablePingTest = True)
        Local $Reg
       
        ;## Perform a quick ping test to verify the system is online
            If $EnablePingTest And Ping($HostName) = 0 Then Return SetError(1, 0, False)
       
        ;## Connect to the Remote system's Registry Tree
            $__RegistryConnectFailed = ObjEvent("AutoIt.Error", "__RegistryConnectFailed")
                $Reg=ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $HostName & "\root\default:StdRegProv")
            $__RegistryConnectFailed = Default
       
        ;##
        If Not IsObj($Reg) Then Return SetError(2, 0, False)
       
        Return $Reg
       
    EndFunc
   
    Func __RegistryConnectFailed()
       
        MsgBox(4096 + 48, @ScriptName, "Unable to connect to the remote systems Registry tree."  & @CRLF & @CRLF & _
            "Description: "      & @TAB & $__RegistryConnectFailed.description    & @CRLF & _
            "Windows description:"  & @TAB & $__RegistryConnectFailed.windescription & @CRLF & _
            "Number: "        & @TAB & hex($__RegistryConnectFailed.number,8)  & @CRLF & _
            "Last DLL Error: "    & @TAB & $__RegistryConnectFailed.lastdllerror   & @CRLF & _
            "Scriptline: "      & @TAB & $__RegistryConnectFailed.scriptline     & @CRLF & _
            "Source: "        & @TAB & $__RegistryConnectFailed.source         & @CRLF & _
            "Help file: "         & @TAB & $__RegistryConnectFailed.helpfile       & @CRLF & _
            "Help context: "        & @TAB & $__RegistryConnectFailed.helpcontext _
        )
    EndFunc
   
    Func _EnableRemoteAssist($Reg)
        Local Const $RegTerminalServ        = "Software\Policies\Microsoft\Windows NT\Terminal Services"
        Local Const $RegRAUnsolicit   = $RegTerminalServ & "\RAUnsolicit"
        Local Const $HKEY_LOCAL_MACHINE     = 0x80000002
       
        Local $RC     = 0
       
        $Reg.CreateKey($HKEY_LOCAL_MACHINE, $RegTerminalServ)
        $Reg.CreateKey($HKEY_LOCAL_MACHINE, $RegRAUnsolicit)
       
        $RC += $Reg.SetDWORDValue($HKEY_LOCAL_MACHINE,   $RegTerminalServ,    "fAllowUnsolicited",            1)
        $RC += $Reg.SetDWORDValue($HKEY_LOCAL_MACHINE,   $RegTerminalServ,    "fAllowUnsolicitedFullControl",    1)
        $RC += $Reg.SetStringValue ($HKEY_LOCAL_MACHINE,    $RegRAUnsolicit,   "helper",                             "helper")
       
        Return SetError($RC, 0, $RC = 0)
   
    EndFunc
   
    Func _DisableRemoteAssist($Reg)
        Local Const $RegTerminalServ        = "Software\Policies\Microsoft\Windows NT\Terminal Services"
        Local Const $RegRAUnsolicit   = $RegTerminalServ & "\RAUnsolicit"
        Local Const $HKEY_LOCAL_MACHINE     = 0x80000002
       
        Local $RC = 0
       
        $RC += $Reg.DeleteValue($HKEY_LOCAL_MACHINE, $RegTerminalServ,  "fAllowUnsolicited")
        $RC += $Reg.DeleteValue($HKEY_LOCAL_MACHINE, $RegTerminalServ,  "fAllowUnsolicitedFullControl")
        $RC += $Reg.DeleteValue($HKEY_LOCAL_MACHINE, $RegRAUnsolicit,   "helper")
       
        Return SetError($RC, 0, $RC = 0)
    EndFunc
#EndRegion
Edited by Zinthose

--- TTFN

Link to comment
Share on other sites

Very nice. I like this a lot. It's much simpler than walking a user through setting up a Remote Assist request or NetMeeting session. Well done.

edit: Minor bug found. When connecting to a machine with mutiple sessions the objcall fails because of the params passed to it. Lines 84 and 85 read:

$UserDomain     = $SelectedUser[0]
                        $UserID         = $SelectedUser[1]
Edited by spudw2k
Spoiler

Things I've Made: Always On Top Tool ◊ AU History ◊ Deck of Cards ◊ HideIt ◊ ICU ◊ Icon Freezer ◊ Ipod Ejector ◊ Junos Configuration Explorer ◊ Link Downloader ◊ MD5 Folder Enumerator ◊ PassGen ◊ Ping Tool ◊ Quick NIC ◊ Read OCR ◊ RemoteIT ◊ SchTasksGui ◊ SpyCam ◊ System Scan Report Tool ◊ System UpTime ◊ Transparency Machine ◊ VMWare ESX Builder
Misc Code Snippets: ADODB Example ◊ CheckHover ◊ Detect SafeMode ◊ DynEnumArray ◊ GetNetStatData ◊ HashArray ◊ IsBetweenDates ◊ Local Admins ◊ Make Choice ◊ Recursive File List ◊ Remove Sizebox Style ◊ Retrieve PNPDeviceID ◊ Retreive SysListView32 Contents ◊ Set IE Homepage ◊ Tickle Expired Password ◊ Transpose Array
Projects: Drive Space Usage GUI ◊ LEDkIT ◊ Plasma_kIt ◊ Scan Engine Builder ◊ SpeeDBurner ◊ SubnetCalc
Cool Stuff: AutoItObject UDF â—Š Extract Icon From Proc â—Š GuiCtrlFontRotate â—Š Hex Edit Funcs â—Š Run binary â—Š Service_UDF

 

Link to comment
Share on other sites

Very nice. I like this a lot. It's much simpler than walking a user through setting up a Remote Assist request or NetMeeting session. Well done.

edit: Minor bug found. When connecting to a machine with mutiple sessions the objcall fails because of the params passed to it. Lines 84 and 85 read:

$UserDomain     = $SelectedUser[0]
                        $UserID         = $SelectedUser[1]
Good eye spudw2k... Corrected :)

--- TTFN

Link to comment
Share on other sites

Hi,

I'm very new at this, so I apologize if my questions are simplistic.

I compiled and ran this, but nothing seemed to happen. Is there supposed to be a front-end that opens and asks for the hostname variable?

What should I see when this script is run?

Thanks.

Link to comment
Share on other sites

  • 2 weeks later...

Hi,

I'm very new at this, so I apologize if my questions are simplistic.

I compiled and ran this, but nothing seemed to happen. Is there supposed to be a front-end that opens and asks for the hostname variable?

What should I see when this script is run?

Thanks.

The original code used a hard coded hostname... I added an InputBox to prompt for a Hostname to connect to.

--- TTFN

Link to comment
Share on other sites

The original code used a hard coded hostname... I added an InputBox to prompt for a Hostname to connect to.

Well what can I say but OMFG thankyou and very niceley written..Been looking for something like this for some time. The only thing that I have found is you need to copy two files to the remote system first. These two files enable you to take control of the other persons computer without asking permission when you need to fix something. If you need the two files let me know and I will send them two you.

"\\" & $Hostname & "\c$\windows\pchealth\HelpCtr\System\Remote Assistance\helpeeaccept.htm", 1)

"\\" & $Hostname & "\c$\windows\pchealth\HelpCtr\System\Remote Assistance\Interaction\Server\TakeControlMsgs.htm", 1)

Thanks again..

Link to comment
Share on other sites

It works now, what should I enter in input box ? because nothing works....

You will enter the Hostname, also know as the computer name, of the remote Windows XP system you wish to offer remote assistance. The remote system must be administratively accessible by the source system.

Also, Please note the additional requirements in the first post.

--- TTFN

Link to comment
Share on other sites

I have the requirements but I don't understand how it works because if I enter the hostname of a friend, how can he receive my message?

This example dose not work over the internet unless the systems are connected through a VPN or Hamachi network connection due to firewall and security concerns.

--- TTFN

Link to comment
Share on other sites

  • 1 month later...

yes it is indeed

you can do 2 things

1) convert it to whatever you like and then compile it with visual studio

2) download autoit (the zipped one if you don't want an installation) and run aut2exe or the wrapper

Some Projects:[list][*]ZIP UDF using no external files[*]iPod Music Transfer [*]iTunes UDF - fully integrate iTunes with au3[*]iTunes info (taskbar player hover)[*]Instant Run - run scripts without saving them before :)[*]Get Tube - YouTube Downloader[*]Lyric Finder 2 - Find Lyrics to any of your song[*]DeskBox - A Desktop Extension Tool[/list]indifference will ruin the world, but in the end... WHO CARES :P---------------http://torels.altervista.org

Link to comment
Share on other sites

  • 3 years later...

cant make this work, dont have a domain, is it possible to use workgroup if u have your own account on remote machine?

Tryed all kind of solutions from internet, u have any idea?

------

ERROR

Unable to connect to the remote systems Registry tree.

Description:

Windows description: Ã…tkomst nekad.

Number: 80070005

Last DLL Error: 0

Scriptline: 205

Source:

Help file:

Help context: 5439580->16:29:35 AutoIT3.exe ended.rc:1

Edited by lgvlgv
Link to comment
Share on other sites

Hi again, it worked if i had an identical account on remote system, but does anyone know how to connect useing another account?

Cant figure out how to connect over wmi useing a local existing account on remote machine, can i send the account information somehow in

$Reg=ObjGet("winmgmts:{impersonationLevel=impersonate}!" & $HostName & "rootdefault:StdRegProv")
Edited by lgvlgv
Link to comment
Share on other sites

i solved it with RunAs()

Hi again, it worked if i had an identical account on remote system, but does anyone know how to connect useing another account?

Cant figure out how to connect over wmi useing a local existing account on remote machine, can i send the account information somehow in

$Reg=ObjGet("winmgmts:{impersonationLevel=impersonate}!" & $HostName & "rootdefault:StdRegProv")

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...