Windows / Powershell get Program Version into variable - powershell

I'm close but not there. I can get the version of my application via powershell, but it's got a bunch of text along with it.
This command:
powershell -NoLogo -NoProfile -Command ^
(get-item -Path 'c:\myapp.exe').VersionInfo ^| ^
Format-List -Force | findstr "ProductVersion" > c:\version.txt
produces (in a text file):
ProductVersion : 1.6.7.0
Is it possible via a single command in powershell to split it? I can't run ps scripts in my environment. But if I could, I would run this:
$mystr = (get-item -Path 'c:\myapp.exe').VersionInfo | Format-List -Force | findstr ProductVersion
$arr = $mystr -split ": "
$arr[1]
Is there a way to put this on a single line and put it into a environment (batch) variable?

Given your provided method, with some modification, perhaps this would do it?
#Echo Off
For /F "Delims=" %%A In ('Powershell -C^
"(GI 'C:\myapp.exe').VersionInfo.ProductVersion"') Do Set "PV=%%A"
Echo=%PV%
Pause

Mayhap
| for /f "tokens=3" %%a in ('findstr "ProductVersion"') do echo %%a>filename
or
| for /f "tokens=3" %%a in ('findstr "ProductVersion"') do set "prodver=%%a"
or
| for /f "tokens=3" %%a in ('findstr "ProductVersion"') do setx prodver "%%a"
but no guarantees. Note the setx version may establish a registry entry for future process instances, not for the current instance. /m would need to be added to make it a HKLM instead of a HKCU variable (if it works)

You can also use WMIC to get version of your application :
#echo off
Title Get File Version of any Application using WMIC
Set "Version="
Set "AppFullPath=%Windir%\notepad.exe"
Call :Get_AppName "%AppFullPath%" AppName
Call :Add_backSlash "%AppFullPath%"
Call :GetVersion %Application% Version
If defined Version (
echo Vesrion of %AppName% ==^> %Version%
)
pause>nul & Exit
::*******************************************************************
:Get_AppName <FullPath> <AppName>
Rem %1 = FullPath
Rem %2 = AppName
for %%i in (%1) do set "%2=%%~nxi"
exit /b
::*******************************************************************
:Add_backSlash <String>
Rem Subroutine to replace the simple "\" by a double "\\" into a String
Set "Application=%1"
Set "String=\"
Set "NewString=\\"
Call Set "Application=%%Application:%String%=%NewString%%%"
Exit /b
::*******************************************************************
:GetVersion <ApplicationPath> <Version>
Rem The argument %~1 represent the full path of the application
Rem without the double quotes
Rem The argument %2 represent the variable to be set (in our case %2=Version)
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='%~1'" get version /format:Textvaluelist 2^>^nul'
) DO FOR /F "delims=" %%A IN ("%%I") DO SET "%2=%%A"
Exit /b
::*******************************************************************

Just use the ProductVersion property on the VersionInfo object and assign the result to an environment variable:
$ENV:MyEnvVariable = (get-item -Path 'c:\myapp.exe').VersionInfo.ProductVersion

Related

Getting a variable from a powershell script, in a batch file

