Sign in to follow this  
Followers 0
kschwarz

How to see Script Icon in Notification area when Script is started by a Service as System

12 posts in this topic

I have a service written with Autoit and that is working correctly and started under Local System account. This service starts another AutoIt application that generates a Tray Menu but the TrayIcon is not being shown in the Notification Area. When I run this application from my account the Tray Icon is shown and I can access the menu items accordingly.

Is there any way to make the Tray Icon be shown when running as Local System account?

Another question: The above described Tray Menu has an Menu Item that starts another application. Note that the Tray Menu application is running under Local System Account. Is there any way to start that application with the account of the user that is selecting (clicking) that Menu Item?

Thanks,

Klaus

Share this post


Link to post
Share on other sites



When you installed the service did you set it to interact with the desktop as it shows in the AutoIt Wiki FAQ?

RegWrite("HKLM\SYSTEM\CurrentControlSet\Services\[ServiceName]", "Type", "REG_DWORD", 0x110)

Adam

Share this post


Link to post
Share on other sites

When you installed the service did you set it to interact with the desktop as it shows in the AutoIt Wiki FAQ?

RegWrite("HKLM\SYSTEM\CurrentControlSet\Services\[ServiceName]", "Type", "REG_DWORD", 0x110)

Adam

I have made the change in the service settings to include the option to interact with the desktop and it is now showing the Icon. Thanks

What about the question abaout starting another application from the Service Tray Manu as the user that makes this selection instead of starting it as Local System? Any hint?

Klaus

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Glad I could help. Now about your other problem, here is an idea that I would use.

Try using Run in the script with SCHTASK, with /create, to create a scheduled task to run under the current logged in user using /ru. Then you could use /run with /u to run the task with the currently logged in username. Depending on how often the process is used you can leave the scheduled task and use /query to see if the task exist, /run with /u to run it each time, and /delete to delete the tasks when the script closes. I have not fully tested this, but at least it give you some ideas and a direction to go.

There is one catch, @UserName will not work in creating the task, since @UserName is the user running the script, which is SYSTEM, and not the currently logged in user. Here is a small function and example script to get the currently logged in user. This function does not have detailed WMI Error handling, so you will need to add it.

FileWriteLine("test.txt", "Current User: " & @UserName)
FileWriteLine("test.txt", "User Logged in: " & _CurrentUserLoggedIn())


Func _CurrentUserLoggedIn($sHostName = Default)
    Local $oWMIService, $oComputers, $oComputer

    If $sHostName = Default Then $sHostName = "."

    $oWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $sHostName & "\root\cimv2")
    If Not IsObj($oWMIService) Then Return SetError(2, 1, "")

    $oComputers = $oWMIService.ExecQuery("Select * from Win32_ComputerSystem")

    For $oComputer in $oComputers
        If $oComputer.UserName = "" Then
            Return SetError(1, 0, "")
        Else
            Return $oComputer.UserName
        EndIf
    Next

EndFunc

Compile this script and set it as a scheduled task to run under SYSTEM. You will see SYSTEM as the "Current User", but "User Logged In" will not be SYSTEM. It will be the currently logged in user.

Edit: typos

Edit: Changed _CurrentUserLoggedIn function to return "" instead of 0 on error.

Adam

Edited by AdamUL

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

I have made the change in the service settings to include the option to interact with the desktop and it is now showing the Icon. Thanks

What about the question abaout starting another application from the Service Tray Manu as the user that makes this selection instead of starting it as Local System? Any hint?

Klaus

It worked on Windows XP but on Windows 7 the icon did not show up.

Any idea?

Edited by Klaus

Share this post


Link to post
Share on other sites

This has to do with Session 0 isolation that was first implemented in Windows Vista. Here is a discussion about it on MSDN. You can try running it in Windows XP compatibility mode.

Adam

Share this post


Link to post
Share on other sites

Glad I could help. Now about your other problem, here is an idea that I would use.

