How can I send a batch variable to a powershell command - powershell

I don't know how to fix it...
I'm trying to move random files from one folder to another but I want so I can determine the folders inside the batch file but when I run the batch file it doesn't work and if I change the %var% manual from editing the batch file it's working.
I'm sorry if this is a simple question but I'm kinda new to batch and still learning.
#echo off
set /p var1=Enter first dir:
set /p var2=Enter second dir:
::Var (Folder Directory)
echo %var1%
echo %var2%
powershell -Command "& {%var1% | Get-Random -Count 5 | Copy-Item -Destination %var2%}"
pause

Use $env:var in PowerShell
#echo off & cd /d "%~dp0"
set /p "var1=Enter first dir: "
set /p "var2=Enter second dir: "
echo %var1% & echo %var2%
powershell -nop -c "ls $env:var1 | Get-Random -Count 5 | Copy-Item -Destination $env:var2"
pause

There's no reason access those variables from within PowerShell itself, as they are parsed/expanded by cmd.exe before being passed to it.
The biggest issues with your shown method, is that you should use Get-ChildItem, (gci, dir, ls), to list the items in %var1%, and enclose your variables within single quotes, or escaped doublequotes, to ensure they are understood to be valid strings.
%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoProfile "Get-ChildItem \"%var1%\" -File -Force | Get-Random -Count 5 | Copy-Item -Destination \"%var2%\""

Related

Comments in a long-line PowerShell code in a Batch script

