VBS reboot and wait on same server - sql

I would like to run the following script as part of my guest customization so when I deploy a VM from a template, the windows volumes have their correct drive letters. The script below works but requires a reboot, following the reboot I would like to call my SQL setup command which currently is just one line in a .cmd file. Could anyone help me to add a wait command to the drive letters script and then call the cmd after a reboot?
Also is there an easier way with PowerShell?
CMD File;
cd c:
C:\Setup\SQL2008R2_SP2\Setup.exe /CONFIGURATIONFILE=C:\Setup\SQL2008R2.ini /INDICATEPROGRESS
Change Drive Letters (Original source http://imallvirtual.com/?p=482)
' Script that changes drive letters
' Note: Do NOT use it on SYSTEM or BOOT partition drive letters !!!
set objShell = CreateObject("WScript.Shell")
' objShell.Run("regedit /s C:\Setup\MsgBox.reg")
sComputer = "."
Const HKLM = &H80000002
' from/to
If ChangeDrvLetter("D:", "T:") Then
End If
If ChangeDrvLetter("F:", "X:") Then
End If
If ChangeDrvLetter("G:", "D:") Then
End If
Function ChangeDrvLetter(sSourceDrive, sTargetDrive)
bOK = True ' Init value
Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
& sComputer & "\root\default:StdRegProv")
sKeyPath = "SYSTEM\MountedDevices"
sSrc = "\DosDevices\" & UCase(sSourceDrive)
iRC = oReg.GetBinaryValue(HKLM, sKeyPath, sSrc, sValue)
If iRC = 0 Then
sTrg = "\DosDevices\" & UCase(sTargetDrive)
iRC = oReg.SetBinaryValue(HKLM, sKeyPath, sTrg, sValue)
If iRC = 0 Then
oReg.DeleteValue HKLM, sKeyPath, sSrc
Else
bOK = False
End If
Else
bOK = False
End If
ChangeDrvLetter = bOK
End Function
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "C:\WINDOWS\system32\shutdown.exe -r -t 0"

To run after reboot, you can sure have the script set a one time task in task-scheduler to run the one line command. (the task can even be set to delete himself after running)

Related

manual entry in cmd window works, VBA executing CMD works, but not VBA when I use run (so I can hide the window)

SECOND EDIT/UPDATE: tried the path change recommendations, did not see any changes to the command string, still does not work. I re-wrote the code to use a fixed text file instead of a random temp file so I could monitor the contents of the file during execution. Able to conclusively show it is the
oShellObject.Run sCommandStringToExecute & " > " & sShellRndTmpFile, 0, True
code line that doesn't behave as expected. Still works with the w32tm command line, but not with the ntpq command line. With ntpq command, no changes made to the file, no error flags. I also tried out (again) the exec version of this problem where the window is supposed to flash a bit before it gets hidden programmatically. I get the expected reslut using exactly the same command string, cut and pasted into the other code. So the same command line works with manual entry into CMD, into PowerShell, and in the .exec code version, not the .run code version.
End of second edit. -------------------
EDIT: more debugging... ntpq -p works if I do .exec instead of .run, but then of course can't hid the cmd window. Extra test code at the end.
This Works: If I run these two commands in manually opened cmd window, or PowerShell window, both give the expected results.
w32tm /stripchart /computer:time.nist.gov /dataonly /samples:3 /rdtsc /period:1
ntpq -p
The second, ntpq -p, is bundled with NTP windows software from the home of the Network Time Protocol project that gives similar information to windows' w32tm when NTP is set up to look at the same time service computer as in the w32tm command.
This Doesn't work:
When I try to use these two command string when running CMD functions hidden using the classic "write to file" method shown in SO here and other places, the w32tm version gives the same results as the manual version, but the ntpq version just returns "error".
I read every single one of the recommended links for this question as well as searching OS and Google, and have not found an answer.
I am stuck on next step to troubleshoot the problem...only thing I could think of was to run the commands manually to confirm they work there. I can't imagine it being a administrator privileges issue since I can run them both in CMD line or PowerShell windows opened at normal rights level.
What should I look at next?
Here is the test code.
Option Explicit
Sub TestShellRun()
Dim sCmd As String, sReturnNTP As String
sCmd = "w32tm /stripchart /computer:time.nist.gov /dataonly /samples:3 /rdtsc /period:1 " ' /packetinfo"
sCmd = "%ComSpec% /C %SystemRoot%\system32\" & sCmd
sReturnNTP = fShellRun(sCmd) 'good return value, same as manual cmd line
Debug.Print sReturnNTP
sCmd = "ntpq -p"
sCmd = "%ComSpec% /C %SystemRoot%\system32\" & sCmd
sReturnNTP = fShellRun(sCmd) 'ERROR return value, even though manual cmd line has good values
Debug.Print sReturnNTP
End Sub
Public Function fShellRun(sCommandStringToExecute) As String
' This function will accept a string as a DOS command to execute.
' It will then execute the command in a shell, and capture the output into a file.
' That file is then read in and its contents are returned as the value the function returns.
' "myIP" is a user-selected global variable
Dim oShellObject, oFileSystemObject, sShellRndTmpFile
Dim oShellOutputFileToRead
Dim iErr As Long
Set oShellObject = CreateObject("Wscript.Shell")
Set oFileSystemObject = CreateObject("Scripting.FileSystemObject")
sShellRndTmpFile = oShellObject.ExpandEnvironmentStrings("%temp%") & oFileSystemObject.GetTempName
On Error Resume Next
oShellObject.Run sCommandStringToExecute & " > " & sShellRndTmpFile, 0, True
iErr = Err.Number
On Error GoTo 0
If iErr <> 0 Then
fShellRun = "error"
Exit Function
End If
On Error GoTo err_skip
fShellRun = oFileSystemObject.OpenTextFile(sShellRndTmpFile, 1).ReadAll
oFileSystemObject.DeleteFile sShellRndTmpFile, True
Exit Function
err_skip:
fShellRun = "error"
oFileSystemObject.DeleteFile sShellRndTmpFile, True
End Function
sCommand = "ntpq.exe -p"
Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(sCommand)
strOutput = WshShellExec.StdOut.ReadAll
Debug.Print strOutput
Your fShellRun function didn't work due to error in temporary file path. Here is fixed version.
Function fShellRun(sCommandStringToExecute) As String
...
'invalid file path without path separator between directory path and filename!
sShellRndTmpFile = oShellObject.ExpandEnvironmentStrings("%temp%") & _
oFileSystemObject.GetTempName
'valid path with path separator between directory path and filename
sShellRndTmpFile = oFileSystemObject.BuildPath( _
Environ("temp"), oFileSystemObject.GetTempName)
...
End Function