Try using Run in the script with SCHTASK, with /create, to create a scheduled task to run under the current logged in user using /ru. Then you could use /run with /u to run the task with the currently logged in username. Depending on how often the process is used you can leave the scheduled task and use /query to see if the task exist, /run with /u to run it each time, and /delete to delete the tasks when the script closes. I have not fully tested this, but at least it give you some ideas and a direction to go.

There is one catch, @UserName will not work in creating the task, since @UserName is the user running the script, which is SYSTEM, and not the currently logged in user. Here is a small function and example script to get the currently logged in user. This function does not have detailed WMI Error handling, so you will need to add it.

<snip>

Compile this script and set it as a scheduled task to run under SYSTEM. You will see SYSTEM as the "Current User", but "User Logged In" will not be SYSTEM. It will be the currently logged in user.

Edit: typos

Edit: Changed _CurrentUserLoggedIn function to return "" instead of 0 on error.

Adam

Thank you Adam, for your suggestion. I will give it a try. Sorry for the delayed answer.

Klaus

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Adam,

I have tryed your _CurrentUserLoggedIn() function and it worked on Windows 7, but WMI could not be accessed using WmiRM that is not available in "Windows Server 2003 with SP1, Windows Server 2003, Windows XP, and Windows 2000".

On "Windows XP SP3" it returns

Current User : myusername

User Logged in: domainname\myusername

On "Windows XP x64 SP2" it returns

Current User : myusername

User Logged in: domainname\myusername

But On "Windows Server 2003 SP1" it returns

Current User : myusername

User Logged in:

Is there another way to obtain the Username?

Could you help me with this?

Thanks, Klaus

Edited by Klaus

Share this post


Link to post
Share on other sites

Thank you Adam, for your suggestion. I will give it a try. Sorry for the delayed answer.

Klaus

I have tryed the Task Scheduler hint on Windows 7 and it worked perfectly. But when I have tryed it on a Windows XP x64 machine it is always asking for the "run as password". See whole message bellow:

Please enter the run as password for domain\username:

WARNING: When the run as password is empty, the scheduled task may not run because of the security policy.

WARNING: The scheduled task "TaskName" has been created, but may not run because the account information could not be set.

And the Eventlog shows "Unknown user name or bad password". The user exists and as I am not giving the password it is failing.

Seems this procedure does not work on versions prior to Windows 7 (or Vista perhaps).

Any remindings, hints, etc?

Klaus

Share this post


Link to post
Share on other sites

Another question: The above described Tray Menu has an Menu Item that starts another application. Note that the Tray Menu application is running under Local System Account. Is there any way to start that application with the account of the user that is selecting (clicking) that Menu Item?

Thanks,

Klaus

Klaus

I've not used this UDF, but it may be what you are looking for.

Elevate Your Script to the SYSTEM Account

These two functions in particular.

_ImpersonateUserStart()

_ImpersonateUserEnd()

or this?

Run a Process as Limited User DropMyRights replacement


I see fascists...

Share this post


Link to post
Share on other sites

Klaus,

Sorry of the late replay. Way too many projects running concurrently.

Here are two more versions of _CurrentUserLoggedIn.

This one uses PsLoggedOn by Sysinternals. PsLoggedOn must be in the script directory or the system path.

