split an argument and add include the items in url - windows

I'm trying to solve a problem at work, where it's required to access project folders on a shared drive.
However the naming convention is a bit tricky. The URLs on the server start with the static FS\XXX\00 followed by the project number (6 digits long) which is split into pieces of two and between slashes. For example the project folder for project 123456 would look like FS\XXX\00\12\34\56.
What I'm trying to sort out is how to create a .bat file, put it in the environment path and call it with the Run command, so for example I would call the file ex.bat by entering the following sequence in the Run console:
ex 123456
Then the program should split the number, build up and open the following URL:
FS\XXX\00\12\34\56
Any ideas?

%1 is the first parameter. Save it to a variable (%p%) do be able to do substring substitution (see set /?) and build and output the desired string:
#echo off
set p=%1
echo FS\XXX\00\%p:~0,2%\%p:~2,2%\%p:~4,2%
pause

Because powershell was tagged, here's a powershell implementation. Save this as a script in the environment path somewhere:
[CmdLetBinding()]
param
(
[string] $ProjectNumber = '123457'
)
$root = 'FS\XXX\00\'
# Create a string with backslashes every 2 chars
$out = (&{for ($i = 0;$i -lt $ProjectNumber.length;$i += 2)
{
$ProjectNumber.substring($i,2)
}}) -join '\'
# Create final path
$path = Join-Path -Path $root -ChildPath "$out\"
# Run explorer with the path
explorer $path
and call from run/cmd like this:
powershell "& "Script.ps1 -ProjectNumber 123456""

Related

How can I convert part of a filename to become the file extension?

I downloaded a backup folder of about 3,000 files from our email service provider. None of the files have an associated filetype; instead the file extension was appended to the name of each individual file. For example:
community-involvement-photo-1-jpg
social-responsibility-31-2012-png
report-02-12-15-pdf
I can manually change the last dash to a period and the files work just fine. I'm wondering if there is a way to batch convert all of the files so they can be sorted and organized properly. I know in the Command Line I can do something like ren *. *.jpg but there are several different file types contained in the folder, so it wouldn't work for all of them. Is there any way I can tell it to convert the last "-" in each file name into a "." ?
I'm on Windows 10; unable to install any filename conversion programs unless I want to go through weeks of trouble with the IT group.
$ordner = "c:\temp\pseudodaten"
$Liste = (get-childitem -path $Ordner).Name
cd $ordner
foreach ($Datei in $Liste) {
$Length = $datei.length
$NeuerName=$Datei.Substring(0,$Length-4)+"."+$datei.Substring($Length - 3, 3)
rename-item -Path $Datei -NewName $NeuerName
}

Issue with Robocopy on Windows Server 2019

