I'm trying to create an array that will remove files from the destination path and then copy from the source path to the destination path. I've created a .txt document on the build server with a list of files with their relative path. When I run the below block of code it's removing all contents in folder B and copy Folder A(without any contents) to Folder B.
This is what I'm running
$files = get-content "C:\files.txt"
foreach ($filepath in $files)
{
$source = '\\Server1\Folder A' + $filepath
$dest = '\\Server2\Folder B' + $filepath
foreach ($removefile in $dest)
{
rd $removefile -recurse -force
}
foreach ($addfile in $source)
{
cp $addfile -destination $dest
}
}
Soda,
I've tried your suggestion but it's trying to remove from/copy to the incorrect directory.
Code:
$targetList = Get-Content "C:\MCSfiles.txt"
foreach ($target in $targetList) {
$destPath = Join-Path "\\Server2\MCSWebTest" $target
$destFiles = Get-ChildItem $destPath
foreach ($file in $destFiles) {
Remove-Item $file -Recurse -Force
}
$sourcePath = Join-Path "\\Server1\WebSites\McsWeb2" $target
$sourceFiles = Get-ChildItem $sourcePath
foreach ($file in $sourceFiles) {
Copy-Item $file -Destination $destPath
}
}
Error:
Remove-Item : Cannot find path 'C:\Program Files (x86)\Jenkins\jobs\MCSTest\workspace\App_Code' because it does not exist.
At C:\Users\SVC-VI~1\AppData\Local\Temp\jenkins5893875881898738781.ps1:9 >char:1
9
+ Remove-Item <<<< $file -Recurse -Force
+ CategoryInfo : ObjectNotFound: (C:\Program >File...kspace\App_Co
de:String) [Remove-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.Remov
eItemCommand
Copy-Item : Cannot find path 'C:\Program Files (x86)\Jenkins\jobs\MCSTest\works
pace\App_Code' because it does not exist.
At C:\Users\SVC-VI~1\AppData\Local\Temp\jenkins5893875881898738781.ps1:16 >char:
18
+ Copy-Item <<<< $file -Destination $destPath
+ CategoryInfo : ObjectNotFound: (C:\Program >File...kspace\App_Co
de:String) [Copy-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.CopyI
temCommand
Soda,
Neither of the suggestions work. It's still removing everything in the destination directory and adding the source directory folder to the destination directory without files. I'm a little lost here.
you are missing backslashes in your paths, use Join-Path to build your strings to avoid that (or maybe leading backslashes are included in files.txt)
you iterate on $dest and $source but these are strings, not file collections, which you should be able to retrieve with Get-ChildItem $dest and Get-ChildItem $source, for instance
Also, for readability, you should not use aliases in scripts (rd and cp)
PS: I believe your script produces errors, you should include them in your question (you can edit it)
EDIT regarding comments:
Try this (untested, remove -WhatIf's to process):
$targetList = Get-Content "D:\files.txt"
foreach ($target in $targetList) {
$destPath = Join-Path "D:\destination" $target
Remove-Item $destPath -Recurse -Force -WhatIf
$sourcePath = Join-Path "D:\source" $target
Copy-Item $sourcePath -Destination $destPath -Recurse -WhatIf
}
EDIT2: I have corrected and simplified the code above, my logic was slightly off.
This could even be simpler, and better, to group remove statements and run them before the copy statements, like:
$targetList = Get-Content "D:\files.txt"
#remove all
$targetList | ForEach-Object {
Remove-Item (Join-Path "D:\destination" $_) -Recurse -Force -WhatIf
}
#copy all
$targetList | ForEach-Object {
Copy-Item (Join-Path "D:\source" $_) (Join-Path "D:\destination" $_) -Recurse -Force -WhatIf
}
Both snippets have been tested with a sample folder structure.
Just for the sake of completeness, the error you got with my first attempt was due to passing the $file objects to the processing cmdlets, instead of full paths ($file.FullName).
The issue is you are trying to loop too many times. The outer loop processes the files one at a time. There should be no inner loop. Also, you aren't validating the file exists before issuing a deletion.
$files = Get-Content "C:\test.txt"
$source_base="C:\TEMP\source\"
$dest_base="C:\TEMP\dest\"
foreach ($filepath in $files)
{
$source = $source_base + $filepath
$dest = $dest_base + $filepath
if(Test-Path $dest) {rd $dest -recurse -force}
cp $source -destination $dest
}
Related
I am working on a disk space script for our clients in my off time. I just tested it using the ISE, and it looks like it was working until I checked the transcript.
There are sections during the first removal cycle around line 32 where it is removing files in C:\Windows\System32\, which of course I didn't want it to. I am sure I did something wrong, but I have checked for typos, and I do not understand how it can get %system32% from a users directory.
If (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
{
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + ' (Elevated)'
$Host.UI.RawUI.BackgroundColor = 'DarkBlue'
Clear-Host
}
Else
{
$newProcess = New-Object Diagnostics.ProcessStartInfo 'PowerShell'
$newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"
$newProcess.Verb = 'runas'
[Diagnostics.Process]::Start($newProcess) | Out-Null
exit
}
If ((Test-Path "C:\DiskSpaceCleanupLog\") -eq $False)
{
New-Item -ItemType Directory -Path "C:\DiskSpaceCleanupLog\"
}
$Date = [string]::Format( "{0:dd-MM-yyyy}", [datetime]::Now.Date )
$LogName = "C:\DiskSpaceCleanupLog\" + $Date + "Log.txt"
Start-Transcript $LogName
$Path = #()
$Array = #(Get-ChildItem C:\Users | Select-Object Name)
Read-Host -Verbose "Removing User Account temp files..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\Temp\")
}
Foreach ($Path IN $Array)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Remove-Variable Path
Read-Host -Verbose "Removing User Account crash dumps..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\CrashDumps\")
}
Foreach ($Path IN $Array)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Remove-Variable Path
Read-Host -Verbose "Removing User Account reporting files..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\Microsoft\Windows\WER\ReportArchive\")
}
Foreach ($Temp IN $Path)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Remove-Variable Path
Read-Host -Verbose "Removing User Account temp files from Internet Explorer..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\Microsoft\Windows\Temporary Internet Files\")
}
Foreach ($Temp IN $Path)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Read-Host -Verbose "Removing Recycle Bin files..."
Remove-Item -LiteralPath 'C:\$Recycle.Bin\' -Recurse -WhatIf
Read-Host -Verbose "Removing global crash dumps..."
Remove-Item "C:\ProgramData\Microsoft\Windows\WER\ReportQueue" -Recurse -WhatIf
Remove-Item "C:\ProgramData\Microsoft\Windows\WER\ReportArchive" -Recurse -WhatIf
Read-Host -Verbose "Removing Windows Update cached files..."
Stop-Service -DisplayName 'Windows Update'
Remove-Item "C:\Windows\SoftwareDistribution\Download\*" -Recurse -WhatIf
Start-Service -DisplayName 'Windows Update'
Remove-Variable Array, Path
Read-Host -Verbose "Cleaning base image of update cache..."
DISM.exe /Online /Cleanup-Image /SPSuperseded
Read-Host -Verbose "Running Windows Clean Manager..."
$OSVersion = Get-WMIObject -Class Win32_OperatingSystem | Format-Table Version
If ($OSVersion -le 6.1)
{
cleanmgr.exe /verylowdisk
}
Read-Host -Verbose "Removal is complete. Sending logs..."
Stop-Transcript
$SecurePassword = ConvertTo-SecureString "InsertPasswordHere" -AsPlainText -Force
$emailcredential = New-Object System.Management.Automation.PSCredential ("email#domain.com", $SecurePassword)
Send-MailMessage -To "Name Here <email#domain.com>" -From "Name Here <email#domain.com>" -Subject ("Disk Space Cleanup Log - " + $Date) -Body "Attached is the log from the script." -Attachments $LogName -SmtpServer "smtp.office365.com" -Credential $emailcredential -UseSSL -Port "587" -DeliveryNotificationOption OnFailure
Line 32 is Get-ChildItem | Remove-Item -Recurse -WhatIf
The are several things that should be adjusted in your code but the issue that is befalling you now is that you have not specified a -Path. Therefore Get-ChildItem will be returning items from the working directory!
Get-ChildItem | Remove-Item -Recurse -WhatIf
Should be instead
Get-ChildItem $path | Remove-Item -Recurse -WhatIf
Like I said though there are several potential pitfalls and areas of improvement there to be addressed. You use the same loop 5 times. A couple are exactly the same.
I believe the issue is on line 23, where the code is not populating the array with full pathnames. See Get full path of the files in PowerShell for some advice on how to get the full pathnames instead.
so, trying to rename any file found in the current script directory and all subfolders. Doesn't want to work. This is what I have so far...what am I doing wrong? The issue I'm having is that it is not renaming files in the subfolders.
<# Renames all files in the working directory to have an extension of .hd #>
$files = Get-ChildItem $PSScriptRoot -Recurse | Where-Object {$_.Extension -match ".jpg|.jpeg|.png|.bmp|.gif|.3gp|.mp4|.webm|.mkv"}
ForEach ($file in $files) {
$filenew = $file.Name + ".hd"
Rename-Item $file $filenew
}
you are passing a filesystem object to path parameter of rename-item instead of a string path.
change this :
Rename-Item $file $filenew
to this:
Rename-Item -Path $file.fullname -NewName $filenew
You could also simplify your script to this:
Get-ChildItem -Path $Path -Include *.jpg,*.png,*.mp4 -Recurse |
Rename-Item -NewName { $_.Name + '.hd' } -WhatIf
Note: remove -whatif to apply the rename action
Anyway, so $file.Name contains the extension so you need $file.Basename
$files = Get-ChildItem $PSScriptRoot -Recurse | Where-Object {$_.Extension -match ".jpg|.jpeg|.png|.bmp|.gif|.3gp|.mp4|.webm|.mkv"}
ForEach ($file in $files) {
$filenew = $file.BaseName + ".hd"
Rename-Item $file $filenew
}
I am working on folders that contain many types and sizes of files within them. What I want to do is move files that are not contained in one folder into a new folder. I have embedded a picture link that helps illustrate what I am aiming to do.
I would like test123.pdf to be moved to a new location because it's not contained within the other folder. Below I have some code that simply compares the contents of each folder and outputs which file is out of place. I have been researching some things online, but have come up empty. Can anyone help me proceed?
Disclaimer: I know the path is wrong, but I can't show it for security reasons.
$Folder1 = Get-ChildItem -Recurse -path "Enter Path here"
$Folder2 = Get-ChildItem -Recurse -path "Enter the Path here"
Compare-Object -ReferenceObject $Folder1 -DifferenceObject $Folder2
It sounds like you want to compare the contents of two folders, ID the file(s) that are not present in both folders, and then move them to a third folder. To accomplish this, you can define your 2 paths in variables, compare the contents of the folders, grab the full path names of the different items, and then move them to the new destination.
$path1 = yourfirstpath
$path2 = yoursecondpathforcomparing
$path3 = yourdestinationpath
diff (ls $path1 -recurse) (ls $path2 -recurse) | ForEach {$_.InputObject.FullName} | Move-Item -Destination $path3
diff = Compare-Object , ls = Get-ChildItem
This will do the work, any file that is not in both Folder1 & Folder2 will be moved to Folder 3
$Folder1 = 'C:\folder1'
$Folder2 = 'C:\folder2'
$Folder3 = 'C:\folder3'
foreach ($file in Get-ChildItem -Recurse $Folder1)
{
if (-not(Test-Path "$Folder2\$file"))
{
Move-Item $file.FullName $Folder3
}
}
This will compare by file name, and maintain the directory structure the extra files were found in, and handle the recursion properly. The output of the code demonstrates the directory structure I tested with.
# be explict here to ensure everything is lowercase
# so when this is cut and pasted, it does not break
# when you enter the real path
$d1 = "d:\test\one".ToLower()
$d2 = "d:\test\two".ToLower()
$f1 = gci -Recurse $d1 -File | % {$_.FullName.ToLower()}
$f2 = gci -Recurse $d2 -File | % {$_.FullName.ToLower()}
"f1"
$f1
"`nf2"
$f2
$same = #()
$extra = #()
foreach ($f in $f2)
{
$f2tof1path = $f.Replace($d2, $d1)
if ($f1.Contains($f2tof1path) -eq $false)
{
$extra += $f
}
else {
$same += $f
}
}
"`nSame"
$same
"`nExtra"
$extra
"`nMOVE"
$folder3 = "d:\test\three"
foreach ($f in $extra)
{
# move files somewhere, create dir if not exists
$dest = $f.Replace($d2,$folder3)
$destdir = $(Split-Path -Parent -Path $dest)
if (!(Test-Path $destdir))
{
# remove quotes to do new-item, keep them to show what it will do
"New-Item -ItemType Directory -Force -Path $destdir"
}
# remove quotes to do move-item, keep them to show what it will do
"Move-Item $f $dest"
}
Output
f1
d:\test\one\1.txt
d:\test\one\2.txt
d:\test\one\sub\1.txt
d:\test\one\sub\2.txt
f2
d:\test\two\1.txt
d:\test\two\2.txt
d:\test\two\3.txt
d:\test\two\sub\1.txt
d:\test\two\sub\2.txt
d:\test\two\sub\3.txt
Same
d:\test\two\1.txt
d:\test\two\2.txt
d:\test\two\sub\1.txt
d:\test\two\sub\2.txt
Extra
d:\test\two\3.txt
d:\test\two\sub\3.txt
MOVE
New-Item -ItemType Directory -Force -Path d:\test\three
Move-Item d:\test\two\3.txt d:\test\three\3.txt
New-Item -ItemType Directory -Force -Path d:\test\three\sub
Move-Item d:\test\two\sub\3.txt d:\test\three\sub\3.txt
If this does not solve your problem, it should get you 99% there. Play around with the code, have fun, and good luck.
How can I copy the folder names to the filenames during the copy. At the moment the script copies only files from the subdirectory without all folder and sub-foldername. However, I want which takes the absolute pathname while copying.
Here an example:
Folder1
Subfolder1
Subfolder2
Subfolder3
Subfolder4
File1
Folder2
Then a copied file would be called so:
Folder1_Subfolder1_Subfolder2_Subfolder3_Subfolder4_File.pdf
Powershell code:
Get-ChildItem –path C:\12 -Recurse -Include "*.???" |
Foreach-Object { copy-item -Path $_.fullname -Destination c:\12 }
Ok, if I'm understanding you correctly, you want a file like:
C:\12\foo\bar\baz.txt
To be copied to:
C:\12\foo_bar_baz.txt
If I'm understanding that correctly, then something like the following should work:
function Copy-FileUsePath {
[cmdletbinding()]
param(
[parameter(Mandatory=$true,Position=0)][string]$Path,
[parameter(Mandatory=$true,Position=1)][string]$Destination
)
$files = Get-ChildItem -Path $Path -Recurse -Include "*.???"
foreach ( $file in $files ) {
$discard = $Destination.Length
if( $Destination -notlike "*\" ) {
$discard++
}
$newFileName = $file.FullName.Replace('\', '_').Remove( 0, $discard )
$newFile = $Destination + '\' + $newFileName
Write-Verbose "Copy-Item -Path $file.fullname -Destination $newFile"
Copy-Item -Path $file.fullname -Destination $newFile
}
}
To use this, save it to a file (I called it Copy-FileUsePath.ps1), and you can do the following:
. .\Copy-FileUsePath.ps1
Copy-FileUsePath -Path C:\12 -Destination C:\export
I have this bit of powershell script but i can't get the $DirectoryName to behave as expected.
1,2,3 |
foreach {
$count = $_;
$x = gci -Path \\myserver-web$count\d$\IISLogs\ -include *.log -recurse
$x | Copy-Item -Destination D:\ServerLogsAndBackups\IIS\w$count\$_.DirectoryName_$_.Name -whatIf
}
When I run this though I get
What if: Performing operation "Copy File" on Target "Item: \myserver-web1\d$\IISLogs\W3SVC1165836668\ex101224.log Destination: D:\ServerLogsAndBackups\IIS\w1\1.DirectoryName_1.Name".
What I want it to be is
W3SVC1165836668_ex101206.log
where my directory structure is like:
\\myserver-web1\d$\IISLogs\W3SVC1165836668
\\myserver-web1\d$\IISLogs\W3SVC1165837451
\\myserver-web1\d$\IISLogs\W3SVC1165836966
\\myserver-web1\d$\IISLogs\W3SVC1165812365
with files called ex101206.log in each folder
Cheers
You need to evaluate the $_.Directoryname_$_.Name part. Like so,
$x | Copy-Item -Destination $(D:\ServerLogsAndBackups\IIS\w$count\$_.DirectoryName_$_.Name) -whatIf
1,2,3 |
foreach {
$count = $_;
gci -Path \\myserver-web$count\d$\IISLogs\ -include *.log -recurse | % { $dirName = $_.directoryname.Substring($_.directoryname.LastIndexOf("\")+1); $logname = $_.Name; $_ | Copy-Item -Destination $("D:\ServerLogsAndBackups\IIS\w"+$count+"\"+$dirname+"_"+$logName) -whatif }
}