I have a large batch script to which I need to add some Powershell code for some regex capture which I am unable to do in batch. I was hoping to have this code integrated in my batch script using the method outlined in Link, but when adding comments I get a missing } error. I've simplified my code just to be able to replicate the issue.
This, without a comment, works:
#echo OFF
setlocal enabledelayedexpansion enableextensions
set "var=variable"
PowerShell ^
foreach ($file in Get-ChildItem -File -Include *.* -Recurse) ^
{ ^
Write-Host $file; ^
Write-Host $env:var; ^
}
%End PowerShell%
echo Test
pause > nul
This, with a comment, does not work:
#echo OFF
setlocal enabledelayedexpansion enableextensions
set "var=variable"
PowerShell ^
foreach ($file in Get-ChildItem -File -Include *.* -Recurse) ^
{ ^
#Comment ^
Write-Host $file; ^
Write-Host $env:var; ^
}
%End PowerShell%
echo Test
pause > nul
I have tried escaping the # in a few different ways, but no matter what I do, I get the error message
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndCurlyBrace
The only difference is the comment. Does anyone know how to get around this? (using this long-line method that is). If it's not at all possible I guess I will go for base64 encoding
What works for me if when I do the comment line in between <# and #> as if it were a comment block.
Then of course for cmd you need to escape the < and > characters with a ^:
^<# Comment #^> ^
P.S. Don't forget that using Get-ChildItem without a -Path or -LiteralPath, the cmdlet will use PowerShell's current working folder ($pwd), which is most probably not the same as the current working path cmd uses..
This an hybrid code Batch and Powershell exmaple is just to show you how to put a multiline comment block with powershell and how to execute Batch section and powershell section :
<# : Batch Script Section
#rem # The previous line does nothing in Batch, but begins a multiline comment block in PowerShell. This allows a single script to be executed by both interpreters.
#echo off
Title Wifi Passwords Recovery by Hackoo 2022 & Mode 70,3
setlocal
cd "%~dp0"
Color 0B & echo(
Echo( Please Wait a while ... Getting SSID and Wifi Keys ...
Powershell -executionpolicy bypass -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
EndLocal
goto:eof
#>
# Powershell Script Section begin here...
# here we execute our powershell commands...
$Var=netsh wlan show profiles|SLS "\:(.+)$"|%{$SSID=$_.Matches.Groups[1].Value.Trim(); $_}|%{(netsh wlan show profile name="$SSID" key=clear)}|SLS "Conte.*:(.+)$"|%{$pass=$_.Matches.Groups[1].Value.Trim(); $_}|%{[PSCustomObject]#{SSID=$SSID;PASSWORD=$pass}}
$var | Format-List | Out-File -FilePath ".\WifiKeys_List_Format.txt"
$var | ConvertTo-Json | Out-File -FilePath ".\WifiKeys_JSON_Format.txt"
$var | OGV -Title "Wifi Passwords Recovery by Hackoo 2022" -wait
ii ".\WifiKeys_JSON_Format.txt"
ii ".\WifiKeys_List_Format.txt"

Want to retrieve the Modified date for list of file names present inside a file in CMD prompt

I have a list of file names present inside a file called My_text.txt, may be more than 100. I want to retrieve the Date modified, basically the DIR command output for all those file names.
My_Text.txt contains
D:\Users\dsa99_p\Desktop\My_Program1.txt
D:\Users\dsa99_p\Desktop\My_Program2.txt
D:\Users\dsa99_p\Desktop\My_Program3.txt
D:\Users\dsa99_p\Desktop\My_Program4.txt
and so on..
I want to retrieve the Date modified for all these My_Program1, My_Program2, My_Program3, My_Program4 files. How to do it? Please help.
If it's possible over Powershell then let me know.
In PowerShell the file content can be loaded by Get-Content and file information can be obtained with Get-ChildItem. So this is how it can be done in PowerShell:
Get-Content My_text.txt | ForEach-Object { (Get-ChildItem $_).LastWriteTime }
(Get-ChildItem (Get-Content My_text.txt)).LastWriteTime
Both commands do the same thing. Shorter form of them:
gc My_text.txt |% { (ls $_).LastWriteTime }
(ls (gc My_text.txt)).LastWriteTime
If you want a batch file solution
FOR /F "usebackq delims=" %%G IN ("My_Text.txt") DO ECHO FileName:%%G Modified:%%~tG
Because it is possible that one or more of the files may not exist, I would probably structure my code a little differently. I would first check whether each line related to an existing file, and only then get its information.
The first example I'll provide is for PowerShell, whilst it may seem like more text, it will be far more configurable, especially with regards to modifying the layout and content of the results.
powershell command line:
(Get-Content -Path '.\My_Text.txt') | ForEach-Object { If (Test-Path -LiteralPath $_ -PathType Leaf) { Get-Item -LiteralPath $_ | Select-Object -Property LastWriteTime, Name } }
cmd command line:
For /F "UseBackQ Delims=" %G In (".\My_Text.txt") Do #If "%~aG" Lss "d" If "%~aG" GEq "-" Echo %~tG: %~nxG
Single line batch-file version:
#(For /F "UseBackQ Delims=" %%G In (".\My_Text.txt") Do #If "%%~aG" Lss "d" If "%%~aG" GEq "-" Echo %%~tG: %%~nxG)&Pause
In all examples above, I have assumed that My_Text.txt is in the current directory, if it isn't please change its currently relative location .\ as necessary without modifying its quoting.

Command to list all files in a folder and its sub-folders showing filenames only (no paths) using Win cmd.exe

I'm looking for a command using cmd.exe (Win 10) that will list all files in a folder and its sub-folders, alphabetically, irrespective of the paths, and that will show the filenames only (no paths).
The commands that I'm familiar with (including, for example, "dir ..\samplefolder /b /s /A-D /o:n > filelist.txt") all include the paths in the output, and so are not what I'm looking for.
Thank you.
(for /r "c:\startfolder" %%A in (*) do echo %%~nxA)|sort
(this is batch file syntax; for use directly on the command line, replace every %% with just %)
for /r loops recursively over all (non-hidden) files.
%%~nxA shows name and extension only (if you want just the name without extension, use %%~nA)
See for /? for more information on those modifiers.
If the machine is on the current PowerShell 5 or higher, you could use:
(Get-ChildItem -Recurse -File -Path '..\samplefolder').Name |
Sort-Object |
Out-File -PSPath 'filelist.txt' -Encoding ascii
In a .bat file script.
>"filelist.txt" powershell -NoLogo -NoProfile -Command ^
"(Get-ChildItem -Recurse -File -Path '..\samplefolder').Name | Sort-Object"
If the machine does not have a current PowerShell, it should be upgraded or use:
>"filelist.txt" powershell -NoLogo -NoProfile -Command ^
"(Get-ChildItem -Recurse -Path '..\samplefolder'|" ^
"Where-Object { -not $_.IsContainer}).Name |" ^
"Sort-Object"

Check if a file with a pattern is available in the directory using batch script

A file is dropped in a directory when another job finished processing it.
The requirement is to run a batch script to check whether the file is available for today. and if available, I need to execute certain batch script. (Example: File with Naming pattern ABC-D*.txt should be available with modification date=today)
What I have figured out till now is:
FOR /F "tokens=1,2,3* Delims=/ " %%I in ('DATE /T') DO set TODAY=%%I-%%J-%%K
xcopy C:\BatchJobs\Odd*.* /L /D:%TODAY%
Running this is giving the output:
C:\BatchJobs\OddEven.txt
File cannot be copied onto itself
0 File(s)
C:\BatchJobs\OddEven.txt, showing in console is what I need. But I need to store it in some file or in some variable to be able to use this path later in my batch script. Can somebody help me in storing this file path in a variable or a file? Or suggest some other ways to achieve this goal?
You could use forfiles which is capable of filtering files by their last modification date, but not regarding the time:
forfiles /P "D:\ROOT" /M "ABC-D*.txt" /D +0 /C "cmd /C echo #file"
Instead of echo you can state your batch script to execute.
This code will identify "ABC-D*.txt" files last written today. Place the code below into a file such as doit.ps1 (but choose a better name). I did an attrib command on the file, but you will want to do something else.
$srcdir = 'C:\src\t\empty'
Get-ChildItem -File -Path $srcdir -Filter 'ABC-D*.txt' |
Where-Object { $_.LastWriteTime -ge [datetime]::Today } |
ForEach-Object {
# Do something to the $_ file
& attrib $_
}
Then, you can run it from a cmd shell with:
powershell -NoProfile -File doit.ps1

Create a script to collect files from yesterday

I'm working in Sterling B2B Integrator and I have to create a Business Process to collect only the files from "yesterday" (the previous date) The problem is that B2Bi doesn't have a service to do that and the colection directory has over than 7000 files, so I can't use a GetDocInfo service to collect the dates into tags because the Sterling may colapse.
So, I decided to use the Command Line Adapter to invoke a script that would do that for me. The problem is that the script doesn't work either:
set var1=%1 /* UNC File Path */
set var2=%2 /* Source directory */
set var3=%3 /* "yesterday" date */
set var4=%4 /* save the list of files into a .txt*/
set var5=%5 /* copy the files from yesterday into this directory */
PUSHd **%var1%** &
forfiles /p **%var2%** /s /C " cmd /c echo #path #FDATE | findstr /m **%var3%**" > %var4% &
for /f %%a in (**%var4%**) do copy %%a **%var5%** &
Function: The script should collect the files from yesterday and save them into a specific directory.
Example:
PUSHd "\\emea\e801\Public" &
forfiles /p _AppData\CAMS\PDFS\Digital\CertificadoCancelado /s /C " cmd /c echo #path #FDATE | findstr /m "27/07/17"" > _Shared\_AppData\MFT\BackupSterling\temp_puente_PRO\Lista_DIGCRT02\ficherosAyer.txt &
for /f %%a in (_Shared\_AppData\MFT\BackupSterling\temp_puente_PRO\Lista_DIGCRT02\ficherosAyer.txt) do copy %%a _Shared\_AppData\MFT\BackupSterling\temp_puente_PRO\Lista_DIGCRT02\DIGCRT02 &
Why is this script not working?
The script is not working because it is not syntactically correct. What are the asterisks doing around the variable names.
Here is a brief PowerShell script that is the core of what you need to do. It needs to have a Parms() block. When you are satisfied that it will copy the files correctly, remove the -WhatIf from the Copy-Item command.
Please note that this does not maintain the subdirectory structure from the src_dir. This will not work well if you have selected files with the same name in different subdirectories.
$src_dir = 'C:\src\t' #var2
$the_date = '2017-07-21' #var3
$log_file = 'C:\src\xxx' #var4
$dest_dir = 'C:\src\xxx' #var5
if (Test-Path $log_file) { Remove-Item $log_file }
Get-ChildItem -Path $src_dir -File -Recurse |
ForEach-Object {
if ((Get-Date $_.LastWriteTime -Format yyyy-MM-dd) -eq $the_date) { $_.FullName }
} |
Tee-Object -FilePath $log_file -Append |
Copy-Item -Destination $dest_dir -WhatIf
If you -must- do this from a .bat script, put the script above into a filename with a .ps1 extension such as Move-FilesDated.ps1. Then, call it from the .bat script.
powershell -NoProfile -File "Move-FilesDated.ps1"