Write console output into a file - vbscript

I'm attempting to list a Lenovo computer BIOS settings with a VBScript and write the result into a file. I've came to a point where I can write the stuff into a text file, however it writes in only the first setting (record). How do I write all the settings into one file - one by one?
On Error Resume Next
Dim colItems, fso
Set fso = WScript.CreateObject("Scripting.Filesystemobject")
Set f = fso.CreateTextFile("bios-settings" & ".txt", True)
strComputer = "LOCALHOST"
strOptions
Set objWMIService = GetObject("WinMgmts:" _
&"{ImpersonationLevel=Impersonate}!\\" & strComputer & "\root\wmi")
Set colItems = objWMIService.ExecQuery("Select * from Lenovo_BiosSetting")
For Each objItem In colItems
If Len(objItem.CurrentSetting) > 0 Then
Setting = ObjItem.CurrentSetting
StrItem = Left(ObjItem.CurrentSetting, InStr(ObjItem.CurrentSetting, ",") - 1)
StrValue = Mid(ObjItem.CurrentSetting, InStr(ObjItem.CurrentSetting, ",") + 1, 256)
Set selItems = objWMIService.ExecQuery("Select * from Lenovo_GetBiosSelections")
For Each objItem2 In selItems
objItem2.GetBiosSelections StrItem + ";", strOptions
Next
f.WriteLine StrItem
f.WriteLine " current setting = " + StrValue
f.WriteLine " possible settings = " + strOptions
f.WriteLine
End If
f.Close
Next
This is the part where the actual writing to the file is carried out:
f.WriteLine StrItem
f.WriteLine " current setting = " + StrValue
f.WriteLine " possible settings = " + strOptions
f.WriteLine
It writes the BIOS setting name (StrItem), current setting value (StrValue) and possible setting values (strOptions).

The first thing you need to do is remove the
on error resume next
from your script. This should only be used in specific circumstances to do error handling, not as a way to cut corners for lazy developers.
If you do so you will get an error complaining about not being able to write to a closed file.
That then leads to the actual error, you are closing the file after the first write.
Move the line
f.Close
outside of your for each loop and it will probably work a lot better.

Related

VBScript, Delete Exact String Only

Hi I have the following VBscript to remove printers, however when I run it, it is also deleting just Canon IR70.
Dim aPrinterModels(2)
aPrinterModels(0)="Canon IR70 (Cpoy 1)"
aPrinterModels(1)="Canon IR70 (Cpoy 2)"
aPrinterModels(2)="Canon IR70 (Cpoy 3)"
for each printer in aPrinterModels
RemovePrinterAndPort(printer)
next
Sub RemovePrinterAndPort(strModelMask)
on error resume next
msiMessageTypeError = &H01000000
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
'objWMIService.Security_.Privileges.AddAsString "SeLoadDriverPrivilege", True
Set colInstalledPrinters = objWMIService.ExecQuery("Select * from Win32_Printer where name like'" & strModelMask & "%'")
if colInstalledPrinters.count<>0 then
For each objPrinter in colInstalledPrinters
Set colInstalledPorts = objWMIService.ExecQuery("Select * from Win32_TCPIPPrinterPort where name like '" & objPrinter.PortName & "'")
objPrinter.Delete_
For Each objPort in colInstalledPorts
objPort.Delete_
Next
Next
end if
Set colInstalledPrinters = Nothing
Set colInstalledPorts = nothing
Set objWMIService = Nothing
End Sub
How can I get it to only delete the exact string in aPrinterModels??
Many thanks in advance.
I cannot try wmi query with your scenario and like comparison but I'd use = comparison as follows:
Set colInstalledPrinters = objWMIService.ExecQuery( _
"Select * from Win32_Printer where name = '" & strModelMask & "'")
The code snippet with objPort.Delete execute only on the assumption that ports for copied printer instances differ from original printer port.
In more presumable case of the same port for all printer instances (original and copies): modify code snippet with objPort.Delete to be performed conditionally or suppress it at all and remove unused ports as an independent task:
for each printer in aPrinterModels
RemovePrinter(printer)
next
RemoveUnusedPorts
Sub RemovePrinter(strModelMask)
'on error resume next
msiMessageTypeError = &H01000000
Set objWMIService = GetObject( _
"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colInstalledPrinters = objWMIService.ExecQuery( _
"Select * from Win32_Printer where name = '" & strModelMask & "'")
if colInstalledPrinters.count<>0 then
For each objPrinter in colInstalledPrinters
' wscript.Echo "Printer to Delete " & objPrinter.Name
objPrinter.Delete_
Next
end if
Set colInstalledPrinters = Nothing
Set objWMIService = Nothing
End Sub
Sub RemoveUnusedPorts
' code snippet to remove unused ports here
End Sub

