I have a VBScript which tries to merge data from two CSV files based upon common field. When I am running my script, then I get an error on Line 5 char 1:
Subscript out of range.
The two files which I am trying to merge based upon the value of a common field between the two are in the same folder where script is also placed.
My code is :
'Instatiate FSO.
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Open the CSV file for reading. The file is in the same folder as the script and named csv_sample.csv.
Wscript.Echo "Path " & objFSO.GetParentFolderName(WScript.ScriptFullName)
'Open the store locations file first
Set brandCSV = objFSO.OpenTextFile(objFSO.GetParentFolderName(WScript.ScriptFullName) & "\" & "SizeGuideLookup_test.csv",1,False)
'Set header status to account for the first line as the column headers.
IsHeader = True
'Initialize the var for the output string.
OutRecord = ""
'Read each line of the file.
Wscript.Echo "Starting Brand File loop"
Do Until brandCSV.AtEndOfStream
brandLine = brandCSV.ReadLine
If IsHeader Then
OutTxt = "PIM Size Type,PIM Identifier,Structure Group,PIM Size Groupd Value Lookup,Size Group To Upload" & vbCrLf
IsHeader = False
Else
'parse brandrecord and get brand id
brandLineArray=Split(brandLine,";")
brandBrandId = brandLineArray(0)
' loop through Store Location file and get matching data
foundLocation=false
Set storeLocCSV = objFSO.OpenTextFile(objFSO.GetParentFolderName(WScript.ScriptFullName) & "\" & "SizeGuideMapping.csv",1,False)
Do Until storeLocCSV.AtEndOfStream
outLine=""
storeLine=storeLocCSV.ReadLine
storeLineArray=Split(storeLine,";")
storeBrandId = storeLineArray(0)
'if the brand IDs match, append the brand data to the end of the store data.
If brandBrandId = storeBrandId Then
' match found - ouptut data (specific fields from store Line + brand line)
outLine = outLine & brandLineArray(0)
outLine = outLine & "," & brandLineArray(1)
outLine = outLine & "," & brandLineArray(2)
outLine = outLine & "," & storeLineArray(1)
outLine = outLine & "," & storeLineArray(1)
foundLocation=true
'append created line to end of output text data
OutTxt = OutTxt & outLine & vbCrLf
End If
Loop
'Close the store location file.
storeLocCSV.close
'if we havent found the data, add empty fields to end of line
if foundLocation=false Then
' no locations for this brand - create brand-only record
outLine = brandLineArray(0) & ",,,"
outLine = outLine & "," & brandLineArray(1)
outLine = outLine & "," & brandLineArray(2)
outLine = outLine & "," & storeLineArray(1)
outLine = outLine & "," & storeLineArray(1)
'append created line to end of output text data
OutTxt = OutTxt & outLine & vbCrLf
end if
End If
Loop
'Close the brand file.
brandCSV.Close
'Open the output file for writing.
Set objOutCSV = objFSO.CreateTextFile(objFSO.GetParentFolderName(WScript.ScriptFullName) & "\" & "brandfile.csv",True)
'Write the var OutTxt to the file overwriting existing contents.
objOutCSV.Write OutTxt
'Close the file.
objOutCSV.Close
Set objFSO = Nothing
The line the error occurs on doesn't tally with the source you have provided (guessing that's not all of it) but it's likely the
WScript.Arguments(0)
causing the Subscript out of range error as the script is expecting an argument (WshUnnamed or WshNamed objects) being passed but there doesn't appear to be one at index 0 in the WshArguments collection object.
If the argument is indeed a file path, then you want to be calling it with either wscript.exe or cscript.exe something like this (at a Command Prompt);
cscript.exe /nologo "yourscript.vbs" "C:\some\file\path"
Then when
WScript.Echo "Path " & WScript.Arguments(0)
is called you should get (based off this example)
C:\some\file\path
Useful Links
Arguments Property (WScript Object)
WshArguments Object
If i am right, you want to get the folder path of the executing script.
For this purpose, you don't want to use WScript.Arguments(0) but FSO.GetParentFolderName(WScript.ScriptFullName).
Related
I'm using a piece of software called Chronoscan which uses VBScript.
I am attempting to create and append to a file, which in part is successful. However, I am trying to place an argument based on a child table as to whether or not to export the data.
Firstly I am counting the number of records contained in a table named 'batch' (unique id) and looping this against the record number I am assigning variables, within this loop I have another loop which is doing the same for a child table named 'Grid' again assigning variables. I am then writing these variables to the file. Therefore I am writing a value for the number of records held in the child table for each record held in its parent.
What I actually want to do is to argue against the child table and only write records if it meets my argument.
The child table has a field called SkuType which has 3 possible values M, A or NULL.
My argument needs to be if the child table has a value of M write the record else don't, if the child table does not have a value of M in any of its records relating to it parent then only write the first record from the child table and ignore the remainder.
Please see below example of my code, which works fine for exporting ALL records from the child table.
Dim fso
Dim FilePathName
Dim FilePath
Dim NumDocs
Dim numRows
Dim Station
Dim StationDate
Dim StationTime
Dim StationName
Dim Exp
GridPanel = 1 'first panel
Set Batch = ChronoApp.GetCurrentBatch
CurrentBatchname = Batch.Getname
NumDocs = Batch.GetDocCount
'Set output filename and path here
Station = ChronoApp.GetVariableValue("station_user")
StationDate = Left(ChronoApp.GetVariableValue("station_date_full"), 10)
StationName = ChronoApp.GetVariableValue("station_name")
Set fso = CreateObject("Scripting.FileSystemObject")
'Loop the batch here
For numDoc = 0 To NumDocs-1
FilePath = "C:\Users\" & Station & "\Google Drive\Driver Scans\ChronoPlans\" &_
Left(Batch.GetUserField(numDoc, "Movement Date"),2) &_
Mid(Batch.GetUserField(numDoc, "Movement Date"),4,2) &_
Right(Batch.GetUserField(numDoc, "Movement Date"),2) & "\"
FilePathName = FilePath & StationName & "_" & StationDate & ".CSV"
If Not fso.FolderExists(FilePath) Then FSO.CreateFolder (FilePath) 'create folder if it does not exist
Set inputFile = fso.OpenTextFile(FilePathName, 8, True)
'Get header level fields here
StationTime= Left(ChronoApp.GetVariableValue("station_date_full"), 16)
'Loop grid here
numRows = Batch.GetXgridRowCount (numDoc, GridPanel)
For row = 0 To numRows-1
'Get grid level fields here
SkuType = Batch.GetXgridFieldValue (numDoc, GridPanel, row, "SkuType")
'Get Serial
SKU = Batch.GetXgridFieldValue (numDoc, GridPanel, row, "SKU")
'Write to file here
inputFile.WriteLine(_
Chr(34) & SKU & Chr(34) & "," &_
Chr(34) & StationTime & Chr(34)& "," &_
Chr(34) & SkuType & Chr(34) )
Next 'loop Grid
inputFile.Close
Next 'Loop Batch
'Now cleanup
inputFile.Close
Set inputFile = Nothing
Set fso = Nothing
Ok, so we need to create a GPO that allows our users to only use specific programs.
GPO Location:
User Configuration
Policies
Administrative Templates [...]
System
Run only specified Windows applications
Then setting the GPO to enabled and clicking on List of allowed applications --> Show...
I have created an excel spreadsheet containing the names of all the programs and their associated executable files with other pertinent information so that we can easily organize, add, delete, etc. the executable files that we need to allow our users access to.
This spreadsheet then dumps all the executable files into a text file.
Here is an example of what the text file looks like:
Acrobat.exe
chrome.exe
calc.exe
.
.
.
There are a lot of entries and these are likely subject to change. What I am trying to do is create a script that will take that text file and populate the GPO automatically. I don't care if we have to open the window and then run it, it does not need to run from the task scheduler (although that would be amazing if someone has that code ready). We just need it to populate this ridiculous amount of executable filenames into the fields.
Here is code I found (VBScript) that when run, should populate the fields automatically, however I cannot get it to run in the Group Policy Management Editor (it runs in the windows explorer window instead and ends up searching for some of the files)
' Open the text file, located in the same path as the script
Set objFSO = CreateObject("Scripting.FileSystemObject")
strPath = Mid(Wscript.ScriptFullName, 1, InStrRev(Wscript.ScriptFullName, wscript.ScriptName) -1)
Set objFile = objFSO.OpenTextFile(strPath & "appList.txt")
' Activate the "Show Contents" window with the "List of allowed applications".
' Note the window must be opened already and we should have selected where in
' the list we want to enter the data before running the script
set WshShell = WScript.CreateObject("WScript.Shell")
WScript.Sleep 1000
WshShell.AppActivate "Show Contents"
' Read the file line by line
Do While objFile.AtEndOfStream <> True
' Each line contains one EXE name
exeName = objFile.ReadLine
' Escape forbidden chars { } [ ] ( ) + ^ % ~
exeName = Replace(exeName, "[", "{[}")
exeName = Replace(exeName, "]", "{]}")
exeName = Replace(exeName, "(", "{(}")
exeName = Replace(exeName, ")", "{)}")
exeName = Replace(exeName, "+", "{+}")
exeName = Replace(exeName, "^", "{^}")
exeName = Replace(exeName, "%", "{%}")
exeName = Replace(exeName, "~", "{~}")
' Send the EXE name to the window
WScript.Sleep 100
WshShell.SendKeys exeName
' Move to the next one
WshShell.SendKeys "{TAB}"
Loop
objFile.Close
from: http://blogs.msdn.com/b/alejacma/archive/2011/03/24/how-to-update-quot-run-only-specified-windows-applications-quot-gpo-programmatically-vbscript.aspx
"C:\Windows\System32\GroupPolicy\User\Registry.pol"
Is where my policies are stored. It's a semi text file. Try writing to that file.
Ok, so I tried it many different ways. If anyone is looking for an answer to do this, this is the way I've figured it out and the way I've decided to proceed. I will post all relevant code below.
In Excel, the format of my table is as follows:
(With obviously WAY more entries)
Here is the VBA code I used to turn the data from this file into the proper format for the registry key:
VBA - In Excel
Public Sub ExportToTextFile(FName As String, _
Sep As String, SelectionOnly As Boolean, _
AppendData As Boolean)
Dim WholeLine As String
Dim FNum As Integer
Dim RowNdx As Long
Dim ColNdx As Integer
Dim StartRow As Long
Dim EndRow As Long
Dim StartCol As Integer
Dim EndCol As Integer
Dim CellValue As String
Application.ScreenUpdating = False
On Error GoTo EndMacro:
FNum = FreeFile
StartRow = 2
If SelectionOnly = True Then
With Selection
StartCol = .Cells(2).Column
EndRow = .Cells(.Cells.Count).Row
EndCol = .Cells(2).Column
End With
Else
With ActiveSheet.UsedRange
StartCol = .Cells(2).Column
EndRow = .Cells(.Cells.Count).Row
EndCol = .Cells(2).Column
End With
End If
If AppendData = True Then
Open FName For Append Access Write As #FNum
Else
Open FName For Output Access Write As #FNum
End If
For RowNdx = StartRow To EndRow
WholeLine = ""
For ColNdx = StartCol To EndCol
If Cells(RowNdx, ColNdx).Value = "" Then
CellValue = ""
Else
CellValue = Cells(RowNdx, ColNdx).Value
End If
WholeLine = WholeLine & Chr(34) & CellValue & ".exe" & Chr(34) & "=" & Chr(34) & CellValue & ".exe" & Chr(34) & Sep
Next ColNdx
WholeLine = Left(WholeLine, Len(WholeLine) - Len(Sep))
Print #FNum, WholeLine; ""
Next RowNdx
EndMacro:
On Error GoTo 0
Application.ScreenUpdating = True
Close #FNum
End Sub
Sub PipeExport()
Dim FileName As Variant
Dim Sep As String
FileName = Application.GetSaveAsFilename(InitialFileName:="appList", filefilter:="Text (*.txt),*.txt")
If FileName = False Then
''''''''''''''''''''''''''
' user cancelled, get out
''''''''''''''''''''''''''
Exit Sub
End If
Sep = "|"
If Sep = vbNullString Then
''''''''''''''''''''''''''
' user cancelled, get out
''''''''''''''''''''''''''
Exit Sub
End If
Debug.Print "FileName: " & FileName, "Extension: " & Sep
ExportToTextFile FName:=CStr(FileName), Sep:=CStr(Sep), _
SelectionOnly:=False, AppendData:=False
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
PipeExport
End Sub
The file that is created is appList.txt and its format is the same format as the registry key:
"Acrobat.exe"="Acrobat.exe"
"AcroRd32.exe"="AcroRd32.exe"
Now in your GPO, add a unique program name to the allowed applications list (say test1234.exe) and in your registry editor, go to Edit > Find test1234.exe.
Export that registry key under File > Export. Remove the test1234.exe line and paste in your text file. Then reimport that file and you're done!
I'm taking a scripting class and im having some issues with my script. According to the lab assignment all my syntax is correct. However i keep getting a input past end of file error on line 60,1. I've starred at the program forever and checked all lines letter for letter for quite some time with no luck. Any help would be greatly appreciated. Here is the script.
dim ipAddress(5,3)
ipAddress(0,0)="192.168.10.11"
ipAddress(0,1)="192.168.10.12"
ipAddress(0,2)="192.168.10.13"
ipAddress(0,3)="192.168.10.14"
ipAddress(1,0)="192.168.10.19"
ipAddress(1,1)="192.168.10.20"
ipAddress(1,2)="192.168.10.21"
ipAddress(1,3)="192.168.10.22"
ipAddress(2,0)="192.168.10.27"
ipAddress(2,1)="192.168.10.28"
ipAddress(2,2)="192.168.10.29"
ipAddress(2,3)="192.168.10.30"
ipAddress(3,0)="192.168.10.35"
ipAddress(3,1)="192.168.10.36"
ipAddress(3,2)="192.168.10.37"
ipAddress(3,3)="192.168.10.38"
ipAddress(4,0)="192.168.10.43"
ipAddress(4,1)="192.168.10.44"
ipAddress(4,2)="192.168.10.45"
ipAddress(4,3)="192.168.10.46"
ipAddress(5,0)="192.168.10.51"
ipAddress(5,1)="192.168.10.52"
ipAddress(5,2)="192.168.10.53"
ipAddress(5,3)="192.168.10.54"
const READ = 1
const WRITE = 2
const APPEND = 8
const ASCII = 0
dim fileName
fileName = "IP_Addresses.csv"
dim ipAddrStr
ipAddrStr = ""
dim fso
Set fso = Wscript.CreateObject("Scripting.FileSystemObject")
Set ipFileObj = fso.CreateTextFile(fileName,True,ASCII)
For room = 0 to 5
For computer = 0 to 3
ipAddrSr = CStr(room+100) & "," & CStr(computer+1) & "," ipAddress(room,computer)
& vbCrlf
ipFileObj.write(ipAddrStr)
Next
Next
ipFileObj.close
Set ipFileObj = fso.OpenTextFile(fileName,READ,ASCII)
WScript.Echo ipFileObj.ReadAll **' this is line 60**
ipFileObj.Close
As you don't use "Option Explicit", you get what you deserve: You (try to) concatenate the lines into ipAddrSr but write ipAddrStr to the file. So nothing gets written to the file.
Fix the syntax error and the bad name to:
ipAddrStr = CStr(room+100) & "," & CStr(computer+1) & "," & ipAddress(room,computer) & vbCrlf
Assuming that the file isn't empty, perhaps you need to specify the directory the file is in? I think this can be done either in your script:
fileName = "c:\your_directory\IP_Addresses.csv"
Or if you run it in the command line via cscript...
cscript.exe your.vbs "c:\your_directory\IP_Addresses.csv"
You can check the file size before executing your Echo if you like...
if fileName.size > 0 then
Set ipFileObj = fso.OpenTextFile(fileName,READ,ASCII)
WScript.Echo ipFileObj.ReadAll **' this is line 60**
ipFileObj.Close
else
WScript.Echo = "File was empty"
end if
See details of passing an argument to your script here.
I am using the following VBscript to get the total row count from my csv files. I need help in exporting the returned line count to a csv which will have two columns Name and Count name will be anything and the count is the returned count.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
myFile = objArgs(0)
Set objFile = objFSO.OpenTextFile(myFile,1)
Do Until objFile.AtEndOfLine
line = objFile.Line
objFile.ReadLine
Loop
WScript.Echo "Line count of", myFile , "is", line
The way i would like to call the script would be:
Cscript 'vbscript_name' file_name_to_count 'custom_name' 'export_count.csv'
Thanks
Maybe I not see where is the break, as you only need to create new file and write just 2 lines in, but it w'd be something like this:
Set objFile = objFSO.OpenTextFile(objArgs(2), 2, True)
objFile.WriteLine "Name,Count"
objFile.WriteLine objArgs(1) & "," & line
objFile.Close
And just to become more friendly, here is the whole deal:
Set objArgs = WScript.Arguments
iLinesCount = FileLinesCount(objArgs(0))
DumpResult objArgs(2), objArgs(1), iLinesCount
WScript.Echo "File: " & objArgs(0) & " has " & iLinesCount & " lines"
Function FileLinesCount(strFileName)
With CreateObject("Scripting.FileSystemObject")
With .OpenTextFile(strFileName, 1)
Do Until .AtEndOfStream
Call .ReadLine
Loop
FileLinesCount = .Line
End With
End With
End Function
Sub DumpResult(strFileName, strCustomName, iCount)
With CreateObject("Scripting.FileSystemObject")
With .OpenTextFile(strFileName, 2, True)
.WriteLine "Name,Count"
.WriteLine strCustomName & "," & iCount
End With
End With
End Sub
Also it's good to add error checks for your command line arguments, but I live this simple task to you, cheers!
P.S. I suppose you'll prefer to append your count data to existing file instead of creating new file for each counted source file. If so, you have a very little work on DumpResult function, just need to open the file for appending (ForAppending = 8) and add "header" (column names) only then needs (i.e. when the file is newly created):
' modified version w`d be:
Sub DumpResult(strFileName, strCustomName, iCount)
With CreateObject("Scripting.FileSystemObject")
With .OpenTextFile(strFileName, 8, True)
If .Line = 1 Then ' new empty file
.WriteLine "Name,Count" ' add column names
End If
.WriteLine strCustomName & "," & iCount
End With
End With
End Sub
I have a VBScript that checks for the existence of a file in a directory on a remote machine. I am looking to retrieve the "Product Version" for said file (NOT "File Version"), but I can't seem to figure out how to do that in VBScript.
I'm currently using Scripting.FileSystemObject to check for the existence of the file.
Thanks.
I use a function that is slightly modified from the previous example. The function takes the path and file name and returns the "Product Version"
Function GetProductVersion (sFilePath, sProgram)
Dim FSO,objShell, objFolder, objFolderItem, i
Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FileExists(sFilePath & "\" & sProgram) Then
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(sFilePath)
Set objFolderItem = objFolder.ParseName(sProgram)
Dim arrHeaders(300)
For i = 0 To 300
arrHeaders(i) = objFolder.GetDetailsOf(objFolder.Items, i)
'WScript.Echo i &"- " & arrHeaders(i) & ": " & objFolder.GetDetailsOf(objFolderItem, i)
If lcase(arrHeaders(i))= "product version" Then
GetProductVersion= objFolder.GetDetailsOf(objFolderItem, i)
Exit For
End If
Next
End If
End Function
I've found that the position of the attributes has occasionally changes (not sure why) in XP and Vista so I look for the "product version" attribute and exit the loop once it's found. The commented out line will show all the attributes and a value if available
You can use the Shell.Namespace to get the extended properties on a file, one of which is the Product Version. The GetDetailsOf function should work. You can test with the following code to get an idea:
Dim fillAttributes(300)
Set shell = CreateObject("Shell.Application")
Set folder = shell.Namespace("C:\Windows")
Set file = folder.ParseName("notepad.exe")
For i = 0 to 299
Wscript.Echo i & vbtab & fillAttributes(i) _
& ": " & folder.GetDetailsOf(file, i)
Next
One thing to be aware of:
The extended properties of a file differs between versions of Windows. Hence, the product version index numbers changes based on the version of Windows you are using. You can use the code above to determine what they are. From my testing, I believe they are as follows:
Window XP - 39
Windows Vista - 252
Windows 7 - 268
Windows 2008 R2 SP1 - 271
Windows 2012 R2 - 285
You may also find the following post helpful.
The product version can be retrieved directly with the ExtendedProperty method.
function GetProductVersion(Path)
dim shell, file
set shell = CreateObject("Shell.Application")
const ssfDesktop = 0
set file = shell.Namespace(ssfDesktop).ParseName(Path)
if not (file is nothing) then
GetProductVersion = _
file.ExtendedProperty("System.Software.ProductVersion")
end if
end function
By contrast with a couple of older answers,
This does not require looping over an unknown or arbitrary number of columns with GetDetailsOf.
This uses the canonical name of the property, not the display name. One can also use the FMTID and PID: "{0CEF7D53-FA64-11D1-A203-0000F81FEDEE} 8".
This avoids the need to split the path into directory and name, by starting at the root (desktop) namespace.
' must explicitly declare all variables
Option Explicit
' declare global variables
Dim aFileFullPath, aDetail
' set global variables
aFileFullPath = "C:\Windows\Notepad.exe"
aDetail = "Product Version"
' display a message with file location and file detail
WScript.Echo ("File location: " & vbTab & aFileFullPath & vbNewLine & _
aDetail & ": " & vbTab & fGetFileDetail(aFileFullPath, aDetail))
' make global variable happy. set them free
Set aFileFullPath = Nothing
Set aDetail = Nothing
' get file detail function. created by Stefan Arhip on 20111026 1000
Function fGetFileDetail(aFileFullPath, aDetail)
' declare local variables
Dim pvShell, pvFileSystemObject, pvFolderName, pvFileName, pvFolder, pvFile, i
' set object to work with files
Set pvFileSystemObject = CreateObject("Scripting.FileSystemObject")
' check if aFileFullPath provided exists
If pvFileSystemObject.FileExists(aFileFullPath) Then
' extract only folder & file from aFileFullPath
pvFolderName = pvFileSystemObject.GetFile(aFileFullPath).ParentFolder
pvFileName = pvFileSystemObject.GetFile(aFileFullPath).Name
' set object to work with file details
Set pvShell = CreateObject("Shell.Application")
Set pvFolder = pvShell.Namespace(pvFolderName)
Set pvFile = pvFolder.ParseName(pvFileName)
' in case detail is not detected...
fGetFileDetail = "Detail not detected"
' parse 400 details for given file
For i = 0 To 399
' if desired detail name is found, set function result to detail value
If uCase(pvFolder.GetDetailsOf(pvFolder.Items, i)) = uCase(aDetail) Then
fGetFileDetail = pvFolder.GetDetailsOf(pvFile, i)
End If
Next
' if aFileFullPath provided do not exists
Else
fGetFileDetail = "File not found"
End If
' make local variable happy. set them free
Set pvShell = Nothing
Set pvFileSystemObject = Nothing
Set pvFolderName = Nothing
Set pvFileName = Nothing
Set pvFolder = Nothing
Set pvFile = Nothing
Set i = Nothing
End Function
Wscript.Echo CreateObject("Scripting.FileSystemObject").GetFileVersion("C:\Windows\notepad.exe")