Bash script to copy files in PowerShell - bash

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 --%

Related

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

Appending date/time to file AND updating last modified/save date

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.

powershell copy-item doesn't copy when filter is used

I'm trying to copy files using copy-item. Specifically, I want to copy files with a particular extension that are within a folder or its subfolders to another location, and to retain the subfolder hierarchy. I've tried using -filter and -include to specify the file extension, but no files are copied.
My source and destination paths are stored in variables $packageSourcePath and $objPath. When called, $packageSourcePath will be like the following ".\src\projects\Project1\PackageFiles" and $objPath will be like the following ".\bld\Project1\obj".
The command I've tried using is this:
Copy-Item -Path $packageSourcePath\* -Filter *.resw -Destination $objPath -Recurse
I've also tried variations, such as leaving off * from the path, or using -Include instead of -Filter. Nothing works. If I leave out the -Filter argument, then files copy, but all of the files are copied. I only want files with the particular extension.
I've given up on Copy-Item. JohnLBevan's answer didn't actually do what I want since all files in the source root get copied, even though they don't match the filter. I tried piping Convert-Path | Select-String | Copy-Item but still got all files in the source root being copied.
A contact in a different context provided a couple of suggestions:
1)
Get-ChildItem -Force -Recurse -ErrorAction Ignore -Path $packageSourcePath -Filter *.resw | % {
$src = $_.FullName
$dst = Join-Path $objPath $src.SubString($packageSourcePath.Length)
echo "copy ""$src"" ""$dst"""
}
I think this is a bit harder to follow, hence less maintainable for the next person (likely another PS-neophyte like me) a year from now. ("Why is the -ErrorAction parameter needed here? What's the behaviour of the Substring() method, and why can't I find that using Get-Help?")
This suggestion is a bit clearer, after re-familiarizing with attrib and checking the effect of the xcopy switches:
2)
cd $packageSourcePath
attrib -a /s
attrib +a *.resw /s
xcopy /eidlm $packageSourcePath $objPath
But if we're going to use xcopy, we don't need to call attrib:
xcopy $packageSourcePath*.resw $objPath /s /i > $null
The only problem with this for my scenario is that xcopy emits an error if no matching files are found. My script is being used for a VSTS build task, and the xcopy errors cause the build task to fail. (For that reason, I'm guess that suggestion 2 also wouldn't work for me.)
So, I've opted for this:
# In PS version 5.1, nothing gets copied using Copy-Item $packageSourcePath\* -Filter *.resw ...
# so resorting to using xcopy, which mostly works. The one issue is that xcopy will output an
# error if no matching file is found, so using GCI first to test for a matching file.
if ($(Get-ChildItem $packageSourcePath\*.resw -Recurse).count -gt 0) {
xcopy $packageSourcePath\*.resw $objPath /s /i > $null
}
The condition using GCI is added to check there are matching files before calling xcopy, thereby avoiding any errors.
I'm still amazed that Copy-Item -Filter -Recurse didn't work.
This should do it (obviously this could be done in 1 line; I've assigned values to the variables just to help make it readable / self-explanatory):
[string]$filter = '*.resw'
[string]$source = Join-Path -Path $packageSourcePath -ChildPath '*'
[string]$target = $objPath
$source | Convert-Path | Copy-Item -Filter $filter -Recurse -Destination $target -Container #-Force
Notes:
We append the asterisk to the source path to ensure that we copy the contents of the source folder to the destination, without copying the source's root folder into the destination (i.e. say we're copying c:\temp\from to c:\temp\to, we don't want c:\temp\to\from (unless it's a copy of c:\temp\from\from)).
We use the Join-Path cmdlet to append this asterisk to ensure the appropriate slashes are inserted into the path.
We do a Convert-Path on the source to resolve the asterisk to the child folder/file names... for some reason copy-item doesn't handle these asterisks well. NB: Convert-Path will potentially return an array of paths; i.e. if there's more than one file/subfolder directly under the source folder. Get-Item or Resolve-Path could equally be used for this; I prefer Convert-Path since it returns a simple string array, rather than a more complex type; but there's no strong argument for using any one over the others.
We pipe these source paths to the Copy-Item command so it can be applied to each path returned by Convert-Path.
We include -Recurse to say we're interested in anything in the subfolders of the copied path.
We include the -Container parameter to say that we want to preserve any folder structure when copying. Strictly this is not needed, as this switch is defaulted to true (i.e. rather we should specify if we don't want this behaviour: -Container:$false; but I like to be clear that I deliberately want to preserve the directory structure, as opposed to leaving the assumption that I may not have thought of this. There's a better explanation of this here: https://stackoverflow.com/a/21798660/361842.
You could optionally include -Force; this would mean that should an item of the same name already exist in the target we overwrite it instead of getting an error.
Related documentation:
Join-Path
Convert-Path
Copy-Item
Update 2018-01-03
Per comments, this solution should ensure that only those items you want get copied, and pre-existing directories shouldn't cause issues.
[string]$filter = '*.resw'
[string]$source = $packageSourcePath
[string]$target = $objPath
#copy all files in subfolders of the source
$source | Get-ChildItem -Directory | Copy-Item -Filter $filter -Recurse -Destination $target -Container -Force
#copy all files in root of the source
$source | Get-ChildItem -File -Filter $filter | Copy-Item -Destination $target -Container -Force
This solution uses 2 steps; there's probably a better option, but due to the peculiarities / bug in this cmdlet the above's a reliable option.

How to use PowerShell Remove-Item to delete a directory with long name? [duplicate]

I'm writing a simple script to delete USMT migration folders after a certain amount of days:
## Server List ##
$servers = "Delorean","Adelaide","Brisbane","Melbourne","Newcastle","Perth"
## Number of days (-3 is over three days ago) ##
$days = -3
$timelimit = (Get-Date).AddDays($days)
foreach ($server in $servers)
{
$deletedusers = #()
$folders = Get-ChildItem \\$server\USMT$ | where {$_.psiscontainer}
write-host "Checking server : " $server
foreach ($folder in $folders)
{
If ($folder.LastWriteTime -lt $timelimit -And $folder -ne $null)
{
$deletedusers += $folder
Remove-Item -recurse -force $folder.fullname
}
}
write-host "Users deleted : " $deletedusers
write-host
}
However I keep hitting the dreaded Remove-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
I've been looking at workarounds and alternatives but they all revolve around me caring what is in the folder.
I was hoping for a more simple solution as I don't really care about the folder contents if it is marked for deletion.
Is there any native Powershell cmdlet other than Remove-Item -recurse that can accomplish what I'm after?
I often have this issue with node projects. They nest their dependencies and once git cloned, it's difficult to delete them. A nice node utility I came across is rimraf.
npm install rimraf -g
rimraf <dir>
Just as CADII said in another answer: Robocopy is able to create paths longer than the limit of 260 characters. Robocopy is also able to delete such paths. You can just mirror some empty folder over your path containing too long names in case you want to delete it.
For example:
robocopy C:\temp\some_empty_dir E:\temp\dir_containing_very_deep_structures /MIR
Here's the Robocopy reference to know the parameters and various options.
I've created a PowerShell function that is able to delete a long path (>260) using the mentioned robocopy technique:
function Remove-PathToLongDirectory
{
Param(
[string]$directory
)
# create a temporary (empty) directory
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
$tempDirectory = New-Item -ItemType Directory -Path (Join-Path $parent $name)
robocopy /MIR $tempDirectory.FullName $directory | out-null
Remove-Item $directory -Force | out-null
Remove-Item $tempDirectory -Force | out-null
}
Usage example:
Remove-PathToLongDirectory c:\yourlongPath
This answer on SuperUser solved it for me: https://superuser.com/a/274224/85532
Cmd /C "rmdir /S /Q $myDir"
I learnt a trick a while ago that often works to get around long file path issues. Apparently when using some Windows API's certain functions will flow through legacy code that can't handle long file names. However if you format your paths in a particular way, the legacy code is avoided. The trick that solves this problem is to reference paths using the "\\?\" prefix. It should be noted that not all API's support this but in this particular case it worked for me, see my example below:
The following example fails:
PS D:\> get-childitem -path "D:\System Volume Information\dfsr" -hidden
Directory: D:\System Volume Information\dfsr
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs 10/09/2014 11:10 PM 834424 FileIDTable_2
-a-hs 10/09/2014 8:43 PM 3211264 SimilarityTable_2
PS D:\> Remove-Item -Path "D:\System Volume Information\dfsr" -recurse -force
Remove-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260
characters, and the directory name must be less than 248 characters.
At line:1 char:1
+ Remove-Item -Path "D:\System Volume Information\dfsr" -recurse -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (D:\System Volume Information\dfsr:String) [Remove-Item], PathTooLongExcepti
on
+ FullyQualifiedErrorId : RemoveItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS D:\>
However, prefixing the path with "\\?\" makes the command work successfully:
PS D:\> Remove-Item -Path "\\?\D:\System Volume Information\dfsr" -recurse -force
PS D:\> get-childitem -path "D:\System Volume Information\dfsr" -hidden
PS D:\>
If you have ruby installed, you can use Fileman:
gem install fileman
Once installed, you can simply run the following in your command prompt:
fm rm your_folder_path
This problem is a real pain in the neck when you're developing in node.js on Windows, so fileman becomes really handy to delete all the garbage once in a while
This is a known limitation of PowerShell. The work around is to use dir cmd (sorry, but this is true).
http://asysadmin.tumblr.com/post/17654309496/powershell-path-length-limitation
or as mentioned by AaronH answer use \?\ syntax is in this example to delete build
dir -Include build -Depth 1 | Remove-Item -Recurse -Path "\\?\$($_.FullName)"
If all you're doing is deleting the files, I use a function to shorten the names, then I delete.
function ConvertTo-ShortNames{
param ([string]$folder)
$name = 1
$items = Get-ChildItem -path $folder
foreach ($item in $items){
Rename-Item -Path $item.FullName -NewName "$name"
if ($item.PSIsContainer){
$parts = $item.FullName.Split("\")
$folderPath = $parts[0]
for ($i = 1; $i -lt $parts.Count - 1; $i++){
$folderPath = $folderPath + "\" + $parts[$i]
}
$folderPath = $folderPath + "\$name"
ConvertTo-ShortNames $folderPath
}
$name++
}
}
I know this is an old question, but I thought I would put this here in case somebody needed it.
There is one workaround that uses Experimental.IO from Base Class Libraries project. You can find it over on poshcode, or download from author's blog. 260 limitation is derived from .NET, so it's either this, or using tools that do not depend on .NET (like cmd /c dir, as #Bill suggested).
Combination of tools can work best, try doing a dir /x to get the 8.3 file name instead. You could then parse out that output to a text file then build a powershell script to delete the paths that you out-file'd. Take you all of a minute. Alternatively you could just rename the 8.3 file name to something shorter then delete.
For my Robocopy worked in 1, 2 and 3
First create an empty directory lets say c:\emptydir
ROBOCOPY c:\emptydir c:\directorytodelete /purge
rmdir c:\directorytodelete
This is getting old but I recently had to work around it again. I ended up using 'subst' as it didn't require any other modules or functions be available on the PC this was running from. A little more portable.
Basically find a spare drive letter, 'subst' the long path to that letter, then use that as the base for GCI.
Only limitation is that the $_.fullname and other properties will report the drive letter as the root path.
Seems to work ok:
$location = \\path\to\long\
$driveLetter = ls function:[d-z]: -n | ?{ !(test-path $_) } | random
subst $driveLetter $location
sleep 1
Push-Location $driveLetter -ErrorAction SilentlyContinue
Get-ChildItem -Recurse
subst $driveLetter /D
That command is obviously not to delete files but can be substituted.
PowerShell can easily be used with AlphaFS.dll to do actual file I/O stuff
without the PATH TOO LONG hassle.
For example:
Import-Module <path-to-AlphaFS.dll>
[Alphaleonis.Win32.Filesystem.Directory]::Delete($path, $True)
Please see at Codeplex: https://alphafs.codeplex.com/ for this .NET project.
I had the same issue while trying to delete folders on a remote machine.
Nothing helped but... I found one trick :
# 1:let's create an empty folder
md ".\Empty" -erroraction silentlycontinue
# 2: let's MIR to the folder to delete : this will empty the folder completely.
robocopy ".\Empty" $foldertodelete /MIR /LOG+:$logname
# 3: let's delete the empty folder now:
remove-item $foldertodelete -force
# 4: we can delete now the empty folder
remove-item ".\Empty" -force
Works like a charm on local or remote folders (using UNC path)
Adding to Daniel Lee's solution,
When the $myDir has spaces in the middle it gives FILE NOT FOUND errors considering set of files splitted from space. To overcome this use quotations around the variable and put powershell escape character to skip the quatations.
PS>cmd.exe /C "rmdir /s /q <grave-accent>"$myDir<grave-accent>""
Please substitute the proper grave-accent character instead of <grave-accent>
SO plays with me and I can't add it :). Hope some one will update it for others to understand easily
Just for completeness, I have come across this a few more times and have used a combination of both 'subst' and 'New-PSDrive' to work around it in various situations.
Not exactly a solution, but if anyone is looking for alternatives this might help.
Subst seems very sensitive to which type of program you are using to access the files, sometimes it works and sometimes it doesn't, seems to be the same with New-PSDrive.
Any thing developed using .NET out of the box will fail with paths too long. You will have to move them to 8.3 names, PInVoke (Win32) calls, or use robocopy

Batch file no longer executes after running find/replace Powershell script on it

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.

Resources