• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2305
  • Last Modified:

Automation of "RUNAS" command..

Is there a method to run RUNAS command *without* prompting for a password?  I realise that this is a huge security hole by having the password visible in the batch/script which calls the Runas command, but I'm more than willing to accept that given the nature of the problem I'm trying to resolve.

Please note this is tied to a VB question where I am seeking a workaround for this issue there as well.  If someone here beats the VB guys to it, I'll wax that Q.  If they beat ya'll to it, I'll wax this one.  :)


Thank you.
1 Solution
EDStechAuthor Commented:
Unfortunately, I need the capacity do the entire process via a script.  The intervention required in making it a scheduled task isn't going to work... :(

Thank you.
Create a textfile e.g. textfile.txt with only the password in it.

  runas /netonly <all other parameters> < textfile.txt

This should do the trick.
[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

EDStechAuthor Commented:
hendrik999: That doesn't work, it returns invalid password...
With my system it is working. The textfile only contains one line with the password.

Can you tell me the exact command that you are using ?
EDStechAuthor Commented:

echo adminpassword >> password.txt
runas /user:localmachine\administrator net localgroup administrators localmachine\myaccount /add < password.txt

Returns: Invalid user or password.

If I exclude the password.txt, and key in adminpassword by hand, it works fine, so the command is valid.
EDStechAuthor Commented:

echo adminpassword >> password.txt
runas /user:localmachine\administrator net localgroup administrators localmachine\myaccount /add < password.txt

Returns: Invalid user or password.

If I exclude the password.txt, and key in adminpassword by hand, it works fine, so the command is valid.
You did forget the /netonly option.
runas /netonly ...........
Can you try it with this option added.
Also it's better to put the command between quotes (").
So the command would be:
runas /netonly /user:localmachine\administrator "net localgroup administrators localmachine\myaccount /add" < password.txt

Hope this works.
EDStechAuthor Commented:
Odd.  I don't see why /netonly is needed, but testing on this PC here, it works.  My actual machine I'm doing the project on is currently shut down and locked in a desk, but once I pull it out after lunch, I'll see if it makes the difference there too.

I also don't know.
Good luck on the other PC.
EDStechAuthor Commented:
C:\>echo mypassword >> password.txt
C:\>runas /netonly /user:mylocalpc\administrator "cmd.exe" < password.txt
Enter password for mylocalpc\administrator:RUNAS ERROR: Unable to change echo mode


It *did* work on this desktop here, so there's something else afoot on that dang laptop.  I'll keep playing around, maybe grab another one instead.
EDStechAuthor Commented:
Ok, latest development in the ongoing saga...

It's working on the other laptop, BUT... it's not giving admin access to the executed command.

"runas /netonly /user:mylocalpc\administrator "net localgroups mydomain\myuser /add" < password.txt"

Executes successfully, but the command still gets Access Denied from the net command.  This happens if I specify a localdomain or the localpc, doesn't matter.

So, it's not giving access to the command.
EDStechAuthor Commented:
If i issue the command...

runas /user:mylocalpc\administrator "blah blah"

And key the PW in by hand, it works fine.  /Netonly is screwing it up, but the < password.txt doesn't work unless /netonly is present.  Go figure.
I found a possible solution without the use of the /netonly switch.
The disadvantage of this that I'm using a logon script tool called KixTart programmed by someone from Microsoft.
Do you know it ?
From version 3.61 and higher the following code is possible.

run '%WINDIR%\system32\runas.exe /user:localmachine\administrator "net localgroup administrators localmachine\myaccount /add"'

After runas started up KixTart will continue with the code and send the password via SENDKEYS to the runas program.

I tried, but unfortunately I can't get the same functionality with Visual Basic at the moment.

You can download KixTart from this location:
For Windows NT/2000/XP you only need the file KIX32.EXE

How are you doing EDStech.
Any progress on this ?
EDStechAuthor Commented:

Sorry for the delay in getting back to this, I've been busy, and to be frank, I'm also kinda flakey.  :)