vba shell command executing but no output

I am having some problems running a shell command and checking the output of the data. I wish to check using vba if the current remote user of the DB is Active. In
command prompt =
for /f "tokens=1-8" %a in ('quser') do #if "%d"== "Active" echo %COMPUTERNAME% %a %d
returns the users logged on and their state I wish to check that none of them are disconnected ("Disc"). I used this function to check the shell and return the pipe value as a string in a message box
Public Function ShellRun(sCmd As String) As String
'Run a shell command, returning the output as a string'
Dim oShell As Object
Set oShell = CreateObject("WScript.Shell")
'run command'
Dim oExec As Object
Dim oOutput As Object
Set oExec = oShell.Exec(sCmd)
Set oOutput = oExec.StdOut
Debug.Print sCmd
'handle the results as they are written to and read from the StdOut object'
Dim s As String
Dim sLine As String
While Not oOutput.AtEndOfStream
sLine = oOutput.ReadLine
If sLine <> "" Then s = s & sLine & vbCrLf
Wend
ShellRun = s
'example MsgBox ShellRun("cmd.exe /c" & "dir c:\")
End Function
Call Command used on click event
Dim CMDLineCommand As String
CMDLineCommand = "for /f ""tokens=1-8"" %a in ('quser') do #if ""%d""== ""Active"" echo %COMPUTERNAME% %a %d"
'(CMDLineCommand = "dir c:\")<------ THIS WORKS FINE
MsgBox ShellRun("cmd.exe /c " & CMDLineCommand)
This works fine for loads of command line commands I have tested it with but not query and therefore query user. The query user command works fine from command line but does not return anything when issued through a VBA Shell commands.
Any thoughts would be appreciated.
because shell does not know the path of the query.exe(quesr) it does not continue where as command prompt can use system variables to find exe's. solution find the query.exe and copy it to a working directory then run the shell command. mine was located in a hashed folder within C:\Windows\WinSxS be careful as here are 64bit versions and 32 bit.

VB FTP code works in Debug (F10) but not when run or F5

