ignore workstations that are offline and resume - vbscript

I have this VBScript to help me remove local users from the local admins. I can't seem to get it to ignore workstations that are not on the network.
Is there a way to ignore workstations that are not found and have it continue to the next line under the computers.txt file?
For example, say PC1 and PC3 are found but PC2 is not found I want it to ignore not found workstations and continue until the end of the list of computers.
I've tried On Error Resume Next (didnt work), and I tried Const ForReading = 1, Const ForAppending = 8, Const OverwriteExisting = True (didnt work either).
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\adminScript\computers.txt")
strComputer = objFile.ReadLine
Set objGroup = GetObject("WinNT://" & strComputer & "/Administrators")
For Each objUser In objGroup.Members
If objUser.Name <> "Administrator" AND objUser.Name <> "Domain Admins" AND objUser.Name <> "G_SCCMAgent" AND objUser.Name <> "User" Then
Wscript.Echo objUser.Name
objGroup.Remove(objUser.ADsPath)
End If
Next
wscript.Echo "I am done!"

Contrary to popular belief On Error Resume Next doesn't magically make errors go away. Neither does defining symbolic constants for parameters of the OpenTextFile method.
If you want to skip over computers that aren't available you need to actually test the availability of each computer. A common way to do this is the Win32_PingStatus WMI class.
Set wmi = GetObject("winmgmts://./root/cimv2")
isAvailable = False
qry = "SELECT * FROM Win32_PingStatus WHERE Address='" & strComputer & "'"
For Each res In wmi.ExecQuery(qry)
If res.StatusCode = 0 Then isAvailable = True
Next
If isAvailable Then
'modify administrators group
End If
Also, you probably need to process the content of computers.txt in a loop. Your current code reads only the first line. To process more than one line from the file use something like this:
Set objFile = objFSO.OpenTextFile("C:\adminScript\computers.txt")
Do Until objFile.AtEndOfStream
strComputer = objFile.ReadLine
'...
Loop
objFile.Close

Related

Listing printers on remote machines. Not seeing the same results as I would if I were logged on locally as the user

