Running a PowerShell script inside a Batch file - powershell

I've been trying to integrate a PowerShell script inside a Batch file but I seem to get some errors when trying to do so.
This is my code so far:
for /F "tokens=* delims=," %%A in (C:\MACs.log) do (
#ECHO OFF
PowerShell.exe "& arp -a | select-string "%%A" |% {$_.ToString().Trim().Split(" ")[0]} >> C:\tempfile.log
Ok so, when I run this command in PowerShell everything is working OK but in Batch I get some token errors.
The main post of this code is to create a loop from the MACs.log where I have a couple of MAC addresses that I want the IP addresses to and output them to tempfile.log.
If someone can lend a helping hand it would be greatly appreciated.

Why not directly solve it from the batch file?
(for /f %%a in ('
arp -a ^| findstr /l /i /g:"c:\MACs.log"
') do #echo %%a) > c:\tempfile.log
The inner pipe command will execute the arp and filter its output using the mac addresses found in MACs.log. This list is processed by the for /f command that will retrieve the first token in the line (default behaviour), that is, the ip address, and echo it. All the output is sent to a tempfile.

Related

Grab an unknown IP from ipconfig and edit an unknown .ini line with that IP with BATCH script

Currently i have a setup where a program wants my LAN IP to attach their data to and this LAN IP are always random when i reboot my system. My LAN IP is always different as i do use a VPN so it's kind of a hazzle everytime i either change network or reboot as i do need to run the program, change it, restart it.
I do have a script that will make a variable with the correct IP, as it's always the first IPv4 Address. I did find it on this site.
set ip_address_string="IPv4 Address"
rem Uncomment the following line when using older versions of Windows without IPv6 support (by removing "rem")
rem set ip_address_string="IP Address"
for /f "usebackq tokens=2 delims=:" %%f in (`ipconfig ^| findstr /c:%ip_address_string%`) do (
echo Your IP Address is: %%f
goto :eof
)
This is golden, but every .ini edit post i've found do not actually work for me as it prints the line infinetly instead of editing the line.
As the size of the .ini is unknown i do need a powershell script in order for it to work as BATCH has limitations.
One user on Stackoverflow had this code:
(Get-Content C:\ProgramData\Nuance\NaturallySpeaking12\nssystem.ini) | ForEach-Object { $_ -replace 'Default NAS Address=.*','Default NAS Address=BHPAPPDGN01V' } | Set-Content C:\ProgramData\Nuance\NaturallySpeaking12\nssystem.ini
The line that needs to be changed is mostly random. Well, not random, but it'll move sometimes as users can make some changes and it'll push the IP line down or up depending on the settings.
I'm a bit novice when it comes to BATCH and powershell and i haven't figured out a way to transfer information to powershell. For example, BATCH will grab the IP, make a variable, run a powershell script editing the .ini. I do remember having a code that grabbed the IP to clipboard but i cannot find it in this moment.
My current progress is
#echo off
setlocal EnableExtensions
echo Exiting PROGRAM...
taskkill /IM PROGRAM.exe
timeout /t 1 /nobreak>nul
:check
for /F %%a in ('tasklist /NH /FI "IMAGENAME eq PROGRAM.exe"') do if %%a == PROGRAM.exe goto waiting
echo Restarting PROGRAM...
start "" "%ProgramFiles%\PROGRAM\PROGRAM.exe"
timeout /t 1 /nobreak>nul
exit
:waiting
echo PROGRAM is still running. Retrying...
timeout /t 3 /nobreak>nul
goto check
I don't need setlocal EnableExtensions but i did try to get it to work and it was needed then.
Currently the script look if the program is running, if it is, kill it softly (wait for it to natively quit) then restart it. My goal is to kill it softly, edit the .ini and then restarting it with the changed made.
A pure PowerShell solution would be most likely the best for this task because of Windows command processor cmd.exe is not designed for editing files.
But here is a pure batch file solution for determining the current IPv4 address and write it into the INIĀ file if it contains currently a different address.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "IniFile=C:\ProgramData\Nuance\NaturallySpeaking12\nssystem.ini"
if exist "%IniFile%" goto GetIpAddress
echo ERROR: File missing: "%IniFile%"
echo/
pause
goto EndBatch
:GetIpAddress
set "ip_address_string=IPv4 Address"
rem Uncomment the following line when using older versions of Windows without IPv6 support (by removing "rem")
rem set "ip_address_string=IP Address"
rem The string above must be IP-Adresse on a German Windows.
for /F "tokens=2 delims=:" %%I in ('%SystemRoot%\System32\ipconfig.exe ^| %SystemRoot%\System32\findstr.exe /C:"%ip_address_string%"') do set "IpAddress=%%I" & goto IpAddressFound
echo ERROR: Could not find %ip_address_string% in output of ipconfig.
echo/
pause
goto EndBatch
:IpAddressFound
set "IniEntry=Default NAS Address"
rem Remove leading (and also trailing) spaces/tabs.
for /F %%I in ("%IpAddress%") do set "IpAddress=%%I"
rem Do not modify the INI file if it contains already the current IP address.
%SystemRoot%\System32\findstr.exe /L /X /C:"%IniEntry%=%IpAddress%" "%IniFile%" >nul
if errorlevel 1 goto UpdateIniFile
echo The file "%IniFile%"
echo contains already the line: %IniEntry%=%IpAddress%
echo/
goto EndBatch
:UpdateIniFile
for %%I in ("%IniFile%") do set "TempFile=%%~dpnI.tmp"
(for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "%IniFile%" 2^>nul') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined Line echo(
for /F delims^=^=^ eol^= %%J in ("!Line!") do (
set "FirstToken=%%J"
if "!FirstToken!" == "%IniEntry%" (
echo %IniEntry%=%IpAddress%
) else echo(!Line!
)
endlocal
))>"%TempFile%"
rem Replace the INI file by the temporary file, except the temporary file is empty.
if exist "%TempFile%" (
for %%I in ("%TempFile%") do if not %%~zI == 0 (
move /Y "%TempFile%" "%IniFile%" >nul
echo Updated the file "%IniFile%"
echo with the %ip_address_string% "%IpAddress%" for INI entry "%IniEntry%".
echo/
)
del "%TempFile%" 2>nul
)
:EndBatch
endlocal
Please read my answer on How to read and print contents of text file line by line?
It explains the awful slow code to update the INI file using just Windows Commands.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
ipconfig /?
move /?
pause /?
rem /?
set /?
setlocal /?
See also Single line with multiple commands using Windows batch file for an explanation of operator &.
Read the Microsoft article about Using command redirection operators for an explanation of >, 2>nul and |. The redirection operator | must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with ipconfig and findstr with using a separate command process started in background with %ComSpec% /c and the command line between the two ' appended.
Mofi had a great batch solution, but he mentioned that CMD was not really designed for file output like this. So here's a pure powershell solution that should do what you want. It does borrow a bit from the powershell snippet you included in your question.
$ip = Get-NetIPAddress -InterfaceAlias "Ethernet" #| Out-File PathTo:\net.ini
$content = get-content PathTo:\net.ini | ForEach-Object { $_ -replace "172.23.*","$($ip.IPAddress)"}
$content | Set-Content PathTo:\net.ini
Obviously this depends on you knowing the Interface Alias you want to grab, but you can find that easily with Get-NetIPAddress, and it shouldn't change. You'll also need to update the path information.

Is there a way to capture the file path and name in the same batch function?

I am creating a batch script to perform robocopy functions. Currently I am having to call two different PowerShell selections, one for the file name and then one for the source folder, can I combine this?
Using the code below I can capture the file name, but can I capture both using one method?
echo Select your file
set pwshcmd=powershell -NoProfile -Command "&{[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null;$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog; $OpenFileDialog.ShowDialog()|Out-Null; $OpenFileDialog.SafeFileName}"
for /f "delims=" %%I in ('%pwshcmd%') do (
set "FileName=%%I"
)
echo %FileName%
pause
I wish for the user to make one selection with PowerShell and it set two variables %FileName% and %FilePath%, as this will be used in the robocopy script.
I appreciate everyone's input on this question. I had solved it shortly after posting, however I did run into the fact that robocopy wants a directory path without the ending "\". The method used to gather both paths were:
for /f "delims=" %%I in ('%pwshcmd%') do (
set "r_copy_file_source_path=%%~dpI"
set "r_copy_file_source=%%~nxI"
)
This provided me with both variables required, then I trimmed the ending "\" from the path with:
set r_copy_file_source_path=%r_copy_file_source_path:~0,-1%
Again, I appreciate the responses! Thank you!

Psexec batch file foor loop error

I have problem. All working on local machine but when use psexec i get error.
This is scrap of my .bat file
psexec.exe \%pc% cmd.exe /k for /f "tokens=2 delims=:" %%g in ('certutil -verifystore My ^| findstr /i "serial"') do echo %%g
On local cmd all its work but on remote i get error:
"At this point | was unexpected"
Could you help me?
Correct part of code
(...) in ('"certutil -verifystore My | findstr /i serial"') do (...)

for /f is not working in .bat file but it works with command prompt in windows 2003

for /f "tokens=1-7 delims=,: " %a in ('query user ^| find /i "disc"') do logoff %b
This above code is used for logoff remote desktop users where state is "Disconnected" in windows 2003.It will work perfect when I run in command prompt. But it will not run when I made a .bat file or .cmd file in windows 2003.so may know where i am going wrong?
Inside batch files the percent signs used in the for replaceable parameters need to be escaped
for /f "tokens=1-7 delims=,: " %%a in ('query user ^| find /i "disc"') do logoff %%b
User585,
Yes, inorder to implement the for loop inside a bat/cmd session, you need to place the variable with
%%a
like this
for /f %%a in (.\hosts) do quser /server:\\%%a

Command Prompt "dir /b /s > file.txt" need to remove directories from results

I am using the following command to dump the complete file listings recursively from a directory.
dir /b /s c:\myfolder > c:\mylist.txt
This works fine but it is display the results with the full path as well, beacuse I am using a regex expression on the results I need them to display only the filenames.
Anyone any ideas?
Kind of an old question but if someone stumbles across this hoping for an answer, perhaps this will help them out.
Running this from the windows command line (CMD.exe) use:
setlocal enabledelayedexpansion
for /f "delims=" %a in ('dir /b /s c:\myfolder"') do (#echo %~nxa >>c:\mylist.txt)
endlocal
Running this from a windows .BAT script use:
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('dir /b /s c:\myfolder"') do (#echo %%~nxa >>c:\mylist.txt)
endlocal
The output might look something like this depending on what files are in the folder you're running the code in:
file1.fil
file2.fil
file3.fil
UNDERSTANDING WHAT THE CODE IS DOING
for /f
means to run a loop through files in this case using the dir /b /s command to help get those files names from directories (folders) and subdirectories (subfolders). As stated in the question, this will give you complete paths to the files. So instead of file.txt you will get C:\folder\file.txt.
"delims="
in this case tells the for loop that it wants the variable %a or %%a
to only have 1 folderpath and filename for every loop.
%a (CMD.exe) %%a (.BAT)
as mentioned above is a variable that changes with each loop. so
everytime the command dir /b /s finds a new filename the variable
%%a changes to the filename.
example:
Loop 1: %%a = c:\folder\file1.fil
Loop 2: %%a = c:\folder\file2.fil
dir /b /s
is the command to print out the files of a directory (folder). By
using the /b and /s the questioner is adding additional criteria.
the command dir not only prints out the files and directories
(folders) in that directory (folder) but also some additional
information about the directory.
the /b tells the command dir that it doesn't want the additional
information.. just the filenames.
The /s tells the command dir to include all the files and
subdirectories (subfolders) in that folder.
do
is the part of the loop that tells what to do during that particular
loop. So in this case it is only doing this one command every loop
(#echo %%~nxa >>c:\mylist.txt)
#echo
is a simple command that prints out whatever you want either to your
computer screen or in this case to a txt file by using #echo %%~nxa
>>c:\mylist.txt
the >> before c:\mylist.txt is especially important. Every time a
loop happens it starts a new line in the txt file and writes the
variable to that line. If only one > is specified it will overwrite
the line in the txt file everytime the loop happens. Which will
defeat the purpose of what this script is designed to do.
%~nxa (CMD.exe) %%~nxa (.BAT)
is the variable %%a as mentioned above except it is parsed (edited)
out the way the questioner #fightstarr20 asked for. Instead of
printing out the variable as C:\myfolder\myfile.fil the variable
will print out as myfile.fil
the ~ in %%~nxa tells the program you want to modify the variable
%%a. In this case by adding n and x.
the n in %%~nxa tells the program you want to modify the variable %%a by
excluding the path from the variable.
example.
-variable %%a = C:\folder\filename.fil
-variable %%~na = filename.
-If you notice however that it leaves the extension .fil off of the filename.
the x in %%~nxa tells the program you want to modify the variable %%a
by excluding the path and the filename from the variable, so all you will get is the extension of the filename.
example.
-variable %%a = C:\folder\filename.fil
-variable %%~xa = .fil
so if you combine both of the modifiers n and x to the variable %%a
you will get the full filename including the extension.
example:
-variable %%a = c:\folder\filename.fil
-variable %%~nxa = filename.fil
setlocal enabledelayedexpansion
explained simply is a command that needs to be in the script before
the for loop in order to allow the variable %%a to be modified or "expanded".
endlocal
this turns off the setlocal enabledelayedexpansion command
To get a very helpful explanation and reference for CMD commands I recommend reading ss64.com and for a great forum to get CMD answers I'd recommend dostips.com
Change your regex to get the filename from the entire path.
If you can use powershell, look at Get-ChildItem. You can have more powerful options with it.
Use it like this
dir /b /s C:\myfolder>C:\temp.txt
echo exit>>C:\temp.txt
goto loop
:loop
set /p _x=<temp.txt
findstr /v /c:"%_x%" temp.txt>temp2.txt
type temp2.txt>temp.txt
set _x=%_x:*\=%
echo %_x%>file.txt
if "%_x%" == "exit" (
del temp.txt
del temp2.txt
exit
)
goto loop
You can use for instead of goto if you like, but it will be basicaly the same.
Sorry about the last one...
I know I'm a bit late, but it hurts me that nobody said to take away the /s
dir /b c:\myfolder > c:\mylist.txt
That should do it.
This would surely work, as it works for me.
dir D:(Path to files) /s /b >d:\filelist.txt
You can just use this code:
dir /b > A_fileslist.txt
Copy inside a notepad editor and save as "Fileslist.bat".