Is it possible to extend the functionality of the TAB based autocomplete? - batch-file

When using the TAB key in the dos command prompt you can cycle through the names of files and folders in the current directory... (and it even seems to work with historical commands via DOSKEY as well). Does anyone know if it's possible to extend this somehow so that pressing TAB (or any other key combination) would autocomplete from a provided list of items as well as the previously mentioned sources? I think an example is in order....
My desired behavior is to add another source to the possible items that would appear when TAB is used. At my job we make heavy use of a scheduling product called AutoSys and administer it almost exclusively through command prompt. Basically I would love to find a way to cycle through job names so the prompt would autocomplete the names when we have the first part of the job name entered already...
Common command usage:
'autorep -J JOBNAME'
Example of what I'd like to do:
'autorep -J ABC_C_EXPORT_Re' [TAB]
where the TAB key press allows me to cycle through the jobs that start with 'ABC_C_EXPORT_Re' until I find the one I want.
It seems like a possible (but very poor) ïsolution would be to have one empty file created and named for each job in the environment... But this doesn't strike me as an effective solution to the problem, especially considering that at any one time we can have between fifty thousand and a hundred thousand jobs in our environment.
I apologize for posing this strange question in an even stranger way..... I hope I was at least able to convey a sense of the central question I'm asking. Something like this would be a huge help to our operations support staff who have to find jobs by command line all day long!
Thanks for having a look!
Scott

You can make your own command processor pretty easy.
Here's something from Filter.vbs. Unlike this you'd want to read characters rather than lines (so .read(1) rather than .readline). Echo out each character, do something special on tab, when user presses enter execute the command line you built in memory, capturing it's stdout using wshshell.exec.
Here's something from help
Do While Not WScript.StdIn.AtEndOfLine
Input = Input & WScript.StdIn.Read(1)
Loop
WScript.Echo Input
Here's a menu, not everything is included.
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Showmenu
Sub ShowHelpMenu
outp.writeline " -----------------------------------------------------------------------------"
outp.writeblanklines(1)
outp.writeline " Menu"
outp.writeline " ----"
outp.writeblanklines(1)
outp.writeline " 1 Help 2 HTML Help 3 Version 4 History"
outp.writeblanklines(1)
outp.writeline " 5 Exit"
outp.writeblanklines(1)
outp.write "Filter>"
End Sub
'=============================================
Sub ShowMenu
Do
ShowHelpMenu
Answ=Inp.readline
If Answ = "1" Then
ShowGeneralHelp "TEXT"
Elseif Answ = "2" Then
ShowGeneralHelp "HTML"
Elseif Answ = "3" Then
Version
Elseif Answ = "4" Then
History
Elseif Answ = "5" Then
Exit Do
End If
Loop
End Sub
'=============================================
Sub History
On Error Resume Next
WshShell.Run """" & FilterPath & "FilterHistory.txt""" , 1, False
err.clear
End Sub
'=============================================
Sub Version
outp.writeblanklines(1)
outp.writeline " Version"
outp.writeline " -------"
outp.writeblanklines(1)
outp.writeline " Filter Ver 0.6 - 2015 (Public Domain)"
outp.writeblanklines(1)
outp.writeline " by David Candy"
outp.writeblanklines(1)
End Sub

Related

How do I use VBScript to rename files in a directory prepending the folder name to all files in the folder?

