Remove percentages from robocopy log - powershell

I'm using an older version of robocopy that includes percentages in the log even if the /NJH and /NJS paramters are set. So I'd like to remove the percentages from the log:
72880735 H:\1.txt
100%
33038490 H:\10.txt
100%
64878348 H:\2.txt
100%
25875810 H:\3.txt
0%
100%
I've tried with
(Get-Content $logfile) | Where-Object {
$_ -match '[\s](\d{1,})(\s+)(\w\W\W.+)'
} | Set-Content $logfile
But that results in
72880735 H:\1.txt
33038490 H:\10.txt
64878348 H:\2.txt
25875810 H:\3.txt
0%
So I get the 100%'s stripped out, but not the 0%.

/njh and /njs have nothing to do with the percentage information. You need to suppress progress output by adding the option /np to your robocopy commandline.
From the documentation:
/np Specifies that the progress of the copying operation (the number of files or directories copied so far) will not be displayed.
Edit: After taking a look at your actual commandline it looks like /np is not compatible with /mt. Adding the latter parameter makes robocopy display progress output even if /np is present. If you don't require running multi-threaded I'd remove that parameter (add /ndl to prevent directories from appearing in the output).
I would also recommend using splatting instead of putting the parameter list into a single string:
$params = $src, $dest, ('/LOG:"{0}"' -f $logpath), '/L', '/NP', '/NC', '/BYTES',
'/NJH', '/NJS', '/NDL', '/E', '/MOVE', '/XC', '/XN', '/XO', '/XD',
$excludedFoldersList
& robocopy #params
If for some reason you must use multi-threading you should be able to remove progress information from the log after completion like this:
(Get-Content $logpath) | Where-Object {
$_ -notmatch '^\s*\d{1,3}%\s*$'
} | Set-Content $logpath

Related

How to use robocopy mirror without output?

I am trying to delete a folder using robocopy mirroring like this:
Start-Process -FilePath "robocopy.exe" -ArgumentList "$emptyDir $sourcePath /mir /e /np /ns /nc /njs /njh /nfl /ndl" -Wait -PassThru -NoNewWindow but still get a line of output for every deleted file
I tried adding >nul 2>&1 as explained in another answer here Start-Process -FilePath "robocopy.exe" -ArgumentList "$emptyDir $sourcePath /mir /e /np /ns /nc /njs /njh /nfl /ndl >nul 2>&1" -Wait -PassThru -NoNewWindow but still get the same output.
Since you're running robocopy in the current console window (-NoNewWindow), synchronously (-Wait), there is no reason to use Start-Process at all - just invoke robocopy directly, which also allows you to use > redirections effectively:
robocopy.exe $emptyDir $sourcePath /mir /e /np /ns /nc /njs /njh /nfl /ndl *>$null
Note:
Direct execution makes a program's stdout and stderr output directly available to PowerShell, via its success and error output streams.
*>$null is a convenient PowerShell shortcut for silencing all output streams - see about_Redirection.
Another benefit of direct invocation is that the external program's process exit code is reported in PowerShell's automatic $LASTEXITCODE variable.
See also:
This answer provides background information.
GitHub docs issue #6239 provides guidance on when use of Start-Process is and isn't appropriate.
As for what you tried:
You fundamentally cannot suppress output from a process launched with Start-Process -NoNewWindow on the PowerShell side.
Trying to silence command output at the source, i.e. as part of the target process' command line with >nul 2>&1, would only work if cmd.exe were the -FilePath argument and you passed a robocopy command to it. > redirections are a shell feature, and robocopy itself isn't a shell.
You can try to pass arguments via splatting, and then use the object pipeline to parse line by line.
In the example below, I'm going to split the arguments into two groups, in case you wanted to change out the options programmatically.
$roboFileArgs = #(
<#
If you're sure your argument is already a string or
a primitive type, there's no need to quote it.
#>
$emptyDir
$sourcePath
)
$roboFlags = "/mir","/e","/np","/ns","/nc","/njs","/njh","/nfl","/ndl"
# We can use splatting to pass both lists of arguments
robocopy.exe #roboFileArgs #roboFlags |
Foreach-Object {
<#
process output line by line and turn it into objects
or pipe to Out-Null if you truly don't care.
#>
}

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.

Robocopy: Copying files from variable source