Attempting to extract printers from users machine and then outputting to a text fill.

I am attempting to extract the printers from a users machine and then output to a text file but when I run the test I get a invalid procedure call or argument for this specific line of code.
Set objOutputFile = objFSO.OpenTextFile(outFile, ForAppending, True)
I have attempted to change OpenTextFileto CreateTextFile but I need the lines to appended to file as it will be running as a log on script.
I have done some research and used the Microsoft developer articles to help me debug the issue in the code but I don't have much experience in Visual Basic.
I have added the entire script to give context to the what is going on.
dim objComputerName, ObjNetwork , strText , objfile, StrComputer
dim wshnetwork
Set wshnetwork = CreateObject ("Wscript.network")
StrComputer = WshNetwork.ComputerName
If IsEmpty(StrComputer) Then Wscript.Quit
Set WshNetwork = CreateObject("WScript.Network")
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colInstalledPrinters = objWMIService.ExecQuery("Select * from Win32_Printer")
Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
outFile = "C:\scripts\Printers" & StrComputer
Set objOutputFile = objFSO.OpenTextFile(outFile, ForAppending, True)
For Each objPrinter in colInstalledPrinters
strTest = Left(objPrinter.Name, 2)
objOutputFile.WriteLine(objPrinter.Name)
objfile.close
Next
Set objPrinter = WshNetwork.EnumPrinterConnections
'Set objOutputFile = objFSO.OpenTextFile (filOutput, ForAppending, True)
If objPrinter.Count = 0 Then
WScript.Echo "No Printers Mapped "
else
For intDrive = 0 To (objPrinter.Count -1) Step 2
intNetLetter = IntNetLetter +1
printer = "UNC Path " & objPrinter.Item(intDrive) & " = " & objPrinter.Item(intDrive +1) & " Printer : " & intDrive
objOutputFile.WriteLine(printer)
Next
end if
objOutputFile.Close``*
Invalid procedure call or argument
You passed an invalid parameter in your procedure call. This could be because the parameter was out of range, or contained invalid data. Alternately, you may have invoked a procedure at an unexpected time.
To correct this error
Verify that the parameters being passed to the procedure are valid.
Verify that you are calling the function at an appropriate time.
My guess is this line is an ilegal filename.
outFile = "C:\scripts\Printers" & StrComputer
On my computer this is c:\scripts\PrintersSerenity which is probably not right that your text file is called PrintersSerenity without an extension.

Skipping computers with error

