Jump to content

Safely Eject a USB Drive


wraithdu
 Share

Recommended Posts

Have you tested this successfully with Devcon? I was under the impression what you ask cannot be done.

Devcon does work with XP SP2, although the commands are slightly different to what I guessed at earlier.

This is what I did, first I stopped a USB key (F:) using your script

Here is the devcon stuff I tried:

D:\Temp\Manage USB\Devcon\i386>devcon rescan
Scanning for new hardware.
Scanning completed.

Command executed OK, but the USB key did not reappear

Then tried the following:

D:\Temp\Manage USB\Devcon\i386>devcon find usb\*
USB\ROOT_HUB\4&EB80878&0                                    : USB Root Hub
USB\ROOT_HUB20\4&242750EB&0                              : USB Root Hub
USB\VID_0718&PID_0246\07760D952600                        : USB Mass Storage Device 3 matching device(s) found.

D:\Temp\Manage USB\Devcon\i386>devcon enable *pid_0246*
USB\VID_0718&PID_0246\07760D952600                        : Enabled
1 device(s) enabled.

Again the commands appear to execute OK, but no USB key.

This command indicated why the USB key was not appearing

D:\Temp\Manage USB\Devcon\i386>devcon status *pid_0246*
USB\VID_0718&PID_0246\07760D952600
    Name: USB Mass Storage Device
    Device has a problem: 21.
1 matching device(s) found.

Success! ... this command worked, USB key re-appeared in My Computer without me removing and re-inserting the key

D:\Temp\Manage USB\Devcon\i386>devcon restart *pid_0246*
USB\VID_0718&PID_0246\07760D952600                        : Restarted
1 device(s) restarted.

D:\Temp\Manage USB\Devcon\i386>devcon status *pid_0246*
USB\VID_0718&PID_0246\07760D952600
    Name: USB Mass Storage Device
    Driver is running.
1 matching device(s) found.

So using Devcon, in XP SP2 a USB key and perhaps other USB devices can be re-enabled

VW

Edited by VeeDub
Link to comment
Share on other sites

  • 10 months later...
  • 5 months later...
  • 2 months later...

Great job indeed.

I'm testing on XP, works great in your code, but when I make a service from it, I'm not able to make it work. The SINK event does nothing when I direct some text to a file. Is it because of running it as "system" account or what? I will keep trying...

[topic="51913"]Restrict USB Storage usage to group membership[/topic] * [topic="48699"]Using nircmd library[/topic] * Some admin notes

Link to comment
Share on other sites

As I said before, any idea why this code does not work? The file test.txt should have something inside when I have an USB pen connected or disconnected...

#include <Services.au3>
Global $sServiceName = "test"
Global $ServiceName = "test"
$file = FileOpen("c:\temp\test.txt", 2)
$ServicePath = @SystemDir & "\" & @ScriptName

$wmiSink = ObjCreate("WbemScripting.SWbemSink")
ObjEvent($wmiSink , "SINK_")

$Obj_WMIService = ObjGet('winmgmts:\\localhost\root\cimv2')

If Not @error Then
    $obj_WMIService.ExecNotificationQueryAsync($wmiSink, "SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_LogicalDisk'")
    ConsoleWrite("Ready and waiting for changes" & @CRLF)
EndIf

CheckAndInstallService()

Func _Svc_Main()
    While $gServiceStateRunning
        Sleep(1000)
    WEnd
    _Service_Cleanup()
    FileClose($file)
    Exit
EndFunc

Func SINK_OnObjectReady($objLatestevent, $objAsyncContext)
    Switch $objLatestEvent.Path_.Class
        Case "__InstanceCreationEvent"
            FileWriteLine($file, "Creation Event")
        Case "__InstanceDeletionEvent"
            FileWriteLine($file, "Deletion Event")
    EndSwitch
EndFunc

Func CheckAndInstallService()
    ConsoleWrite("start install service")
    If Not _Service_Exists($sServiceName) Then
        InstallService()
    Else
        _Service_Init($sServiceName)
    EndIf
    Sleep(5000)
    _Service_Start($sServiceName)
    Exit
EndFunc

Func InstallService()
    ConsoleWrite("Installing Service, Please Wait" & @CRLF)
    _Service_Create($sServiceName, $ServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_START, $SERVICE_ERROR_IGNORE, '"' & $ServicePath & '"')
EndFunc

[topic="51913"]Restrict USB Storage usage to group membership[/topic] * [topic="48699"]Using nircmd library[/topic] * Some admin notes

Link to comment
Share on other sites

It doesn't work cause your service code is wrong. Study the examples from the service thread and ask any further questions over there. FYI, even once you get that straightened out, I don't know if WMI will work in service mode.

Link to comment
Share on other sites

I have many code working as a service, my newest usb protection uses the new code and runs fine, I was just trying to change it to an event driven mode. WMI does work since I'm also using AD.au3 UDF and I get valid values from "_AD_IsMemberOf". Thanks anyway.

[topic="51913"]Restrict USB Storage usage to group membership[/topic] * [topic="48699"]Using nircmd library[/topic] * Some admin notes

Link to comment
Share on other sites

/edit

Hmm, not sure.

Do some more error checking and logging. Is the file ever created? Are there any errors with the Event calls?

/edit2

FYI, _Service_Start should only be called after InstallService. Unless you really are trying to create an endless loop...

Edited by wraithdu
Link to comment
Share on other sites

Yes, the files get created but they are empty. I've added some debug lines like this:

$wmiSink = ObjCreate("WbemScripting.SWbemSink")

FileWriteLine($file, "objcreate: " & @error)

$obj=ObjEvent($wmiSink , "SINK_")

FileWriteLine($file, "objevent: " & $obj & @error)

$Obj_WMIService = ObjGet('winmgmts:\\localhost\root\cimv2')

FileWriteLine($file, "obj_wmi: " & @error)

I get in the file:

objcreate: 0

objevent: 0

obj_wmi: 0

All seems to work fine, no errors. But the function "SINK_OnObjectReady" doesn't run, I don't know why.

[topic="51913"]Restrict USB Storage usage to group membership[/topic] * [topic="48699"]Using nircmd library[/topic] * Some admin notes

Link to comment
Share on other sites

Sorry, but it seems ExecNotificationQueryAsync does not work in service mode. I ran your code, but it hangs there, and the service manager kills it. If you comment out the line, the service starts, runs, and stops as normal. The code I ended up with:

#NoTrayIcon

#include <Services.au3>
Global $sServiceName = "test"
Global $ServiceName = "test"
$file = FileOpen("c:\temp\test.txt", 1 + 8)
$ServicePath = @ScriptDir & "\" & @ScriptName

$wmiSink = ObjCreate("WbemScripting.SWbemSink")
If Not @error Then FileWriteLine($file, "created sink")
ObjEvent($wmiSink , "SINK_")
If Not @error Then FileWriteLine($file, "set event")

$Obj_WMIService = ObjGet('winmgmts:\\localhost\root\cimv2')

If Not @error Then
    FileWriteLine($file, "got wmi")
;~     $obj_WMIService.ExecNotificationQueryAsync($wmiSink, "SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_LogicalDisk'")
    FileWriteLine($file, "Ready and waiting...")
EndIf

CheckAndInstallService()

Func _Svc_Main()
    FileWriteLine($file, "Service started...")
    While $gServiceStateRunning
        Sleep(1000)
    WEnd
    FileWriteLine($file, "Service stopping...")
    _Service_Cleanup()
    FileWriteLine($file, "Service stopped...")
EndFunc

Func SINK_OnObjectReady($objLatestevent, $objAsyncContext)
    Switch $objLatestEvent.Path_.Class
        Case "__InstanceCreationEvent"
            FileWriteLine($file, "Creation Event")
        Case "__InstanceDeletionEvent"
            FileWriteLine($file, "Deletion Event")
    EndSwitch
EndFunc

Func CheckAndInstallService()
    FileWriteLine($file, "Check and install service")
    If Not _Service_Exists($sServiceName) Then
        InstallService()
    Else
        _Service_Init($sServiceName)
    EndIf
;~     Sleep(5000)
;~     _Service_Start($sServiceName)
    FileClose($file)
    Exit
EndFunc

Func InstallService()
    FileWriteLine($file, "Installing Service, Please Wait")
    _Service_Create($sServiceName, $ServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_START, $SERVICE_ERROR_IGNORE, '"' & $ServicePath & '"')
    _Service_Start($sServiceName)
EndFunc
Link to comment
Share on other sites

When I stop the service, somehow the routine gets called, since after stopping and re-checking test.txt, it gets 2 entries:

objcreate: 0

objevent: 0

