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

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"

Related

How can I send a batch variable to a powershell command

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%\""

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"

Slow for loop iteration in batch file

So I'm making a batch script and I need to run a powershell command inside a for but it's running really slow, I don't know how to make it more efficient, I'm very new in this stuff. Here's part of my code:
for /f "tokens=*" %%G in (myfile.txt) do (
powershell -command '%%G' -replace ',+', ' ' >> newfile.txt
)
Since you say you are new to this. It's really important you get some ramp up on the topic. Using either all the free stuff Microsoft offers (Microsoft Virtual Academy or MS Channel9 or TechNet Virtual Labs or labsondemand), or youtube or at minimum review the help files first. There are lots of free eBooks as well and step by step blogs.
As the others have said, why not just do this in PS directly, to read and process the file. Though you don't have to, you can call a .ps1 from a .bat/.cmd/.vbs, etc., but you don't have to use it to process what PS can do.
# Giving a target file to be modified
# Check what is in the file
# Note: I am using Get-Content here, but if you have a .csv, then use the *csv* cmdlets
Get-Content -Path 'd:\temp\myfile.txt'
# Results
LIC,+CLIENT
12345,+Client1
54321,+Client2
34251,+Client3
# Test new file path
Test-Path -Path 'd:\temp\newfile.txt'
# Results
False
# Decide what to replace, code the replace
# and see what the new file content will look like when replaced
Get-Content -Path 'd:\temp\myfile.txt' |
ForEach{$_ -replace '\,\+',' '}
# Results
LIC CLIENT
12345 Client1
54321 Client2
34251 Client3
# Modify to send to a new file.
Get-Content -Path 'd:\temp\myfile.txt' |
ForEach{
$_ -replace '\,\+',' ' |
Out-File -FilePath 'D:\Temp\newfile.txt' -Append
}
# Results
Test-Path -Path 'd:\temp\newfile.txt'
True
Get-Content -Path 'd:\temp\newfile.txt'
# Results, should be the same as screen output.
LIC CLIENT
12345 Client1
54321 Client2
34251 Client3
Since you mentioned in your comment that you were trying to do it all in a batch script here is the basic syntax for string replacement. You have to first assign the FOR variable to an environmental variable before you can do any string replacement. You would also need to enable delayed expansion because you are manipulating a variable inside a parentheses code block.
#echo off
setlocal enabledelayedexpansion
(for /f "delims=" %%G in (myfile.txt) do (
set "line=%%G"
echo !line:+= !
)
)>newfile.txt
You could also do this without delayed expansion by using CALL ECHO
#echo off
(for /f "delims=" %%G in (myfile.txt) do (
set "line=%%G"
CALL echo %%line:+= %%
)
)>newfile.txt

How To Remove Substring Using Batch File

