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
Related
Is it possible to copy files using bash script (.sh) on powershell?
Tried using cp and copy, but got command not found error. However, if use cp or copy in the powershell command line, it does work.
I tried
Copy-Item -path "$file_path" -Destination "C:\destination\"
where $file_path is a variable with the source file This resulted in syntax errors-
Unexpected EOF while looking for matching ' " '
syntax error: unexpected end of file
The exact same copy-item command works when executed in powershell command line.
You don't need double quotes for simple string text or a simple variable.
Copy-Item -path $file_path -Destination 'C:\destination'
Double quotes are for variable expansion use cases where it is needed and in some formatting use cases. For example, combining a variable with something else, so say a file path.
Get-ChildItem -Path 'D:\Temp' |
ForEach {
$PSItem
$PSitem.BaseName
'Processing ' + $PSItem.FullName
"Processing $($PSItem.FullName)"
} |
Select -First 4 |
Format-Table -AutoSize
# Results
<#
Directory: D:\Temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 06-May-20 20:30 AddressFiles
AddressFiles
Processing D:\Temp\AddressFiles
Processing D:\Temp\AddressFiles
#>
So, if I took your sample and refactor a bit so you can see what I mean:
$File_path = 'D:\Temp'
Get-ChildItem -Path $File_path -File |
Select -First 4 |
ForEach {
Copy-Item -Path $PSItem.FullName -Destination 'D:\Temp\est' -WhatIf
}
# Results
<#
What if: Performing the operation "Copy File" on target "Item: D:\Temp\(MSINFO32) command-line tool switches.pdf Destination: D:\Temp\est\(MSINFO32) comm
and-line tool switches.pdf".
What if: Performing the operation "Copy File" on target "Item: D:\Temp\23694d1213305764-revision-number-in-excel-book1.xls Destination: D:\Temp\est\23694
d1213305764-revision-number-in-excel-book1.xls".
What if: Performing the operation "Copy File" on target "Item: D:\Temp\5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url Destination: D:\T
emp\est\5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url".
What if: Performing the operation "Copy File" on target "Item: D:\Temp\abc.bat Destination: D:\Temp\est\abc.bat".
#>
Yet again, as [David C. Rankin], unless your environment is properly configured, you can only run PowerShell commands in the PowerShell consolehost, ISE or VSCode.
You can run external executables in PowerShell, but you must call it properly, especially if you are using the PowerShell ISE.
• PowerShell: Running Executables
Table of Contents
Direct - Using the environment path or local folder
Invoke-Expression (IEX)
Invoke-Command (ICM)
Invoke-Item (II)
The Call Operator &
cmd /c - Using the old cmd shell
Start-Process (start/saps)
[Diagnostics.Process] Start()
WMI Win32_Process Create() Method
Stop-Parsing Symbol --%
I am trying to automate some file renaming but also need the file to update it's "last modified" time as I have a field inserted within the Word document that dynamically updates the last time the file was edited.
copy C:\path\to\file\test\test.docx "C:\path\to\file\test2\test-%date:~-7,2%-%date:~-10,2%-%date:~-4,4% %time:~-11,2%%time:~-8,2%.docx"
I tried to integrate the following syntax:
copy /b filename.ext +,,
That I got from:
https://superuser.com/questions/10426/windows-equivalent-of-the-linux-command-touch/764716
However it did not output anything when I put the + after the source file.
copy /b "C:\path\to\file\test\test.docx" + "C:\path\to\file\test2\test-
%date:~-7,2%-%date:~-10,2%-%date:~-4,4% %time:~-11,2%%time:~-8,2%.docx"
I also tried invoking a PowerShell script within the batch file to update last modified date:
$file = Get-Item C:\Path\TO\test.docx
$file.LastWriteTime = (Get-Date)
copy C:\path\to\file\test\test.docx "C:\path\to\file\test2\test-
%date:~-7,2%-%date:~-10,2%-%date:~-4,4% %time:~-11,2%%time:~-8,2%.docx"
powershell -file C:\path\to\powershell.ps1
Can't get it to work either way, I'm new to this so probably missing something simple.
I was able to figure this one out. My batch file is now as follows:
powershell -command "(Get-Item "C:\path\to\file\test\test.docx").LastWriteTime = (Get-
Date)"
copy C:\path\to\file\test\test.docx "C:\path\to\file\test2\test-%date:~-7,2%-
%date:~-10,2%-%date:~-4,4%%time:~-11,2%%time:~-8,2%.docx"
Which first modifies the last edited date of the file, and then copies it over to test 2 folder with the time and date appended.
I'm a bit curious what you mean with:
I have a field inserted within the Word document that dynamically updates the last time the file was edited.
If you copy a file it's content is not altered and the LastWriteTime stays the same,
so why do you want to set LastWriteTime to current date&time?
As per your attempt with copy in cmd.exe you did omit the two commas, this should do:
copy /b "C:\path\to\file\test\test.docx" + , , "C:\path\to\file\test2\test-%date:~-7,2%-%date:~-10,2%-%date:~-4,4% %time:~-11,2%%time:~-8,2%.docx"
The PowerShell suggestion from my comment:
'C:\path\to\file\test\test.docx' |
Get-Item |
Copy-Item -Destination {'{0}\{1}-{2:MMddyyyy\ HHmm}{3}' -f `
$_.Directory, $_.Basename,
$_.LastWriteTime, $_.Extension} -WhatIf
Could be modified to rename all files with date time appendix to reflect the actual LastWriteTime.
Get-ChildItem -File -Filter *.docx |
Where BaseName -Match '-\d{8} \d{4}$' |
Rename-Item -NewName {'{0}-{1:MMddyyyy\ HHmm}{2}' -f `
$_.Basename.Replace($Matches[0],''),
$_.LastWriteTime, $_.Extension} -WhatIf
If the NewName is the same, Rename-Item ignores it.
In contrast to Copy-Item, Rename-Item doesn't allow a directory.
Yesterday I ran the following script on some batch files on our server to replace an individual's email address as she is no longer with the company. When examining the text it worked perfectly and the log file wrote correctly as well. However, now the batch file no longer executes when I double click on it. I see a quick flash of the console window but there does not appear to be any text in it. Adding PAUSE statements is not helpful as it does not seem to execute any of the text in the file.
I copied and pasted the text to a new batch file and it works fine. I noticed that the powershell-edited file is 6KB and the new copied-and-pasted file is 3KB so clearly the script has done something unexpected to the file. Copying and pasting each file obviously defeats the purpose of using a script to batch process things. Any ideas where I'm going wrong?
I've been running the script from my development machine and I have full administrator permissions to everything on our network.
If it matters we are running Windows Server 2008 R2 Enterprise on the server.
# Finds string in batch files recursively and replaces text with other text
#
#get command line arguments
param (
[string]$Text = $( Read-Host "Input the text to search for"),
[string]$Replacement = $( Read-Host "Input the replacement text")
)
$Today=get-date -format yyyymmdd
$Results = "{server name}\c$\Batch Jobs\Find Text In Batch Jobs\ReplaceTextInBatchJobs-" + $Text + "-" + $Today + ".txt"
$Path = "{server name}\c$\Batch Jobs"
# get all the files in $Path that end in ".bat".
Get-ChildItem $Path -Filter "*.bat" -Recurse |
Where-Object { $_.Attributes -ne "Directory"} |
ForEach-Object {
#Find whether there is a matching string
If (Get-Content $_.FullName | Select-String -Pattern $Text) {
#Replace the text in this file
(Get-Content $_.FullName) | Foreach-Object {$_ -replace $Text, $Replacement} |
Out-File $_.FullName #write the new results back to the file
#write the file name to a log file
$_.FullName >> $Results
}
}
Out-File defaults to Unicode encoding (which is why the file doubles in size; each character is 16 bits). You can either use Out-File -Encoding ASCII or Set-Content which defaults to ASCII.
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")
I need to write a script to unzip zip files into unique folders and execute a bat file within them.
I am able to get through the unzipping process with the below code. I having a problem with executing the bat file. I need to execute the bat file in a way that it is able to perform its operation on the files of the folder it is presently in.
The bat file contain this code
copy *.prn /b \\PC\Printer
My Current Powershell Script
$shell=new-object -com shell.application
$CurrentLocation=get-location
$CurrentPath=$CurrentLocation.path
$Location=$shell.namespace($CurrentPath)
# Find all the Zip files and Count them
$ZipFiles = get-childitem *.zip
$ZipFiles.count | out-default
# Set the Index for unique folders
$Index = 1
# For every zip file in the folder
foreach ($ZipFile in $ZipFiles)
{
# Get the full path to the zip file
$ZipFile.fullname | out-default
# Set the location and create a new folder to unzip the files into - Edit the line below to change the location to save files to
$NewLocation = "E:\BCode\$Index"
$A = "E:\BCode\$Index"
New-Item $NewLocation -type Directory
# Move the zip file to the new folder so that you know which was the original file (can be changed to Copy-Item if needed)
Move-Item $ZipFile.fullname $NewLocation
# List up all of the zip files in the new folder
$NewZipFile = get-childitem $NewLocation *.zip
# Get the COMObjects required for the unzip process
$NewLocation = $shell.namespace($NewLocation)
$ZipFolder = $shell.namespace($NewZipFile.fullname)
# Copy the files to the new Folder
$NewLocation.copyhere($ZipFolder.items())
#NOT WORKING
#ITS NOT SENDING FILES TO THE PRINTER
#PRINTER NAME & PC NAME ARE PREFECT
$PC = "$A\*.prn" + ' /b //Samsung-2012/Zebra'
cmd \c COPY $PC
# Increase the Index to ensure that unique folders are made
$Index = $Index + 1
}
$destination = 'E:\BCode'
Get-ChildItem -Path $Destination -Recurse | Remove-Item -force -recurse
Why not embed the one line from the batch file in the powershell script, then you can use the variables in your powershell script.
Simply put cmd /c before the copy:
cmd /c copy "$NewLocation\*.prn" /b \\PC\Printer