I've tried searching for this answer for awhile now, but can't seem to find what I'm after. Perhaps I'm wording it strangely.
I need a script that will recursively delete a specific file from each child directory in a network share.
For example:
\\\share\\*\a\b\file.settings
The * represents n number of child directories. The rest of the path will always be the same. It seems like I might be able to do this with a combination of Get-childitem and remove-item in Powershell, but I'm having trouble working out the exact command I need.
Any help would be immensely appreciated! Thanks.
Something like this should work:
Get-ChildItem '\\server\share' -Recurse | ? {
$_.FullName -like '*\a\b\file.settings'
} | Remove-Item
If you're just interested in files .\a\b\file.settings in the immediate child folders of \\server\share you could simplify the code to something like this:
Get-ChildItem '\\server\share\*\a\b\file.settings' | Remove-Item
Breaking out my comment code into long form:
$folders = Get-ChildItem "\\server\share\" -Directory
ForEach ($folder in $folders) {
$file = Join-Path $folder.FullName "\a\b\file.settings"
if (Test-Path $file) { Remove-Item $file }
}
While I wasn't able to get this to work with Powershell, the below VBS I put together does seem to work well:
Set FSfolder = FSO.GetFolder(\\server\share)
For Each subfolder In FSfolder.SubFolders
UserProfile=subfolder.Name
SettingFile="\\server\share\" & UserProfile & "\a\b\file.settings"
If FSO.FileExists(SettingFile) Then
FSO.DeleteFile(SettingFile)
End If
Next
Related
Alright, been working on this for hours and researching like crazy, but still not getting something to work. I need a string[] object created from get-childitem to pass to the Copy-Item -exclude parameter.
The hurdle is that I need to do recursion and need to have relative paths, so this is what I came up with:
$((Get-ChildItem -Path $Dest -Recurse -File).FullName.TrimStart($Dest))
This results in a clean list of existing files in $dest that are presented with a relative path to $dest. The problem is, if I add this to the copy-item -exclude parameter it seems to ignore it. Further research online suggests that copy-item will ignore the -exclude parameter if it is not of type string[].
If I check the type returned by the above command, I get System.Object[]. I expect it to be System.String[] or just plain String[].
How do I convert the output of the above command to a string array?
The full command using copy-item, for clarity, is:
Copy-Item -Path (Join-Path $src "*") -Destination $dest -Recurse -Force -Exclude $((Get-ChildItem -Path $Dest -Recurse -File).FullName.TrimStart($Dest))
My end goal is to copy files recursively without overwriting existing files.
To get a string[] from the names of get-childitem cmdlet use the following
[string[]]$files = (Get-ChildItem).Name
This will do what it appears you say that you want? But, I think that may not be everything to your question.
$((Get-ChildItem -Path $Dest -Recurse -File).FullName.Replace("$Dest",'.'))
#mklement0 is right, -Exclude and -Include support file name patterns (i.e. "*.txt") and not an array of explicit paths.
This sounds like an awful lot like an XY Problem ;-)
If you simply want to copy files recursively without overwriting them, use Robocopy with the Mirror switch. e.g.:
robocopy C:/Source C:/Dest /mir
EDIT:
By default Copy-Item will always overwrite the files on copy, and there is no switches to get around this. I usually recommend Robocopy as it really simplifies things like this and is very "robust" and reliable.
If your requirements are for a "pure" PowerShell version, then you have to break the scrip out into two parts, 1. Get a list of all the files 2. Iterate through the filer and test to see if they are already in the destination before copying.
$SrcPath = "C:/Source"
$DestPath = "C:/Dest"
$SrcFiles = Get-ChildItem $SrcPath -Recurse
#Iterate through files testing:
$SrcFiles | ForEach-Object {
#Calculate Destination File/Folder name/path
$DestObj = $_.FullName.Replace($SrcPath, $DestPath)
if(Test-Path -LiteralPath $DestObj)
{
#File already Exists
Write-Host "File already Exists: $DestObj"
}
else
{
#File Does not exist - Copy
Write-Host "File Does not Exist Copy: $DestObj"
Copy-Item -Path $_ -Destination $DestObj
}
}
I am looking to search a directory that also has sub-directories for any and all files ending in the extension .kfm
I have managed to pick up all the files from the current directory using dir *.kfm but I also need to loop through each of the results in a for loop so I can add additional code.
Thank you in advance
I know you did not ask for a PowerShell solution, but it is pretty straightforward. From your earlier comment, I added filtering out those files whose path includes \UPT\.
Get-ChildItem -Path 'C:\the\dir' -Recurse -File -Filter '*.kfm' |
Where-Object { -not ( $_.FullName -like "*[/\]UPT[/\]*") }
ForEach-Object {
# work on the $_.FullName file here
}
I'm trying to use Powershell ISE to help me do the following:
Perform a search for many files (with an extension of *props.tmpl) under a certain folder and to include all sub-directories.
When found, I want to copy that file to its current location, but with an extension of *.tmpl2 (what I really want is to skip this step and copy *props.tmpl to a file called *props)
Then rename all *.tmpl2 files and remove the tmpl2 entirely, leaving just the *.props extension.
Ideally, what I want is to copy existing files to the same directory with a new name. It seems like all of the searches I've ran on Powershell ISE are not coming up with the right info I need (or I'm not searching for the right way to do it - trying 'powershell ise copy many files with new names' didn't help.
I had the replacement piece down and working, but I no longer want to eliminate the original tmpl files (they are templates so I may want to review them later for their original content).
What I was doing to replace them was this:
Get-ChildItem -Filter "*props.tmpl" -Recurse |
Rename-Item -NewName { $_.name -replace '.tmpl',''}
Which works great other than completely removing the original file.
I started trying to piece something together, but I'm not understanding how to properly name the copy and stopped at this point with just an error (this was an attempt to skip the extra copy and just simply rename the copy instead of adding the extra step of '*.tmpl2'):
# Get all *props.tmpl files
Get-ChildItem -Filter "*props.tmpl" -Recurse |
# Iterate through each found file
ForEach-Object {
Copy-Item $_.name |
Rename-Item -NewName { $_.name -replace '.props.tmpl','.props' }
}
Any help would be really appreciated (not much of a Powershell guy, but I'm trying to learn since powershell tends to be a little more dynamic then oldschool batch scripts).
Thanks in advance
Final version of this script per help from #ssennett
Here's my final version:
# Get all *props.tmpl files
Get-ChildItem -Filter "*props.tmpl" -Recurse |
# Iterate through each found file and copy it to non-template form in same location
ForEach-Object {
Copy-Item $_.FullName ($_.Name -replace '.tmpl','')
}
You're not too far from the answer! It's just how Copy-Item is being handled.
Without a Destination being specified, the Copy-Item will effectively try and copy the file onto itself. Instead of piping it to Rename-Item, you can handle the renaming with the -Destination parameter, as below.
$files = Get-ChildItem -Filter "*props.tmpl" -Recurse
$files | % { Copy-Item -Path $_.FullName -Destination ($_.Name -replace 'props.tmpl','.props') }
This would copy a file called RandomFileprops.tmpl into another file RandomFile.props. If you want to remove the original, you can use the Move-Item cmdlet with the same parameters, which effectively renames the original file.
I have looked for questions relating to my issue, but can't find the correct syntax to use for what I want to achieve.
I want to take all the filenames from a folder using Get-ChildItem, and store these in a variable, then rename all the files in another folder using these names.
From what I have seen, I need something similar to:
CD directory a
$newnames = Get-ChildItem
CD directory b
Get-ChildItem | Foreach {$name = $newnames} | Rename-Item -Newname {$name}
I think perhaps the issue I am facing, is calling the name correctly from the $newnames variable.
Can anyone advise the correct syntax for what I need to do?
Here's one way assuming you have the same count of files in those folders. Remove the -WhatIf switch to actually rename the files:
[array]$a = Get-ChildItem .\DirA
[array]$b = Get-ChildItem .\DirB
for($i=0; $i -lt $a.Length; $i++)
{
$b[$i] | Rename-Item -NewName $a[$i] -WhatIf
}
I have created a simple Powershell script to copy files during a deployment from a target directory to a source directory and I would like to exclude a list of files. The caveat however is that I would like the ability to exclude files only from a sub directory if specified. This is the snippet I'm using to perform the copy and exclude a list of files:
$SourceDirectory = "C:\Source"
$DestinationDirectory = "C:\Destination"
$Exclude = #("*.txt*", "*.xml*")
Get-ChildItem $SourceDirectory -Recurse -Exclude $Exclude | Copy-Item -Destination {Join-Path $DestinationDirectory $_.FullName.Substring($SourceDirectory.length)}
This will exclude the specified files wherever they appear in the directory tree. Where I would like to get to with the Exclude list is something like this:
$Exclude = #("*Sub1\.txt*", "*.xml*").
This would exclude .txt files only under the Sub1 folder while .xml files would be excluded throughout. I know this doesn't work, but I hope that it helps to better demonstrate the problem I'm trying to solve.
I have considered using a multidimensional array, but I'm not sure if that might be overkill. Any help would be appreciated.
This is one way to do it
$SourceDirectory = 'C:\Source'
$DestinationDirectory = 'C:\Destination'
$ExcludeExtentions = '*.txt*', '*.xml*'
$ExcludeSubDirectory = 'C:\Source\bad_directory1', 'C:\Source\bad_directory2'
Get-ChildItem $SourceDirectory -Recurse -Exclude $ExcludeExtentions |
Where-Object { $ExcludeSubDirectory -notcontains $_.DirectoryName } |
Copy-Item -Destination $DestinationDirectory
Your best friend here is Where-Object, or where. It takes a scriptblock as parameter and uses that scriptblock to validate each object that goes through pipeline. Only objects that make script return $true are passed through Where-Object.
Also, take a look at the object that represents a file you get from Get-ChildItem. It has Name, Directory and DirectoryName containing pieces of file's FullName already split respectively. Directory is actually an object that represents parent directory, and DirectoryName is a string. Get-Member commandlet will help you to discover hidden gems like.
$SourceDirectory = 'C:\Source'
$DestinationDirectory = 'C:\Destintation'
$ExcludeExtentions1 = "^(?=.*?(SubDirectory1))(?=.*?(.xml)).*$"
$ExcludeExtentions2 = "^(?=.*?(SubDirectory2))(?=.*?(.config)).*$"
$ExcludeExtentions3 = "^(?=.*?(.ps1))((?!SubDirectory1|SubDirectory2).)*$"
$ExcludeExtentions4 = ".txt|.datasource"
$files = Get-ChildItem $SourceDirectory -Recurse
foreach ($file in $files)
{
if ($file.FullName -notmatch $ExcludeExtentions1 -and $file.FullName -notmatch $ExcludeExtentions2 -and $file.FullName -notmatch $ExcludeExtentions3-and $file.FullName -notmatch $ExcludeExtentions4)
{
$CopyPath = Join-Path $DestinationDirectory $file.FullName.Substring($SourceDirectory.length)
Copy-Item $file.FullName -Destination $CopyPath
}
}
In this solution, using regex and -notmatch I am able to exclude specific file types from specific directories. $ExcludeExtentions1 will exclude xml files only from SubDirectory1, $ExcludeExtentions2 will exclude config files only from SubDirectory2, $ExcludeExtentions3 will exclude ps1 files as long as they are not in either of the two SubDirectories, $ExcludeExtentions4 will exclude txt and datasource files throughout the entire tree.
We are not actually using all of these matches in our solution, but since I was working on this, I thought I would add multiple conditions in case others could benefit from this approach.
Here are a couple of links that also helped:
http://www.tjrobinson.net/?p=109
http://dominounlimited.blogspot.com/2007/09/using-regex-for-matching-multiple-words.html