this is the example.
what if the array should be from Mynum1="1" to MyNum100="100"
MyNum1="1"
MyNum2="2"
MyNum3="3"
wat is the best way to declare this.
To iterate through a 100 of these:
Dim myNum(99)
for i = 0 to 99
myNum(i) = i+1
next
for i = 0 to 99
wscript.echo i & " - " & myNum(i)
next
Declare it as an Array:
MyNums = Array("1", "2", "3")
You can access each one with:
foo = MyNums(1)
Which will assign foo to "2".
Technically it is feasible, but it is a very bad practice. You can execute code that is created on the fly with the Execute statement:
Dim i
for i = 1 to 100
Execute "Dim myNum" & i & " : myNum" & i & " = """ & i & """"
' Creates and executes strings like: Dim myNum1 : myNum1 = "1"
next
Again, don't do this if there is any other way, like the use of an array as DesertIvy and ServerGuy showed you.
Related
I do PowerShell not VBScript, so I am a little lost. I am trying to list all mapped drives (drive letter and share path) in a MsgBox. I get a type mismatch error when running the script. If I change "Dim myArray()" to "Dim myArray" I get only one item from the variable.
Set objNetwork = WScript.CreateObject("WScript.Network")
Set colDrives = objNetwork.EnumNetworkDrives
Dim myArray()
For i = 0 to colDrives.Count-1 Step 2
myArray = colDrives.Item(i) & vbTab & colDrives.Item (i + 1)
Next
MsgBox(myArray)
How can I get the data saved to an array, then output to a MsgBox?
The reason why your code doesn't work is because you're creating fixed-size array without an actual size (Dim myArray()), and then try to assign values to that array. In VBScript you must assign values to array positions (myArray(pos) = val), and you cannot append to the built-in arrays (at least not without some additional work).
The most straightforward approach in your case would be the method #Bond suggested. However, you can do this with arrays if you want. You just need a resizable array like this:
ReDim myArray(-1) 'empty array
For i = 0 to colDrives.Count-1 Step 2
ReDim Preserve myArray(UBound(myArray)+1)
myArray(UBound(myArray)) = colDrives.Item(i) & vbTab & colDrives.Item(i+1)
Next
MsgBox Join(myArray, vbNewLine)
or (using an ArrayList), like this:
Set myArray = CreateObject("System.Collections.ArrayList")
For i = 0 to colDrives.Count-1 Step 2
myArray.Add colDrives.Item(i) & vbTab & colDrives.Item(i+1)
Next
MsgBox Join(myArray.ToArray, vbNewLine)
Since the size of the array can already be determined before entering the loop you could also dimension the array with the proper size right away to avoid repeated redimensioning (which tends to perform poorly for VBScript built-in arrays):
ReDim myArray(colDrives.Count \ 2 - 1)
For i = 0 to colDrives.Count-1 Step 2
myArray(i\2) = colDrives.Item(i) & vbTab & colDrives.Item(i+1)
Next
MsgBox Join(myArray, vbNewLine)
Another option would be using a Dictionary:
Set myArray = CreateObject("Scripting.Dictionary")
For i = 0 to colDrives.Count-1 Step 2
myArray(colDrives.Item(i)) = colDrives.Item(i) & vbTab & colDrives.Item(i+1)
Next
MsgBox Join(myArray.Items, vbNewLine)
You can use a string and keep appending (&) to it.
Dim s
For i = 0 To colDrives.Count-1 Step 2
s = s & colDrives.Item(i) & vbTab & colDrives.Item (i + 1) & vbCrLf
Next
MsgBox s
i am trying to execute a vbscript from another vbscript. The think is, i have to pass a dictionary as parameter, but i always get the same error message.
Here is my code so far:
dim objShell
Set objShell = Wscript.CreateObject("WScript.Shell")
dim dicExp
Set dicExp = CreateObject("Scripting.Dictionary")
dic.add 0, 10
objShell.Run "C:\Users\groeschm\Desktop\ODBCAktuell.vbs " & dicString
But i always get this error message:
Error 800A01C2 - Wrong number of arguments of invalid property assignment.
Greetings,
Michael
You cannot pass an object reference to WScript.Shell.Run. See http://msdn.microsoft.com/en-us/library/d5fk67ky(v=vs.84).aspx, it says the command line argument is a string, and nothing else.
You cannot pass a Scripting.Dictionary reference, nor can you encode that reference into the string argument.
It´s as simple as that!
And even if you could, this would be useless because the called VBS does not share the same global scope as the caller code.
You should consider alternatives to Run. You could put the ODBCAktuell.vbs code into a function, and call that instead. Or you consider ExecuteFile or one of the related intrinsics.
(Without knowing what ODBCAktuell.vbs contains, and without knowing what exactly you are trying to accomplish, it is difficult to advise you further than that.)
There is a similar question based on the same brainbug: Create instance for a class(resides in B.vbs) from another .VBS file
The OT's code is messed up. dicString is undefined. It does not throw the error claimed, but an "Object Required", because the dictionary is named dicExp, not dic.
While TheBlastOne is right to state that you can't pass anything except strings via the command line, the wish to communicate other (more complex) types of data is legitimate. Making numbers or dates from command line args is standard procedure. And: wanting to re-use code via some kind of import/using/include mechanism isn't a brainbug but essential for good programming.
A general approach to serialisation (via strings) is JSON, but it's not easy to use it in VBScript (cf).
The starting point(s) for a 'roll your own' approach for simple cases (dictionaries with numbers/scalars/simple strings as keys and values) is trivial:
Stringify:
cscript passdic.vbs
cscript recdic.vbs "1 2 3 4"
1 => 2
3 => 4
passdic.vbs:
Option Explicit
Function d2s(d)
ReDim a(2 * d.Count - 1)
Dim i : i = 0
Dim k
For Each k In d.Keys()
a(i) = k
i = i + 1
a(i) = d(k)
i = i + 1
Next
d2s = Join(a)
End Function
Function qq(s)
qq = """" & s & """"
End Function
Dim d : Set d = CreateObject("Scripting.Dictionary")
d(1) = 2
d(3) = 4
Dim c : c = "cscript recdic.vbs " & qq(d2s(d))
WScript.Echo c
Dim p : Set p = CreateObject("WScript.Shell").Exec(c)
WScript.Echo p.Stdout.ReadAll()
recdic.vbs:
Option Explicit
Function s2d(s)
Set s2d = CreateObject("Scripting.Dictionary")
Dim a : a = Split(s)
Dim i
For i = 0 To UBound(a) Step 2
s2d.Add a(i), a(i + 1)
Next
End Function
Dim d : Set d = s2d(WScript.Arguments(0))
Dim k
For Each k In d.Keys()
WScript.Echo k, "=>", d(k)
Next
Code re-use:
cscript passdic2.vbs
cscript recdic2.vbs
1 => 2
3 => 4
passdic2.vbs
Option Explicit
Function d2s(d)
ReDim a(d.Count - 1)
Dim i : i = 0
Dim k
For Each k In d.Keys()
a(i) = "cd.Add " & k & "," & d(k)
i = i + 1
Next
d2s = "Function cd():Set cd=CreateObject(""Scripting.Dictionary""):" & Join(a, ":") & ":End Function"
End Function
Dim d : Set d = CreateObject("Scripting.Dictionary")
d(1) = 2
d(3) = 4
CreateObject("Scripting.FileSystemObject").CreateTextFile("thedic.inc").Write d2s(d)
Dim c : c = "cscript recdic2.vbs"
WScript.Echo c
Dim p : Set p = CreateObject("WScript.Shell").Exec(c)
WScript.Echo p.Stdout.ReadAll()
thedic.inc
Function cd():Set cd=CreateObject("Scripting.Dictionary"):cd.Add 1,2:cd.Add 3,4:End Function
recdic2.vbs
Option Explicit
ExecuteGlobal CreateObject("Scripting.FileSystemObject").OpenTextFile("thedic.inc").ReadAll()
Dim d : Set d = cd()
Dim k
For Each k In d.Keys()
WScript.Echo k, "=>", d(k)
Next
I have the following XML I am trying to parse:
<host>
<object>
<objectname>Server1</objectname>
<objecttype>host</objecttype>
<location>USA</location>
<fcadapterports>
<port>
<portwwn>1000-0000-CCXX-B2B4</portwwn>
</port>
<port>
<portwwn>1000-0000-AW8D-23AB</portwwn>
</port>
</object>
</host>
So I can get values until I get to the portwwn and I'm in way over my head.
So far I have this -
Set objHosts = objConfigXml.selectNodes("//host/object")
For Each objMap in objHosts
Set objSingle = objMap
objSheet.Cells(iY,1).Value = objSingle.selectSingleNode("objectname").Text
objSheet.Cells(iY,2).Value = objSingle.selectSingleNode("objecttype").Text
objSheet.Cells(iY,3).Value = NEED HELP
objSheet.Cells(iY,4).Value = NEED HELP
objSheet.Cells(iY,5).Value = objSingle.selectSingleNode("location").Text
Next I have to retrieve the multiple values for portwwn and assign those to the next cells in the spreadsheet like objSheet.Cells(iY,3) and objSheet.Cells(iY,4), etc.
This demo script:
Dim sXml : sXml = Join(Array( _
"<host>" _
, " <object>" _
, " <objectname>Server1</objectname>" _
, " <objecttype>host</objecttype>" _
, " <location>USA</location>" _
, " <fcadapterports>" _
, " <port>" _
, " <portwwn>1000-0000-CCXX-B2B4</portwwn>" _
, " </port>" _
, " <port>" _
, " <portwwn>1000-0000-AW8D-23AB</portwwn>" _
, " </port>" _
, " </fcadapterports>" _
, " </object>" _
, "</host>" _
))
Dim sXPath : sXPath = "/host/object/fcadapterports"
Dim objMSXML : Set objMSXML = CreateObject("Msxml2.DOMDocument")
objMSXML.setProperty "SelectionLanguage", "XPath"
objMSXML.async = False
objMSXML.loadXml sXml
If 0 = objMSXML.parseError Then
Dim ndFnd : Set ndFnd = objMSXML.SelectSingleNode(sXPath)
If ndFnd Is Nothing Then
WScript.Echo qq(sXPath), "not found"
Else
WScript.Echo ndFnd.xml
WScript.Echo ndFnd.childNodes(0).tagName, "1", ndFnd.childNodes(0).firstChild.text
WScript.Echo ndFnd.childNodes(1).tagName, "2", ndFnd.childNodes(1).firstChild.text
Dim nCol : nCol = 3
Dim ndChild
For Each ndChild In ndFnd.childNodes
WScript.Echo "col", nCol, ndChild.SelectSingleNode("portwwn").text
nCol = nCol + 1
Next
End If
Else
WScript.Echo objMSXML.parseError.reason
End If
output #1:
End tag 'object' does not match the start tag 'fcadapterports'.
output #2 (after closing the tag):
<fcadapterports>
<port>
<portwwn>1000-0000-CCXX-B2B4</portwwn>
</port>
<port>
<portwwn>1000-0000-AW8D-23AB</portwwn>
</port>
</fcadapterports>
port 1 1000-0000-CCXX-B2B4
port 2 1000-0000-AW8D-23AB
col 3 1000-0000-CCXX-B2B4
col 4 1000-0000-AW8D-23AB
should show
The how and why of error checking to catch blunders like your missing </fcadapterports>
Access to childNodes via index, firstChild, and For Each
Working with extra info - e.g. column numbers - when looping over a (childNodes) collection
Update wrt comments:
This
Set nodeslist = objConfigXml.selectNodes("//host/object/fcadapterports/port")
For i = 0 To nodeslist.Length -1 Step 2
objSheet.Cells(iY,4).Value = nodeslist(i).Text & nodeslist(i+1).text
Next
kind of works with 2 issues:
It puts all the values in a single excel cell (because
objSheet.Cells(iY,4) = ... puts everything each time in
objSheet.Cells(iY,4))
Its not iterating through - its only picking the last value (because
the stepped counted loop is nonsense (and exactly the opposite of
the For Each I proposed))
I'm still tempted to write a disclaimer:
This answer is to be used by programmers, not by copy and paste artist
who ignore all advice.
OTOH, maybe changing the line
WScript.Echo "col", nCol, ndChild.SelectSingleNode("portwwn").text
to
WScript.Echo ndChild.SelectSingleNode("portwwn").text, "should go in objSheet.Cells(iY," & nCol & ").Value"
new output
cscript 22821889.vbs
..
1000-0000-CCXX-B2B4 should go in objSheet.Cells(iY,3).Value
1000-0000-AW8D-23AB should go in objSheet.Cells(iY,4).Value
will help to understand what I meant with "Working with extra info - e.g. column numbers - when looping over a (childNodes) collection"
I am using dictonary in VBscript. I have some problems that I don't understand some of the behaviour:
Dim CmdData
Set CmdData = CreateObject("System.Dictonary")
CmdData.Add "11", "tttzz"
CmdData.Add "sssid", "KRN"
WScript.Echo(" ZZZZZZZZ= " & CmdData.Count) 'It prints zero and not 2
Dim s
s = CmdData.Item("11")
alert(s)
WScript.Echo(s) 'It prints empry box and not tttzz
Dim a, j
a = CmdData.Keys
For j = 0 To CmdData.Count -1
WScript.Echo(" ZZZZZZZZ= " & CmdData.Count)
WScript.Echo(a(j)) ' doesn not print
Next
If (CmdData.Exists("-ad")) Then
'WScript.Echo (" RR ") ' It prints it although not in the dictonary
End If
Thanks
VBScript's Dictionary is "Scripting.Dictionary":
>> set syd = CreateObject("System.Dictionary")
>> syd.add "a",1
>>
Error Number: 429
Error Description: ActiveX component can't create object
>> set scd = CreateObject("Scripting.Dictionary")
>> scd.add "a",1
>> WScript.Echo scd.Count, scd("a")
>>
1 1
I'm working on a project to capture various disk performance metrics using VBScript and would like to use a sub procedure with an object as an argument. In the following code samples the object I'm referring to is objitem.AvgDiskQueueLength which will provide a value for the disk queue length. I haven't found a way to make it work since it is recognized as a string and then doesn't capture the value. My goal is to make it easy for anyone to change the counters that are to be captured by only having to make a change in one location(the procedure call argument). The way I'm going about this may not be the best but I'm open to suggestions. The sub procedure call is below.
PerfCounter "Average Disk Queue Length", "disk_queueLength", "objItem.AvgDiskQueueLength"
The following code is the sub procedure.
Sub PerfCounter(CounterDescription, CounterLabel, CounterObject)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk",,48)
args_index = args_index + 1
arrCriteria = split(command_line_args(args_index),",")
strDriveLetter = UCase(arrCriteria(0))
intCriticalThreshold = arrCriteria(1)
intWarningThreshold = arrCriteria(2)
For Each objItem in colItems
With objItem
WScript.Echo "objitem.name = " & objitem.name
If InStr(objItem.Name, strDriveLetter & ":") > 0 Then
intChrLocation = InStr(objItem.Name, strDriveletter)
strInstanceName = Mid(objItem.Name, intChrLocation, 1)
End If
If strDriveLetter = strInstanceName AND InStr(objItem.Name, strDriveLetter & ":") > 0 Then
If intActiveNode = 1 OR Len(intActiveNode) < 1 Then
WScript.Echo "CounterDescription = " & CounterDescription
WScript.Echo "CounterLabel = " & CounterLabel
WScript.Echo "CounterObject = " & CounterObject
If CInt(CounterOjbect) => CInt(intCriticalThreshold) Then
arrStatus(i) = "CRITICAL: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 2
arrExitCode(i) = intExitCode
ElseIf CInt(CounterOjbect) => CInt(intWarningThreshold) AND CInt(CounterObject) < CInt(intCriticalThreshold) Then
arrStatus(i) = "WARNING: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 1
arrExitCode(i) = intExitCode
Else
arrStatus(i) = "OK: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 0
arrExitCode(i) = intExitCode
End If
Else
PassiveNode CounterDescription, CounterLabel
End If
End If
End With
Next
i = i + 1
ReDim Preserve arrStatus(i)
ReDim Preserve arrTrendData(i)
ReDim Preserve arrExitCode(i)
End Sub
Why cant you do this...
PerfCounter "Average Disk Queue Length", "disk_queueLength", objItem.AvgDiskQueueLength
To pass an object you have to pass an object, not a string. To make this method work as expected you would have to have the object prior to the procedure call, but in your code example it looks like you are trying to pass an object that you don't have. A working example:
Set objFSO = CreateObject("Scripting.FileSystemObject")
UseFileSystemObject objFSO
Sub UseFileSystemObject( objfso)
'Now I can use the FileSystemObject in this procedure.
End Sub
But calling the UseFileSystemObject procedure like this will not work,
UseFileSystemObject "objFSO"
because you are passing in a string not an object.
The only way I can think of to accomplish what you want is to use a select statement to write the appropriate attribute of the object, something like this.
Call PerfCounter "Average Disk Queue Length", "disk_queueLength", "AvgDiskQueueLength"
Sub PerfCounter(CounterDescription, CounterLabel, CounterObjectAttribute)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk",,48)
For Each objItem in colItems
Select Case CounterObjectAttribute
Case "ObjectAttribute1"
Case "ObjectAttribute2"
Case "AvgDiskQueueLength"
Wscript.Echo objItem.AvgDiskQueueLength
End Select
Next
End Sub
So in the select you would have to add a case for each attribute that can be used, but it would allow you to pass a string into the procedure. I might be way off on this, but I don't know how you can pass an object if you don't have the object first.