Parsing and removing text with cmd or powershell - 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'
}

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.

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 can i run multiple replace commands from one line of batch file

I have minimum to none knowledge of powershell :(
Hi I have two possible options to replace text from an .ini file, one is a menu-style batch, where choosing an option will execute a command.
My problem is: if I use the batch code I can only change a known resolution, because I don't know how to add multiple replace actions so they work if one fails.
The Powershell code does executes MULTIPLE replace commands, but I don't know how to edit it to use it as a batch command (powershell -command etc.)
Thank you in advance :)
Batch script:
#echo off
set ffile='resolutions.ini'
set HDReady='/resolution:1280,720'
set FullHD='/resolution:1920,1080'
set QuadHD='/resolution:2560,1440'
set UltraHD='/resolution:3840,2160'
powershell -Command "(gc %ffile%) -replace %hdready%, %fullhd% | Out-File %ffile% -encoding utf8"
Powershell script:
$original_file = 'path\resolutions.ini'
$destination_file = 'path\resolutions.ini'
(Get-Content $original_file) | Foreach-Object {
$_ -replace '/resolution:1280,720', '/resolution:1920,1080' `
-replace '/resolution:2560,1440', '/resolution:1920,1080' `
-replace '/resolution:3840,2160', '/resolution:1920,1080'
} | Set-Content $destination_file
Is one (1) line what you really want?
(Get-Content 'path\resolutions.ini') | Foreach-Object {$_ -replace '/resolution:1280,720', '/resolution:1920,1080' -replace '/resolution:2560,1440', '/resolution:1920,1080' -replace '/resolution:3840,2160', '/resolution:1920,1080'} | Set-Content 'path\resolutions.ini'
or
$original_file = 'path\resolutions.ini'; $destination_file = 'path\resolutions.ini'; (Get-Content $original_file) | Foreach-Object {$_ -replace '/resolution:1280,720', '/resolution:1920,1080' -replace '/resolution:2560,1440', '/resolution:1920,1080' -replace '/resolution:3840,2160', '/resolution:1920,1080'} | Set-Content $destination_file
You can also place your script in a file and run it as such:
powershell.exe -file My\FilePath.ps1
Here is the help section from the powershell executable:
PowerShell -Help
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.

Ignore first line in FINDSTR search

I am searching an object-oriented Modelica library for a certain string using the following command in the Windows 7 PowerShell:
findstr /s /m /i "Searchstring.*" *.*
click for findstr documentation
The library consists of several folders containing text files with the actual code in them. To reduce the number of (unwanted) results, I have to ignore the first line of every text file.
Unfortunately, I cannot work out how to do this with the findstr command.
You can use Select-String instead of findstr
To get all matches excluding the ones on the first line try something like this:
Select-String -Path C:\dir\*.* -pattern "Searchstring*" | where {$_.LineNumber -gt 1}
If you have to search subdirectories you can pair it with Get-Childitem:
Get-Childitem C:\dir\*.* -recurse | Select-String -pattern "Searchstring*" | where {$_.LineNumber -gt 1}
If you want to keep using findstr you could simply pipe the output into Select-Object:
findstr /s /m /i "Searchstring.*" *.* | select -Skip 1