2

I'm trying to search for the latest .msi file, and install it in the background.

I have tried following the help from this link but it did not help.

This is what I currently have:

  @echo off
setlocal

if _%1_==_payload_  goto :payload

:getadmin
    echo %~nx0: elevating self
    set vbs=%temp%\getadmin.vbs
    echo Set UAC = CreateObject^("Shell.Application"^)                >> "%vbs%"
    echo UAC.ShellExecute "%~s0", "payload %~sdp0 %*", "", "runas", 1 >> "%vbs%"
    "%temp%\getadmin.vbs"
    del "%temp%\getadmin.vbs"
goto :eof

:payload

::ENTER YOUR CODE BELOW::   

FOR /F "eol=| delims=" %%I IN ('DIR "directory" /A-D /B /S /O-D /TW 2^>nul') 
DO (
    ECHO %%~I
    SET "NewestFile=%%~I"
    GOTO FoundFile
)
ECHO No *.msi file found!
GOTO :EOF

:FoundFile
msiexec.exe /I "%NewestFile%" /Q

::END OF YOUR CODE::

echo.
echo...Script Complete....
echo.

I'm guessing the problem is with the :FoundFile and the execution part or finding the correct file based off of time.

I was thinking maybe I have to use:

forfiles /p "dir" /m *.msi /S /D +%Date%

but I'm not entirely sure.

  • This isnt powershell. This is batch. – ArcSet May 31 '19 at 14:10
  • 1
    didn't you notice the syntax error? `for`syntax is `for ... in (...) do (` (no line break before `do`) – Stephan May 31 '19 at 14:23
  • 3
    oh - and you need to `msiexec.exe /I "%NewestFile%" /Q` (`%%I` isn't defined anymore after the `for` loop closed; that's why you set `NewestFile` in the first place). – Stephan May 31 '19 at 14:26
  • The `DO (` should be on the same line as the `FOR`. Seems you are repeating that typo with your edit. Ensure you fix it else it will syntax error, when run. – michael_heath May 31 '19 at 17:02

2 Answers2

1

A proposal for a solution using Powershell:

Get-ChildItem *msi | Sort-Object -Property LastWriteTime | Select -Last 1 | %{Start-Process $_.FullName -WindowStyle Hidden}

This will launch in the background the .msi file with the most recent write time in your current folder.

BeMayer
  • 380
  • 1
  • 9
  • Hi, mind helping me out and telling me where I could specify a folder in that command? Let me know, I appreciate your reply and I hope you can help, thanks! – Mitchell Monarch May 31 '19 at 14:20
  • You can either change your current directory (e.g.: `Set-Location "C:\Temp\"`) or specify the folder you want to look in with the Get-ChildItem cmdlet (`Get-ChildItem "C:\Temp\*msi"`) – BeMayer May 31 '19 at 14:36
1
@echo off
setlocal

rem Search in this directory path.
set "searchdir=%~dp0directory\"

rem Escape the directory path.
set "searchdir=%searchdir:\=\\%"

rem Display the directory path.
echo %searchdir%

rem Get the latest msi file.
for /f "usebackq tokens=1,* delims= " %%A in (`
 wmic datafile where "extension='msi' and name like '%searchdir%%%'"
 get lastmodified^, name ^| sort /r ^| findstr "\\"
`) do (
    set "NewestFile=%%~B"
    echo FoundFile: %%~B
    goto :FoundFile
)

echo No *.msi file found!
exit /b

:FoundFile
rem Install the latest msi file.
msiexec.exe /i "%NewestFile%" /q
exit /b 0

The directory fullpath is setup as directory which is appended to the directory of the script. The backslashes need to be escaped for use with wmic, so variable substition to change \ to \\ is done. The directory path is then echoed for inspection.

The for loop uses wmic to get the lastmodified timestamp and name which will be the fullpath to the found msi file. sort /r will reverse the sorted order so the latest is the first. findstr "\\" will only output values with a path separator \. The variable named NewestFile stores the msi fullpath, echo outputs the msi path to stdout for inspection, and the goto :FoundFile event occurs.

msiexec.exe runs installation with the newest file.

Note:

NewestFile may contain a msi path with trailing spaces. This should do no harm to leave and I chose not to trim in case of causing harm in an unneeded trim operation.

Testing shows that wmic processes actual paths, not reparse points i.e. symlinked paths. Ensure running the script from an actual path else the name like ... query of wmic may not match anything.

You can replace the code between the ::ENTER YOUR CODE BELOW:: and ::END OF YOUR CODE:: in your posted code, without the @echo off and setlocal as you already have those lines.

michael_heath
  • 5,262
  • 2
  • 12
  • 22
  • I feel like this is super close but I also need to query subfolders/directories and I'm under the assumption this only specifies the current directory? – Mitchell Monarch May 31 '19 at 14:44
  • 1
    True, only in `"directory"`. Added `/S` for `dir` to recurse into `"directory"`. – michael_heath May 31 '19 at 14:56
  • not quite: `dir /s` does list files folder by folder, so you can't assume you really found the latest file with this method. – Stephan May 31 '19 at 15:17
  • I feel like this is getting closer, we're almost there. It runs but I'm under the assumption it's not finding the .msi file to install? It's a folder containing 6 folders, and in it hosts the .msi I need to install, with that one needing to be installed the latest one, if this makes sense? So what I think is happening is Folder -> Folder but doesn't go into the folder to find the msi to install? If this make sense? Thank you for your help, I really appreciate it, I'm a little new at traversing and batch incase you haven't noticed – Mitchell Monarch May 31 '19 at 15:22
  • 1
    @MitchellMonarch I added an echo into the loop to ease assumption. If the msi files in a subfolder searched recursively tests OK for me. Assumptions do little to help me understand any problem that you experience. – michael_heath May 31 '19 at 15:53
  • Indeed, I'm not necessarily sure how to go about debugging a batch script, I've updated my current code to show you what I'm working with, elevated the command prompt and also integrated your code, I really do appreciate your input and that you're taking the time out to help a rookie like myself – Mitchell Monarch May 31 '19 at 15:59
  • @MitchellMonarch Elevating the script to admin can put the working directory into the System32 directory. Suggest a `cd` before the `for` loop so you get to see the current directory. If wanted, to work in the script directory, try `pushd "%~dp0"`. – michael_heath May 31 '19 at 16:05
  • @Stephan If the msi files are in the same folder, then it gets the latest. If the msi files are spread across different folders, then I agree with you that the latest chosen will be from the 1st folder found with msi files, which may not be the latest from all of them in other folders. That is what my testing shows. – michael_heath May 31 '19 at 16:17
  • Sorting over all subfolders [can be done](https://stackoverflow.com/a/37621769/2152082), but it's quite hacky and not recommended (involves changing registry settings). – Stephan May 31 '19 at 17:04
  • To answer the question, they are spread across folders which means I need to find a way to sort over all the subfolders without necessarily changing registry settings. Sounds like this just got alot more complicated, I appreciate the help you guys, the forfiles was the way I was going to sort through it and find the largest number. The files are integrated 1,3,5,6,8 etc, Increasing by number – Mitchell Monarch May 31 '19 at 17:25
  • 1
    `forfiles` @keywords are also affected by date locale settings. If you do not have [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) short date set i.e. `yyyy-MM-dd`, then sorting becomes a problem. I do not understand the integrated numbers, perhaps are version numbers. I have no info about integrated numbers so kept with the file date idea and updated the code with using `wmic`. – michael_heath Jun 01 '19 at 08:40