I need to FTP a local file to Mainframe and have written the below script to create a local Batch text file using streamwriter and then use this file with the ftp -s: command to run it.
Here is the code.
Shared Sub TestFTP()
' BP DEFINED INPUTS ANDF OUTPUTS
'Inputs
Dim hostname As String
Dim username As String
Dim password As String
Dim mainfile As String
Dim localfile As String
'Outputs
Dim success As Boolean
Dim message As String
'-------------
'Test DATA
'-------------
hostname = "XXIBM2"
username = "USER1"
password = "XXX1234"
mainfile = "XXTSO.USER1.TEST2"
localfile = "D:\TestFTP.txt"
'=============================BP Code========================
Try
Dim localPath As String = "C:\BPFTP"
Dim isExists As Boolean = System.IO.Directory.Exists(localPath)
If (isExists = False) Then
System.IO.Directory.CreateDirectory(localPath)
End If
' Open StreamWriter And create batch file
Using writer As StreamWriter = New StreamWriter(localPath + "\\FTP.txt")
writer.WriteLine("open " + hostname)
writer.WriteLine(username)
writer.WriteLine(password)
writer.WriteLine("put " + localfile + " '" + mainfile + "'")
writer.WriteLine("bye")
writer.WriteLine("exit")
End Using
' Perform FTP
Interaction.Shell("ftp -n -s:C:\BPFTP\FTP.txt")
' Delete batch file
System.IO.File.Delete("C:\\BPFTP\\FTP.txt")
success = True
Catch e As Exception
success = False
message = e.Message
End Try
End Sub
If I run the code using F5 the file does not appear on the mainframe.
If I set a breakpoing at the Shell command and run the code (f5) to here and then F5 to the end the file does not get FTPd to the mainframe.
HOWEVER.
If I run the code to the breakpoint and then simply 'Step Over' the Shell command line using F10 then the file successfully FTPs to the mainframe.
When you run in debug mode, you are forcing a synchronous operation, you need to tell shell and your ftp application to wait in order to completely send the file.
Interaction.Shell("ftp -n -s:C:\BPFTP\FTP.txt", AppWinStyle.MinimizedFocus, True, 30000)
See here
This will force it to wait 30 seconds before continuing, if you set it to -1 it waits forever which can cause undesirable behavior.

Add new network location, not map network drive

Let's say I have 100 users and I need to add several network locations for each user. They cannot be network drives (e.g. Q:) as some users already have more than 26 drives mapped.
I was hoping to do this using either a batch file or a VB script. I've managed to get it working using a VB script by adding network shortcuts but this isn't the solution the users need.
I've been searching and can't find anything related specifically to Network Locations.
I'm open to trying other methods.
EDITED to properly answer the question; the original answer, that creates a shortcut in Network Locations, is kept at the end.
After some testing, a network location is a read-only folder located in the %AppData%\Microsoft\Windows\Network Shortcuts folder, with two files inside: desktop.ini with a precise content (see in code) and a target.lnk shortcut to the target.
Option Explicit
Function CreateNetworkLocation( networkLocationName, networkLocationTarget )
Const ssfNETHOOD = &H13&
Const fsATTRIBUTES_READONLY = 1
Const fsATTRIBUTES_HIDDEN = 2
Const fsATTRIBUTES_SYSTEM = 4
CreateNetworkLocation = False
' Instantiate needed components
Dim fso, shell, shellApplication
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set shell = WScript.CreateObject("WScript.Shell")
Set shellApplication = WScript.CreateObject("Shell.Application")
' Locate where NetworkLocations are stored
Dim nethoodFolderPath, networkLocationFolder, networkLocationFolderPath
nethoodFolderPath = shellApplication.Namespace( ssfNETHOOD ).Self.Path
' Create the folder for our NetworkLocation and set its attributes
networkLocationFolderPath = fso.BuildPath( nethoodFolderPath, networkLocationName )
If fso.FolderExists( networkLocationFolderPath ) Then
Exit Function
End If
Set networkLocationFolder = fso.CreateFolder( networkLocationFolderPath )
networkLocationFolder.Attributes = fsATTRIBUTES_READONLY
' Write the desktop.ini inside our NetworkLocation folder and change its attributes
Dim desktopINIFilePath
desktopINIFilePath = fso.BuildPath( networkLocationFolderPath, "desktop.ini" )
With fso.CreateTextFile(desktopINIFilePath)
.Write "[.ShellClassInfo]" & vbCrlf & _
"CLSID2={0AFACED1-E828-11D1-9187-B532F1E9575D}" & vbCrlf & _
"Flags=2" & vbCrlf
.Close
End With
With fso.GetFile( desktopINIFilePath )
.Attributes = fsATTRIBUTES_HIDDEN + fsATTRIBUTES_SYSTEM
End With
' Create the shortcut to the target of our NetworkLocation
Dim targetLink
targetLink = fso.BuildPath( networkLocationFolderPath, "target.lnk" )
With shell.CreateShortcut( targetLink )
.TargetPath = networkLocationTarget
.Save
End With
' Done
CreateNetworkLocation = True
End Function
CreateNetworkLocation "Tests", "\\192.168.1.2\c$"
Tested in Windows 7.
Original answer - Just in case someone finds it useful.
All you need to do is to create a shortcut in the folder:
%AppData%\Microsoft\Windows\Network Shortcuts
Just a VBScript sample (as indicated in the question, not sure if the tags points to another needs):
Option Explicit
Const ssfNETHOOD = &H13&
Dim fso, shell, shellApplication
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set shell = WScript.CreateObject("WSCript.Shell")
Set shellApplication = WScript.CreateObject("Shell.Application")
Dim networkLocationsFolder
networkLocationsFolder = shellApplication.Namespace( ssfNETHOOD ).Self.Path
With shell.CreateShortcut(fso.BuildPath( networkLocationsFolder, "Test PC.lnk" ))
.TargetPath = "\\192.168.1.10\c$"
.WindowStyle = 1
.IconLocation = "shell32.dll, 9"
.Description = "Access to Test computer drive"
.WorkingDirectory = "\\192.168.1.10\c$"
.Save
End With