I have seen some similar questions on this here on stack overflow, but I cannot get any of the answers to far to work.
I have this .ps1 file that mounts a drive and echos the drive letter (expected $driverLetter = "G" || "H" || "I"):
$mountDisk = Mount-DiskImage -ImagePath $args[0] -Passthru
$driveLetter = ($mountDisk | Get-Volume).DriveLetter
echo $driveLetter
I'm running it from this batch file:
FOR /F "usebackq delims=" %%i IN (`powershell -File ./mountDisk.ps1 "%1"`) DO SET "d=%%i"
Echo %d%
Each time I get an empty variable. I've tried setting environment variables, but yield same result.
Here's how I'd probably do it, assuming that the initial path passed to the batch file is double-quoted as necessary.
#Echo Off & SetLocal EnableExtensions & Set "ISODrv="
If /I Not "%~x1" == ".iso" (Exit /B 1) Else For %%G In ("%~1") Do If "%%~aG" GEq "d" Exit /B 2
For /F %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "(Mount-DiskImage -ImagePath \"%~1\" -PassThru | Get-Volume).Driveletter" 2^>NUL') Do Set "ISODrv=%%G"
If Not Defined ISODrv (Exit /B 3) Else Echo %ISODrv%
Doing it this way eliminates the need for pre-creating a PowerShell script, and then any subsequent modifications to the execution policy. It only proceeds with the image mount if the received input value was an existing ISO file too. If you're running this batch file from a process which retrieves its exit code, 1 means that the input did not end with the case insensitive string .iso, 2 would mean that the input did end with the case insensitive string .iso, but it was a directory, not a file, and 3 would indicate that there was an error returning the mounted ISO image drive letter.
Try the following to run the cmd from the PowerShell and pathing their variables to it
# The command to pass to cmd.exe /cript
$var = "echo hello world & ping $ip & pause"
$ip = "192.168.1.1"
$var2 = "ping $ip & pause"
# Start the process asynchronously, in a new window,
# as the current user with elevation (administrative rights).
# Note the need to pass the arguments to cmd.exe as an *array*.
Start-Process -Verb RunAs cmd.exe -Args '/c', $var2, $var

How to set a variable in cmd which is a string from powershell command result?

