I´ve a small problem i didnt understand...
i want to fire-up robocopy with source/target information from a variable.
$source = $TDU2Backup_Path+$dir_array[$i]+$file_array[$i]
$target = $TDU2Unpacked_Path+$dir_array[$i]+$file_array[$i]
when i print the var. content with write-host everything is fine, i get something like that:
D:\spiele\TDU2Community\Euro\Bnk\islands\ibiza\level\area-1\area-1-3\sector-1-3-4-2.bnk
D:\spiele\TDU2Community\Backup\gas-station-xandernl\Euro\Bnk\islands\ibiza\level\area-1\area-1-3\sector-1-3-4-2.bnk
but, if i use the var. with robocopy (or xcopy or something like that), i have always a backslash at the end
---------------------------------------------------------------------------
Quelle : D:\spiele\TDU2Community\Euro\Bnk\islands\ibiza\level\area-1\area-1-3\sector-1-3-4-2.bnk\
Ziel : D:\spiele\TDU2Community\Backup\gas-station-by-xandernl\Euro\Bnk\islands\ibiza\level\area-1\area-1-3\sector-1-3-4-2.bnk\
Dateien : * . *
Optionen: * . * /DCOPY:DA /COPY:DAT /R:1000000 /W:30
Here is a screenshot:
Related
I am putting together a Powershell script that syncs a source code tree into another directory. It creates a list of directories to ignore, per the output of robocopy /?:
# ----------------------------------------------------------------------------
# Source file directories
# ----------------------------------------------------------------------------
$reactjs = "C:\Users\me\Projects\prj\reactjs"
# ----------------------------------------------------------------------------
# Target directories
# ----------------------------------------------------------------------------
$synergy = "C:\Users\me\Projects\sync\reactjs"
$synReactjs = $synergy + "\prj-JS"
# ----------------------------------------------------------------------------
# Directories to be ignored
# ----------------------------------------------------------------------------
$reactIgnores = #(
$reactjs + "\.git",
$reactjs + "\node_modules",
$reactjs + "\build"
)
# ----------------------------------------------------------------------------
# Copy/sync files
# ----------------------------------------------------------------------------
Robocopy /l $reactjs $synReactjs /mir /xd $reactIgnores
However, robocopy immediately descends into the .git directory, though the output header looks like it parsed my switches correctly:
-------------------------------------------------------------------------------
ROBOCOPY :: Robust File Copy for Windows
-------------------------------------------------------------------------------
Started : Wednesday, October 31, 2018 12:00:32 PM
Source : C:\Users\me\Projects\prj\reactjs\
Dest : C:\Users\me\Projects\sync\reactjs\prj-JS\
Files : *.*
Exc Dirs : C:\Users\me\Projects\prj\reactjs\.git C:\Users\me\Projects\prj\reactjs\node_modules C:\Users\me\Projects\prj\reactjs\build
Options : *.* /L /S /E /DCOPY:DA /COPY:DAT /Z /R:1000000 /W:30
------------------------------------------------------------------------------
New Dir 8 C:\Users\me\Projects\prj\reactjs\
New File 634 .eslintrc.json
New File 206 .gitignore
New File 55 .npmrc
New File 521255 package-lock.json
New File 1015 package.json
New File 1001 package.json.react16
New File 10391 README
New File 1639 README.md
New Dir 9 C:\Users\me\Projects\prj\reactjs\.git\
New File 135 COMMIT_EDITMSG
New File 319 config
New File 73 description
New File 125 FETCH_HEAD
<...>
What am I missing with the /xd switch? It works fine with a single directory.
Edit: I included the Powershell tag because /xd ignores the list of files if I include them in the command line explicitly. Loading them via the array does not work. This results in an exc line of (compare to above):
Exc Dirs : C:\Users\me\Projects\prj\reactjs\.git
C:\Users\me\Projects\prj\reactjs\node_modules
C:\Users\me\Projects\prj\reactjs\build
In
$reactIgnores = #(
$reactjs + "\.git",
$reactjs + "\node_modules",
$reactjs + "\build"
)
try putting the full path.
This array worked for me, escaping double quotes with single quotes. You don't need the full path and I used a single /XD $eXcludeDirectories command:
$eXcludeDirectories = #(
'"Folder01"',
'"Folder02"',
'"Folder03"'
)
Hopefully this will help someone else.
I'm trying to use Log Parser within PowerShell to export a Windows Evtx log file to CSV:
$logparser = "c:\program files (x86)\Log Parser 2.2\logparser.exe"
$allArgs = ("SELECT * INTO c:\logs\logs.csv FROM c:\logs\logs.evtx", "-i:evt", "-o:csv")
$ps = Start-Process -FilePath $logparser -ArguementList $allArgs -Wait -Passthru -NoNewWindow;
$ps.WaitForExit()
$ps.ExitCode;
But when I run this I get an error:
Error: detected extra argument "*" after query
The error code is 13. I tried putting the paths in single quotes and running it from the same directory as the logs but it keeps returning the same error.
You need to preserve the double quotes around the query string, otherwise it won't be recognized as a single argument by the spawned process.
Putting the query string (with double quotes) in single quotes might work:
$allArgs = '"SELECT * INTO c:\logs\logs.csv FROM c:\logs\logs.evtx"',
"-i:evt",
"-o:csv"
However, a much simpler solution to the problem would be to avoid Start-Process entirely and use the call operator (&) instead:
$logparser = "c:\program files (x86)\Log Parser 2.2\logparser.exe"
$query = "SELECT * INTO c:\logs\logs.csv FROM c:\logs\logs.evtx"
& $logparser -i:evt -o:csv $query
I'm using a .baat to move several files into another folder, but before the actual move part, I want to replace the LAST line (it is a known line), for example I have a file output.txt like this:
HEADER
BODY
FOOTER
Using this snippet of code:
powershell -Command "(gc output.txt) -replace 'FOOTER', 'ONE_MORE_LINE `r`n FOOTER' | Out-File output.txt"
The return that I expected was
HEADER
BODY
ONE_MORE_LINE
FOOTER
But what I got was:
HEADER
BODY
ONE_MORE_LINE `r`n FOOTER
I've tried:
\n
<br>
"`r`n"
"`n"
echo ONE_MORE_LINE >> output.txt; echo. >> output.txt; echo FOOTER >> output.txt"
This last one got close, but the result was some broken characters.
Other suggestions besides the PowerShell are welcome. I'm only using it because it was an easy get way to do the adding lines and replace it.
EDIT :
Tried this command
powershell -Command "(gc output.txt) -replace 'FOOTER;', ""ONE_MORE_LINE `r`n FOOTER"" | Out-File output.txt "
And returned this error:
A cadeia de caracteres não tem o terminador: ".
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
EDIT2 - Possible Solution:
I realized that using the PowerShell command altered the encoding of the file, breaking the echo ONE_MORE_LINE, and using the suggestion from #AnsgarWiechers, I made this code
findstr /v "FOOTER" output.sql > new_output.sql
TYPE new_output.sql > output.sql
del new_output.sql
ECHO. >> %%f
ECHO ONE_MORE_LINE >> %%f
ECHO FOOTER >> %%f
ECHO. >> %%f
What it does is using the commant findstr /v "FOOTER" I look for all lines that are not FOOTER in the file output.sql and Write it on new_output.sql
Then I TYPE it back to the original file, and DEL the new_output.sql
Then I Echo all the lines I need right under it.
It works BUT, for big files I think that re-writing it twice will take a lot of time, but I can't figure an other solution.
When working with big files it's best to use a file stream. More typical methods of reading a file line-by-line using a Batch for /f loop or using Get-Content in PowerShell to read the entire file into memory can slow the process to a crawl with large files. Using a file stream on the other hand, you can nearly instantly seek back from the end of the file to the beginning of the last line, insert your desired data, and then reassemble the bytes you overwrote.
The following example will use PowerShell's access to .NET methods to open a file as a byte stream for rapid reading and writing. See inline comments for details. File encoding will hopefully be preserved. Save this with a .bat extension and give it a shot.
<# : batch portion
#echo off & setlocal
set "file=test.txt"
set "line=Line to insert!"
powershell -noprofile "iex (${%~f0} | out-string)"
goto :EOF
: end batch / begin PowerShell hybrid #>
# construct a file stream for reading and writing $env:file
$IOstream = new-object IO.FileStream((gi $env:file).FullName,
[IO.FileMode]::OpenOrCreate, [IO.FileAccess]::ReadWrite)
# read BOM to determine file encoding
$reader = new-object IO.StreamReader($IOstream)
[void]$reader.Read((new-object byte[] 3), 0, 3)
$encoding = $reader.CurrentEncoding
$reader.DiscardBufferedData()
# convert line-to-insert to file's native encoding
$utf8line = [Text.Encoding]::UTF8.GetBytes("`r`n$env:line")
$line = [Text.Encoding]::Convert([Text.Encoding]::UTF8, $encoding, $utf8line)
$charSize = [math]::ceiling($line.length / $utf8line.length)
# move pointer to the end of the stream
$pos = $IOstream.Seek(0, [IO.SeekOrigin]::End)
# walk back pointer while stream returns no error
while ($char -gt -1) {
$IOstream.Position = --$pos
$char = $reader.Peek()
$reader.DiscardBufferedData()
# break out of loop when line feed preceding non-whitespace is found
if ($foundPrintable) { if ($char -eq 10) { break } }
else { if ([char]$char -match "\S") { $foundPrintable++ } }
}
# step pointer back to carriage return and read to end into $buffer with $line prepended
$pos -= $charSize
$IOstream.Position = $pos
$buffer = $encoding.GetBytes($encoding.GetString($line) + $reader.ReadToEnd())
$IOStream.Position = $pos
"Inserting data at byte $pos"
$IOstream.Write($buffer, 0, $buffer.Length)
# Garbage collection
$reader.Dispose()
$IOstream.Dispose()
This method should be much more efficient than reading the file from the beginning, or copying the entire file into memory or on disk with a new line inserted. In my testing, it inserts the line into a hundred meg file in about 1/3 of a second.
I have the following script code
#[string]$password = $( Read-Host "Input password, please" )
param (
[string]$ReleaseFile = $(throw "-ReleaseFile is required"),
[string]$Destination = $(throw "-Destination is required")
)
function unzipRelease($src, $dst)
{
$shell = new-object -com shell.application
$zip = $shell.NameSpace($src)
foreach($item in $zip.items())
{
$shell.Namespace($dst).copyhere($item)
}
}
# .\deployrelease.ps1 -ReleaseFile ".\deploy.zip" -Destination "."
unzipRelease –Src '$ReleaseFile' -Dst '$Destination'
I run the script with: .\deployrelease.ps1 -ReleaseFile ".\deploy.zip" -Destination "."
But I keep getting this:
PS C:\Users\Administrator\Documents\Tools> .\deployrelease.ps1 -ReleaseFile ".\deploy.zip" -Destination
The string starting:
At C:\Users\Administrator\Documents\Tools\deployrelease.ps1:19 char:16
+ unzipRelease â? <<<< "Src '$ReleaseFile' -Dst '$Destination'
is missing the terminator: ".
At C:\Users\Administrator\Documents\Tools\deployrelease.ps1:19 char:55
+ unzipRelease â?"Src '$ReleaseFile' -Dst '$Destination' <<<<
+ CategoryInfo : ParserError: (Src `'$ReleaseF...'$Destination`':String) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
I couldn't find the fix as I do not see any problem.
Any help?
Look closely at the two dashes in
unzipRelease –Src '$ReleaseFile' -Dst '$Destination'
This first one is not a normal dash but an en-dash (– in HTML). Replace that with the dash found before Dst.
In my specific case of the same issue, it was caused by not having the Powershell script saved with an encoding of Windows-1252 or UFT-8 WITH BOM.
This can also occur when the path ends in a '' followed by the closing quotation mark.
e.g. The following line is passed as one of the arguments and this is not right:
"c:\users\abc\"
instead pass that argument as shown below so that the last backslash is escaped instead of escaping the quotation mark.
"c:\users\abc\\"
In your script, why are you using single quotes around the variables? These will not be expanded. Use double quotes for variable expansion or just the variable names themselves.
unzipRelease –Src '$ReleaseFile' -Dst '$Destination'
to
unzipRelease –Src "$ReleaseFile" -Dst "$Destination"
This error will also occur if you call .ps1 file from a .bat file and file path has spaces.
The fix is to make sure there are no spaces in the path of .ps1 file.
You can spot the error when using # prefix/suffix with multiline string while you actually have the ending suffix "#.
My script looked like that:
Add-Type #"
public class SomeClass {
...
}"#
and I still got the: The string is missing the terminator: "#.
Message was misleading because all I needed to do was to put "# into new line without any leading space:
Add-Type #"
public class SomeClass {
...
}
"#
my folder contained ' symbol. After I removed it, the issue resolved.
if you're using RHEL, try replacing " with ' - this fixed the error for me
cheers
I am working on a script that needs RoboCopy switches to be passed in dynamically based on user input, hence using array seems like the best option. However I see the following issue when using I specify parameters like /XF that have a space and value.
This works as expected:
RoboCopy C:\Dir1 C:\Dir2 /NP /NFL /NS /NDL /NJH /NJS /XF *.config
This works as expected:
$Switches = #("/NP", "/NFL", "/NS", "/NDL", "/NJH", "/NJS", "/E")
RoboCopy C:\Dir1 C:\Dir2 $Switches
This throws ERROR : Invalid Parameter #10 : "/XF *.config":
$Switches = #("/NP", "/NFL", "/NS", "/NDL", "/NJH", "/NJS", "/E", "/XF *.config")
RoboCopy C:\Dir1 C:\Dir2 $Switches
I tried few things like using quotes with /XF parameter but no success. Any hint/help is appreciated.
Can you try this, I can't test it but let me know..:
$Switches = #("/NP", "/NFL", "/NS", "/NDL", "/NJH", "/NJS", "/E", "/XF", "*.config")
My variant (more XD/XF parameters):
$RobocopyParams = #("/NP", "/NFL", "/NS", "/NDL", "/NJH", "/NJS", "/E")
$XD = #("Cookies", "His6", "SendTo", "Temp", "Temporary Internet Files", "Windows")
$XF = #("*.pif", "$UserName.INI", "$UserName.OPS", "$UserName.INI.*")
robocopy.exe #params /XD #XD /XF #XF