Use a variable in file path in .vbs

Is it possible to usa variable in a path in .vbs. My basic situation is I have a vbs script that will often be run on a computer with one person logged in and run by an admin with a completely different user name (assume the file will be right clicked and "Run As").
The script edits an ini file that is located in the user directory for the person logged in. I know in batch I could simply insert the variable "C:\Users\%Logger%\AppData\Local\stat.ini" and the variable would be replaced. But I can't do this in .vbs. My script thus far. Or look at the bulk of it in an answer here.
Dim blnRes: blnRes = 0
Dim strOld, strNew, logger
strOld = "frogg"
strNew = "frog"
logger = Inputbox("What is your Domain ID exactly as entered when you log into this machine?","Domain ID")
On Error Resume Next
Call update("C:\Users\logger\AppData\Local\stat.ini", strOld, strNew)
blnRes = blnRes Or (Err.Number = 0): Err.Clear
Is there some way I can flag logger as a variable, or is there an easier way to do this?
I guess you meant a script variable. Try this:
logger = Inputbox("What is ID?","Domain ID")
Call update("C:\Users\"& logger &"\AppData\Local\stat.ini", strOld, strNew)
You can use command line arguments with vbs. See the following technet site:
http://technet.microsoft.com/en-us/library/ee156618.aspx
using the example vbs at the bottom, you can have Ping.vbs reply based on the computer name entered after the script name when its called (C:\scripts\Ping.vbs Hostname)
Here's more info on WScript.Aurguments
https://www.google.com/search?q=WScript.Arguments&sourceid=ie7&rls=com.microsoft:en-us:IE-Address&ie=&oe=
'Ping.vbs:
Dim arArguments, strArgument
Set arArguments = WScript.Arguments
WScript.Echo WScript.Arguments.Count
For Each strArgument in arArguments
If Ping(strArgument) Then
WScript.Echo strArgument & " is available."
Else
WScript.Echo strArgument & " is not available."
End If
Next
Function Ping( myHostName )
Dim colPingResults, objPingResult, strQuery
strQuery = "SELECT * FROM Win32_PingStatus WHERE Address = '" & myHostName & "'"
Set colPingResults = GetObject("winmgmts://./root/cimv2").ExecQuery( strQuery )
For Each objPingResult In colPingResults
If Not IsObject( objPingResult ) Then
Ping = False
ElseIf objPingResult.StatusCode = 0 Then
Ping = True
Else
Ping = False
End If
Next
Set colPingResults = Nothing
End Function
If I understand what you're after correctly, you're either going to need to do a string concatenation where you build a string like "string part 1" & logger & "string part 2" or use the replace function to replace %Logger% (e.g. Replace(templateString, "%Logger%", logger)) with your logger variable. There's not a direct equivalent to the %1 sort of format used in batch files.
This worked for me:
Dim fs, ws, Path
Set ws = CreateObject( "WScript.Shell" )
Path = ws.ExpandEnvironmentStrings( "%UserProfile%\testfile.txt" )
ws = Nothing
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.CreateTextFile (Path, True)
f.WriteLine("This is a test")
f.Close()
f = Nothing
Don't assume "C:\Users" will be valid on every system. There are times when you may want to use a different location for user profiles. I also looked at the %AppData% environment variable, but in my case that pointed to AppData\Roaming, and you want AppData\Local.