I need to re-verify it and make sure, but I think the kixtart thing worked.  And since nobody had any other ideas on this thread or the VB thread I made, we'll call this a winner.

Thanks for your answer.

Fortunately I found a way to perform this code in Visual Basic. In VB the code is send to the command windows much too fast and VB is not waiting until it gets a response.
So therefor I have to build in some wait statements.
Although I do not prefer waiting loops the code works without any problem on several computers I tested it with.

Open VB and create a Form1 and add an extra module Module1 via Project |Add Module
Create a command button on Form1 called Command1

Here is the code.

Private Sub Command1_Click()
  Dim ReturnCode As Long
  strCommand = "net localgroup administrators localmachine\myaccount /add"
  ReturnCode = Shell(Environ$("WINDIR") & "\system32\runas.exe /user:localmachine\administrator " & strCommand, vbNormalFocus)
  Wait 100
  AppActivate ReturnCode
  strPassword = "mypassword~"

  For i = 1 To Len(strPassword)
    Wait 100
    strKey = Mid(strPassword, i, 1)
    SendKeys strKey

End Sub

Option Explicit

Private Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type

Private Const WAIT_ABANDONED& = &H80&
Private Const WAIT_ABANDONED_0& = &H80&
Private Const WAIT_FAILED& = -1&
Private Const WAIT_IO_COMPLETION& = &HC0&
Private Const WAIT_OBJECT_0& = 0
Private Const WAIT_OBJECT_1& = 1
Private Const WAIT_TIMEOUT& = &H102&

Private Const INFINITE = &HFFFF
Private Const ERROR_ALREADY_EXISTS = 183&

Private Const QS_HOTKEY& = &H80
Private Const QS_KEY& = &H1
Private Const QS_MOUSEBUTTON& = &H4
Private Const QS_MOUSEMOVE& = &H2
Private Const QS_PAINT& = &H20
Private Const QS_POSTMESSAGE& = &H8
Private Const QS_SENDMESSAGE& = &H40
Private Const QS_TIMER& = &H10
Private Const QS_MOUSE& = (QS_MOUSEMOVE _
                            Or QS_MOUSEBUTTON)
Private Const QS_INPUT& = (QS_MOUSE _
                            Or QS_KEY)
Private Const QS_ALLEVENTS& = (QS_INPUT _
                            Or QS_POSTMESSAGE _
                            Or QS_TIMER _
                            Or QS_PAINT _
                            Or QS_HOTKEY)
                            Or QS_PAINT _
                            Or QS_TIMER _
                            Or QS_POSTMESSAGE _
                            Or QS_MOUSEBUTTON _
                            Or QS_MOUSEMOVE _
                            Or QS_HOTKEY _
                            Or QS_KEY)

Private Declare Function CreateWaitableTimer Lib "kernel32" _
    Alias "CreateWaitableTimerA" ( _
    ByVal lpSemaphoreAttributes As Long, _
    ByVal bManualReset As Long, _
    ByVal lpName As String) As Long
Private Declare Function OpenWaitableTimer Lib "kernel32" _
    Alias "OpenWaitableTimerA" ( _
    ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal lpName As String) As Long
Private Declare Function SetWaitableTimer Lib "kernel32" ( _
    ByVal hTimer As Long, _
    lpDueTime As FILETIME, _
    ByVal lPeriod As Long, _
    ByVal pfnCompletionRoutine As Long, _
    ByVal lpArgToCompletionRoutine As Long, _
    ByVal fResume As Long) As Long
Private Declare Function CancelWaitableTimer Lib "kernel32" ( _
    ByVal hTimer As Long)
Private Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" ( _
    ByVal hHandle As Long, _
    ByVal dwMilliseconds As Long) As Long