My script is supposed to list all the printers installed on a remote machine and write that data to a text file while designating if the printer is Local or Network. When I run the script against my local machine with my profile logged on I get the following results:
Local
Microsoft XPS Document Writer
Network
\\PrintServer\PT-NJ-CPR-B-CORPIT-1
Network
\\PrintServer\PT-NJ-CPR-B-ITTEMP-1
Network
\\PrintServer\CPR5A26D1A
These results are exactly what I want however when I run the same script against a remote machine I still get results but they seem to be for a more generic user
Local
Send To OneNote 2010
Local
Microsoft XPS Document Writer
Local
Fax
My question is how do I customize my script to truly impersonate the logged on user thus returning me the full results even from a remote machine?
Const ForAppending = 8
Const ForReading = 1
Dim WshNetwork, objPrinter, intDrive, intNetLetter, fso
Set fso = CreateObject("Scripting.FileSystemObject")
Set InputFile = fso.OpenTextFile("C:\xVBS Scripts\Printer Scripts\Computers.txt", 1)
Do Until InputFile.AtEndOfStream
strComputer = InputFile.ReadLine
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")
For Each objItem in colItems
UserName = objItem.UserName
arrUserName = Split(UserName, "\", -1, 1)
varUserName = arrUserName(1)
Next
filOutput = varUserName & ".txt"
If objFSO.FileExists(filOutput) Then
objFSO.DeleteFile(filOutput)
End If
Set objOutputFile = objFSO.OpenTextFile (filOutput, ForAppending, True)
For Each objPrinter in colInstalledPrinters
If objPrinter.Attributes And 64 Then
strPrinterType = "Local"
strTest = Left(objPrinter.Name, 2)
objOutputFile.WriteLine(strPrinterType)
objOutputFile.WriteLine(objPrinter.Name)
objOutputFile.WriteLine(vbNewLine)
Else
strPrinterType = "Network"
strTest = Left(objPrinter.Name, 2)
objOutputFile.WriteLine(strPrinterType)
objOutputFile.WriteLine(objPrinter.Name)
objOutputFile.WriteLine(vbNewLine)
End If
Next
Wscript.Sleep 1500
MsgBox "Printer mapping report is located" & vbNewLine & "in the following directory: " & filOutput , vbInformation, "Report Located At"
WshShell.Run "Notepad " & filOutput,1,False
Loop
InputFile.Close
Wscript.Quit
I dont think there is an actual answer to this. The more I learn about VB Script and Powershell it appears as if WMI is most useful when run interactively. It doesn't know how to process users who are not currently logged in. I bypass this problem by running the script as a GPO Link/Enforced that calls the script as a log on script. – JRN just now edit

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

how to add a log to my vbscript

i have this script that reads a list of computers and check to see if the computers have the right software version install. the script echo to me the computers with the wrong version, but i want to make a log instead
Dim strComputer, objFSO, ObjShell, strDisplayName, objList, strObject
Dim objReg, arrSubKeys, strProduct, strVersion, strReqVersion
Const For_Writing = 2
Const ForReading = 1
const ForAppending = 3
Const HKLM = &H80000002
Const strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
strReqVersion = "8.2.1 MP2"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objList = objFSO.OpenTextFile("c:\test\test.txt",ForReading)
Do While Not objList.AtEndOfStream
strComputer = objList.ReadLine
If HostOnline(strComputer) = True Then
Inventory(strComputer)
End If
Loop
Function Inventory(strComputer)
Set objTextFile = objFSO.OpenTextFile("c:\test\inventory.txt",2,true)
'creating a dictionary object
Set objDictionary = CreateObject("Scripting.Dictionary")
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
' Enumerate the subkeys of the Uninstall key
objReg.EnumKey HKLM, strKeyPath, arrSubKeys
For Each strProduct In arrSubKeys
' Get the product's display name
objReg.GetStringValue HKLM, strKeyPath & "\" & strProduct, "DisplayName", strDisplayName
' Process only products whose name contain 'symantec'
If InStr(1, strDisplayName, "Symantec", vbTextCompare) > 0 Then
' Get the product's display version
objReg.GetStringValue HKLM, strKeyPath & "\" & strProduct, "DisplayVersion", strVersion
If strReqVersion <> strVersion Then
WScript.Echo strObject
objDictionary.Add strComputer, strVersion
For Each strObject In objDictionary
WScript.Echo strObject
objTextFile.WriteLine(strObject)
Next
objTextFile.Close
End If
End If
Next
End Function
Function HostOnline(strComputername)
'---------- Test to see if host or url alive through ping -----------------
' Returns True if Host responds to ping
'
' strComputername is a hostname or IP
Const OpenAsASCII = 0
Const FailIfNotExist = 0
Const ForReading = 1
Dim objShell, objFSO, sTempFile, fFile
Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
sTempFile = objFSO.GetSpecialFolder(2).ShortPath & "\" & objFSO.GetTempName
objShell.Run "cmd /c ping -n 2 -l 8 " & strComputername & ">" & sTempFile, 0 , True
Set fFile = objFSO.OpenTextFile(sTempFile, ForReading, FailIfNotExist, OpenAsASCII)
Select Case InStr(fFile.ReadAll, "TTL=")
Case 0
HostOnline = False
Case Else
HostOnline = True
End Select
ffile.close
objFSO.DeleteFile(sTempFile)
Set objFSO = Nothing
Set objShell = Nothing
End Function
can some one help me please thanks
There are several ways to do this. The simplest way, without any modification to your script, would be to call the script with cscript.exe (in a command prompt) and redirect the output to a file:
cscript your.vbs > output.log
However, if you want a log to be created even when users double-click your script you'll have to change your script so that it writes to a file instead of echoing the output. Open the log file at the beginning of the script:
Set myLog = objFSO.OpenTextFile("C:\my.log", For_Writing, True)
replace WScript.Echo ... with myLog.WriteLine ..., and close the file before you exit from the script:
myLog.Close
A somewhat more sophisticated approach would be to create a set of logging functions, which will allow you create log lines depending on certain conditions, e.g. LogInfo() for informational log messages and LogError() for errors.
Shameless plug: Some time ago I got fed up with writing the same boilerplate logging functions over and over again, so I wrote a logger class that encapsulates the usual logging facilities (interactive console, files, eventlog) and provides logging methods for 4 log levels (Error, Warning, Information, Debug). The class can be used for logging to a file like this:
Set myLog = New CLogger
myLog.LogToConsole = False
myLog.LogFile = "C:\my.log"
myLog.LogInfo "info message"
...
myLog.LogError "an error occurred"
The log file is automatically closed when the object is released.
Why not use the system's event log? I described how in this answer
It means most of the work is done for you and you don't need to worry about where to put your log file

Delete shortcut from remote computers with multiple users

Warning I have zero VB knoeledge
So I found this handy script this morning:
InputFile = "C:\MachineList.Txt"
Const DeleteReadOnly = True
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(InputFile)
Do While Not (objFile.AtEndOfStream)
strComputer = objFile.ReadLine
On Error Resume Next
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFile("\\" & strComputer & "\c$\Documents and Settings\all users\Desktop\Malwarebytes Anti-Malware.LNK")
Err.Clear
Loop
MsgBox "Done"
It did the job great. The problem I am facing is the shortcut is not always under all users or their name lets call it user1
So I would love for it to go through MachineList.txt and browse through all of the profiles searching for Malwarebytes Anti-Malware.LNK. I have seen a few scripts on this but I just cannot wrap my head around VB is a short amount of time. I appreciate any input.
I assume that what you provided results in valid paths... therefore this should work:
InputFile = "C:\MachineList.Txt"
Const DeleteReadOnly = True
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(InputFile)
Do While Not (objFile.AtEndOfStream)
strComputer = objFile.ReadLine
For Each objsubfolder In objFSO.GetFolder("\\" & strComputer & "\c$\Documents and Settings\").subfolders
If objFSO.FileExists(objsubfolder.Path & "\desktop\Malwarebytes Anti-Malware.LNK") Then
objFSO.DeleteFile (objsubfolder.Path & "\desktop\Malwarebytes Anti-Malware.LNK")
End If
'To check another file uncomment this
'Add as many of these as you like here
'If objFSO.FileExists(objsubfolder.Path & "\desktop\Otherfile.LNK") Then
' objFSO.DeleteFile (objsubfolder.Path & "\desktop\Otherfile.LNK")
'End If
Next
Loop
MsgBox "Done"

Resources