I'm having an issue with a VBScript that looks for printers on computers from a list on an Excel sheet and then finds them through WMI. It matches them through the IP address name and then writes a batch file that I can install them from. My issue is that when I have a computer that is turned off I get a 462 error which is then cleared but then the printers for the previous computer are written again. I'm quite new at this so I'm not sure if I'm just missing something really basic here.
Batch = "printerOutput.txt"
Const ForWriting = 2 'Set to 8 for appending data
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(Batch, ForWriting)
On Error Resume Next
Dim printerDictionary 'Create Printer dictionary of names and IP addresses
Set printerDictionary = CreateObject("Scripting.Dictionary")
printerDictionary.Add "Printer","xxx.xxx.xxx.xxx"
Set objExcel_1 = CreateObject("Excel.Application")
' Statement will open the Excel Workbook needed.
Set objWorkbook = objExcel_1.Workbooks.Open _
("x\p.xls")
If Err.Number <> 0 Then
MsgBox "File not Found"
Wscript.Quit
End If
'Checks for errors
f = 1 'Sets variable that will loop through Excel column
Do
' Msgbox f,, "Begining of Do Loop"
strComputer = objExcel_1.Cells(f, 1).Value
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")
For Each objPrinter in colPrinters 'For ever objPrinter found in the computers WMIService
If Err.Number = 0 Then
objFile.WriteLine Err.Number
If InStr(ObjPrinter.PortName,".") = 4 then 'If the printers IP port name is written like 128.xxx.xxx.xxx
'MsgBox ObjPrinter.Name & " " & ObjPrinter.PortName,, "IfStatement"
PrtDict ObjPrinter.PortName, StrComputer
ElseIf InStr(ObjPrinter.PortName,"_") = 3 Then 'If the printers IP port name is written like IP_128.xxx.xxx.xxx
cleanIP = GetIPAddress(objPrinter.PortName) 'Clean IP
PrtDict cleanIP, StrComputer
End If
Else
objFile.WriteLine "REM " & strComputer & " - Error: " & err.number
Err.Clear
End If
Next
f = f + 1
Loop Until objExcel_1.Cells(f, 1).Value = ""
objExcel_1.ActiveWorkbook.Close
ObjExcel_1.Quit
Function PrtDict(PrtMn, CMP) 'Loops through the dictionary to find a match from the IP address found
For Each x in printerDictionary
'MsgBox PrtMn & "=" & printerDictionary.Item(x),,"InPtrDict"
If printerDictionary.Item(x) = PrtMn Then
objFile.WriteLine "psexec -u \%1 -p %2 " & CMP & " path\" & x & ".bat"
End If
Next
End Function
'100
Function GetIPAddress(Address) 'For cleaning up IP address with names like IP_128.xxx.xxx.xxx
IPtext = InStr(Address,"_")
IPaddress = len(Address) - IPtext
GetIPAddress = Right(Address,IPaddress)
End Function
What happens is this:
On Error Resume Next
This enables error-handling (or rather error suppression) for the rest of the script, since it's never disabled.
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
This command fails, because strComputer is not reachable. Because of the error the variable Err is set and objWMIService retains its previous value.
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")
This command succeeds and re-reads the printer list from the previous computer, because objWMIService still refers to that computer.
For Each objPrinter in colPrinters
The script enters the loop, because colPrinters got populated with the printers from the previous computer (again), …
If Err.Number = 0 Then ... Else ... End If
… but because Err is still set, the script goes into the Else branch, where the error is reported and cleared:
objFile.WriteLine "REM " & strComputer & " - Error: " & err.number
Err.Clear
Then the script goes into the next iteration of the loop. Err is now cleared, so the rest of the printers in colPrinters is being processed normally.
Global On Error Resume Next is the root of all evil. Don't do this. EVER.
If you absolutely must use On Error Resume Next, enable error-handling locally, put some actual error handling code in place, and disable error-handling right afterwards. In your case one might implement it like this:
...
Do
strComputer = objExcel_1.Cells(f, 1).Value
On Error Resume Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
If Err Then
objFile.WriteLine "REM " & strComputer & " - Error: " & err.number
Set objWMIService = Nothing
End If
On Error Goto 0
If Not objWMIService Is Nothing Then
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")
For Each objPrinter in colPrinters
...
Next
f = f + 1
End If
Loop Until objExcel_1.Cells(f, 1).Value = ""
...

VBscript to check for the existance of a file (with the ability to use a wildcard) within a certain time frame

