VBScript - relative path not working - windows

I'm trying to use a relative path to reference a cab file named wsusscn2.cab from a VBscript. For some reason, it's not working. The wsusscn2.cab is located in the same directory as the script. Based on the documentation I've read, this SHOULD work, but doesn't:
Set UpdateSession = CreateObject("Microsoft.Update.Session")
Set UpdateServiceManager = CreateObject("Microsoft.Update.ServiceManager")
Set UpdateService = UpdateServiceManager.AddScanPackageService("Offline Sync Service", "..\wsusscn2.cab")
Set UpdateSearcher = UpdateSession.CreateUpdateSearcher()
WScript.Echo "Searching for updates..." & vbCRLF
UpdateSearcher.ServerSelection = 3 ' ssOthers
UpdateSearcher.ServiceID = UpdateService.ServiceID
Set SearchResult = UpdateSearcher.Search("IsInstalled=0")
Set Updates = SearchResult.Updates
If searchResult.Updates.Count = 0 Then
WScript.Echo "There are no applicable updates."
WScript.Quit
End If
WScript.Echo "List of applicable items on the machine when using wssuscan.cab:" & vbCRLF
For I = 0 to searchResult.Updates.Count-1
Set update = searchResult.Updates.Item(I)
WScript.Echo I + 1 & "> " & update.Title
Next
WScript.Quit
Generates this error: The system cannot find the path specified.

try this:
Set UpdateService = UpdateServiceManager.AddScanPackageService("Offline Sync Service", "../wsusscn2.cab")
but be sure that this cab is in the folder one level above the page you calling for it, that is what you have there.
or if cab in the same folder do it like this:
Set UpdateService = UpdateServiceManager.AddScanPackageService("Offline Sync Service", "wsusscn2.cab")