I'm trying to copy a specific folder w/ files from a network drive using Robocopy.
The catch is, that the files I want to copy are updated often, and placed in folders with version-numbers. Would it be possible to use Robocopy to grab files from whatever folder has the highest number?
Ex: The source path looks like this:
K:\program\versions\6.7.0.144\
with '144' being the number that is changed often.
The path K:\Program\versions\ contains all versions, each in their own folder, like so:
http://i.stack.imgur.com/zDL16.png
So, each time I run the script, I want it to get files from the latest version/highest number.
So far, my script looks like this:
robocopy \\K:\program\versions\6.7.0.*\bin\config C:\Target /e /z /A-:R
Robocopy does not accept the * in the source-path. So, is this possible with Robocopy, or do I have to use a different approach?
You cannot with robocopy alone. You have to script it a bit.
Assuming you first versions are zeroed (like 6.7.001), then it is easy to get the highest version number you requested.
I provide below snippets for batch & powershell.
Batch:
set SRCPATH=K:\program\versions
for /f %%f in ('dir /b /ad /o-n %SRCPATH%') do set SRCVER=%%f & goto NEXT
:NEXT
echo # Version %SRCVER% will be used
robocopy %SRCPATH%\%SRCVER%\bin\config C:\Target /E /Z /A-:R /LOG:C:\backup.log
goto NEXT is to break for loop after first element, since we sorted by name, descending
Powershell:
$SRCPATH = "K:\program\versions"
$SRCPATH = "D:\temp"
$SRCVER = (Get-ChildItem $SRCPATH | Where-Object { $_.PsISContainer } | Sort-Object -Property Name -Descending | Select-Object -First 1).FullName
$SRCFULL= $SRCVER + '\bin\config'
echo "# Version $SRCVER will be used"
& robocopy $SRCFULL C:\Target /E /Z /A-:R /LOG:C:\backup.log
HTH
The only thing I can suggest vis using Robocopy only is the /MAXAGE: flag.
Otherwise I'd wrap Robocopy in a Powershell Script to do the directory selection for me.
$dirlist = "k:\program\version\6.7.0.1","k:\program\version\6.7.0.144","k:\program\version\6.7.0.77"
$pattern = [regex]'.*6\.7\.0\.(\d*)'
$maxvers = 0
foreach ($dirname in $dirlist) {
$vers = $pattern.match( $dirname ).Groups[1].Value
if($vers -gt $maxvers) { $maxvers = $vers }
}
$robodir = "k:\program\version\6.7.0.$maxvers\bin\config"
robocopy $robodir c:\Target /e /z /A-:R

Piping output from get-childitem to robocopy

I have an array of files that need to be moved to a backup locations. I am collecting the array of desired items using a get-childitem command. I am looking to use robocopy to move stuff once the list of collected items is ready.
$paths=#()
$srcitems = get-childitem $paths
robocopy $srcitems $dest /move
Does this work?
If not what is the best way to pipe to each individual item to robocopy?
Thanks
Steeluser
Usage :: ROBOCOPY source destination [file [file]...] [options]
source :: Source Directory (drive:\path or \\server\share\path).
destination :: Destination Dir (drive:\path or \\server\share\path).
file :: File(s) to copy (names/wildcards: default is "*.*").
Robocopy is expecting a source directory, a destination directory, and a file spec as arguments. It's difficult to give a definitive answer without knowing what your "list of collected items" looks like. If it's source directories, then you can foreach that list through a an ivocation of robocopy, and hardcode a wildcard spec for the file names. If you've got a list of files, you'll need to split those off into directory/file (I'd use split-path), and do an invocation of robocopy for each source directory, specifying the list of files in that directory.
Similar scenario, posting in case it helps:
I needed to copy (move) some folders all beginning with "Friday" and items within from a source to a destination, and came up with this that seems to be working:
Get-ChildItem T:\ParentFolder -Filter "Friday*" -Name | ForEach-Object { robocopy "T:\ParentFolder\$_" "E:\$_" /z /s /MOVE }
The "Get-ChildItem" portion lists the folder names (-Name) starting
with "Friday" (-Filter "Friday*").
This gets piped to the ForEach-Object where robocopy will execute for every instance found.
The robocopy /MOVE argument obviously moves the folders/files.
I'm fairly new to Powershell; not sure if there is a better way. The script is still running, but so far so good.
#walid2mi uses Move-Item which I'm sure works; I just like robocopy b/c it has a restartable mode (/Z).
Syntax that worked for me:
$srcPath = "C:\somefolder"
$dstPath = "C:\someOtherFolder"
$srcitems = get-childitem $srcPath #whatever condition
$srcitems | Select Name | ForEach-Object {robocopy $srcPath $dstPath $_.name}
(which is obvious according to the robocopy documentation)
robocopy
Get-ChildItem $paths | Move-Item -Destination $dest -WhatIf

Powershell 2.0 out-file formatting nightmare

How can I get Powershell to output a file IDENTICAL to the file produced by the following command?
dir /s /b /a-d *.* > C:\files.txt
should be easy, right?!!
EDIT:
I found ps was truncating the output based on the screen buffer width. Fix that with format-table and it pads with spaces... try format-list and you get property headings...you get the idea.
Does it have to be exact? Why? As the saying goes, if you're parsing strings in Powershell, you're probably doing something wrong...anyway...
1) Just call into cmd.exe.
PS> cmd /c "dir /s /b /a-d *.* > c:\files.txt"
2) I believe you can get the same results from native Powershell. But I can't be responsible for testing every edge case with NTFS junctions, hidden files, etc.
PS> gci -r | ?{ !$_.psiscontainer } | %{ $_.fullname } | out-file c:\files.txt
I personally hate the fact you can't use "select" to retrieve the FullName property without weird side effects on downstream cmdlets. If the pointlessness of the foreach loop bothers you as much as it does me, use Get-PropertyValue from PSCX or Linq-Select from Josh Einstein.
There are many ways to write information to a file. One is Set-Content, which does not have the width problem. Also, converting a FileInfo object to a string results in the FullName.
dir * -r | ?{!$_.PSIsCcontainer} | Set-Content C:\files.txt
The reason you have a problem with Out-File is that all the Out-* cmdlets use the automatic formatting views. Those views are created with the console in mind.