I want to store the result of powershell command in cmd variable as String : powershell -com "(ls | select -Last 1).FullName". How to do this?
CMD does not have a straightforward way of assigning command output to a variable. If the command produces just a single line you could use a for loop
for /f "delims=" %a in ('some_command /to /run') do #set "var=%a"
However, if the command produces multiple lines that will capture only the last line. A better approach would be redirecting the output of the command to a file and then reading that file into a variable:
set "tempfile=C:\temp\out.txt"
>"%tempfile%" some_command /to /run
set /p var=<"%tempfile%"
del /q "%tempfile%"
If you literally need only the last file in a directory you don't need to run PowerShell, though. That much CMD can do by itself:
for /f "delims=" %f in ('dir /a-d /b') do #set "var=%~ff"
Beware that you need to double the % characters when running this from a batch file.
A FOR loop can provide the path to the file. If the default directory sorting order is not the result needed, specify additional command line switches on the DIR command.
FOR /F "delims=" %F IN ('DIR /B') DO (SET "THE_FILE=%~fF")
ECHO THE_FILE is "%THE_FILE%"
In a .bat file script, double the percent characters on FOR loop variables.
FOR /F "delims=" %%F IN ('DIR /B') DO (SET "THE_FILE=%%~fF")
ECHO THE_FILE is "%THE_FILE%"
The .bat file scripts can also run PowerShell scripts. It is best practice to not use aliases such as ls in scripts.
FOR /F "delims=" %%F IN ('powershell -NoLogo -NoProfile -Command ^
"(Get-ChildItem -File | Select-Object -Last 1).FullName"') DO (SET "THE_FILE=%%~fF")
ECHO THE_FILE is "%THE_FILE%"
The problem with cmd here is that I want to get the full paths for
FOLDERs NOT recursive... this dir /ad /b doesn't give full paths and
this dir /ad /b /s does it recursively... – stakowerflol 2 hours ago
That's not a problem, you can return the full file path without recursing.
If you are changing directory to the path you need to check then it's stored in %CD%
If you need the path to whee the Script itself is it's stored in %~dp0
If you want to provide an argument to specify and arbitrary path and get all of the listings it will be that argument term (EG %~1)
With all three possible options you can do the same thing:
Either
Prepend the provided variable to the output of the chosen directory enumeration method
OR
Use a For loop to get the file names at that path and show the result with the full path.
IE
Jenkins_A_Dir.bat
#(
SETLOCAL
ECHO OFF
SET "_Last="
ECHO.%~1 | FIND /I ":\" > NUL && (
SET "_CheckHere=%~1"
)
IF NOT DEFINED _CheckHere (
SET "_CheckHere=C:\Default\Path\When\No Argument\Specified"
)
)
REM Use a For loop to get everything in one variable
FOR %%A IN (
"%_CheckHere%\*"
) DO (
SET "_Last=%%A"
)
ECHO.Found "%_Last%"
REM Use `FOR /F` with DIR, and append the path to Check:
SET "_Last="
FOR /F "Tokens=*" %%A IN ('
DIR /A-D /B "%_CheckHere%\*"
') DO (
SET "_Last=%_CheckHere%\%%A"
)
ECHO.Found "%_Last%"
Of course you don't NEED to have set a variable such as _CheckHere
Instead, you can just replace all of the instances of %_CheckHere% with `%~1 instead, that would work just fine in the above examples too.
Okay, what if you just wanted to check the location the script was running in.
Then either change the above to use SET "_CheckHere=%~dp0" or Replace %_CheckHere% with %~dp0 throughout.
Okay but what if you don't want to set a variable you want to it to use the current working directory.
When then, even easier:
Jenkins_Current_Dir.bat
#(
SETLOCAL
ECHO OFF
SET "_Last="
)
REM Use a For loop to get everything in one variable
FOR %%A IN (
"*"
) DO (
SET "_Last=%%~fA"
)
ECHO.Found "%_Last%"
REM Use `FOR /F` with DIR, and let it append the current working directory to the path:
SET "_Last="
FOR /F "Tokens=*" %%A IN ('
DIR /A-D /B "*"
') DO (
SET "_Last=%%~fA"
)
ECHO.Found "%_Last%"

Folder being used for another process on batch script

I have a issue with a backup script I wrote. The backup is pretty simple. It will copy a directory to a destination path, and then zip it. I have a few If clauses to, example, delete the oldest backup if there are 5 or more .zip from previous backups.
The problem I'm facing is: after the XCOPY command has finished running I then run a PowerShell script from my Batch to zip the backup, but I get this error:
This happens becaus the .bat file is running. I've checked.
The code for both the batch and power shell script follows:
BATCH:
echo "========================================="
echo "=====| Backuping DCT Light's Files |====="
echo "========================================="
SET dct-light_src=\\w102xnk172\c$\inetpub\wwwroot\DCT_NEW
For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set dct_light_startting_date=%%c-%%a-%%b)
For /f "tokens=1-2 delims=/:" %%a in ("%TIME%") do (set dct_light_startting_time=%%a%%b)
SET starttime=%dct_light_startting_date%
CD C:\Users\william_silva4\Desktop\tools_backup\dct_light\
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A "N=0"
FOR /F %%f IN ('DIR /B /A:-D "*"') DO (SET /A "N=!N!+1")
IF %n% == 5 (
powershell.exe -noexit -file "C:\Users\william_silva4\Desktop\remove_oldest.ps1"
) ELSE (
IF EXIST C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%starttime%\ (
MD C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%starttime%\dctlight_backup
SET dct-light_dtn=C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%starttime%\dctlight_backup
echo A folder for this backup already exists. Beggining overwrite...
) ELSE (
MD C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%starttime%\dctlight_backup
SET dct-light_dtn=C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%starttime%\dctlight_backup\
)
)
CD C:\Users\william_silva4\Desktop\backup_completo
XCOPY %dct-light_src% %dct-light_dtn% /w /e /y /EXCLUDE:C:\Users\william_silva4\Desktop\backup_completo\exclusion.txt
For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set dct_light_finished_date=%%c-%%a-%%b)
For /f "tokens=1-2 delims=/:" %%a in ("%TIME%") do (set dct_light_finished_time=%%a%%b)
SET startdate=%dct_light_finished_date%
SET starttime=%dct_light_startting_date%_%dct_light_startting_time%
SET finishedtime=%dct_light_finished_date%_%dct_light_finished_time%
CD C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%startdate%\
echo.LOG of %starttime%'s Backup>LOG_%startdate%.txt
echo.Start time: %starttime%>>LOG_%startdate%.txt
echo.Finished time: %finishedtime%>>LOG_%startdate%.txt
CD C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_%startdate%\dctlight_backup\
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A "N=0"
FOR /F %%f IN ('DIR /S /B /A:-D "*"') DO (SET /A "N=!N!+1")
CD ../
echo.Files copied: %N%>>LOG_%startdate%.txt
powershell.exe -noexit -file "C:\Users\william_silva4\Desktop\zip_backups.ps1"
pause>nul
POWER SHELL:
#DCT Light's zipping
Start-Sleep -s 15
$source = "C:\Users\william_silva4\Desktop\tools_backup\dct_light"
$date = Get-Date -UFormat "%Y-%m-%d"
$destination = "C:\Users\william_silva4\Desktop\tools_backup\dct_light\dctlight_backup_$date.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
Remove-Item $source\* -Recurse -Exclude *.zip
What I have tried to solve the problem:
Create a Master.ps1 with a list of scripts to run, where the first one is, obliviously, the backup batch file and then the zipping ps1 file.
Call the zipping ps1 file from the backup batch file on another window and then kill the batch. In this case, the first line of the zipping script was:
Start-Sleep -s 15
So I was certain that the batch was killed before I really started zipping.
None of the above worked. Any help? If nothing works I'll just schedule them as separated tasks on Windows.

how to pass variable from PowerShell to batch variable

I call the powershell command in batch and want to save the $tmpVersion to batch variable "version".
set version = powershell.exe -Command "$tmpVersion = (Get-ItemProperty 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\myapp').DisplayVersion;"
You can use a For loop to save the result of a command as a variable:
powershell.exe example:
#Echo Off
Set "RegRoot=HKLM"
Set "RegKey=SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\myapp"
Set "RegVal=DisplayVersion"
Set "Version="
For /F %%A In (
'PowerShell -NoP -NoL "(GP '%RegRoot%:%RegKey%').%RegVal%" 2^>Nul'
) Do Set "Version=%%A"
If Not Defined Version Exit /B
Echo %Version%
Pause
reg.exe example:
#Echo Off
Set "RegRoot=HKLM"
Set "RegKey=SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\myapp"
Set "RegVal=DisplayVersion"
Set "Version="
For /F "Tokens=2*" %%A In ('Reg Query "%RegRoot%\%RegKey%" /V "%RegVal%" 2^>Nul'
) Do Set "Version=%%B"
If Not Defined Version Exit /B
Echo %Version%
Pause
WMIC.exe example:
#Echo Off
Set "RegRoot=&H80000002"
Set "RegKey=SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\myapp"
Set "RegVal=DisplayVersion"
Set "Version="
For /F Tokens^=2Delims^=^" %%A In ('WMIC Class StdRegProv
Call GetStringValue hDefKey^="%RegRoot%" sSubKeyName^="%RegKey%"
sValueName^="%RegVal%" 2^>Nul') Do Set "Version=%%A"
If Not Defined Version Exit /B
Echo %Version%
Pause

How to set variable with the result of findstr

I am trying to write a batch file which searches for pdf files and finds how many pages they have and loop all pages.
I wrote the following. I can find the files, I can even find the pagecounts with a tool named pdftk. The results is as below.
C:\Users\test\Documents\fishes\Fish_1.pdf
NumberOfPages: 5
How can I set a variable which has the value of 5?
#ECHO off
for /R %%i IN (*.pdf) DO (
ECHO %%i
"C:\Program Files (x86)\PDF Labs\PDFtk Server\bin\pdftk.exe" %%i dump_data | findstr NumberOfPages
set pagecount = findstr NumberOfPages ???
FOR /L %%j IN (1,1,%pagecount%) DO (
ECHO "page " + %%j
)
)
You were already 90% there. Use the FOR /F command to process the results of a command. Type HELP FOR from the command prompt for more info.
for /f "tokens=2" %%A in (
'"C:\Program Files (x86)\PDF Labs\PDFtk Server\bin\pdftk.exe" %%i dump_data ^| findstr NumberOfPages'
) do set numberOfPages=%%A