I have a large number of image files spanning nearly two decades where the subject is identified by the directory name and most of the photos themselves have a generic name however some of them have more specific names.
I am writing a script to prepend the directory name to the filename for all files in a specific directory. Well, I am trying to at least.
It has been a few years since I used VBScript and it seems I am VERY rusty.
I am facing challenges with the syntax format.
When I have Option Explicit (on line 6) it gives an error of Line 6, Char 1, Error: Expected Statement, Code: 800A0400 (In my shared code it would be line 7 because of the added Beginning of File line)
If I comment that out, I get an error on the import statements instead of Line 3, char 1, Error: Type mismatch: 'Imports', Code: 800A000D (In my shared code, it would be line 4 because of the added Beginning of File line)
I have spent a few hours googling for possible causes but to no avail and so I am turning to the community for help with getting the formatting of this script set correctly.
Any comments on a better script approach for accomplishing this task would be appreciated as well.
I am going to put in the entire code for the file because I do not know what part of it will be the relevant aspect.
In the code, it is currently set to only create a message box for each file as a test measure to ensure the variables have the values I think they have.
The commented out code for renaming the file is the truly intended purpose.
I am stuck on the proper formatting of the first part of the file however.
In general, I am executing this from the command line using: cscript.exe c:\MyTools\addDir2FileName.vbs
I launched it through windows explorer to get the more specific error codes with line numbers though.
I added the Beginning of File and End of File comments just for the purpose of clarity in this post.
' ####### Beginning of File
' Renames all files in a directory prepending the directory name to the file name
Imports System
Imports System.IO
Option Explicit
Dim WshShell, strOldFull, strNewFull, strFullPath, strCurDir
Dim strCurrentName, strNewName, strMessage, dir, fileObj, fs, fo
' Get the current directory
Set WshShell = CreateObject("WScript.Shell")
strFullPath = WshShell.CurrentDirectory
'Get folder properties to get just the name without path
Set fs=Server.CreateObject("Scripting.FileSystemObject")
Set fo=fs.GetFolder(strFullPath)
strCurDir = fo.Name
'Iterate through the directory
set dir = DirectoryInfo(strFullPath)
For Each fileObj In dir.GetFiles()
strCurrentName = fileObj.Name
strNewName = strCurDir & " - " & strCurrentName
' For testing purposes to make sure everything is as expected
' Creates a message box for each file instead of actually renaming it
strMessage = "Old Name: " & strCurrentName & chr(13) & chr(10) & "New Name: " & strNewName
MsgBox strMessage
' Renaming the file
' strOldFull = fs.BuildPath(CurrentDirectory, strCurrentName)
' strNewFull = fs.BuildPath(CurrentDirectory, strNewName)
' My.Computer.FileSystem.RenameFile(strOldFull, strNewFull)
Next
WshShell = Nothing
fo = Nothing
fs = Nothing
' ### End of File
The expectation is that a file "C:\Pictures\Trip to Nice\DCM001.jpg" will get renamed to "C:\Pictures\Trip to Nice\Trip to Nice - DCM001.jpg" and that all files in the directory that the script is run in will be similarly renamed.
Well, to be more precise, the output as currently formatted will produce a message box that says "Old Name: C:\Pictures\Trip to Nice\DCM001.jpg New Name: C:\Pictures\Trip to Nice\Trip to Nice - DCM001.jpg" and that a message box will be produced for all files in the directory. Yes, I will only run message box version in a test directory with 3 files. I would hate to get 50,000 message boxes, lol.
There is no output at current because of the formatting issues with either the Import Statement or the Option Explicit, or perhaps some other syntax piece I am missing or have wrong.
Thank you for your time and any help that anyone is able to provide. This is the first time I am posting to the community but I have long appreciated the answers provided. Usually, I can find my questions already answered, but I am stumped on this one...
Okay, through a lot of trial and error, I figured out a method to complete the task where I did not use System and so avoided the error that I was receiving before.
I thought to post the final script, in case anyone was interested.
' Renames all files in a directory prepending the directory name to the file name
Option Explicit
Dim WshShell, strOldFull, strFullPath, strCurDir, lastSlash
Dim strCurrentName, strNewName, strMessage, fileObj, fileSpec, fs, fo, ff
' Get the current directory
Set WshShell = CreateObject("WScript.Shell")
strFullPath = WshShell.CurrentDirectory
'Get folder object
Set fs = CreateObject("Scripting.FileSystemObject")
Set fo = fs.GetFolder(strFullPath)
set ff = fo.Files
'Get just the folder name
lastSlash = inStrRev(strFullPath, "\")
strCurDir = right(strFullPath, len(strFullPath) - lastSlash )
'Iterate through the directory
For Each fileObj in ff
strCurrentName = fileObj.Name
strNewName = strCurDir & " - " & strCurrentName
' For testing purposes to make sure everything is as expected
' Creates a message box for each file instead of actually renaming it
' strMessage = "Old Name: " & strCurrentName & chr(13) & chr(10) & "New Name: " & strNewName
' MsgBox strMessage
' Renaming the file
strOldFull = strFullPath & "\" & strCurrentName
set fileSpec = fs.GetFile(strOldFull)
fileSpec.Name = strNewName
Next
' Declare variables
Dim objFSO, objParentFolder, objFolder, objFile
' Set the parent directory to be processed
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objParentFolder = objFSO.GetFolder("C:\path\to\parent\directory")
' Function to process the subfolders
Sub ProcessSubFolders(folder)
' Loop through all files in the folder
For Each objFile In folder.Files
' Get the current file name
strFileName = objFile.Name
' Get the folder name
strFolderName = folder.Name
' Build the new file name
strNewFileName = strFolderName & "_" & strFileName
' Rename the file
objFile.Name = strNewFileName
Next
' Loop through all subfolders
For Each objFolder In folder.SubFolders
' Recursively call the function for the subfolder
ProcessSubFolders(objFolder)
Next
End Sub
' Call the function to process the top-level folder
ProcessSubFolders(objParentFolder)
' Clean up
Set objFile = Nothing
Set objParentFolder = Nothing
Set objFSO = Nothing

Access Corrupted/Trying to Export Forms

I have an MS Access (ACCDB File) that is corrupted. The error is the generic "The Microsoft Access Database Engine could not find the object 'Databases'. I have tried searching Google, tried using Stellar Phoenix software to recover the database, and also tried importing the database into a new one. None of which have worked to recover the Forms. The data is safe as it's stored in SharePoint.
Does anyone know of a way to export the Forms from this corrupted database to BAS Files? I cannot get this database to open at all and the most recent backup is 3 weeks ago (apparently my computer wasn't backing up to the remote server it should have been and what a way to discover that).
Any help is appreciated!
If you save the following script to a VBScript file, for example, Decompile.vbs, and drag and drop a copy of your corrupt database on to the script file, or just use the message box to enter the path for the copy, there is a possibility you can recover your forms. I am using Windows 7 64 bit, but I think the path to MS Access should work.
Option Explicit
Dim WSHShell
Dim fs, sPath, sPathTemp, sAccessPath, sKey
Set fs = CreateObject("Scripting.FileSystemObject")
If WScript.Arguments.Count > 0 Then
sPath = WScript.Arguments.Item(0)
Else
sPathTemp = Left(WScript.ScriptFullname, _
InStrRev(WScript.ScriptFullname, "\"))
sPath = InputBox("Enter Path and Name of .mdb or accdb", "Decompile", sPathTemp)
End If
If sPath = "" Or fs.FileExists(sPath) = False Then
MsgBox "Not a valid file: " & vbCrLf & sPath, 64, "Decompile" '64=vbInformation
Else
Set WSHShell = CreateObject("WScript.Shell")
sKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\MSACCESS.EXE\"
sAccessPath = WSHShell.RegRead(sKey)
WSHShell.Run Chr(34) & sAccessPath & Chr(34) & " " & Chr(34) & sPath & Chr(34) & " /decompile"
End If

VBScript - Notification when file not created today

Goal: To run a VBScript that checks a folder daily, and reports if no files were saved to it that day. Ignore the files that exist from previous days.
Scenario: A logfile is created everyday in C:\Temp at 3am. This is what tells us that the system performed a task. If a log file isn't generated, then the task crashed. I wrote this to check the Temp folder for a file created today, and to email me if it doesn't exist.
Solution thus far:
option explicit
dim fileSystem, folder, file
dim path
path = "C:\Temp"
Set fileSystem = CreateObject("Scripting.FileSystemObject")
Set folder = fileSystem.GetFolder(path)
for each file in folder.Files
if file.DateLastModified > dateadd("h", -24, Now) then
'WScript.Echo file.Name & " last modified at " & file.DateLastModified
else
SendEmail
'WScript.Echo "this should have sent an email."
end if
next
Function SendEmail()
'Send Email notification function here (this part works already)
End Function
Issue I am having:
I can't seem to wrap my head around a way to have the script ignore files in the folder from previous days.
In my test, I have C:\Temp populuated with a file modified today, and a file modified on 7/10/12. Because this scenario matches both the 'then' and the 'else' statement, it's doing both.
I think I just need a slight modification on the loop to tell it
- Ignore files not dated 'today'
- Send an email if no files exist today.
Any help would be awesome. I just can't seem to 'see' the answer.
You're close. The problem is is you were looping through and checking every single file. You need to only check if one file doesn't exist. I'm not that familiar with vbscript, so you may need to tweak this a bit, but what I did is add a variable found and initialized it to false. If you find a file created in past 24 hours, set it to true. once you're done looping, if it's still false, no files were modified in past 24 hours
option explicit
dim fileSystem, folder, file
dim path
Dim found
found = false
path = "C:\Temp"
Set fileSystem = CreateObject("Scripting.FileSystemObject")
Set folder = fileSystem.GetFolder(path)
for each file in folder.Files
if file.DateLastModified > dateadd("h", -24, Now) then
found = true
end if
next
if (found = false) then
SendEmail
End If
Function SendEmail()
'Send Email notification function here (this part works already)
End Function
I would suggest first removing the time from the date check
Second Since you stated that the file is created each night I would check the DateCreated and not DateModified.
I modified your code below to add a variable Dim myDate and then set it to the previous day
Dim myDate
myDate = dateadd("d", -1, FormatDateTime(Now, 2))
I then changed the line
if file.DateCreated > myDate then
to look at the new variable.
Running this with the echo command worked as you described
and notified my of only the file that was created today.
option explicit
dim fileSystem, folder, file
dim path
path = "C:\Temp"
Set fileSystem = CreateObject("Scripting.FileSystemObject")
Dim myDate
myDate = dateadd("d", -1, FormatDateTime(Now, 2))
Set folder = fileSystem.GetFolder(path)
for each file in folder.Files
if file.DateCreated > myDate then
'WScript.Echo file.Name & " last modified at " & file.DateCreated
SendEmail
'WScript.Echo "this should have sent an email."
end if
next
Function SendEmail()
'Send Email notification function here (this part works already)
End Function
This script:
Option Explicit
' config data, fixed
Const csPATH = "..\data"
' config data, computed, show use of DateValue() to cut off time
Dim dtCheck : dtCheck = DateValue(DateAdd("d", 0, Now))
WScript.Echo "dtCheck:", dtCheck
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim bFound : bFound = False ' assume no up-to-date file found
Dim oFile
For Each oFile In oFS.GetFolder(csPATH).Files
WScript.Echo "Check:", DateValue(oFile.DateLastModified), oFile.Name
If DateValue(oFile.DateLastModified) = dtCheck Then
WScript.Echo "Found:", DateValue(oFile.DateLastModified), oFile.Name
WScript.Echo "no need for further loopings"
bFound = True
Exit For
End If
Next
If Not bFound Then
WScript.Echo "Sending email ..."
End If
output 1:
dtCheck: 12.07.2012
Check: 11.07.2012 11434579.kpf
Check: 11.07.2012 11434579.notes
Check: 11.07.2012 11434579-UE15.prj
Sending email ...
output 2:
dtCheck: 12.07.2012
Check: 11.07.2012 11434579.kpf
Check: 11.07.2012 11434579.notes
Check: 11.07.2012 11434579-UE15.prj
Check: 12.07.2012 11458011.notes
Found: 12.07.2012 11458011.notes
no need for further loopings
expands on Ghost's approach by breaking/exiting the loop as soon as a/the up-to-date file is found, avoids re-computings of the check date (based on volatile Now!) in the loop, and demonstrates the importance of code you don't write (e.g.: Set folder = ..., If (found = false) ..).

Hide empty console window in a all GUI Powershell script?

I have made a very simple Powershell script with WinForms GUI.
Everything works as intended but, when I run the .ps1 script with PowerShell a black empty console window appears at first and then the GUI shows.
Anyway to make the console window dissapear?
Best regards
I wrote a small article on this subject (sorry in french) one year ago.
Here is the common solution using a small VBS script to start PowerShell hidding his window (the trick is in the last ,0).
Set Args = Wscript.Arguments
'MsgBox "Chemin LDAP: " & Args(0)
'MsgBox "Classe: " & Args(1)
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "c:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -nologo -Noninteractive -file c:\SlxRH\RhModif.ps1 " & chr(34) & Args(0) & chr(34) , 0
I also embeded PowerShell in an executable with no console called slxPShell2.EXE.
I found the above didn't work for me. I used this:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "CMD /C START /B " & objShell.ExpandEnvironmentStrings("%SystemRoot%") & "\System32\WindowsPowerShell\v1.0\powershell.exe -file " & "YourScript.ps1", 0, False
Set objShell = Nothing
Hope that helps.
This solution Minimizes Powershell window after it starts. Powershell window opens, then disapears, without using any outside code. Put at beginning of your script.
$t = '[DllImport("user32.dll")] public static extern bool ShowWindow(int handle, int state);'
add-type -name win -member $t -namespace native
[native.win]::ShowWindow(([System.Diagnostics.Process]::GetCurrentProcess() | Get-Process).MainWindowHandle, 0)
This is how I got this working:
Have the Winforms GUI script in one ScriptOne.ps1 file
Create another LaunchScriptOne.ps1 file with the content:
powershell.exe -WindowStyle Hidden -File "C:\path\to\ScriptOne.ps1".
The solution was provided in another thread on the same topic: Hide or Minimize the powershell prompt after Winform Launch
I hope someone will find a way to put this into one single script as well. The answers above in this thread did not help me, but maybe I did something wrong, idk.
I'm nube so no rep so can't comment inline... though wrt #Ipse's solution which I'm a fan of, I also make sure to close the hidden window when the script is done... not sure if PS gets around to this sort of auto-garbage collection, but suspect it's good best practice.
eg. at end of your script I'd suggest doing:
stop-process -Id $PID
(which should terminate that hidden window v. just leave it lurking around and tying up those resources).

.VBS to run DNSCMD /enumrecords in a for loop on an array of node names. CLI shows as if I ran a DNSCMD /?

I'm trying to run DNSCMD.exe /enumrecords from a .vbs on our Windows Server 2003 DNS server and dump the results into a .csv file for each node name under a DNS Zone.
I have entered the Nodes I want to run the command against under the zone into an array and entered a list of filenames into another array.
The idea being to run a for loop to walk through each node name and file name 0-42 and run the command for each node name and outputting to each filename in sequence.
Option Explicit
Dim ncpArr, NODE, fnameArr, FILE, DNSCMD, objWSHShell, QComm
Set objWSHShell = WScript.CreateObject("WScript.Shell")
ncpArr = Array(42 item array of DNS Nodes)
fnameArr = Array(42 item array of filenames)
QComm = "DnsCmd DNSservername /enumrecords contoso.com " & ncpArr(NODE) & " /Additional> c:\DNSData\" & fnameArr(NODE) & ".csv"
For NODE = 0 to 42
objWSHShell.Run QComm,1,True
'objWshShell.Exec QComm
'wscript.echo "| " & ncpArr(NODE) & " | | " & fnameArr(NODE) & " |"
'wscript.echo DNSCMD
Next
The intent was to save myself some time but if anything I've tripled the time it would have taken to run these 42 commands while writing this script.
What I have figured out so far is:
When I run this command on the DNS server it outputs a CSV exactly like I want it to
DnsCmd dnsservername /enumrecords zone.name node.st.name /Additional /continue> c:\DNSData\state_city_net.csv
When I run the same command like this:
Set objWSHShell = WScript.CreateObject("WScript.Shell")
objWSHShell.run "dnscmd /enumrecords zone.name node.st.name /additional> c:\DNSData\state_city_net.csv"
The command line box pops up briefly showing the instructions for DNSCMD as if I ran a DNSCMD /?. I've only been able to get a look at it by running the loop above and hitting Pause/Break at just the right time. Not sure if it's possible to get the Command Line box to stay open to show any errors
One thing I noticed is normally when you run it with an incorrect syntax it will have some information about the error at the top. In this case it literally looks like the DNSCMD /? instructions with no error at the top.
I'm seriously wondering if it's just not possible to run DNSCMD /enumrecords using a .vbs. as you can see from the commented out parts I've tried a few things to show the syntax is correct. When I Echo the output of the loop I can enter the exact syntax into the command line on the DNS server and it works!
If ANYONE could just peek at what I have above and tell me why when I run my script it does that or if you could even just confirm that my scripting is sound and it's something with DNSCMD it would really help me sleep better.
Thanks
Drew
When you enter
DnsCmd dnsservername /enumrecords zone.name node.st.name /Additional /continue> c:\DNSData\state_city_net.csv
in a shell ('DOS box'), the redirection (>) is provided by this shell. Your
objWSHShell.run "dnscmd /enumrecords zone.name node.st.name /additional> c:\DNSData\state_city_net.csv"
just runs a process and can't do redirection. Change your line to
objWSHShell.run "%comspec% /c dnscmd /enumrecords zone.name node.st.name /additional> c:\DNSData\state_city_net.csv"
and think about the (missing) /continue. For (single) testing, you can change the /c (close when done) to /k (keep open). Probably re-reading about (using?) all three parameters of the .Run method and paying attention to the return value may be a good idea.

Resources