Func _CurrentUserLoggedIn($sComputer = @ComputerName) ;Uses PsLoggedOn.exe.
    ;Use #include <Constants.au3> if $STDOUT_CHILD is used somewhere else in the script.

    Const $STDOUT_CHILD = 2 ;Comment out if #include <Constants.au3> is used.
    $sPSLoggedOnOutputHeader1 = "Connecting to Registry of \\" & $sComputer & "..."
    $sPSLoggedOnOutputHeader2 = "loggedon v1.33 - See who's logged on" & @CRLF & "Copyright ¬ 2000-2006 Mark Russinovich" & @CRLF & "Sysinternals - www.sysinternals.com" & @CRLF
    $iPIDPSLoggedOn = Run('psloggedon -x \\' & $sComputer, '', @SW_HIDE, $STDOUT_CHILD)
    If @error Then Return SetError(2, 1, "")
    ProcessWaitClose($iPIDPSLoggedOn)
    $sPSLoggedOnOutput = StringStripWS(StdoutRead($iPIDPSLoggedOn), 3)
    If Not StringInStr($sPSLoggedOnOutput, "Error opening HKEY_USERS") Then
        $sPSLoggedOnOutput = StringReplace($sPSLoggedOnOutput, $sPSLoggedOnOutputHeader1, "")
        $sPSLoggedOnOutput = StringReplace($sPSLoggedOnOutput, $sPSLoggedOnOutputHeader2, "")
        $sPSLoggedOnOutput = StringReplace($sPSLoggedOnOutput, "Users logged on locally:" & @CRLF, "")
        $sPSLoggedOnOutput = StringReplace($sPSLoggedOnOutput, "NT AUTHORITY\LOCAL SERVICE" & @CRLF, "")
        $sPSLoggedOnOutput = StringReplace($sPSLoggedOnOutput, "NT AUTHORITY\NETWORK SERVICE" & @CRLF, "")
        $sPSLoggedOnOutput = StringReplace($sPSLoggedOnOutput, "NT AUTHORITY\SYSTEM" & @CRLF, "")
        $sPSLoggedOnOutput = StringStripWS($sPSLoggedOnOutput, 3)
        If StringInStr($sPSLoggedOnOutput, "Users logged on via resource shares:") Then $sPSLoggedOnOutput = StringLeft($sPSLoggedOnOutput, StringInStr($sPSLoggedOnOutput, "Users logged on via resource shares:") - 1)
        If StringInStr($sPSLoggedOnOutput, "No one is logged on via resource shares.") Then $sPSLoggedOnOutput = StringLeft($sPSLoggedOnOutput, StringInStr($sPSLoggedOnOutput, "No one is logged on via resource shares.") - 1)
        $sPSLoggedOnOutput = StringStripWS($sPSLoggedOnOutput, 3)
    Else
        Return SetError(1, 2, "")
    EndIf

    Return $sPSLoggedOnOutput
EndFunc

This one searches the Registry. I had to modify the DLL call in _Security__LookupAccountSid because it only had one parameter, for SID, and there was not one for System. This caused problems when checking for local accounts on a remote computer. I renamed the function _Security__LookupAccountSidEx, and it is included below the function.

#include <Security.au3>
Func _CurrentUserLoggedIn($sComputer = @ComputerName) ;Uses Registry.
    ;Uses #include <Security.au3>
    ;Uses _Security__LookupAccountSidEx see below.
    ;Uses #include <Array.au3> for testing.
    $iSIDCount = 1
    While 1
        $sUserSID = RegEnumKey("\\" & $sComputer & "\HKEY_USERS", $iSIDCount)
        Switch @error
            Case 1, 2, 3
                Return SetError(1, 2, "")
            Case -1
                ExitLoop
        EndSwitch
        If StringLen($sUserSID) > 8 And Not StringInStr($sUserSID, "_Classes") Then
;~          $vUserAcct = _Security__LookupAccountSid($sUserSID) ;Will not pull Local Accounts from a Remote PC.
            $vUserAcct = _Security__LookupAccountSidEx($sUserSID, $sComputer) ;Will now pull Local Accounts from a Remote PC.
            If IsArray($vUserAcct) Then
