Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft VBScript Runtime error on Windows #1004

Closed
rakeshdas1 opened this issue Jan 8, 2017 · 16 comments
Closed

Microsoft VBScript Runtime error on Windows #1004

rakeshdas1 opened this issue Jan 8, 2017 · 16 comments

Comments

@rakeshdas1
Copy link

rakeshdas1 commented Jan 8, 2017

  • Etcher v1.0.0-beta.17
  • Windows 10 x64

I am receiving a Microsoft VBScript error when I installed this and ran it on Windows 10, this is the first time that I have encountered this issue. Screenshot of the full error:
image

@jviotti
Copy link
Contributor

jviotti commented Jan 9, 2017

Interesting, thanks for reporting! It seems we have an issue in our VBScript drive detection script: https://github.com/resin-io-modules/drivelist/blob/master/scripts/win32.bat.

I'll look at it today and see if I can find the issue. Its unlikely that I'll be able to reproduce, so I might bother you to confirm my fix :)

BTW, can you actively reproduce? You can try running the script above directly and see if you can still reproduce, so we discard any issue caused by Electron packaging or any interference between the GUI application and the drive detection script.

@rakeshdas1
Copy link
Author

Just to confirm, do you want me to see if I could reproduce the bug by running the bat script or the js script?

1 similar comment
@rakeshdas1
Copy link
Author

Just to confirm, do you want me to see if I could reproduce the bug by running the bat script or the js script?

@jviotti
Copy link
Contributor

jviotti commented Jan 9, 2017

Hi @rakeshdas1 ,

Yeah, if you could do that, it would be awesome! :)

@rakeshdas1
Copy link
Author

Same error, same line!
image

@rakeshdas1
Copy link
Author

Also, just opened up said batch file, and these are the contents.

@jviotti
Copy link
Contributor

jviotti commented Jan 9, 2017

So the issue happens on the Add() method of our custom List class:

Public Sub Add(element)
    Dictionary.Add element, ""
End Sub

This class is used in several places, and Windows doesn't seem to give us a precise stack trace.

Can you try running the following (slightly modified) script? I've added some debugging information which should hopefully help us trace down the issue:

<!-- : Begin batch script
@echo off

:: Ensure System32 is in the PATH, to avoid weird
:: 'cscript' is not recognized as an internal or external command"" errors.
set PATH=%PATH%;%SYSTEMROOT%\System32

cscript //nologo "%~f0?.wsf"
exit /b

----- Begin wsf script --->
<job><script language="VBScript">

Class List
	Private Dictionary

	Private Sub Class_Initialize()
		Set Dictionary = CreateObject("Scripting.Dictionary")
	End Sub

	Public Sub Add(element)		
		Dictionary.Add element, ""
	End Sub

	Public Function GetArray()
		GetArray = Dictionary.Keys()
	End Function

	Public Function Count
		Count = UBound(Dictionary.Keys()) + 1
	End Function
End Class

Set WMIService = GetObject("winmgmts:\\.\root\cimv2")

Function BooleanToString(ByVal Value)
	If Value Then
		BooleanToString = "True"
	Else
		BooleanToString = "False"
	End If
End Function

Function GetOperatingSystemDevice()
	Set OperatingSystemsColumn = WMIService.ExecQuery("SELECT SystemDrive FROM Win32_OperatingSystem")
	Err.Clear
	For Each OperatingSystem in OperatingSystemsColumn
		On Error Resume Next
		GetOperatingSystemDevice = OperatingSystem.Properties_("SystemDrive")
		If Err.Number <> 0 Then
			GetOperatingSystemDevice = Nothing
			Err.Clear
		End If
	Next
End Function

Function GetLogicalDisks(ByVal DriveDevice)
	Wscript.Echo "Created GetLogicalDisks"
	Set GetLogicalDisks = new List
	Set DrivePartitionsColumn = WMIService.ExecQuery _
		("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
			DriveDevice & """} WHERE AssocClass = " & _
				"Win32_DiskDriveToDiskPartition")

	For Each DrivePartition In DrivePartitionsColumn
		Set DriveLogicalDisksColumn = WMIService.ExecQuery _
			("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
				DrivePartition.DeviceID & """} WHERE AssocClass = " & _
					"Win32_LogicalDiskToPartition")

		For Each DriveLogicalDisk In DriveLogicalDisksColumn
			Set LogicalDisk = CreateObject("Scripting.Dictionary")
			LogicalDisk.Add "Device", DriveLogicalDisk.DeviceID
			LogicalDisk.Add "IsProtected", DriveLogicalDisk.Access = 1
			GetLogicalDisks.Add(LogicalDisk)
		Next
	Next