obj_wmi: 0

exec_not: 0

in the loop

in the loop

(...)

in the loop

Creation Event

Deletion Event

Creation Event

Deletion Event

It records all events but only when I stop the service I get the notifications... strange uh?

Do you know any API that can monitor drive mount or unmount? Or maybe I can do it in pure AutoIt too instead... Thanks!

Edited by BullGates

[topic="51913"]Restrict USB Storage usage to group membership[/topic] * [topic="48699"]Using nircmd library[/topic] * Some admin notes

Link to comment
Share on other sites

  • 1 month later...

I´m new to AutoIt.

I´m learning the language. It´s great!

In my test with this program I receive the following error:

E:\PPP\Eject USB drive.au3 (274) : ==> Subscript used with non-Array variable.:

ConsoleWrite("Parent DeviceID: " & $res[2] & @CRLF)

ConsoleWrite("Parent DeviceID: " & $res^ ERROR

Can you help me?

I´m in the right place to request thia?

Regards

Roberto.

Link to comment
Share on other sites

Very sorry.

I thought the forum informs about what post I´m talking.

Post: Safely Eject a USB Drive

OS: WinXP Prof SP3

I copied the example in the first post and executed it.

Then ocurred this problem.

I hope this information is all you need.

Thanks.

Link to comment
Share on other sites

  • 3 months later...

@wraithdu

I having issues understanding how this script is to be used whats I come up with so far is this [please bare in mind this is a snippet if you feel the full script would be required I would be more than happy to post] See code under 'Case 3'

Func _mapdrive($DriveLtr, $DrivePath)
    Local $var, $var1, $var2, $var_DrivePath
    $var_DrivePath = _StringBetween($DrivePath, "\\", "\")
    _add_log_line($DrivePath & " " & $var_DrivePath)
    $var = $var_DrivePath[0]
    $var1 = _ping($var, 25)
    If $var1 Then
        ; so now the function will not try to connect to a device that is not present,
        ; make sure your firewall allows ICBM echo requests.
        $var2 = DriveMapAdd($DriveLtr, $DrivePath, 8)
        Switch @error
            Case 1
                _add_log_line("Error! O.M.G Error, An unknown error occured on " & $DrivePath & " trying to be mapped as local drive " & $DriveLtr & " maybe end device is not avilable for mapping")
                $error_code = 1
            Case 2
                _add_log_line("Error! Access Error, Access to the remote share " & $DrivePath & " was denied")
                $error_code = 1
            Case 3
                _add_log_line("Error! Map Drive Error, The device/drive " & $DriveLtr & " is already assigned and will be deleted if possible")
                If DriveGetType($DriveLtr) = "Network" Then
                    DriveMapDel($DriveLtr)
                ElseIf DriveGetType($DriveLtr) = "Removable" Then
                    $drive = StringUpper(StringLeft($DriveLtr, 1))
                    _QueryDrive($drive,True)
                Else
                    _add_log_line("Error! Map Drive Error, The device/drive " & $DriveLtr & " could not be deleted as it a " & DriveGetType($DriveLtr) & " Drive.")
                    Beep(500, 1000)
                EndIf

                $var2 = DriveMapAdd($DriveLtr, $DrivePath, 8)
                If $var2 <> 1 Then
                    _add_log_line("Error! Map Drive Error, The device/drive " & $DriveLtr & " could not be deleted")
                Else
                    $var2 = DriveMapAdd($DriveLtr, $DrivePath, 8)
                EndIf
                $error_code = 1
            Case 4
                _add_log_line("Error! Device Error, Invalid device " & $DriveLtr & " name")
                $error_code = 1
            Case 5
                _add_log_line("Error! Connect to Remote Share Error, Invalid remote share :" & $DrivePath)
                $error_code = 1
            Case 6
                _add_log_line("Error! Password Error for user :" & @UserName & " Invalid password for " & $DriveLtr & $DrivePath)
                $error_code = 1
        EndSwitch
        If $var2 = 1 Then _add_log_line("Completed! Mapped " & $DriveLtr & " to share " & $DrivePath)
    EndIf
EndFunc ;==>_mapdrive

So my question is does this make sense! I wish to use your script to remove removable USB devices that are using conflicting drive assignments which conflict with the logon script when it run.

Thanks in advance for any input..

Edited by PeterAtkin

[topic='115020'] AD Domain Logon Script[/topic]

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...