;~              _ArrayDisplay($vUserAcct, $sComputer) ;For Testing
                Return $vUserAcct[1] & "\" & $vUserAcct[0]
            EndIf
        EndIf

        $iSIDCount += 1
    WEnd

    Return SetError(1, 0, "")
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _Security__LookupAccountSidEx
; Description ...: Retrieves the name of the account for a SID
; Syntax.........: _Security__LookupAccountSidEx($vSID,[, $sSystem = ""])
; Parameters ....: $vSID        - Either a binary SID or a string SID
;                  $sSystem     - Name of the system. This string can be the name of a remote computer.  If this string is blank,
;                  +the account name translation begins on the local system.  If the name cannot be resolved on the local system,
;                  +this function will try to resolve the name using domain controllers trusted by the local system.
; Return values .: Success      - Array with the following format:
;                  |$aAcct[0] - Account name
;                  |$aAcct[1] - Domain name
;                  |$aAcct[2] - SID type, which can be one of the following values:
;                  | 1 - Indicates a user SID
;                  | 2 - Indicates a group SID
;                  | 3 - Indicates a domain SID
;                  | 4 - Indicates an alias SID
;                  | 5 - Indicates a SID for a well-known group
;                  | 6 - Indicates a SID for a deleted account
;                  | 7 - Indicates an invalid SID
;                  | 8 - Indicates an unknown SID type
;                  | 9 - Indicates a SID for a computer
;                  Failure      - 0
; Author ........: Paul Campbell (PaulIA)
; Modified.......: Adam Lawrence (AdamUL)
; Remarks .......:
; Related .......: _Security__LookupAccountName, _Security__GetAccountSid
; Link ..........: @@MsdnLink@@ LookupAccountSid
; Example .......:
; ===============================================================================================================================
Func _Security__LookupAccountSidEx($vSID, $sSystem = "")
    Local $pSID, $aAcct[3]

    If IsString($vSID) Then
        Local $tSID = _Security__StringSidToSid($vSID)
        $pSID = DllStructGetPtr($tSID)
    Else
        $pSID = $vSID
    EndIf
    If Not _Security__IsValidSid($pSID) Then Return SetError(-1, 0, 0)

;~  Local $aResult = DllCall("advapi32.dll", "bool", "LookupAccountSidW", "ptr", 0, "ptr", $pSID, "wstr", "", "dword*", 256, "wstr", "", "dword*", 256, "int*", 0) ;Original DLL call.
    Local $aResult = DllCall("advapi32.dll", "bool", "LookupAccountSidW", "wstr", $sSystem, "ptr", $pSID, "wstr", "", "dword*", 256, "wstr", "", "dword*", 256, "int*", 0) ;Added $sSystem parameter and change to type "wstr".
    If @error Then Return SetError(@error, @extended, 0)
    If Not $aResult[0] Then Return 0

    Local $aAcct[3]
    $aAcct[0] = $aResult[3]     ; Name
    $aAcct[1] = $aResult[5]     ; Domain
    $aAcct[2] = $aResult[7]     ; SNU
    Return $aAcct
EndFunc   ;==>_Security__LookupAccountSidEx

For the Windows XP x64 problem, check the permissions on the Scheduled Tasks folder to make sure the user has rights to it, as noted in kb883273. See if that fixes the problem. If not, then I would also check out the that rover mentioned above, also look at the function _CreateProcessAsUser in that UDF. With _CreateProcessAsUser, you can execute a command line, so you might be able to start the processes you need, in the user context that you need, without using SCHTASK. I haven't fully tested it, but you could give it a try.

Hope this helps,

Adam

Share this post


Link to post
Share on other sites

Klaus,

Sorry of the late replay. Way too many projects running concurrently.

Here are two more versions of _CurrentUserLoggedIn.

This one uses PsLoggedOn by Sysinternals. PsLoggedOn must be in the script directory or the system path.

<snipped>

This one searches the Registry. I had to modify the DLL call in _Security__LookupAccountSid because it only had one parameter, for SID, and there was not one for System. This caused problems when checking for local accounts on a remote computer. I renamed the function _Security__LookupAccountSidEx, and it is included below the function.

<snipped>

For the Windows XP x64 problem, check the permissions on the Scheduled Tasks folder to make sure the user has rights to it, as noted in kb883273. See if that fixes the problem. If not, then I would also check out the that rover mentioned above, also look at the function _CreateProcessAsUser in that UDF. With _CreateProcessAsUser, you can execute a command line, so you might be able to start the processes you need, in the user context that you need, without using SCHTASK. I haven't fully tested it, but you could give it a try.

Hope this helps,

Adam

Hi Adam and rover, I will be giving a try to the new _CurrentUserLoggedIn and the _CreateProcessAsUser functions, but it will take some time because of priority changes. I will let you know if it worked for me or not.

Thanks,

Klaus

Share this post


Link to post
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
Sign in to follow this  
Followers 0