End Function

Function GetTopLevelDrives()
	OperatingSystemDevice = GetOperatingSystemDevice()
	Wscript.Echo "Created GetTopLevelDrives"
	Set GetTopLevelDrives = new List
	Set TopLevelDrivesColumn = WMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")
	For Each TopLevelDrive In TopLevelDrivesColumn
		Set Summary = CreateObject("Scripting.Dictionary")

		DeviceID = Replace(TopLevelDrive.DeviceID, "\", "\\")
		Summary.Add "Device", DeviceID

		Summary.Add "Description", TopLevelDrive.Caption
		Summary.Add "Size", TopLevelDrive.Size

		Wscript.Echo "Created Mountpoints"
		Set Mountpoints = new List
		IsRemovable = InStr(TopLevelDrive.MediaType, "Removable") = 1
		IsProtected = False

		Set LogicalDisks = GetLogicalDisks(DeviceID)

		For Each LogicalDisk In LogicalDisks.GetArray()
			Mountpoints.Add(LogicalDisk.Item("Device"))

			If LogicalDisk.Item("IsProtected") Then
				IsProtected = True
			End If

			If LogicalDisk.Item("Device") = OperatingSystemDevice Then
				IsRemovable = False
			End If
		Next

		Summary.Add "Mountpoints", Mountpoints
		Summary.Add "IsRemovable", IsRemovable
		Summary.Add "IsProtected", IsProtected

		GetTopLevelDrives.Add(Summary)
	Next
End Function

For Each TopLevelDrive In GetTopLevelDrives().GetArray()
	Wscript.Echo "device: """ & TopLevelDrive.Item("Device") & """"
	Wscript.Echo "description: """ & TopLevelDrive.Item("Description") & """"
	Wscript.Echo "size: " & TopLevelDrive.Item("Size")
	Wscript.Echo "raw: """ & TopLevelDrive.Item("Device") & """"
	Wscript.Echo "system: " & BooleanToString(Not TopLevelDrive.Item("IsRemovable"))
	Wscript.Echo "protected: " & BooleanToString(TopLevelDrive.Item("IsProtected"))

	If TopLevelDrive.Item("Mountpoints").Count = 0 Then
		Wscript.Echo "mountpoints: []"
	Else
		Wscript.Echo "mountpoints:"
		For Each Mountpoint In TopLevelDrive.Item("Mountpoints").GetArray()
			Wscript.Echo "	- path: """ & Mountpoint & """"
		Next
	End If

	Wscript.Echo ""
Next
</script></job>

@rakeshdas1
Copy link
Author

@jviotti This was the output:

Created Mountpoints
Created GetLogicalDisks
Created Mountpoints
Created GetLogicalDisks
Created Mountpoints
Created GetLogicalDisks
Created Mountpoints
Created GetLogicalDisks
C:\Users\Rakesh\AppData\Local\Temp\E19D.tmp.bat?.wsf(22, 4) Microsoft VBScript runtime error: This key is already associated with an element of this collection

@jviotti
Copy link
Contributor

jviotti commented Jan 10, 2017

Thanks a lot for the help so far @rakeshdas1. That sadly still doesn't say much :/

Can you try the following new edits?

<!-- : Begin batch script
@echo off

:: Ensure System32 is in the PATH, to avoid weird
:: 'cscript' is not recognized as an internal or external command"" errors.
set PATH=%PATH%;%SYSTEMROOT%\System32

cscript //nologo "%~f0?.wsf"
exit /b

----- Begin wsf script --->
<job><script language="VBScript">

Class List
	Private Dictionary

	Private Sub Class_Initialize()
		Set Dictionary = CreateObject("Scripting.Dictionary")
	End Sub

	Public Sub Add(element)
		Dictionary.Add element, ""
	End Sub

	Public Function GetArray()
		GetArray = Dictionary.Keys()
	End Function

	Public Function Count
		Count = UBound(Dictionary.Keys()) + 1
	End Function
End Class

Set WMIService = GetObject("winmgmts:\\.\root\cimv2")

Function BooleanToString(ByVal Value)
	If Value Then
		BooleanToString = "True"
	Else
		BooleanToString = "False"
	End If
End Function

Function GetOperatingSystemDevice()
	Set OperatingSystemsColumn = WMIService.ExecQuery("SELECT SystemDrive FROM Win32_OperatingSystem")
	Err.Clear
	For Each OperatingSystem in OperatingSystemsColumn
		On Error Resume Next
		GetOperatingSystemDevice = OperatingSystem.Properties_("SystemDrive")
		If Err.Number <> 0 Then
			GetOperatingSystemDevice = Nothing
			Err.Clear
		End If
	Next
End Function

Function GetLogicalDisks(ByVal DriveDevice)
	Wscript.Echo "Created GetLogicalDisks"
	Set GetLogicalDisks = new List
	Set DrivePartitionsColumn = WMIService.ExecQuery _
		("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
			DriveDevice & """} WHERE AssocClass = " & _
				"Win32_DiskDriveToDiskPartition")

	For Each DrivePartition In DrivePartitionsColumn
		Set DriveLogicalDisksColumn = WMIService.ExecQuery _
			("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
				DrivePartition.DeviceID & """} WHERE AssocClass = " & _
					"Win32_LogicalDiskToPartition")

		For Each DriveLogicalDisk In DriveLogicalDisksColumn
			Wscript.Echo "Created LogicalDisk"
			Set LogicalDisk = CreateObject("Scripting.Dictionary")
			Wscript.Echo "Add Device to LogicalDisk"
			LogicalDisk.Add "Device", DriveLogicalDisk.DeviceID
			Wscript.Echo "Add IsProtected to LogicalDisk"
			LogicalDisk.Add "IsProtected", DriveLogicalDisk.Access = 1
			Wscript.Echo "Add LogicalDisk to GetLogicalDisks"
			GetLogicalDisks.Add(LogicalDisk)
		Next
	Next
End Function

Function GetTopLevelDrives()
	OperatingSystemDevice = GetOperatingSystemDevice()
	Wscript.Echo "Created GetTopLevelDrives"
	Set GetTopLevelDrives = new List
	Set TopLevelDrivesColumn = WMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")
	For Each TopLevelDrive In TopLevelDrivesColumn
		Wscript.Echo "Created Summary"
		Set Summary = CreateObject("Scripting.Dictionary")

		DeviceID = Replace(TopLevelDrive.DeviceID, "\", "\\")
		Wscript.Echo "Add Device to Summary"
		Summary.Add "Device", DeviceID

		Wscript.Echo "Add Description to Summary"
		Summary.Add "Description", TopLevelDrive.Caption
		Wscript.Echo "Add Size to Summary"
		Summary.Add "Size", TopLevelDrive.Size

		Wscript.Echo "Created Mountpoints"
		Set Mountpoints = new List
		IsRemovable = InStr(TopLevelDrive.MediaType, "Removable") = 1
		IsProtected = False

		Set LogicalDisks = GetLogicalDisks(DeviceID)

		For Each LogicalDisk In LogicalDisks.GetArray()
			Wscript.Echo "Add LogicalDisk Device to Mountpoints"
			Mountpoints.Add(LogicalDisk.Item("Device"))

			If LogicalDisk.Item("IsProtected") Then
				IsProtected = True
			End If

			If LogicalDisk.Item("Device") = OperatingSystemDevice Then
				IsRemovable = False
			End If
		Next

		Wscript.Echo "Add Mountpoints to Summary"
		Wscript.Echo "Add IsRemovable to Summary"
		Wscript.Echo "Add IsProtected to Summary"
		Summary.Add "Mountpoints", Mountpoints
		Summary.Add "IsRemovable", IsRemovable
		Summary.Add "IsProtected", IsProtected

		Wscript.Echo "Add Summary to GetTopLevelDrives"
		GetTopLevelDrives.Add(Summary)
	Next
End Function

For Each TopLevelDrive In GetTopLevelDrives().GetArray()
	Wscript.Echo "device: """ & TopLevelDrive.Item("Device") & """"
	Wscript.Echo "description: """ & TopLevelDrive.Item("Description") & """"
	Wscript.Echo "size: " & TopLevelDrive.Item("Size")
	Wscript.Echo "raw: """ & TopLevelDrive.Item("Device") & """"
	Wscript.Echo "system: " & BooleanToString(Not TopLevelDrive.Item("IsRemovable"))
	Wscript.Echo "protected: " & BooleanToString(TopLevelDrive.Item("IsProtected"))

	If TopLevelDrive.Item("Mountpoints").Count = 0 Then
		Wscript.Echo "mountpoints: []"
	Else
		Wscript.Echo "mountpoints:"
		For Each Mountpoint In TopLevelDrive.Item("Mountpoints").GetArray()
			Wscript.Echo "	- path: """ & Mountpoint & """"
		Next
	End If

	Wscript.Echo ""
Next
</script></job>

I added way more debugging information on that one :)

@rakeshdas1
Copy link
Author

This is the output:

Created GetTopLevelDrives
Created Summary
Add Device to Summary
Add Description to Summary
Add Size to Summary
Created Mountpoints
Created GetLogicalDisks
Created LogicalDisk
Add Device to LogicalDisk
Add IsProtected to LogicalDisk
Add LogicalDisk to GetLogicalDisks
Add LogicalDisk Device to Mountpoints
Add Mountpoints to Summary
Add IsRemovable to Summary
Add IsProtected to Summary
Add Summary to GetTopLevelDrives
Created Summary
Add Device to Summary
Add Description to Summary
Add Size to Summary
Created Mountpoints
Created GetLogicalDisks
Created LogicalDisk
Add Device to LogicalDisk
Add IsProtected to LogicalDisk
Add LogicalDisk to GetLogicalDisks
Add LogicalDisk Device to Mountpoints
Add Mountpoints to Summary
Add IsRemovable to Summary
Add IsProtected to Summary
Add Summary to GetTopLevelDrives
Created Summary
Add Device to Summary
Add Description to Summary
Add Size to Summary
Created Mountpoints
Created GetLogicalDisks
Created LogicalDisk
Add Device to LogicalDisk
Add IsProtected to LogicalDisk
Add LogicalDisk to GetLogicalDisks
Created LogicalDisk
Add Device to LogicalDisk
Add IsProtected to LogicalDisk
Add LogicalDisk to GetLogicalDisks
Add LogicalDisk Device to Mountpoints
Add LogicalDisk Device to Mountpoints
Add Mountpoints to Summary
Add IsRemovable to Summary
Add IsProtected to Summary
Add Summary to GetTopLevelDrives
Created Summary
Add Device to Summary
Add Description to Summary
Add Size to Summary
Created Mountpoints
Created GetLogicalDisks
Created LogicalDisk
Add Device to LogicalDisk
Add IsProtected to LogicalDisk
Add LogicalDisk to GetLogicalDisks
Created LogicalDisk
Add Device to LogicalDisk
Add IsProtected to LogicalDisk
Add LogicalDisk to GetLogicalDisks
Add LogicalDisk Device to Mountpoints
Add LogicalDisk Device to Mountpoints
C:\Users\Rakesh\AppData\Local\Temp\E19D.tmp.bat?.wsf(22, 4) Microsoft VBScript runtime error: This key is already associated with an element of this collection```

@jviotti
Copy link
Contributor

jviotti commented Jan 11, 2017

Thanks a lot again! So it seems that for some reason, a device has a duplicate mount point coming from Win32_DiskPartition or Win32_LogicalDiskToPartition. Can you relate to this? Have you noticed your PC reporting duplicated drive letters for certain drives?

Here is a new modified script (hopefully the final one). I added extra debugging information to see what is the duplicated letter, and I also fixed the issue, so it should work fine without any errors this time:

<!-- : Begin batch script
@echo off

:: Ensure System32 is in the PATH, to avoid weird
:: 'cscript' is not recognized as an internal or external command"" errors.
set PATH=%PATH%;%SYSTEMROOT%\System32

cscript //nologo "%~f0?.wsf"
exit /b

----- Begin wsf script --->
<job><script language="VBScript">

Class List
	Private Dictionary

	Private Sub Class_Initialize()
		Set Dictionary = CreateObject("Scripting.Dictionary")
	End Sub

	Public Sub Add(element)
		Dictionary.Add element, ""
	End Sub

	Public Function GetArray()
		GetArray = Dictionary.Keys()
	End Function

	Public Function Count
		Count = UBound(Dictionary.Keys()) + 1
	End Function

	' Only works for simple types (e.g: not objects)
	Public Function Has(element)
		Result = False
		For Each Key In Dictionary.Keys()
			If Key = Element Then
				Result = True
			End If
		Next
		Has = Result
	End Function
End Class

Set WMIService = GetObject("winmgmts:\\.\root\cimv2")

Function BooleanToString(ByVal Value)
	If Value Then
		BooleanToString = "True"
	Else
		BooleanToString = "False"
	End If
End Function

Function GetOperatingSystemDevice()
	Set OperatingSystemsColumn = WMIService.ExecQuery("SELECT SystemDrive FROM Win32_OperatingSystem")
	Err.Clear
	For Each OperatingSystem in OperatingSystemsColumn
		On Error Resume Next
		GetOperatingSystemDevice = OperatingSystem.Properties_("SystemDrive")
		If Err.Number <> 0 Then
			GetOperatingSystemDevice = Nothing
			Err.Clear
		End If
	Next
End Function

Function GetLogicalDisks(ByVal DriveDevice)
	Set GetLogicalDisks = new List
	Set DrivePartitionsColumn = WMIService.ExecQuery _
		("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
			DriveDevice & """} WHERE AssocClass = " & _
				"Win32_DiskDriveToDiskPartition")

	Wscript.Echo "DriveDevice: " & DriveDevice

	For Each DrivePartition In DrivePartitionsColumn
		Wscript.Echo "DrivePartition.DeviceID: " & DrivePartition.DeviceID
		Set DriveLogicalDisksColumn = WMIService.ExecQuery _
			("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
				DrivePartition.DeviceID & """} WHERE AssocClass = " & _
					"Win32_LogicalDiskToPartition")

		For Each DriveLogicalDisk In DriveLogicalDisksColumn
			Set LogicalDisk = CreateObject("Scripting.Dictionary")

			Wscript.Echo "DriveLogicalDisk.DeviceID: " & DriveLogicalDisk.DeviceID
			Wscript.Echo "DriveLogicalDisk.Access: " & DriveLogicalDisk.Access
			LogicalDisk.Add "Device", DriveLogicalDisk.DeviceID
			LogicalDisk.Add "IsProtected", DriveLogicalDisk.Access = 1
			GetLogicalDisks.Add(LogicalDisk)
		Next
	Next
End Function

Function GetTopLevelDrives()
	OperatingSystemDevice = GetOperatingSystemDevice()
	Set GetTopLevelDrives = new List
	Set TopLevelDrivesColumn = WMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")
	For Each TopLevelDrive In TopLevelDrivesColumn
		Set Summary = CreateObject("Scripting.Dictionary")

		DeviceID = Replace(TopLevelDrive.DeviceID, "\", "\\")
		Summary.Add "Device", DeviceID

		Summary.Add "Description", TopLevelDrive.Caption
		Summary.Add "Size", TopLevelDrive.Size

		Set Mountpoints = new List
		IsRemovable = InStr(TopLevelDrive.MediaType, "Removable") = 1
		IsProtected = False

		Wscript.Echo "Fetching logical disks"
		Set LogicalDisks = GetLogicalDisks(DeviceID)

		Wscript.Echo "Create Mountpoints List for " & DeviceID
		For Each LogicalDisk In LogicalDisks.GetArray()
			Wscript.Echo "Add LogicalDisk Device: " & LogicalDisk.Item("Device")

			If Mountpoints.Has(LogicalDisk.Item("Device")) Then
				Wscript.Echo "Mountpoint already exists"
			Else
				Wscript.Echo "Mountpoint does not exist"
				Mountpoints.Add(LogicalDisk.Item("Device"))
			End If

			If LogicalDisk.Item("IsProtected") Then
				IsProtected = True
			End If

			If LogicalDisk.Item("Device") = OperatingSystemDevice Then
				IsRemovable = False
			End If
		Next

		Wscript.Echo "Done adding mountpoints"
		Wscript.Echo ""
		Wscript.Echo ""

		Summary.Add "Mountpoints", Mountpoints
		Summary.Add "IsRemovable", IsRemovable
		Summary.Add "IsProtected", IsProtected

		GetTopLevelDrives.Add(Summary)
	Next
End Function

For Each TopLevelDrive In GetTopLevelDrives().GetArray()
	Wscript.Echo "device: """ & TopLevelDrive.Item("Device") & """"
	Wscript.Echo "description: """ & TopLevelDrive.Item("Description") & """"
	Wscript.Echo "size: " & TopLevelDrive.Item("Size")
	Wscript.Echo "raw: """ & TopLevelDrive.Item("Device") & """"
	Wscript.Echo "system: " & BooleanToString(Not TopLevelDrive.Item("IsRemovable"))
	Wscript.Echo "protected: " & BooleanToString(TopLevelDrive.Item("IsProtected"))

	If TopLevelDrive.Item("Mountpoints").Count = 0 Then
		Wscript.Echo "mountpoints: []"
	Else
		Wscript.Echo "mountpoints:"
		For Each Mountpoint In TopLevelDrive.Item("Mountpoints").GetArray()
			Wscript.Echo "  - path: """ & Mountpoint & """"
		Next
	End If

	Wscript.Echo ""
Next
</script></job>

Let me know how that goes, and I'll create a patch with the fix!

@rakeshdas1
Copy link
Author

@jviotti, I did recently change drive letters for two of my drives, I think some symlinks were still left in place and that was causing the issue! Maybe the older drive letters were still left in a cache and still thought they led to a drive when they didn't. Anyways, the script did succeed this time and this was the output in case you are curious:

DriveDevice: \\\\.\\PHYSICALDRIVE0
DrivePartition.DeviceID: Disk #0, Partition #0
DrivePartition.DeviceID: Disk #0, Partition #1
DrivePartition.DeviceID: Disk #0, Partition #2
DriveLogicalDisk.DeviceID: C:
DriveLogicalDisk.Access: 0
Create Mountpoints List for \\\\.\\PHYSICALDRIVE0
Add LogicalDisk Device: C:
Mountpoint does not exist
Done adding mountpoints


Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE2
DrivePartition.DeviceID: Disk #2, Partition #0
DriveLogicalDisk.DeviceID: T:
DriveLogicalDisk.Access: 0
Create Mountpoints List for \\\\.\\PHYSICALDRIVE2
Add LogicalDisk Device: T:
Mountpoint does not exist
Done adding mountpoints


Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE5
Create Mountpoints List for \\\\.\\PHYSICALDRIVE5
Done adding mountpoints


Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE1
DrivePartition.DeviceID: Disk #1, Partition #0
DriveLogicalDisk.DeviceID: D:
DriveLogicalDisk.Access: 0
DrivePartition.DeviceID: Disk #1, Partition #1
DriveLogicalDisk.DeviceID: F:
DriveLogicalDisk.Access: 0
DrivePartition.DeviceID: Disk #1, Partition #2
Create Mountpoints List for \\\\.\\PHYSICALDRIVE1
Add LogicalDisk Device: D:
Mountpoint does not exist
Add LogicalDisk Device: F:
Mountpoint does not exist
Done adding mountpoints


Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE3
DrivePartition.DeviceID: Disk #3, Partition #0
DrivePartition.DeviceID: Disk #3, Partition #1
DriveLogicalDisk.DeviceID: S:
DriveLogicalDisk.Access: 0
DriveLogicalDisk.DeviceID: S:
DriveLogicalDisk.Access: 0
Create Mountpoints List for \\\\.\\PHYSICALDRIVE3
Add LogicalDisk Device: S:
Mountpoint does not exist
Add LogicalDisk Device: S:
Mountpoint already exists
Done adding mountpoints


Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE4
Create Mountpoints List for \\\\.\\PHYSICALDRIVE4
Done adding mountpoints


Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE6
Create Mountpoints List for \\\\.\\PHYSICALDRIVE6
Done adding mountpoints


device: "\\\\.\\PHYSICALDRIVE0"
description: "INTEL SSDPEKKW256G7"
size: 256052966400
raw: "\\\\.\\PHYSICALDRIVE0"
system: True
protected: False
mountpoints:
  - path: "C:"

device: "\\\\.\\PHYSICALDRIVE2"
description: "WDC WD5000AAKS-65A7B2"
size: 500105249280
raw: "\\\\.\\PHYSICALDRIVE2"
system: True
protected: False
mountpoints:
  - path: "T:"

device: "\\\\.\\PHYSICALDRIVE5"
description: "Generic STORAGE DEVICE USB Device"
size:
raw: "\\\\.\\PHYSICALDRIVE5"
system: False
protected: False
mountpoints: []

device: "\\\\.\\PHYSICALDRIVE1"
description: "Samsung SSD 840 EVO 120GB"
size: 120031511040
raw: "\\\\.\\PHYSICALDRIVE1"
system: True
protected: False
mountpoints:
  - path: "D:"
  - path: "F:"

device: "\\\\.\\PHYSICALDRIVE3"
description: "WDC WD6400AAKS-65A7B2"
size: 640132416000
raw: "\\\\.\\PHYSICALDRIVE3"
system: True
protected: False
mountpoints:
  - path: "S:"

device: "\\\\.\\PHYSICALDRIVE4"
description: "Generic STORAGE DEVICE USB Device"
size:
raw: "\\\\.\\PHYSICALDRIVE4"
system: False
protected: False
mountpoints: []

device: "\\\\.\\PHYSICALDRIVE6"
description: "Generic STORAGE DEVICE USB Device"
size:
raw: "\\\\.\\PHYSICALDRIVE6"
system: False
protected: False
mountpoints: []

@jviotti
Copy link
Contributor

jviotti commented Jan 12, 2017

Amazing, looks like S: was the duplicated one:

Fetching logical disks
DriveDevice: \\\\.\\PHYSICALDRIVE3
DrivePartition.DeviceID: Disk #3, Partition #0
DrivePartition.DeviceID: Disk #3, Partition #1
DriveLogicalDisk.DeviceID: S:
DriveLogicalDisk.Access: 0
DriveLogicalDisk.DeviceID: S:
DriveLogicalDisk.Access: 0
Create Mountpoints List for \\\\.\\PHYSICALDRIVE3
Add LogicalDisk Device: S:
Mountpoint does not exist
Add LogicalDisk Device: S:
Mountpoint already exists
Done adding mountpoints

Thanks a lot for your continuous help in debugging and getting this issue fixed, its truly appreciated! I'm going to send a PR to fix this issue very soon.

jviotti pushed a commit to balena-io-modules/drivelist that referenced this issue Jan 12, 2017
We've encountered a case where a different partitions of a single drive
were reported to have the exact same drive letter. This is obviously
weird unexpected behaviour in the first case, which seems to have
accidentally caused while manually fiddling with drive letters (maybe a
Windows bug?).

In any case, the symptom of the issue was the following error:

```
Microsoft VBScript runtime error: This key is already associated with an
element of this collection
```

We have our own `List` data structure based on `Scripting.Dictionary`,
which will complain with the error above if we try to set a key that
already exists.

Checking if an element already exists in the list is sadly not an easy
venture (mainly when dealing with non-scalar types). As a solution,
we've implemented a `Has()` method that only works with scalar types
(for now), and use that to decide whether we add a drive letter to the
list of mount-points or not.

See: balena-io/etcher#1004 (comment)
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
jviotti pushed a commit that referenced this issue Jan 12, 2017
- balena-io-modules/drivelist#130

Change-Type: patch
Changelog-Entry: Fix "This key is already associated with an element of this collection" error when multiple partitions point to the same drive letter on Windows.
Fixes: #1004
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
jviotti pushed a commit that referenced this issue Jan 12, 2017
- balena-io-modules/drivelist#130

Change-Type: patch
Changelog-Entry: Fix "This key is already associated with an element of this collection" error when multiple partitions point to the same drive letter on Windows.
Fixes: #1004
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
@lurch
Copy link
Contributor

lurch commented Jan 13, 2017

Fantastic, great work @jviotti and @rakeshdas1 !

@jviotti
Copy link
Contributor

jviotti commented Jan 13, 2017

I think I should change my LinkedIn title to "VBScript Developer" by now :P

@lurch
Copy link
Contributor

lurch commented Jan 13, 2017

Just as a reminder, I did once suggest using a NodeJS WMI module rather than persevering with VBScript ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants