How can I delete %appdata%, etc.. folders remotely from a txt list of computers? - vbscript

I am trying to delete multiple folders that will be read from a txt file. I am not sure how to get it to loop through the computers in the text file while pulling the currently logged on user. I tried some code but not experience enough to merge it with what I currently have.
I have a working script that deletes folders from a list of computers in a txt file except for the ones with %APPDATA%, etc... which is why I am using vbscript.
Just to note, I am unable to use any software other than what comes installed with Windows 7. This eliminates psexec, etc...
Any help would be greatly appreciated, thanks!
InputFile = "C:\complist.txt"
Const DeleteReadOnly = True
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFile = objFSO.OpenTextFile(InputFile)
Do While Not (objFile.AtEndOfStream)
strComputer = objFile.ReadLine
On Error Resume Next
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFolder("\\" & strComputer & "\c$\test")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%APPDATA%\PGP Corporation")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%LOCALAPPDATA%\PGP Corporation")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%USERPROFILE%\Documents\PGP Corporation")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%ALLUSERSPROFILE%\Application Data\PGP Corporation")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%ALLUSERSPROFILE%\Start Menu\Programs\PGP")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%CommonProgramFiles%\PGP Corporation")
objFSO.DeleteFolder("\\" & strComputer & "\c$\%ProgramFiles%\PGP Corporation")
objFSO.DeleteFolder("\\" & strComputer & "\c$\Windows\System32\config\systemprofile\AppData\Local\PGP Corporation")
Err.clean
Loop
MsgBox "Done"

First and foremost, environment variables don't work in FileSystemObject methods. At all. You need to expand them to actual paths, e.g. like this:
Set sh = CreateObject("WScript.Shell")
dir = sh.ExplandEnvironmentStrings("\\" & strComputer & "\c$\%APPDATA%\PGP Corporation")
objFSO.DeleteFolder dir
Also, the variables are local to the user and system running the script, i.e. the above would resolve %APPDATA% of your user on the system where you run the script, not on the system specified by strComputer. You'd need to read the variables from the registry of the remote host, e.g. like this:
Set reg = GetObject("winmgmts://" & strComputer & "/root/default:StdRegProv")
HKLM = &h80000002
key = "SOFTWARE\Microsoft\Windows\CurrentVersion"
vn = "CommonFilesDir"
rc = reg.GetStringValue(HKLM, key, vn, val)
If rc = 0 Then
commonProgramFiles = val
Else
WScript.Echo "Cannot read value from remote registry (" & rc & ")."
End If
Also, the location where/how some of the variables (specifically %ALLUSERSPROFILE%) are stored in the registry differs across Windows versions. In Windows XP %ALLUSERSPROFILE% is a combination of the 2 registry values ProfilesDirectory and AllUsersProfile, whereas in Windows 7 it's derived from the registry value ProgramData (all located in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList).
And last, but not least, several of your variables are user-specific (namely %APPDATA%, %LOCALAPPDATA% and %USERPROFILE%), so you'd need to process them for each user on the remote host.
An (arguably less precise, but more straightforward) approach would be to read the location of the profile folder from the remote registry and then process all subfolders of that folder on the remote host.
Set reg = GetObject("winmgmts://" & strComputer & "/root/default:StdRegProv")
HKLM = &h80000002
key = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
vn = "ProfilesDirectory"
rc = reg.GetStringValue(HKLM, key, vn, profilesDir)
If rc <> 0 Then
WScript.Echo "Cannot read profiles directory remote registry (" & rc & ")."
WScript.Quit rc
End If
'ugly workaround, b/c %SystemDrive% cannot be determined from the registry
profilesDir = Replace(profilesDir, "%SystemDrive%", "C$")
Set fso = CreateObject("Scripting.FileSystemObject")
For Each sf In fso.GetFolder("\\" & strComputer & "\" & profilesDir).SubFolders
dir = fso.BuildPath(sf.Path, "Documents")
If fso.FolderExists(dir) Then fso.DeleteFolder dir
...
Next

Related

VBS process memory consumption growing over time

I have a VBScript that I run with Windows Script Host. The script reads some stuff from a text file and then launches a desktop shortcut every time a file is added to a certain folder. It starts of at 1.4Mb memory and grows every time I add a file to that folder. Is there a way to solve that? If not, I guess I could have a script that periodically kills the first script and relaunches it? Here is the script:
'- Read some stuff from a file
Set f = CreateObject("Scripting.FileSystemObject").OpenTextFile("D:\Post
Processing Files\Common Files\New Data Folder Watcher\DATA_STORE.txt", 1)
dataStore = replace(f.ReadLine,"Title:","")
f.SkipLine
shortCut = replace(f.ReadLine,"Title:","")
f.Close
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "
{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery("SELECT * FROM
__InstanceCreationEvent WITHIN 5 WHERE " & "Targetinstance ISA
'CIM_DirectoryContainsFile' and " & "TargetInstance.GroupComponent= " &
"'Win32_Directory.Name=" &Chr(34)& dataStore &Chr(34)& "'")
Set objShell = CreateObject("Wscript.Shell")
'- Watch
Do
Set objLatestEvent = colMonitoredEvents.NextEvent
objLatestEvent.TargetInstance.PartComponent
objShell.Run shortCut
'- Delay
WScript.Sleep 120000
Loop
EDIT: Added Set object = Nothing. Process is still growing (a little less though). What else can possibly make it grow?
New code:
'- Read some stuff from a file
Set f = CreateObject("Scripting.FileSystemObject").OpenTextFile("D:\Post
Processing Files\Common Files\New Data Folder Watcher\DATA_STORE.txt", 1)
dataStore = replace(f.ReadLine,"Title:","")
f.SkipLine
shortCut = replace(f.ReadLine,"Title:","")
f.Close
Set f = Nothing
strComputer = "."
' LOOP THROUGH EACH NEWLY ADDED FILE
Do
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE " & "Targetinstance ISA 'CIM_DirectoryContainsFile' and " & "TargetInstance.GroupComponent= " & "'Win32_Directory.Name=" &Chr(34)& dataStore &Chr(34)& "'")
Set objLatestEvent = colMonitoredEvents.NextEvent
Set objShell = CreateObject("Wscript.Shell")
objLatestEvent.TargetInstance.PartComponent
objShell.Run shortCut
'- Delay
WScript.Sleep 120000
'- Clear Memory
Set objLatestEvent = Nothing
Set objShell = Nothing
Set colMonitoredEvents = Nothing
Set objWMIService = Nothing
Loop

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

Starting a process in VBS: path not found

I need to make a simple vbs script to run some process' automatically. I found the following script on microsoft's website. It works fine to run notepad.exe the way the original example shows, but I'm trying to modify it to run myprog.exe. The full path to this program is: C:\myprogdir\myprog.exe
Const SW_NORMAL = 1
strComputer = "."
strCommand = "myprog.exe"
strPath = "C:\myprogdir\"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
' Configure the Notepad process to show a window
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = SW_NORMAL
' Create Notepad process
Set objProcess = objWMIService.Get("Win32_Process")
intReturn = objProcess.Create _
(strCommand, strPath, objConfig, intProcessID)
If intReturn <> 0 Then
Wscript.Echo "Process could not be created." & _
vbNewLine & "Command line: " & strCommand & _
vbNewLine & "Return value: " & intReturn
Else
Wscript.Echo "Process created." & _
vbNewLine & "Command line: " & strCommand & _
vbNewLine & "Process ID: " & intProcessID
End If
I keep getting Return value: 9, which indicates "Path Not Found". However the path is correct. Is there something I'm not getting?
You don't need all that to start a process, you just need the Shell object. Also, be sure to wrap the path of your executable in quotes (in case the path has spaces). Like this:
Option Explicit
Dim shl
Set shl = CreateObject("Wscript.Shell")
Call shl.Run("""C:\myprogdir\myprog.exe""")
Set shl = Nothing
WScript.Quit
Unless the path to your program is included in the system's %PATH% environment variable you need to specify the commandline with the full path to the executable. Specifying the path just as the working directory will not work.
strProgram = "myprog.exe"
strPath = "C:\myprogdir"
Set fso = CreateObject("Scripting.FileSystemObject")
strCommand = fso.BuildPath(strPath, strProgram)
...
intReturn = objProcess.Create(strCommand, strPath, objConfig, intProcessID)
Using the BuildPath method will save you the headaches caused by having to keep track of leading/trailing backslashes.
Note that you need to put double quotes around a path that contains spaces, e.g. like this:
strCommand = Chr(34) & fso.BuildPath(strPath, strProgram) & Chr(34)
As others have already pointed out, there are simpler ways to start a process on the local computer, like Run:
Set sh = CreateObject("WScript.Shell")
sh.Run strCommand, 1, True
or ShellExecute:
Set app = CreateObject("Shell.Application")
app.ShellExecute strCommand, , strPath, , 1
There are some notable differences between Run and ShellExecute, though. The former can be run either synchronously or asynchronously (which means the command either does or doesn't wait for the external program to terminate). The latter OTOH always runs asynchronously (i.e. the method returns immediately without waiting for the external program to terminate), but has the advantage that it can be used to launch programs with elevated privileges when UAC is enabled by specifying the verb "runas" as the 4th argument.
However, these methods only allow for launching processes on the local computer. If you want to be able to launch processes on remote computers you will have to use WMI:
strComputer = "otherhost"
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
See here for more information about WMI connections to remote hosts.

How can I pull the correct data from the HK Current User registry key instead of temp profile information

I am working on a script to pull the value in the key
HKCurrentUser\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Desktop
Currently all it is returning is:
C:\WINDOWS\system32\config\systemprofile\Desktop
When I want/think it should return:
%USERPROFILE%\Desktop
Below is the script that is pulling the infomration from the key and as far as I can tell it should be pulling the correct information. Just wondering if someone can enlighten me as to what I am missing. It also returns the computer name and the logged in username which both return correctly. This is going to be run on quite a few machines remotely.
'These are the constants for the following KEYS'
Const HKClassesRoot = &H80000000 'HKEY_CLASSES_ROOT
Const HKCurrentUser = &H80000001 'HKEY_CURRENT_USER
Const HKLocalMachine = &H80000002 'HKEY_LOCAL_MACHINE
Const HKUsers = &H80000003 'HKEY_USERS
Const HKCurrentConfig = &H80000005 'HKEY_CURRENT_CONFIG
'Setup objects to interact with here'
Set wshShell = WScript.CreateObject("Wscript.Shell")
strComputer = wshShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
Set objNetwork = CreateObject("Wscript.Network")
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Define variable to store the current user and then pull the current user
Dim currentUser
strCurrentUser = objNetwork.UserName
'find the data in the string we want to get the value from'
strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\"
strValueName = "Desktop"
'pull the info and store it in strValue'
objRegistry.GetStringValue HKCurrentUser,strKeyPath,strValueName,strValue
'setup for output of data to the file'
Dim strSpacer
Dim strData
strSpace = "+-------------------------------------------------------------------------------------------------------------------------+"
strData = "| " & strComputer & " == " & strCurrentUser & " == " & strValue & " |"
Dim strFileName
strFileName = "\\server\share\" & strCurrentUser & ".txt"
Set objFile = objFSO.OpenTextFile(strFileName,8,true)
objFile.write vbCrLf & strSpace & vbCrLf
objFile.write strData & vbCrLf
objFile.write strSpace & vbCrLf
'Close file'
objFile.Close
After review I found the answer to my own question. I was reading the registry incorrectly for what I was doing.
strRegkey = "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Desktop"
strDataValue = wshShell.RegRead(strRegKey)
this returns the value stored currently in the key.
I suspect that the environment variable %USERPROFILE% from the registry value gets expanded to the profile of the user running the WMI service (LOCAL SYSTEM). GetStringValue seems to behave the same as GetExpandedStringValue when reading REG_EXPAND_SZ values.

vbscript filesystemobject permission denied

I'm having a problem with Trend OfficeScan Patterns filling up the C:\ drive (no other drives available to change directories) and I'm getting a permission denied error accessing "C:\Program Files\Trend Micro\OfficeScan\PCCSRV\WSS\patterns" running the below script. As I'll be using this script for a few sites, and to make it easy to implement for my colleagues, I don't want to play around adding various permissions.
I tried changing: PatternLocation = (strValue & "WSS\patterns\") to PatternLocation = ("""" & strValue & "WSS\patterns\""") and I get 'Path not found'. Are there any VBScript experts that may be able to recommend an impersonate method to overcome the permissions denied?
' Variable to locate HLM.
const HKEY_LOCAL_MACHINE = &H80000002
Set fso = CreateObject("Scripting.FileSystemObject")
' Checks if the operating system is x86 or x64
Set objShell = CreateObject("WScript.Shell")
osType = objShell.ExpandEnvironmentStrings("%PROCESSOR_ARCHITECTURE%")
' The dot refers to the computer this vbscript has been run on.
strComputer = "."
' Provides connection to the registry.
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_
strComputer & "\root\default:StdRegProv")
' Checks the bit for the operating system
If osType = "x86" Then
' Checks registry for Trend folder path.
strKeyPath = "SOFTWARE\TrendMicro\OfficeScan\Service\Information"
Elseif osType = "AMD64" Then
strKeyPath = "SOFTWARE\Wow6432Node\TrendMicro\OfficeScan\service\Information"
End if
trValueName = "Local_Path"
objReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
' If the registry path is empty it won't install the scheduled task and alert you.
If IsNull(strValue) Then
msgbox("Trend Micro is not installed.")
else
PatternLocation = (strValue & "WSS\patterns\") ' folder to start deleting (subfolders will also be cleaned)
OlderThanDate = DateAdd("d", -2, Date) ''# 2 days (adjust as necessary)
DeleteOldFiles PatternLocation, OlderThanDate
end if
Function DeleteOldFiles(folderName, BeforeDate)
Dim folder, file, fileCollection, folderCollection, subFolder
Set folder = fso.GetFolder(folderName)
Set fileCollection = folder.Files
For Each file In fileCollection
If file.DateLastModified < BeforeDate Then
fso.DeleteFile(file.Path)
End If
Next
Set folderCollection = folder.SubFolders
For Each subFolder In folderCollection
DeleteOldFiles subFolder.Path, BeforeDate
Next
End Function
This is the working script with a few changes for anyone who might find it useful:
'Variable to locate HLM.
const HKEY_LOCAL_MACHINE = &H80000002
Set fso = CreateObject("Scripting.FileSystemObject")
'Checks if the operating system is x86 or x64
Set objShell = CreateObject("WScript.Shell")
osType = objShell.ExpandEnvironmentStrings("%PROCESSOR_ARCHITECTURE%")
'The dot refers to the computer this vbscript has been run on.
strComputer = "."
'Provides connection to the registry.
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_
strComputer & "\root\default:StdRegProv")
'Checks the bit for the operating system
If osType = "x86" Then
'Checks registry for Trend folder path.
strKeyPath = "SOFTWARE\TrendMicro\OfficeScan\Service\Information"
Elseif osType = "AMD64" Then
strKeyPath = "SOFTWARE\Wow6432Node\TrendMicro\OfficeScan\service\Information"
End if
strValueName = "Local_Path"
objReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
'If the registry path is empty it won't install the scheduled task and alert you.
If IsNull(strValue) Then
msgbox("Trend Micro is not installed.")
else
PatternLocation = (strValue & "WSS\patterns") ' folder to start deleting (subfolders will also be cleaned)
'msgbox(PatternLocation)
end if
startFolder = PatternLocation
OlderThanDate = DateAdd("d", -1, Date) ' 1 days
DeleteOldFiles startFolder, OlderThanDate
DeleteEmptyFolders startFolder
Function DeleteOldFiles(folderName, BeforeDate)
Dim folder, file, fileCollection, folderCollection, subFolder
Set folder = fso.GetFolder(folderName)
Set fileCollection = folder.Files
For Each file In fileCollection
If file.DateLastModified < BeforeDate Then
fso.DeleteFile(file.Path)
End If
Next
Set folderCollection = folder.SubFolders
For Each subFolder In folderCollection
DeleteOldFiles subFolder.Path, BeforeDate
Next
End Function
Function DeleteEmptyFolders(foldername)
For Each Folder In fso.GetFolder(foldername).SubFolders
DeleteEmptyFolders(Folder.Path)
If Folder.Files.Count = 0 and Folder.SubFolders.Count = 0 Then
fso.DeleteFolder(Folder.Path)
End If
Next
End Function

Resources