Powershell Script: Search for BATs with specific name and run them - powershell

back with another request to try and make my life a little easier. The problem: one of the programs I use deposits BMPs (yes, bitmaps, this is an ancient app, and no, I can't configure it not to make BMPs) where I don't need them. I've got a BAT file that can sweep a folder and remove them, but what I'd really like to do is put a copy of said BAT file in each folder where it leaves them, and then every time I run a backup cycle, have it search for those BAT files, and wherever it finds one, run it. (I'd also need to know how to tell it "look in the same folder you're in"--I think I can do that by something like $searchfolder = "." but please correct me if I'm wrong)
I'm guessing this is a Get-Childitem and ForEach, but I've taken a few stabs at it and it won't work. Does anyone have an idea how to go about it?
This is what I've got so far for the parent script to find all instances of "Clear_BMPs.bat":
Get-ChildItem $sourceDir -Include Clear_BMPs.bat -Recurse | ForEach-Object { call "Clear_BMPs.bat" }
And this is what I've got in the child script, to get rid of the BMPs themselves (the filename for it is "Clear_BMPs.bat":
$searchfile = "*.bmp"
$targetdir = ".\"
Get-ChildItem $targetdir -Include $searchfile | foreach{ "Removing file $($_.FullName)"; Remove-Item -force $_}
I'm still trying to get the Clear_BMPs.bat files to work properly but in my vision it will only search the root of the folder it's in, and not recurse through subdirectories.

Since you're calling from PowerShell, there's no reason to involve batch files, given that the code is under your control.
Indeed, what you show as the content of a Clear_BMPs.bat batch file is PowerShell code, which means you need to store it in a .ps1 file, not a .bat file.
Therefore, your recursive invocation that executes all .ps1 files should look like this:
# Find all 'Clear_BMPs.ps1' scripts in the subdir. tree of $sourceDir
# and invoke them.
Get-ChildItem -Recurse -LiteralPath $sourceDir -Filter Clear_BMPs.ps1 |
ForEach-Object { & $_.FullName }
And the Clear_BMPs.ps1 files in the various directories should contain:
# Remove all *.bmp files from the same dir. in which this .ps1 script is located.
Remove-Item -Path "$PSScriptRoot/*.bmp"
Note the use of the automatic $PSScriptRoot variable, which refers to the directory in which the enclosing .ps1 file is located.

Related

Powershell Script to find a specific file type in specific subfolders of a directory

I have a directory with several subfolders in it. I specifically want to search for the directory for a set of subfolders that begin with the combination "SS". Once it finds those specific subfolders, I want to run a batch file on those folders and also delete files of specific file type.
I've got the search for the specific subfolders to work using gci and -Recurse using the following code:
$BaseDir = "P:\Directory1\"
$FolderName = "SS"
Get-ChildItem $BaseDir -Recurse | Where-Object {$_.PSIsContainer -and $_.Name.StartsWith($FolderName)}
This finds the correct subfolders, but I'm lost on how after I've gotten these results to run the batch file on them and delete the files with the specific file type. I've tried using foreach and ForEach-Object, but it's not giving any results. I've searched and can't seem to find a solution for this.
You could also use -Include, but it's picky about the path handed to it.
get-childitem( join-path $directory "*") -Include *.txt,*.pdf
The -Include option needs the path to have that trailing * wildcard on it, and WILL NOT work without it.
join-path is also the OS-safe way to create a path without using a directory delimiter that might not work if you're running the code on a non-Windows host.

Powershell Cannot create a file when that file already exists when using Move-Item

I'm trying to move png images in subfolders to a subfolder in the folder they are in.
Main folder is called "stuff", images are in variously named subfolders in the "stuff" main folder, and each of these subfolders have a folder name "Oneshot" in them, I'm trying to move these images that are in M:/Stuff/FolderExample/ to M:/Stuff/FolderExample/Oneshot/.
Current code I am using
Get-ChildItem -Path C:\Users\a\Desktop\stuff\*.png -Recurse | Move-Item -Destination "$($_.FullName)\Oneshot\"
How can I make this work? I'm just trying to learn powershell so I can automate this process as I otherwise would need to repeat the process manually for thousands of times
Use a scriptblock ({...}) as the argument to -Destination - this will allow you to access the current pipeline item as $_ during parameter binding:
Get-ChildItem -Path C:\Users\a\Desktop\stuff\*.png -Recurse |Where-Object Directory -notlike *\OneShot | Move-Item -Destination {"$($_.Directory.FullName)\Oneshot\"}
The Where-Object command in the middle of the pipeline will ensure we don't attempt to move pictures already in one of the OneShot folders.
Powershell is not the best idea to move files. The main reason is that you run into problems in case the path becomes too long >256 characters. I would use robocopy for such tasks. It is part of every current windows version.
robocopy M:/Stuff/FolderExample/ M:/Stuff/FolderExample/Oneshot/ /MIR
Please keep in mind that this code will also delete everything that is in M:/Stuff/FolderExample/Oneshot/ and not in M:/Stuff/FolderExample/. So use /MIR with caution.
You could still invoke robocopy in an ps1 file and wrap other powershell code around it e.g. for variables.

Copying group of folders, first in line get's it's contents spilled in the open

I want to copy a group of folders which have various files inside them from one place to a single folder elsewhere. I want to bind said folder group to a variable.
param(
$folders=('../folder1','../folder2')
)
Copy-Item -Path $folders -Destination '../folder3' -Recurse -Force;
This works, however, inside folder3, folder1's contents are spilled out, while folder2's contents are placed in a folder of the same name just like intended.
I need them both to be copied intact, if I switch their places then folder2 gets the same treatment. It's like the script does not read the first folder in line in same way as the others. Am I missing something?
EDIT:
Managed to find a work-around by running additional command to create a folder inside "folder3" named same as first in line folder before copying. Script then places the files inside that folder correctly. Still rather messy, I wonder if it's a bug.
Use a loop
foreach($folder in $folders){
Copy-Item -Path $folder -Destination '../folder3'-Recurse -Force
}

If a file is present move another file in another folder

in a particular folder I have files created with random name for example:
file1.xml
file2.xml
when these files are succesfully created, a .ack file is created.
So I will have
file1.xml
file1.ack
file2.xml
file2.ack
What I have to do:
Move a .xml file only if the corresponding .ack is created.
The difficult part: file names are random and I have no control over them.
Is there a way to create a .bat or a powershell to check and move with these requirements run at scheduled times?
Many thanks for your help
the ideal would be a powershell task, indeed. Now, you will want to leverage window's Scheduled Tasks in order to run it at a scheduled time.
In a nutshell, what you'll have to do with powershell is to
List the xml files in your folder with Get-ChildItem -filter "*.xml"
Pipe it to a Where-Object statement to make sure the .xml has a .ack counterpart, leveraging Test-Path
For each produced item, move the .xml file.
Move-Item -Path $source -Destination $target
Optionally, you could also clean the .ack files with Remove-Item.
Find every filename that appears with two extensions, and move them both.
gci | group basename |? Count -eq 2 | select -expand group | move -Dest c:\temp
Because it's fun not to use any loops. If you want loops, maybe: to move the XML and delete the .ack.
gci *.ack |% { move ($_.BaseName +'.xml') "c:\temp" ; rm $_ }

Power shell script for copying files with a specific name and a specific extension to a folder from where the script is executing

All,
My intention is to copy all the files with starting with the name 'US.Services' and with the extension .dll from a directory and its sub directories to the place where the script is being executed, i have the following but nothing gets copied. Any help would be appreciated.
Get-Childitem -Path ".\.\" -Filter *US.Services*.dll -Recurse |
Copy-Item -Destination "."
Thanks -Nen
Since PowerShell v3 can use the $PSScriptRoot automatic variable to refer to the location where the script is saved (in PowerShell v2 that would be $here = $MyInvocation.MyCommand.Path | Split-Path.
Be aware the both those approaches work only when the script is executed, if you just paste them to PowerShell console they won't return any value.
If I understand your question correctly you look for files that start with the given string and end with the extension, so you need to use the * wildcard here: US.Services*.dll.
Get-Childitem -Path $PSScriptRoot -Recurse -Filter "US.Services*.dll" |
Copy-Item -Destination $PSScriptRoot
This will likely produce exceptions if there are files with the same name copied to the single directory, as two files cannot be named the same within single directory.