Good morning all,
I have been trying to pull together a VBscript that takes a file path and a file name (that may have a wildcard in it) from the user when the script is exicuted. The script will then check the specified directory for a file that matches the provided file name and then looks at the last modified date to see if it was created/modified within a certain time frame (i.e. 6am plus or minus 5 minutes). It would then copy said file into a zip file.
So far I have been able to get the arguments working, and I have it setup to grab the current time, look at the files in the folder and match a hard coded filename to one in the folder. This is what I have thus far.
currentTime = Now()
filePath = Wscript.Arguments.Item(0)
fileName = Wscript.Arguments.Item(1)
Set fileSystem = CreateObject("Scripting.FileSystemObject")
Set directory = fileSystem.GetFolder(filePath)
For each file in directory.Files
If file.Name = fileName Then
Wscript.echo file.Name & " " & file.DateLastModified
end if
Next
I am a VBscript noob and I am looking forward to learning the way!
Cap3
If you use WMI, it supports wildcards.
Dim strPath
strFile = "*.*"
If WScript.Arguments.Count > 1 Then
strPath = WScript.Arguments.Item(0)
strFile = WScript.Arguments.Item(1)
Elseif WScript.Arguments.Count = 1 Then
strPath = WScript.Arguments.Item(0)
Else
End If
Set objFso = CreateObject("Scripting.FileSystemObject")
If Not objFso.FolderExists(strPath) Then
WScript.Echo "Folder path does not exist."
WScript.Quit
Else
'Remove any trailing slash
If Right(strPath, 1) = "\" Then
strPath = Left(strPath, Len(strPath) - 1)
End If
End If
Set objFso = Nothing
If Not IsNull(strPath) And strPath <> "" Then
strQuery = strPath & "\" & strFile
Else
strQuery = strFile
End If
strQuery = Replace(strQuery, "*", "%")
strQuery = Replace(strQuery, "?", "_")
strQuery = Replace(strQuery, "\", "\\")
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}\\" & strComputer & "\root\cimv2")
Set colFiles = objWMIService.ExecQuery _
("Select * From CIM_DataFile Where FileName Like '" & strQuery & "'")
For Each objFile in colFiles
WScript.Echo "Access mask: " & objFile.AccessMask
WScript.Echo "Archive: " & objFile.Archive
WScript.Echo "Compressed: " & objFile.Compressed
WScript.Echo "Compression method: " & objFile.CompressionMethod
WScript.Echo "Creation date: " & objFile.CreationDate
WScript.Echo "Computer system name: " & objFile.CSName
WScript.Echo "Drive: " & objFile.Drive
WScript.Echo "8.3 file name: " & objFile.EightDotThreeFileName
WScript.Echo "Encrypted: " & objFile.Encrypted
WScript.Echo "Encryption method: " & objFile.EncryptionMethod
WScript.Echo "Extension: " & objFile.Extension
WScript.Echo "File name: " & objFile.FileName
WScript.Echo "File size: " & objFile.FileSize
WScript.Echo "File type: " & objFile.FileType
WScript.Echo "File system name: " & objFile.FSName
WScript.Echo "Hidden: " & objFile.Hidden
WScript.Echo "Last accessed: " & objFile.LastAccessed
WScript.Echo "Last modified: " & objFile.LastModified
WScript.Echo "Manufacturer: " & objFile.Manufacturer
WScript.Echo "Name: " & objFile.Name
WScript.Echo "Path: " & objFile.Path
WScript.Echo "Readable: " & objFile.Readable
WScript.Echo "System: " & objFile.System
WScript.Echo "Version: " & objFile.Version
WScript.Echo "Writeable: " & objFile.Writeable
Next
EDIT..........
You can use a WMI event script with the __InstanceCreationEvent to monitor for new file creation in a specific folder. It looks like this:
strSource = "C:\\somefilepath\\withdoubleshlashes"
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & strComputer & "rootcimv2")
Set colEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE " _
& "Targetinstance ISA 'CIM_DirectoryContainsFile' AND " _
& "TargetInstance.GroupComponent= " _
& "'Win32_Directory.Name=""" & strSource & """'")
Do While True
Set objEvent = colEvents.NextEvent()
copyFile(objEvent.TargetInstance.PartComponent)
Loop
For a full explanation, you can read Monitoring and Archiving Newly Created Files on my blog.
This answer uses Regular Expressions. To make it work it rewrites your pattern format into regular expression format. e.g. *.txt will become ^.*[.]txt$.
The following lists text files in C:\Temp last modified between 5:55 AM and 6:05 AM:
strPath = "C:\Temp"
strFile = "*.txt"
startTime = 555
endTime = 605
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(strPath)
Set files = folder.Files
Set re = New RegExp
re.IgnoreCase = true
re.Pattern = "^" + Replace(Replace(strFile, ".", "[.]"), "*", ".*") + "$"
For Each f in Files
Set matches = re.Execute(f.Name)
If matches.Count > 0 Then
HM = Hour(f.DateLastAccessed) * 100 + Minute(f.DateLastAccessed)
If HM >= startTime And HM <= endTime Then
WScript.Echo f.Name, f.DateLastAccessed
End If
End If
Next
References:
Regular Expression (RegExp) Object
Regular Expressions and Operators
Microsoft Beefs Up VBScript with Regular Expressions
Hey, Scripting Guy! Raising Eyebrows on Regular Expressions
For your example, the easiest way to do this is to use the inStr (In String)function. I find it works in 99% of my wild card tasks. So, in your example, instead of using:
If file.Name = fileName Then
use:
If inStr(file.Name, filename) Then
This doesn't actually allow for wildcards(*) as it won't find a match(with the asterisk in the argument), so you would need to strip the wildcard from the string and replace it with nothing (or just train the user to not use wildcards):
Replace(filename,"*", "")
However, the inStr function does allow for partial or full matches which makes it suitable for most wildcard tasks. Therefore, if your file name is pic.jpg, whether the user searches for:
pic or jpg or p or c or pi etc.
It will return a match. Keep in mind though, that the instr function returns a number where the match shows up in the string. So, if it doesn't create a match, the result will be 0. I've run into examples where NOT doesn't work or I've needed to use the full syntax which in this case would be:
If inStr(file.Name, filename)<>0 Then

VBScript: way to check why the script stopped?

I have this VBScript which runs however, while it is processing, it will randomly stop and require a user to hit the spacebar for it to display the rest of its ongoing output.
How do I figure out why this is happening?
Here is a copy of the script:
'On Error Resume Next
Dim arrFolders()
intSize = 0
Function StampNow()
Dim Hr, Mn, Yr, Mon, Dy, Date1
Date1=Now()
Hr=DatePart("h",Date1)
Mn=DatePart("n",Date1)
Yr = DatePart("yyyy",Date1)
Mon = DatePart("m",Date1)
Dy = DatePart("d",Date1)
StampNow = Yr & "-" & Mon & "-" & Dy
end function
'Output log info.
Function OutputToLog (strToAdd)
Dim strDirectory,strFile,strText, objFile,objFolder,objTextFile,objFSO
strDirectory = "c:\log"
strFile = "\dpadmin_copy2run-"& StampNow & ".bat"
'strText = "dpadmin_copy2"
strText = strToAdd
' Create the File System Object.
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Check that the strDirectory folder exists.
If objFSO.FolderExists(strDirectory) Then
Set objFolder = objFSO.GetFolder(strDirectory)
Else
Set objFolder = objFSO.CreateFolder(strDirectory)
'WScript.Echo "Just created " & strDirectory
End If
If objFSO.FileExists(strDirectory & strFile) Then
Set objFolder = objFSO.GetFolder(strDirectory)
Else
Set objFile = objFSO.CreateTextFile(strDirectory & strFile)
'Wscript.Echo "Just created " & strDirectory & strFile
End If
set objFile = nothing
set objFolder = nothing
' OpenTextFile Method needs a Const value
' ForAppending = 8 ForReading = 1, ForWriting = 2
Const ForAppending = 8
Set objTextFile = objFSO.OpenTextFile _
(strDirectory & strFile, ForAppending, True)
' Writes strText every time you run this VBScript.
objTextFile.WriteLine(strText)
objTextFile.Close
End Function
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
strFolderName = "D:\1\production\Openjobs"
Set colSubfolders = objWMIService.ExecQuery _
("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _
& "Where AssocClass = Win32_Subdirectory " _
& "ResultRole = PartComponent")
dim diffindates
'Init vars for regex.
Dim retVal, retVal2
Dim Lastprop
Dim objRegExpr 'regex variable
Set objRegExpr = New regexp
Set objRegExprX31 = New regexp
objRegExpr.Pattern = "[0-9][0-9][0-9][0-9][0-9][0-9][A-Z][A-Z][A-Z]"
objRegExprX31.Pattern = "[0-9][0-9][0-9][0-9][0-9][0-9]X31"
objRegExpr.Global = True
objRegExprX31.Global = True
objRegExpr.IgnoreCase = True
objRegExprX31.IgnoreCase = True
'Variables for getting last accessed property.
Dim fs, f
Set fs = CreateObject("Scripting.FileSystemObject")
'Current time vars.
Dim currenttime
currenttime = Now()
ParentFolder = "D:\1\Production\Openjobs\ClosedJobs"
For Each objFolder in colSubfolders
intSize = intSize + 1
retVal = objRegExpr.Test(objFolder.Name)
retVal2 = objRegExprX31.Test(objFolder.Name)
if (retVal OR retVal2 ) then
'set filename to array
strFolderName = objFolder.Name
'Get last modified date.
Set f = fs.GetFolder(objFolder.Name)
Lastprop = f.DateLastModified
'MsgBox(Lastprop)
if ( DateDiff("m", f.DateLastModified, Now()) > 4) then
diffindates = DateDiff("m", f.DateLastModified, Now())
Set objShell = CreateObject("Shell.Application")
Set objCopyFolder = objShell.NameSpace(ParentFolder)
OutputToLog("rem " & f.DateLastModified & ":" & objFolder.Name )
outputtolog("move /Y """ & objFolder.Name & """ " & ParentFolder)
wscript.echo(diffindates & ":" & objFolder.Name & vbCr)
end if
end if
Next
Update
It stops at the line:
Set objTextFile = objFSO.OpenTextFile _
(strDirectory & strFile, ForAppending, True)
with the error Microsoft VBScript runtime error: Permission denied
I'm a little confusd by this. The logfile was only 356kb
I was able to run your script several times without it pausing for input. Run your script with the //X flag to start it in the debugger:
>cscript //nologo //X dpadmin_copy2.vbs"
You should be able to then step through the code.
You can also start putting in wscript.echo trace statements everywhere and see if you can narrow down what it's waiting on.
One thing that's gotten me in the past; If your command console is in QuickEdit mode and you accidentally click anywhere in the console window, the console will hang while it waits for you to press a key.
Well the first step is to remove any global On Error Resume Next statements. Better feedback would come if we could see the script.
You usually get an Permission denied when trying to write to a text file when the text file already has an open handle from some other process or because you have previously opened a handle earlier in you code which you have not closed. I haven't tried this but I don't know why this wouldn't work, you can look at using Handle from Sysinternals (Microsoft) to tell you what process has the open handle for the file. Please see here for a further reference of how to use Handle: http://www.orcsweb.com/blog/post/Closing-open-file-handles.aspx You could also write a second script which runs in a loop to monitor the main script. The second script can verify the first script by doing a WMI Process query which returns only processes that match a defined command line. The second script could then restart the main it stops, alert you, log a file, launch a handle search, etc.

Resources