I've had a robocopy script running on Windows Server 2008 (Powershell version 4) with no issues for about 6 months now.
We've recently had to migrate off of this machine to initiate the same script off of a Windows Server 2019 (Powershell 5) machine. The exact same script no longer works, and i'm not quite sure what the issue is. The script is:
# Run BCP Bat file to get list of folders that have changed in the past 12 days and save them to
\\xxxx\xxxx\xxx\xxx\xxx.bat
# Select the starting directory to pull the CSV from. The assumption is that the DB file can #be sent to a dedicated directory that just has only the CSV files
$Filerecentdir = "\\ZZZ\Z\ZZZ\ZZZZZ\ZZZZ\ZZZZZZ"
#
# Filtering for only CSV files
$Filter = "*.csv"
#
# This PS command will search for the file with the latest timestamp on it. Coupling this with #the filter above, we turn $Filerecent into a variable consisting of the most recent CSV
$Filerecent = Get-ChildItem -Path $Filerecentdir -Filter $Filter | Sort-Object LastAccessTime -Descending | Select-Object -First 1
#
# I concatenate $Filerecentdir with the $Filerecent variable to form the full path to the CSV
$FullPath = Join-Path -path $Filerecentdir -ChildPath $Filerecent
#
# $roboSource variable uses import-csv cmdlet to parameterize the one (headerless) column that #the DB file creates
$roboSource = Import-Csv -Header #("a") -Path $FullPath
#
# Arbitrary directory that i'm using to store the logs. We'll change this to something on the #file server so it can be viewable
$logPath = "\\AAAA\A\AAAA\AAAA\AAAA\AAAA\"
#creates a folder to seperate weekly logs based off the output of the bat script
$weeklylogfolder = $Filerecent -replace '_.csv'
New-Item -ItemType Directory -Force -Path "$($logPath)$($weeklylogfolder)"
#
# For each loop to iterate over every single row in the CSV
Foreach($script in $roboSource)
{
# I used the two below variables to replace the two last trailing '\' in each entry
$prefix = $script.a -replace '\{.+'
$suffix = $script.a.Substring($prefix.Length) -replace '\\', '_' #keeping the {} in the file #name.
#$suffix = $script.a.Substring($prefix.Length) -replace '[{}]' -replace '\\', '_'
#
#$logFileName = $prefix + $suffix
$logFileName = $suffix
#
# Same switches that we used
#$StandardSwitches = "/copy:DAT /s /dcopy:DAT /V /L" #no copy
$StandardSwitches = "/copy:DAT /s /dcopy:DAT /V" #Copy
#
# Creates the log file in the same format that we used, so one log file per entry
$log = "/log:`"$($logPath)$($weeklylogfolder)\$($logFileName).log`""
#
# Iterates through each row to create the source and destination
$FileSource = "$($script.a)"
$FileDestination = "$($script.a)"
#
# used this to surround the certain variables with double quotes, otherwise Robo fails
$RoboArgs = '"I:\{0}" "Z:\{1}" {2} {3}' -f
$FileSource, $FileDestination, $StandardSwitches, $log
#
Robocopy $RoboArgs
}
I can't seem to pinpoint what would be causing the issue's I'm seeing. I've tried to run each of the commands within the script alone, and when I do, I am noticing that the $RoboArgs variable seems to cut off which then generates an incomplete $FileDestination
$RoboArgs with the above generates the exact same output as it does on server 2008/Powershell 4. However, it seems that powershell 5 processes this differently. Is there something I'm doing wrong or need to add in order to get this to process correctly?
EDIT:
Here's an example of what $RoboArgs is defined as in Win2019/Powershell5:
PS C:\> echo $RoboArgs
"I:\Fake-directory\Fake-directory\D\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}\Fake\FakeDate" "Z:\Fake-Directory\Fake-Directory\D\{DAFD6721-E854-46F3-B
5CF-7EE1861348A6}\Responses\01182020" /copy:DAT /s /dcopy:DAT /V /log:"I:\FakeDirectory\FakeDirectory\Fake\Logs\Folders_Changed_20200118_21.1
\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}_Responses_01182020.log"
It basically cuts off where the first line ends, and generates the destination in the same manner:
PS C:\> Robocopy "I:\Fake-directory\Fake-directory\D\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}\Fake\FakeDate" "Z:\Fake-Directory\Fake-Directory\D\{DAFD6721-E854-46F3-B
5CF-7EE1861348A6}\Responses\01182020" /copy:DAT /s /dcopy:DAT /V /log:"I:\FakeDirectory\FakeDirectory\Fake\Logs\Folders_Changed_20200118_21.1
\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}_Responses_01182020.log"
2020/01/18 23:17:21 ERROR 123 (0x0000007B) Opening Log File I:\FakeDirectory\FakeDirectory\Fake\Logs\Folders_Changed_20200118_21.1
\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}_Responses_01182020.log
The filename, directory name, or volume label syntax is incorrect.
-------------------------------------------------------------------------------
ROBOCOPY :: Robust File Copy for Windows
-------------------------------------------------------------------------------
Started : Saturday, January 18, 2020 11:17:21 PM
Source - I:\FakeDirectory\FakeDirectory\Fake\D\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}\Responses\01182020\
Dest - Z:\FakeDirectory\FakeDirectory\Fake\D\{DAFD6721-E854-46F3-B
Edit 2:
Comparing this to Win2008/Powershell4, it actually does the same thing in regards to failing if there's a line break. I think the real problem is how the script is trying to define the source and destination. On 2008/Powershell4, running the script generates everything correctly, with the correct source, destination and log file. Running the exact same script on 2019/Powershell5 seems to generate a problem with how Robocopy is defining these paths, placing both Source, Destination, and Log path all into the source variable, even though that's not how it's defined:
PS C:\> echo $FileSource
FakeDirectory\FakeDirectory\D\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}\Responses\01182020
PS C:\> echo $FileDestination
FakeDirectory\FakeDirectory\D\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}\Responses\01182020
PS C:\> echo $log
/log:"I:\FakeDirectory\FakeDirectory\FakeDirectory\Logs\Folders_Changed_20200118_21.1\{DAFD6721-E854-46F3-B5CF-7EE1861348A6}_Responses_01182020.log"
PS C:\> echo $StandardSwitches
/copy:DAT /s /dcopy:DAT /V

Windows Batch sript that moves files based on a (partial char string) looking it up in a CSV/txt file

What I'm looking for might be a variation of this solution: Windows batch file to sort files into separate directories based on types specified in a csv
My Situation: a batch process in a server creates files that look like this: S0028513-010716-0932.txt. S stands for summary, the first five digits stand for a supplier, the last two before the hyphen stand for the Distribution Center. After the hyphen, there is the date and after the second hyphen the timestamp.
What I need to do is:
set a variable for the month/year (e.g. 0716) (this has been set with "set /P c:Please enter MMYY:"). This part is done.
create a folder with subfolders (e.g. 0716\PHARMA, 0716\MEDICAL, etc). I've done this part.
look up the supplier number in a CSV file (e.g. S00285 above) and
move the file to the corresponding folder based on MMYY\PHARMA, etc.
Points 3 and 4 are obvioulsy missing. A practical example: there are three folders where the files can be moved: PHARMA, MEDICAL and CONSUMER
The CSV file looks like this:
S00285 CONSUMER
S00286 PHARMA
S00287 MEDICAL
...
What I want the script to do is to look up the month/year combination in variable c and take all files that correspond to this month/year and move them to the three folders according to the assignment in the CSV file.
Can this be done with standard Windows scripting? Sorry guys, I'm a novice as you can tell. I have only some very basic knowledge of BASH scripting.
Thank you a lot for any advice.
BR
Marcio
This can fairly easily be accomplished with PowerShell
$FolderRoot = "E:\Target\Directory"
Set-Location $FolderRoot
# 1. Have user input month/year string
do{
$MMYY = $(Read-Host 'Please enter MMYY').Trim()
} until ($MMYY -match '\d{4}')
# 2. Create directory
mkdir $MMYY
# ?. Gather input files for that year
$Files = Get-ChildItem -Filter S*.txt |Where-Object {$_.BaseName -match "S\d{7}-\d{2}$MMYY-\d{4}"}
# ?. load CSV file into hash table to easily look up supplier numbers
$SupplierLookupTable = #{}
# Assuming the csv has headers: Supplier,Industry
Import-Csv -Path E:\path\to\suppliers.csv |ForEach-Object {
$SupplierLookupTable[$_.Supplier] = $_.Industry
}
foreach($File in $Files)
{
# Grab the S and first 5 digits from the file name
$Supplier = $File.BaseName.Substring(0,6)
# 3. Look up the industry
$Industry = $SupplierLookupTable[$Supplier]
$Destination = Join-Path $MMYY $Industry
# Create folder if it doesn't already exist
if(-not (Test-Path $Destination))
{
mkdir $Destination
}
# 4. Move the file
Move-Item $File.Fullname -Destination $Destination
}

Batch file for copying every nth file from folder1 to folder2?

I am trying to copy every 30th file from one folder to another and automate the process for other folders. I have already tried the batch script in this thread: windows batch file script to copy every tenth file from a folder to another folder and just get "The syntax in that command is incorrect" when I run the file (and yes, I've tried both versions).
My folders do have spaces in the names (not my choice and cannot be changed). The files are named image00000X.jpg and yes, there are over 100k of them (which is why I really want the script to work).
Ideally, I'd like a way to set the script up so that I could just change the input and output paths and not have to move the script between the different folders when running it but I'll settle for whatever I can get at this point because I have tried just about everything else (including robocopy, Xcopy, five Powershell scripts, and a few BASH scripts).
Thanks!
Here is a simple batch file:
:: copyNth.bat interval sourcePath destinationPath
#echo off
setlocal
set /a n=0
for %%F in ("%~f2.\*") do 2>nul set /a "1/(n=(n+1)%%%1)" || copy "%%F" %3
sampleUsage:
copyNth 30 "c:\someSourcePath" "d:\someDestinationPath"
The "%~f2. is syntax that allows you to safely append a file (or file mask) to any provided path.
The trick to getting every Nth value is to let SET /A intentionally raise a division by 0 error. I redirect the error message to nul and conditionally copy the file only when there was an error.
You can also use just a standard for loop. I added some params as well, so you can change the source, destination, and skip count on the fly:
param(
[string]$Source = $( throw "You Must Specify Source Directory" ),
[string]$Destination = $( throw "You Must Specify Destination Directory" ),
[int]$Skip = 30
)
$Files = Get-ChildItem -Path $Source -File
for( $idx = 0; $idx -lt $Files.count; $idx += $Skip ) {
$Files[$idx] | Move-Item -Destination $Destination
}
Source and Destination are required params, but Skip defaults to 30 if you don't specify a value. To use, name it something like move30th.ps1, and run it like:
.\move30th.ps1 -Source "C:\Path\To\Files" -Destination "C:\New\Path" -Skip 30
You could do a simple Do/While loop like:
$Files = Get-ChildItem C:\Path\To\Files
$i = 0
Do{
$files[$i]|Move-Item -Dest C:\New\Path
$i=$i+30
}While($i -le $files.count)
If you want to use Python you could do something like this.
import glob
import shutil
files = glob.glob("data/set1/*.png")
n = 30
for file in files[0::n]:
shutil.move(file, "data/set3")

How can I source variables from a .bat file into a PowerShell script?

I'm replacing parts of a .bat script with PowerShell. Configuration for the batch files is done via files that set appropriate environment variables. I'm looking for a way to load those variable values into the .ps1 script, without modifying the .bat files (as they are also used in other places.
An example .bat looks as follows:
set VAR_ONE=some_value
set VAR_TWO=/other-value
In a batch script, I'd just CALL the configuration file and the variables would be available. I've tried both dot-sourcing (. filename.bat) and calling (& filename.bat) the configuration files from PowerShell, neither of those makes the variables visible. Tried accessing them with both with $VAR_ONE and $env:VAR_ONE syntax.
What would be a good way to load such configuration file without modifying it's format on disk?
If you are using the PowerShell Community Extensions, it has a Invoke-BatchFile that does this. I use with the Visual Studio vcvarsall.bat file to configure my PowerShell session to use the Visual Studio tools.
I'd parse them (just skip all lines that don't start with set and split them with first = character. You can do it from o small C# cmdlet or directly with a small PowerShell script:
CMD /c "batchFile.bat && set" | .{process{
if ($_ -match '^([^=]+)=(.*)') {
Set-Variable $matches[1] $matches[2]
}
}}
I have this code and I'm sure it comes from somewhere but credits have been lost, I suppose it comes from Power Shell Community Extensions for an Invoke-Batch script.
The preferred option would be to change the configuration to a .ps1 file and change the variable definitions to PowerShell syntax:
$VAR_ONE = 'some_value'
$VAR_TWO = '/other-value'
Then you'll be able to dot-source the file:
. filename.ps1
If you want to stick with the format you currently have, you'll have to parse the values, e.g. like this:
Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object {
Set-Variable $_.Matches.Groups[1].Value $_.Matches.Groups[2].Value
}
Note: The above won't work in PowerShell versions prior to v3. A v2-compatible version would look like this:
Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object {
$_.Matches
} | ForEach-Object {
Set-Variable $_.Groups[1].Value $_.Groups[2].Value
}
You can do that via a Batch file that first call the configuration file and then execute the PowerShell script.
Assuming the .bat is called test.bat, define testps.ps1:
$lines = cat "test.bat"
$output = #{};
foreach ($line in $lines) {
$bits = $line.Split("=");
$name = $bits[0].Split(" ")[1];
$val = $bits[1];
$output[$name] = $val
}
return $output
Then the result is something like:
C:\temp> .\testps.ps1
Name Value
---- -----
VAR_TWO /other-value
VAR_ONE some_value
C:\temp> $x = .\testps.ps1
C:\temp> $x
Name Value
---- -----
VAR_TWO /other-value
VAR_ONE some_value
C:\temp> $x["VAR_ONE"]
some_value
There is probably a nicer way of doing the splits (will edit if I find it)

Resources