Issues with passing long string from powershell expression to cmd - powershell

I am having some issues with modifiying a Powershell/batch hybrid script taken from another stack overflow question (https://stackoverflow.com/a/15885133/1683264).
When selecting a file and echoing the command line parameter with quotation marks it works fine if the file name and path are short, however when the length is longer than the cmd window it will split it into two lines.
I think that this has something to do with using a command line parameter vs using a variable, however I am very new to both batch script and powershell and I'd appreciate any help!
<# : chooser.bat
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
:: https://stackoverflow.com/a/15885133/1683264
#echo off
setlocal
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
echo "%%~I"
)
pause
goto :EOF
: end Batch portion / begin PowerShell hybrid chimera #>
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "DAT Files (*.dat*)|*.dat*|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) {$f.FileNames} else {$f.FileName}
I am looking for the output to be
"fullnameandpath.dat"
however if I have a long path and file name I get something like this:
"fullnamea"
"
"ndpath.dat"

Related

use for loop to add downloading sections to a powershell script

I want to construct a powershell script that downloads a specific set of files. This set will change periodically, so a for loop is the cleanest way to update the process.
The URLs for each file update on a daily basis with both the date and a unique serial number, but I already have a process in place for extracting that info and saving it to a file. I also have a method for constructing a PS script to download a specific file from such a URL:
set /p file_info=<"<path to file with info>"
set file_dir=<known page directories>
set DL=C:\Users\%USERNAME%\Downloads\test.ps1
echo $url = "http://<domain>.com/%file_dir%/%file_info%" > "%DL%"
echo $output = "C:\Users\%USERNAME%\Downloads\%file_info%" >> "%DL%"
echo (New-Object System.Net.WebClient).DownloadFile($url, $output) >> "%DL%"
I can also loop additions to a PS script:
setlocal enabledelayedexpansion
set /p obj=<"<path to file with list of objects>"
set /p file_info=<"<path to file with info>"
set DL=C:\Users\%USERNAME%\Downloads\test.ps1
:: restarting PS script
echo #new > "%DL%"
for %%f in (%obj%) do (
set a=%%f
echo !a!!file_info! >> "!DL!"
)
However, when I replace echo !a!!file_info! >> "!DL!" with the echo lines from the first script (adapted in the same fashion), the PS script is no longer updated with the looped content (note that I now use the PS username to avoid any issues with delayed expansion):
setlocal enabledelayedexpansion
set /p obj=<"<path to file with list of objects>"
set /p file_info=<"<path to file with info>"
set file_dir=<known page directories>
set DL=C:\Users\%USERNAME%\Downloads\test.ps1
:: restarting PS script
echo #new > "%DL%"
for %%f in (%obj%) do (
set a=%%f
echo $url = "http://<domain>.com/!file_dir!/!a!/!file_info!" >> "!DL!"
echo $output = "C:\Users\$env:UserName\Downloads\!file_info!" >> "!DL!"
echo (New-Object System.Net.WebClient).DownloadFile($url, $output) >> "!DL!"
)
::alternative that doesn't work either:
for %%f in (%obj%) do (
set a=%%f
call echo $url = "http://<domain>.com/!file_dir!/!a!/!file_info!" >> "!DL!"
call echo $output = "C:\Users\$env:UserName\Downloads\!file_info!" >> "!DL!"
call echo (New-Object System.Net.WebClient).DownloadFile($url, $output) >> "!DL!"
)
Why are there issues using a for loop to add URL download sections to a PS script? Is there a way to avoid these issues?
The main problem with your code is that your echoed closing parentheses are prematurely closing the for loop parentheses. In my example below, I've escaped those with carets, ^.
Example:
#Echo Off
SetLocal EnableExtensions
Set /P "obj=" 0< "<path to file with list of objects>"
Set /P "file_info=" 0< "<path to file with info>"
Set "file_dir=<known page directories>"
Set "DL=C:\Users\%USERNAME%\Downloads\test.ps1"
( For %%G In (%obj%) Do (
Echo $url = "http://<domain>.com/%file_dir%/%%G/%file_info%"
Echo $output = "C:\Users\$Env:UserName\Downloads\%file_info%"
Echo (New-Object System.Net.WebClient^).DownloadFile($url, $output^)
)
) 1> "%DL%"

How to pass a variable value from powershell back to a batch file which calls it

I have a powershell script named CHECKlicense.ps1 which compares 2 dates:
$enddate = (Get-Date 2017-3-14).toString("yyyy-M-dd")
$today = Get-Date -format yyyy-M-dd
if($today -ge $enddate ){
Write-Output "License is expired"
$status=1
}else{
$status=0
}
exit $status
and I want to call it from a batch file and return the variable "status". I tried either
FOR /F "delims=" %%i IN ('"%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\Powershell.exe -executionpolicy remotesigned -File CHECKlicense.ps1; (Get-Variable status).value"') DO SET VAL=%%i
and
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell "&{CHECKlicense.ps1 %* ;exit $LastExitCode}" set code=%errorlevel%
But neither work. What am I missing
I ran this from the batch file to get the output with desired status value.
%errorlevel% has the value of last executed command... in this case is the powershell return value. You can access and use the variable within the script and in the same command window where you executed the batch file.
#echo off
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell C:\temp\test.ps1
echo This is the code returned by ps1: %errorlevel%
REM You can do other things inside your batch file with %errorlevel%.
Output
License is expired
This is the code returned by ps1: 1

How can I open the 'Save' Dialog Box from my batch file