It appears that the .AddScanPackageService() method does not allow relative paths within it's methods. To repair this, while still maintaining flexible code. You can make the path of the script location via Wscript.ScriptFullName and append it infront of wsussc2.cab. This will maintain the path of the script. So it should work as long as the script and .cab file are together.
Set UpdateService = UpdateServiceManager.AddScanPackageService("Offline Sync Service", Left(WScript.ScriptFullName, InStrRev(WScript.ScriptFullName, "\")) & "wsusscn2.cab")

When I hit this, I wondered if it might've been service permissions vs file location, but nope, just absolute file paths needed.
I used the FileSystemObject's GetAbsolutePathName function to determine the full path, which allows you to throw random relative paths in (like "..\reports\something\blah.cab" or just "local.cab" if you so desire.)
Set fso = CreateObject("Scripting.FileSystemObject")
CabFileArg = Wscript.Arguments(0) ' (cscript updatecheck.vbs wsusscn2.cab)
CabFileAbs = fso.GetAbsolutePathname(CabFileArg)
Then the usual stuff, just using CabFileAbs instead.
Set UpdateSession = CreateObject("Microsoft.Update.Session")
Set UpdateServiceManager = CreateObject("Microsoft.Update.ServiceManager")
Set UpdateService = UpdateServiceManager.AddScanPackageService("Offline CAB", CabFileAbs , 1)
Set UpdateSearcher = UpdateSession.CreateUpdateSearcher()
… etc

Related

Why can't I copy a file to a location using an environment variable?

I have this code that copies outlook PST files, and when used with the full location file path it runs perfectly fine. I've added a method to run %UserProfile% in the first line as this needs to be run in a domain context from GPO and doing it individually is non-feasible. This runs and closes outlook and reopens it at the appropriate time except one thing is amiss.
It is no longer copying the appropriate files. I echoed the initial %userprofile% sections and it is reading the correctly as "drive letter"\users\userprofile. I'm not sure where this is breaking or how to identify it.
'===================BEGIN MODIFY====================================
Set objShell = CreateObject("WScript.Shell")
userProfilePath = objShell.ExpandEnvironmentStrings("%UserProfile%")
'Set the amount of pst-files you want to copy. Start counting at 0!
ReDim pst(1)
'Define the location of each pst-file to backup. Increase the counter!
pst(0) = "%UserProfile%\AppData\Local\Microsoft\Outlook\PST\Outlook Data File - mike.pst"
pst(1) = "%UserProfile%\AppData\Local\Microsoft\Outlook\PST\Archive.pst"
'Define your backup location
BackupPath = "%UserProfile%\Documents\Outlook Backups\"
'Keep old backups? TRUE/FALSE
KeepHistory = FALSE
'Maximum time in milliseconds for Outlook to close on its own
delay = 30000 'It is not recommended to set this below 8000
'Start Outlook again afterwards? TRUE/FALSE
start = TRUE
'===================STOP MODIFY====================================
'Close Outlook
Call CloseOutlook(delay)
'Outlook is closed, so we can start the backup
Call BackupPST(pst, BackupPath, KeepHistory)
'Open Outlook again when desired.
If start = TRUE Then
Call OpenOutlook()
End If
Sub CloseOutlook(delay)
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'If Outlook is running, let it quit on its own.
For Each Process in objWMIService.InstancesOf("Win32_Process")
If StrComp(Process.Name,"OUTLOOK.EXE",vbTextCompare) = 0 Then
Set objOutlook = CreateObject("Outlook.Application")
objOutlook.Quit
WScript.Sleep delay
Exit For
End If
Next
'Make sure Outlook is closed and otherwise force it.
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = 'Outlook.exe'")
For Each objProcess in colProcessList
objProcess.Terminate()
Next
Set objWMIService = Nothing
Set objOutlook = Nothing
set colProcessList = Nothing
End Sub
Sub BackupPST(pst, BackupPath, KeepHistory)
Set fso = CreateObject("Scripting.FileSystemObject")
If KeepHistory = True Then
ArchiveFolder = Year(Now) & "-" & Month(Now) & "-" & Day(Now)
BackupPath = BackupPath & ArchiveFolder & "\"
End If
For Each pstPath in pst
If fso.FileExists(pstPath) Then
fso.CopyFile pstPath, BackupPath, True
End If
Next
Set fso = Nothing
End Sub
Sub OpenOutlook()
Set objShell = CreateObject("WScript.Shell")
objShell.Run "Outlook.exe"
End Sub
When you declared userProfilePath = objShell.ExpandEnvironmentStrings("%UserProfile%"), you put the path of %UserProfile% in the variable named userProfilePath, but afterward you don't use this variable. That's a problem, because a few lines down, what you end up doing is declaring pst(#) with %userprofile% as a string, which doesn't work.
In other words, the %UserProfile% environment path/string needs to be expanded before being used as a path.
Your code would work if you used the userProfilePath variable you declared:
'Define the location of each pst-file to backup. Increase the counter!
pst(0) = userProfilePath+"\AppData\Local\Microsoft\Outlook\PST\Outlook Data File - mike.pst"
pst(1) = userProfilePath+"\AppData\Local\Microsoft\Outlook\PST\Archive.pst"
'Define your backup location
BackupPath = userProfilePath"\Documents\Outlook Backups\"
instead of
'Define the location of each pst-file to backup. Increase the counter!
pst(0) = "%UserProfile%\AppData\Local\Microsoft\Outlook\PST\Outlook Data File - mike.pst"
pst(1) = "%UserProfile%\AppData\Local\Microsoft\Outlook\PST\Archive.pst"
'Define your backup location
BackupPath = "%UserProfile%\Documents\Outlook Backups\"

Use a VBS to edit ini for users %appdata% folder

I have script that edits the a line in the ini file, which sits on users %Appdata% folder i.e C:\Users\<>\AppData\Roaming.
The current script which I have only edits a file pointing to proper file location, but I would like to have script which can edit the file on every logged on users folder
I have a vbs below which look like this , but I am not able to use a variable %appdata% to edit the file under folder when the user is logged on
Const ForReading = 1
Const ForWriting = 2
Dim strUserName, CurrDir
Set objFSO = CreateObject("Scripting.FileSystemObject")
strUserName = InputBox("Please enter your email address below in the following format:" & Vbnewline & "firstname_lastname#test.com" & Vbnewline & Vbnewline & "HINT - If you are unsure, you can look up your name", "Add internet email address")
If strUserName = "" Then
Wscript.Quit
End If
Set objTextFile = objFSO.OpenTextFile("H:\appdata\Linkpoint360\LinkPointConfig.ini", ForReading)
Do Until objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
intLineFinder = InStr(strNextLine, "UserEMailAddress")
If intLineFinder <> 0 Then
strNextLine = "UserEMailAddress=" & strUserName
End If
strNewFile = strNewFile & strNextLine & VbCrLf
Loop
objTextFile.Close
Set objTextFile = objFSO.OpenTextFile("H:\appdata\Linkpoint360\LinkPointConfig.ini", ForWriting)
objTextFile.WriteLine strNewFile
objTextFile.Close
I am not scripting expert, but I have tried best to find a suitable solution over the internet and I have no luck
If someone can please edit this vbs and give a proper script, that will be really appreciated
# Ansgar Wiechers, can't post the image as i don't have 10 repuataion, but here is what I get in pop box:
Script: << Location of file >>
Line: 13
Char: 1
Error: Path not found
Code: 800A004C
Scource: Microsoft VBScript runtime error
the error I get when is use %appdata% in my script.
from the above code I have just edited file location "H:\appdata...." to "%appdata%....."
FileSystemObject methods don't expand environment variables. You need to do it yourself, e.g. like this:
...
Set sh = CreateObject("WScript.Shell")
config = sh.ExpandEnvironmentStrings("%APPDATA%\Linkpoint360\LinkPointConfig.ini")
Set objTextFile = objFSO.OpenTextFile(config, ForReading)
...
You can't reliabily do this in vbscript.
However you can make a safe assumption (disregarding network and profile updating issues that I don't think will matter) that profiles are under Users folder and each user will have the same relative path to AppFolder.
The normal way of handling this problem type is to use logon scripts.

Changing name of directory containing read-only files

I am trying to get this script to work, it gets 4 arguments and ends renaming the the folder (FDirectory) removing spaces and starting a batch file with the new arguments. The problem is that it returns an error "access denied" for folders containing read-only files. Is there a way to get this to work? Thanks in advance.
Set WshShell = CreateObject("WScript.Shell")
currentDirectory = left(WScript.ScriptFullName,(Len(WScript.ScriptFullName))-(len(WScript.ScriptName)))
length = Len(currentDirectory)
State = WScript.Arguments.item(0)
Directory = Left(WScript.Arguments.item(1),length+6)
FDirectory = Replace(WScript.Arguments.item(1)," ",".")
Kind = WScript.Arguments.item(2)
Message = WScript.Arguments.item(3)
'change folder name
If (kind = "multi") And (Directory = currentDirectory & "SFetch") then
Set FS = CreateObject("Scripting.FileSystemObject")
FS.MoveFolder WScript.Arguments.item(1),Replace(WScript.Arguments.item(1)," ",".")
END IF
currentDirectory = currentDirectory & "Rename.bat "
WshShell.RUN currentDirectory & State & " " & Directory & " " & FDirectory & " " & Kind & " " & Message, 0, True
Set WshShell = Nothing
Read-only files don't create an issue - but renaming a folder with open files inside it, or renaming the current working directory will create problems.

VBS script 'Path not found' error when setting file system folder object reference

I am writing a script to determine the combined size of all instances of a particular subfolder within the profile folder of each user who has logged onto a Windows 2003 server, e.g. all users' desktop folders or all users' local settings folders.
Option Explicit
Dim colSubfolders, intCount, intCombinedSize, objFolder2, objFSO1, objFSO2, objUserFolder, strOutput, objSearchFolder, objSubfolder, strSearchFolder, strSubfolderPath
intCount = 0
intCombinedSize = 0
strSearchFolder = "C:\Documents and Settings\"
Set objFSO1 = CreateObject("Scripting.FileSystemObject")
Set objSearchFolder = objFSO1.GetFolder(strSearchFolder)
Set colSubfolders = objSearchFolder.SubFolders
For Each objUserFolder in colSubfolders
strSubfolderPath = objUserFolder.Path & "\Desktop\"
Set objFSO2 = CreateObject("Scripting.FileSystemObject")
Set objSubfolder = objFSO2.GetFolder(strSubfolderPath)
intCount = intCount + 1
intCombinedSize = intCombinedSize + objSubfolder.Size
Next
MsgBox "Combined size of " & CStr(intCount) & " folders: " & CStr(intCombinedSize / 1048576) & " MB"
This code throws a 'Path not found' error (Code 800A004C) at line 15:
Set objSubfolder = objFSO2.GetFolder(strSubfolderPath)
If I print out strSubfolderPath, however, I find that all the strings returned are valid directory paths, so I don't understand why I'm getting this error.
I've tried with and without the trailing backslash at the end of the path and I've tried with 8.3 style paths to remove spaces but to no effect.
When I run your code I get the same error.
Upon further inspection, on my computer there is a folder named C:\Documents and Settings\machinename, where machinename is the name of my computer. This folder only contains one subfolder named ASPNet.
I'm guessing you have something similar.
To minimize multiple-backslash confusion, use the FileSystemObject methods consistently instead of relying on string concatenation:
strSubfolderPath = objFSO1.BuildPath(objUserFolder.Path,"Desktop")

How to change file permissions with WMI?

I'm want to do the equivalent of what is described here from a script. Basically, I want to take ownership of the file, and set the permissions to OWNER/Full Control.
It seems to me that using WMI from a vbs script is the most portable way. That is, I'd like to avoid xcacls, icacls and other tools that either require a download, or are supported only on some versions of windows.
After googling around, I found this code for taking ownership:
'connect to WMI namespace on local machine
Set objServices =
GetObject("winmgmts:{impersonationLevel=impersonate}")
'get a reference to data file
strFile = Wscript.Arguments(0)
Set objFile = objServices.Get("CIM_DataFile.Name='" & strFile & "'")
If objFile.TakeOwnership = 0 Then
Wscript.Echo "File ownership successfully changed"
Else
Wscript.Echo "File ownership transfer operation"
End If
The pieces I'm still missing is setting the permissions, and having it work on relative paths.
Since you're already using TakeOwnership in the CIM_DataFile class, I'd assume you could just use ChangeSecurityPermissions to change the permissions, which is in the same class.
And you might be able to use GetAbsolutePathName to convert your relative paths to absolute paths before you use them.
Taking the hints from ho1's answer, I googled around some more, and eventually came up with this:
This script finds the current user SID, then takes ownership and changes the permissions on the file given in argv[0] to Full Control only to current user.
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}")
Function GetCurrentUserSID
' Get user name '
Set colComputer = objWMI.ExecQuery("Select * from Win32_ComputerSystem")
' Looping over one item '
For Each objComputer in colComputer
currentUserName = objComputer.UserName
Next
Set AccountSIDs = GetObject("Winmgmts:").InstancesOf("Win32_AccountSID")
For Each AccountSID In AccountSIDs
AccountKey = AccountSID.Element
Set objAccount = GetObject("Winmgmts:"+AccountKey)
strName = objAccount.Domain & "\" & objAccount.Name
If strName = currentUserName Then ' that's it
SIDKey = AccountSID.Setting
Set SID = GetObject("Winmgmts:" + SIDKey)
GetCurrentUserSID = SID.BinaryRepresentation
Exit For
End If
Next
End Function
Function LimitPermissions(path, SID)
Set objFile = objWMI.Get("CIM_DataFile.Name='" & path & "'")
Set Trustee = GetObject("Winmgmts:Win32_Trustee").SpawnInstance_
Trustee.SID = SID
Set ACE = getObject("Winmgmts:Win32_Ace").Spawninstance_
ACE.AccessMask = 2032127 ' Full Control
ACE.AceFlags = 3
ACE.AceType = 0
ACE.Trustee = Trustee
Set objSecDescriptor = GetObject("Winmgmts:Win32_SecurityDescriptor").SpawnInstance_
objSecDescriptor.DACL = Array(ACE)
objFile.ChangeSecurityPermissions objSecDescriptor, 4
End Function
Function TakeOwnership(path)
Set objFile = objWMI.Get("CIM_DataFile.Name='" & path & "'")
TakeOwnership = objFile.TakeOwnership
End Function
' Main '
strFilename = Wscript.Arguments(0)
Set fso = CreateObject("Scripting.FileSystemObject")
path = fso.GetAbsolutePathName(strFilename)
SID = GetCurrentUserSID
TakeOwnership path
LimitPermissions path, SID

Resources