Private Declare Function MsgWaitForMultipleObjects Lib "user32" ( _
    ByVal nCount As Long, _
    pHandles As Long, _
    ByVal fWaitAll As Long, _
    ByVal dwMilliseconds As Long, _
    ByVal dwWakeMask As Long) As Long

Public Sub Wait(lNumberOfMsec As Long)
    Dim ft As FILETIME
    Dim lBusy As Long
    Dim lRet As Long
    Dim dblDelay As Double
    Dim dblDelayLow As Double
    Dim dblUnits As Double
    Dim hTimer As Long
    hTimer = CreateWaitableTimer(0, True, App.EXEName & "Timer")
    If Err.LastDllError = ERROR_ALREADY_EXISTS Then
        ' If the timer already exists, it does not hurt to open it
        ' as long as the person who is trying to open it has the
        ' proper access rights.
        ft.dwLowDateTime = -1
        ft.dwHighDateTime = -1
        lRet = SetWaitableTimer(hTimer, ft, 0, 0, 0, 0)
    End If
    ' Convert the Units to nanoseconds.
    dblUnits = CDbl(&H10000) * CDbl(&H10000)
    dblDelay = CDbl(lNumberOfMsec) * 10000
    ' By setting the high/low time to a negative number, it tells
    ' the Wait (in SetWaitableTimer) to use an offset time as
    ' opposed to a hardcoded time. If it were positive, it would
    ' try to convert the value to GMT.
    ft.dwHighDateTime = -CLng(dblDelay / dblUnits) - 1
    dblDelayLow = -dblUnits * (dblDelay / dblUnits - _
        Fix(dblDelay / dblUnits))
    If dblDelayLow < CDbl(&H80000000) Then
        ' &H80000000 is MAX_LONG, so you are just making sure
        ' that you don't overflow when you try to stick it into
        ' the FILETIME structure.
        dblDelayLow = dblUnits + dblDelayLow
    End If
    ft.dwLowDateTime = CLng(dblDelayLow)
    lRet = SetWaitableTimer(hTimer, ft, 0, 0, 0, False)
        ' QS_ALLINPUT means that MsgWaitForMultipleObjects will
        ' return every time the thread in which it is running gets
        ' a message. If you wanted to handle messages in here you could,
        ' but by calling Doevents you are letting DefWindowProc
        ' do its normal windows message handling---Like DDE, etc.
        lBusy = MsgWaitForMultipleObjects(1, hTimer, False, _
    Loop Until lBusy = WAIT_OBJECT_0
    ' Close the handles when you are done with them.
    CloseHandle hTimer

End Sub


This should hopefully solve your problem completely !!!
Good luck.
EDStechAuthor Commented:
Actually, it's done and gone, I'm packaging up the image as we speak, using the kix method.  ;)

I'll take a look at the VB code when I get some free time, but the Kix method is working fine, and we've got no worries.  My biggest concern with using a batch/script was that the admin password would have to be coded into a plain textfile, but I got around that by simply making the password a command argument in the script and passing the password from the VB exe which runs the Kix stuff.  It's not 100% flawless, but I can safely guarantee we don't have any users here smart enough to see the vulnerability in that problem.  

Thanks again for all the help.
How can I use the runas command to execute as the domain administrator & password the following string, within the login script:

"\\server\shared\MS Office 2003\setuppro.exe" TRANSFORMS="\\server\shared\MS Office 2003\2k3.MST" /qb-

This is what I have tried so far and has not worked:

runas /user:DOMAIN\administrator PASSWORD ""\\server\shared\ms office 2003\setuppro.exe" \""\\ramcnt1\shared\MS Office 2003\setuppro.exe" TRANSFORMS="\\ramcnt1\shared\MS Office 2003\2k3.MST" /qb-""

Thank you,

Featured Post

Take Control of Web Hosting For Your Clients

As a web developer or IT admin, successfully managing multiple client accounts can be challenging. In this webinar we will look at the tools provided by Media Temple and Plesk to make managing your clients’ hosting easier.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now