The scenario I have in mind is as follow:
- User drags a file (example text.txt) onto the .bat script.
Batch file opens the Save Dialog box, allowing the user to save this file under another name.
As I understand, I should define the file to be dragged and dropped, as %1 and what I am missing is how to open the Save Dialog box from the batch file.
My current code is:
<# : chooser.bat
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
:: https://stackoverflow.com/a/15885133/1683264
#echo off
setlocal
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
echo You chose %%~I
)
goto :EOF
: end Batch portion / begin PowerShell hybrid chimera #>
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
:: i tried to change $f = new-object Windows.Forms.SaveFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }
I think you should give a filename as input.
Calling the member => FileName.
It seems "Windows.Forms.SaveFileDialog()" should do.

When calling a powershell script from a batch file, and exiting with a value, errorlevel is 0 in batch file, not the exit value

When calling a powershell script from a batch file, and exiting with a value, errorlevel is 0 in batch file, not the exit value
I've tried using the code below to call a powershell script which exits with a number that should be an errorlevel in the batch file, but when I check %errorlevel% in the batch file, it is always zero.
I'm calling it in the For loop as I need to also have it return some text.
This is the powershell script:
# TestReturnValAndCode.ps1
$DataIn = $args[0]
$ReturnVal="You passed in the text '" + $DataIn + "'"
$ReturnVal
exit 1234
This is the batch file:
:: testpscaller.bat
#echo off
set "BaseFolder=C:\temp\test"
set "TestPSScript=%BaseFolder%\TestReturnValAndCode.ps1"
set "TestValue=Test This Text"
for /f "delims=" %%a in ('powershell -executionpolicy bypass -file
"%TestPSScript%" "TestValue"') do set "ReturnVal=%%a"
#echo ErrorLevel=[%ErrorLevel%]
#echo ReturnVal=[%ReturnVal%]
This is the result:
ErrorLevel=[0]
ReturnVal=[You passed in the text 'TestValue']
THe ErrorLevel should be 1234.
What do I need to do to get both my text value and the error level (that is not too klunky/kludgy)
The for command does not return the %errorlevel% of the (last) command executed inside it. You need to "convert" such an %errorlevel% into text inside the for body in order to get it as a second line outside the for:
:: testpscaller.bat
#echo off
set "TestPSScript=.\TestReturnValAndCode.ps1"
set "ReturnVal="
for /f "delims=" %%a in ('powershell -executionpolicy bypass -file "%TestPSScript%" "TestValue" ^& echo %ErrorLevel%') do (
if not defined ReturnVal (
set "ReturnVal=%%a"
) else (
set "ReturnErrorLevel=%%a"
)
)
#echo ErrorLevel=[%ReturnErrorLevel%]
#echo ReturnVal=[%ReturnVal%]
Output:
ErrorLevel=[1234]
ReturnVal=[You passed in the text 'TestValue']
EDIT:
This is strange. I did this method work before. However, it seems that the echo %ErrorLevel% command placed inside the FOR body reports the errorlevel value set by the last execution of powershell outside a FOR command... I don't understand this behavior... :(
A workaround is store the powershell output in a temp file:
:: testpscaller.bat
#echo off
set "TestPSScript=.\TestReturnValAndCode.ps1"
powershell -executionpolicy bypass -file "%TestPSScript%" "TestValue" > TempFile.txt
#echo ErrorLevel=[%ErrorLevel%]
set /P "ReturnVal=" < TempFile.txt
#echo ReturnVal=[%ReturnVal%]

Command line to move the contents of an unnamed folder

I am trying to do a batch that fixes my flash drive from shortcut virus infection. I want to move the files from an unnamed folder (Alt+255) to the root directory of my flash drive, what is hard is that I can't do that with the short name of the folder because it is variable (one time it is 00A0~1 the other is 9DEC~1) so I am thinking of making a command that loops through the folders and prompts them to the user to decide if this is the unnammed folder or no like so (" " is that the folder? (Y/N)) similar to the output of this command:
for /d %d in (*) do rmdir /s "%d"
, but it moves all the contents of it to the root directory not delete it. How to do that?
You might be better off using VBScript or PowerShell for this instead.
VBScript:
Set fso = CreateObject("Scripting.FileSystemObject")
source = "K:\"
quarantine = "C:\quarantine"
Set re = New RegExp
re.Pattern = "^[^a-z0-9_-]"
re.IgnoreCase = True
For Each fldr In fso.GetFolder(source).SubFolders
If re.Test(fldr.Name) Then
answer = MsgBox("Move " & fldr.Path & "'?", vbYesNo, "Folder Check")
If answer = vbYes Then fldr.Move quarantine & "\"
End If
Next
PowerShell:
$source = "K:\"
$quarantine = "C:\quarantine"
Get-ChildItem $source -Force | ? {
$_.PSIsContainer -and $_.Name -match '^[^a-z0-9_-]'
} | % {
$answer = Read-Host "Move $($_.FullName)? [Y/n]"
if ( $answer.Length -eq 0 -or $answer[0] -eq "y" ) {
$_.MoveTo((Join-Path $quarantine $_.Name))
}
}
Both solutions check the source folder for folder names not starting with an alphanumeric character, underscore, or hyphen, prompt the user, and (on confirmation) move that folder to the quarantine folder.
If you want to use the PowerShell version on Windows XP, you have to install the Windows Management Framework first. PowerShell is included with that package.
This might work for you:
for /d %%i in (*) do echo %%~i |findstr "ECHO is" >nul&& move "%%~i" ELSEWHERE
This may move the folder   to ELSEWHERE.
for /d %%i in (*) do echo %%~i |findstr "ECHO is" >nul&& rd "%%~i"
This may remove the folder .
This may help:
#echo off
set "var="
for /f "delims=" %%a in ('dir /ad /b') do (
echo "%%a"
set /p "var=Is that it? press enter for no and Y for yes: "
if defined var (
attrib -h -s -r -a "%%a" /d
move "%%a\*.*" \
)
set "var="
)