I have several thousand files with similar, but different formats, ie:
[Block 1] Thisfile.txt
[Block 1] Thisfile1.txt
[Block 1] Thisfile2.txt
[Backup001] Thatfile1.doc
[Backup001] Thatfile2.doc
[Backup001] Thatfile3.doc
[Explode] Thisplace.xls
[Explode] Thisplace1.xls
[Explode] Thisplace2.xls
I want to remove the "[text] " and keep everything else the same. Since that text varies I can't do a strict number of characters ie
set var=%1
#echo %var:~-7%
I tried to dabble with powershell commandline and tried:
dir *.xls | Rename-Item -NewName {$_.Name -replace '[Explode\s\'}
But was given the following error:
Rename-Item : The input to the script block for parameter 'NewName' failed. Invalid regular expression pattern: [Explode\s\.
At line:1 char:33
+ Dir *.xls | Rename-Item -NewName <<<< {$_.Name -replace '[Explode]\s\'}
+ CategoryInfo : InvalidArgument: (C:\1\[Explode... Thisfile1.xls:PSObject) [Rename-Item], ParameterBindingException
+ FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.RenameItemCommand
I've searched StackExchange, and the 'batch-rename' tag, and found (and tried) several similar things that I thought I could tweak, but no luck.
Here's the latest based on another StachExchange answer:
for %%F in (*.xls) do (
SET string=%%F
SET modified=!string:Explode=1!
echo !modified!
)
I was just trying to get ANY replace to work... No luck.
Your PowerShell was fairly solid, the only issue is that the square braces are reserved characters and have to be escaped with a preceding backslash. The RegEx that should work for you should be:
-replace '\[.*?\]\s*'
You can see the detailed explanation of that at this link:
https://regex101.com/r/yM6sQ9/1
Edit: Sorry, just got into work and saw your messages. I tried that regex with a test file and was able to rename it without issues. Test file created:
C:\Temp\[glarb]ThisIsATest.tst
I then ran the following line in PowerShell:
Get-ChildItem C:\Temp\*.tst | Rename-Item -NewName {$_.Name -replace "\[.*\]\s*"}
After which I looked and was left with the file:
C:\Temp\ThisIsATest.tst
I'm not sure why your code didn't work, perhaps it is a bug in your version of PowerShell. The regex and command do work in PS v4 running in Win8.1.
Using pure batch:
#echo off
for /f "delims=" %%F in (
'dir /b /a-d [*]*'
) do for /f "tokens=1* delims=]" %%A in (
"%%F"
) do for /f "tokens=*" %%C in ("%%B") do ren "%%F" "%%C"
Using my JREN.BAT regular expression renaming utility, a pure script utility (hybrid JScript/batch) that runs natively on any Windows machine from XP onward:
call jren "^\[.*?] *" "" /fm "[*]*"
You can drop the CALL if you use the command directly from the command line.
My RegEx-Foo is not very strong (it's on the to-do list), but you should be able to do this with a sub string.
dir *.xls | Rename-Item -NewName { ($_.Name.Substring($_.Name.IndexOf(']') + 1)).Trim() }
Looking a little closer at what actually changed, we're returning a sub string of $_.Name which is from the index after the first ']' character and then also trims the output, dealing with any extra white spaces (namely spaces).
This has the obvious limitation of not working for files that are in the form of:
this[should]notBeEdited.xls

Parsing and removing text with cmd or powershell

I've checked quite a few other questions here but was unable to find what I need. I am currently trying to automate the process of finding out what VMs are in what Hyper V servers. Here is my current script.
#echo off
set /P dc= "Which DC do you want? "
dsquery computer -name %DC%VUT* > dsquery.txt
type dsquery.txt | findstr /v IMAGINGOU | findstr /v OTHEROU > dsquery2.txt
powershell -command Get-Content dsquery2.txt | ForEach-Object { $_ -replace '"CN=', "" } | Set-Content dsquery3.txt
powershell -command Get-Content dsquery3.txt | ForEach-Object { $_ -replace ',OU=CAM,OU=Exchange,OU=Server,DC=RED001,DC=local"', "" } | Set-Content serverlist.txt
powershell -command .\Get-HyperVMod.ps1 -file output.csv
The problem I have hit is the servers that I can do dsquery from (Win2k3) can't do the ForEach-Object because they have an older version of Powershell and the Win2k8 servers that can do the ForEach-Object can't do a dsquery.
Here is a sample of the dsquery output that I am trying to parse and remove all but the server name.
"CN=SERVER001,OU=VUT,OU=Infastructure,OU=Server,DC=dcname,DC=local"
"CN=SERVER008,OU=ImagingWDS,DC=red002,DC=local"
Output should be
SERVER001
SERVER008
Any suggestions on either doing this with another method or just my small problem of removing the extra text from the file.
run this against your dsquery.txt, it will parse what you need.
#echo off
setlocal enabledelayedexpansion
::Echos your Computer Name only.
for /F "tokens=1,2 delims==," %%G IN (dsquery.txt) DO echo %%H
pause
endlocal
basically what it does is uses two different delimeters: "=" and "," which immediately surround your server names. and looks only for that second token. It works based on the strings you provided above.
The ForEach-Object cmdlet was introduced in PowerShell V1 so you'll have it there.
Jon's regex here shows you how you can pull the common name from a LDAP string.
This will apply the regex to each line in a text file and return the result.
Get-Content file.txt | % { $_ -replace '(CN=)(.*?),.*', '$2' }
Update
Here's how your batch script would translate into PowerShell:
$dc = Read-Host "Which DC do you want?"
& dsquery computer -name "${dc}VUT*" | % {
# Do your processing here...
$_ -replace '(CN=)(.*?),.*', '$2'
}