Need a script to publish build output to a staging server - powershell

I am trying to write a PowerShell script that will copy a subset of files from a source folder and place them into a target folder. I've been playing with "copy-item" and "remove-item" for half a day and cannot get the desired or consistent results.
For example, when I run the following cmdlet multiple times, the files end up in different locations?!?!:
copy-item -Path $sourcePath -Destination $destinationPath -Include *.dll -Container -Force -Recurse
I've been trying every combination of options and commands I can think of but can't find the right solution. Since I'm sure that I'm not doing anything atypical, I'm hoping someone can ease my pain and provide me with the proper syntax to use.
The source folder will contain a large number of files with various extensions. For example, all of the following are possible:
.dll
.dll.config
.exe
.exe.config
.lastcodeanalysisissucceeded
.pdb
.Test.dll
.vshost.exe
.xml
and so on
The script needs to only copy .exe, .dll and .exe.config files excluding any .test.dll and .vshost.exe files. I also need the script to create the target folders if they don't already exist.
Any help getting me going is appreciated.

try:
$source = "C:\a\*"
$dest = "C:\b"
dir $source -include *.exe,*.dll,*.exe.config -exclude *.test.dll,*.vshost.exe -Recurse |
% {
$sp = $_.fullName.replace($sourcePath.replace('\*',''), $destPath)
if (!(Test-Path -path (split-path $sp)))
{
New-Item (split-path $sp) -Type Directory
}
copy-item $_.fullname $sp -force
}

As long as the files are in one directory, the following should work fine. It might be a bit more verbose than needed, but it should be a good starting point.
$sourcePath = "c:\sourcePath"
$destPath = "c:\destPath"
$items = Get-ChildItem $sourcePath | Where-Object {($_.FullName -like "*.exe") -or ($_.FullName -like "*.exe.config") -or ($_.FullName -like "*.dll")}
$items | % {
Copy-Item $_.Fullname ($_.FullName.Replace($sourcePath,$destPath))
}

Related

Place files with prefix in folder with number

I have batch changed multiple files that all start with a prefix of a folder where I need them in.
The files are located on another location, like a folder on the desktop.
For example:
101AA0001.dat
101AA0002.dat
102AA0001.dat
102AA0002.dat
The destination folder will for example be:
C:\destfolder\101\ or C:\destfolder\102\
Files starting with 101 need to go in the 101 folder and the files starting with 102 go to folder 102.
I can find some scripts that creates the folder based on the filename. But in this situation the folders already exist. I also know for sure the files don't exist, so I don't have to overwrite files or something.
I guess it is easy for the people that know PowerShell very well, but I don't know how to do this. Can someone please help me? This can save me a lot of time.
I have tried to move the files with the following rule:
Move-Item -Path C:\Users\Username\Desktop\test*.dat -Destination C:\Users\Username\Desktop\test2\ -include "*.dat"
But it copies the whole folder except for the files.
You can do that quite easily with code like below:
$sourceFolder = Join-Path -Path $env:USERPROFILE -ChildPath 'Desktop'
$destination = 'C:\destfolder'
Get-ChildItem -Path $sourceFolder -File -Filter '*.dat' | ForEach-Object {
$targetFolder = Join-Path -Path $destination -ChildPath $_.Name.Substring(0, 3)
# if the target folder does not exist yet, create it
if (!(Test-Path -Path $targetFolder -PathType Container)) {
$null = New-Item -Path $targetFolder -ItemType Directory
}
$_ | Move-Item -Destination $targetFolder -WhatIf
}
The -WhatIf switch shows what would happen in the console without actually performing the move. If you are satisfied with what is output, remove that switch.
This will take all files that end in ".dat" from the $Source folder into a subfolder inside the $DestinationRoot named for the first three characters of the ".dat" file.
$Source = "C:\Users\Username\Desktop"
$DestinationRoot = "C:\Users\Username\Desktop\test2"
$Filelist = Get-ChildItem -Path $Source -Filter "*.dat" -File
foreach ($File in $Filelist){ $DestinationFolder = $File.Name.Substring(0,3)
$FinalPath = "$DestinationRoot\$DestinationFolder"
Move-Item -Path $File.Fullname -Destination $FinalPath -Whatif }
Remove the -Whatif when you're ready to run it for real.
This doesn't handle folder creation and should error out if the file already exists in the target location so it won't accidentally overwrite anything.

Powershell script to copy files based on filename

I have a folder that contains several thousand files. I would like to write a Powershell script that loops through the files and copies each file whose filename contains a specific keyword. In pseudocode:
For each file in C:\[Directory]
If filename contains "Presentation" Then
copy file in C:\[Directory 2]
Simply like this ?
copy-item "C:\SourceDir\*Presentation*" "C:\DestinationDir"
or like this :
copy-item "C:\SourceDir\*" "C:\DestinationDir" -Filter "*rrrr*"
But a risk exist if you have a directory with "presentation" in his name into the source directory. Then take all method proposed here and add -file in get-childitem command.
Like in this short version of Robdy code :
gci "C:\SourceDir" -file | ? Name -like "*Presentation*" | cpi -d "C:\DestinationDir"
That code should do the trick:
$files = Get-ChildItem -Path "C:\path\to\source\folder"
$files | Where-Object Name -Like "*Presentation*" | Copy-Item -Destination "C:\path\to\destination\folder"
Of course can be written in one line but I put in two for visibility.
Edit: as Esperento57 pointed out, you might want to add -ItemType File to Get-ChildItem cmdlet to not include folders with 'Presentation' in their name. Also, depending on your needs you might also want to use -Recurse param to include files in subfolders.
If you have files in subfolders and you want to keep the path in destination folder you'll have to change the script a bit to something like:
Copy-Item -Destination $_.FullName.Replace('C:\path\to\source\folder','C:\path\to\destination\folder')
And for the above you'll have to make sure that folders are actually created (e.g. by using -Force for Copy-Item.
This seems to work:
$src = "Dir1"
$dst = "Dir2"
Get-ChildItem $src -Filter "*Presentation*" -Recurse | % {
New-Item -Path $_.FullName.Replace($src,$dst) -ItemType File -Force
Copy-Item -Path $_.FullName -Destination $_.FullName.Replace($src,$dst) -Force
}
Try something like this:
Get-ChildItem "C:\Your\Directory" -File -Filter *YourKeyWordToIsolate* |
Foreach-Object { Copy-Item $_.FullName -Destination "C:\Your\New\Directory" }
... but, of course, you'll need to fill in some of the blanks left open by your pseudocode example.
Also, that's a one-liner, but I inserted a return carriage for easier readability.

Find specific files by date modified and copy to the relevant folder

I'm looking for a PowerShell script which can find the files (N30008xx.txt, N30005xx.txt) from the source directory and copy them to the destination directory by creating a folder with the same name of the file's modification date.
I'm able to run the below script which creates the folder by files modified date.
$p = "Filesourcepath"
Get-ChildItem -Path $p |
Where-Object { ! ($_.PSIsContainer) } |
ForEach-Object {
$newDir = Join-Path $p ($_.LastWriteTime).ToString("yyyy-MM-dd")
New-Item -Path $newDir -ItemType Directory -ErrorAction SilentlyContinue
$_ | Move-Item -Destination $newDir
}
Your code should work in principle.
(As of this writing, there's confusion over copying vs. moving, and the aspect of matching only select files is missing.)
Below is a streamlined version of your code, which however, does not explain your symptom - you need to provide more information for us to diagnose your problem.
The streamlined code below:
takes advantage of the PSv3+ -File Get-ChildItem parameter to limit matching to files (as opposed to directories) - this saves the need for Where-Object { ! $_.PSIsContainer }.
uses -LiteralPath to pass the literal $dir path; while -Path (which is also the positional default) often works fine too, it's important to note that it interprets is argument as a wildcard expression, which can have unexpected results).
uses -Filter to provide the file mask (wildcard expression); this is generally preferable to using the -Path parameter, because it filters at the source (Windows API call) and is therefore faster, which can make a noticeable difference when processing large directories.
Caveat: the wildcard language supported in the -Filter argument is more limited than PowerShell's and also burdened with legacy quirks; in short: sticking with * and ? should be fine; for the full story, see this well-researched answer.
uses -Force instead of -ErrorAction SilentlyContinue in order to either create a directory or use a preexisting one.
Note that New-Item -ItemType Directory -Force returns a [System.IO.DirectoryInfo] instance in both scenarios (either the newly created directory or the preexisting one), which the code takes advantage of.
# Create sample dir. with 2 sample files in it.
$tmpDir = New-Item -Force -Type Directory tmpDir
New-Item -Type File -Force -Path ('N30008xx.txt', 'N30005xx.txt' -replace '^', "$($tmpDir.FullName)/")
$dir = $tmpDir
$fileMask = 'N*.txt'
Get-ChildItem -File -LiteralPath $dir -Filter $fileMask | ForEach-Object {
$newDir = Join-Path $dir $_.LastWriteTime.ToString("yyyy-MM-dd")
$_ | Move-Item -Destination (New-Item -ItemType Directory -Force $newDir)
}
Caveat re generalization of this code:
You're creating the target subdirectories inside the source directory.
If you were to use Get-ChildItem -Recurse to process the source directory recursively, you'd end up processing matching files twice: first when moving them, and then again when finding them in their moved-to location.
(In this particular case this would only cause an inefficiency, however, because processing the already-moved files attempts to move them into the directory where they already are, which is a quiet no-op.)
Here is a modified version of your PowerShell that should work.
Note: Your destination directory cannot be located under the source directory otherwise you will have a forever recursive move.
$p = pwd
$dst = "c:/tmp/testdir"
Get-ChildItem -Path $p | Where-Object {
$_.PSIsContainer -eq $false
} | ForEach-Object {
$newdir = Join-Path -Path $dst -ChildPath ($_.LastWriteTime).ToString("yyyy-MM-dd")
if (!(Test-Path -Path $newdir)) {
Write-Host "Create directory $newdir"
New-Item -Path $newdir -ItemType Directory
}
Write-Host "Copy file $_"
Move-Item -Path $_ -Destination $newdir
}

PowerShell to copy files to destination's subfolders while excluding certain folders in the destination

So I have danced with this off and on throughout the day and the timeless phrase "There's more than one way to skin a cat" keeps coming to mind so I decided to take to the community.
Scenario:
Source folder "C:\Updates" has 100 files of various extensions. All need to be copied to the sub-folders only of "C:\Prod\" overwriting any duplicates that it may find.
The Caveats:
The sub-folder names (destinations) in "C:\Prod" are quite dynamic and change frequently.
A naming convention is used to determine which sub-folders in the destination need to be excluded when the source files are being copied (to retain the original versions). For ease of explanation lets say any folder names starting with "!stop" should be excluded from the copy process. (!stop* if wildcards considered)
So, here I am wanting the input of those greater than I to tackle this in PS if I'm lucky. I've tinkered with Copy-Item and xcopy today so I'm excited to hear other's input.
Thanks!
-Chris
Give this a shot:
Get-ChildItem -Path C:\Prod -Exclude !stop* -Directory `
| ForEach-Object { Copy-Item -Path C:\Updates\* -Destination $_ -Force }
This grabs each folder (the -Directory switch ensures we only grab folders) in C:\Prod that does not match the filter and pipes it to the ForEach-Object command where we are running the Copy-Item command to copy the files to the directory.
The -Directory switch is not available in every version of PowerShell; I do not know which version it was introduced in off the top of my head. If you have an older version of PowerShell that does not support -Directory then you can use this script:
Get-ChildItem -Path C:\Prod -Exclude !stop* `
| Where-Object { $_.PSIsContainer } `
| ForEach-Object { Copy-Item -Path C:\Updates\* -Destination $_ -Force }
To select only sub folders which do not begin with "!stop" do this
$Source = "C:\Updates\*"
$Dest = "C:\Prod"
$Stop = "^!stop"
$Destinations = GCI -Path $Dest |?{$_.PSIsContainer -and $_.Name -notmatch $Stop }
ForEach ($Destination in $Destinations) {
Copy-Item -Path $Source -Destination $Destination.FullName -Force
}
Edited Now copies all files from Update to subs of Source not beginning with "!stop" The -whatif switch shows what would happen, to arm the script remove the -whatif.
Edit2 Streamlined the script. If also Sub/sub-folders of C:\Prod shall receive copies include a -rec option to the gci just in front of he pipe.

Looking to find and copy files (with a specific file ext) from a Directory (recurse) using Powershell?

I am looking to Recurse a Folder Structure (ex.F:\Directory\layer1\layer2\layer3) and find all of the files with the specified file extension (ex. ".dll, .txt"). Then I need to copy the listed/found files to a destination folder.
If anyone could send me a good PowerScript that will do this I would much appreciate it.
I have a drive with about 1,000 folders and 5,000 files so this will probably save me a good day or two of manual work. :)
Thank You!
Try the following, modify as needed:
$movetopath = "C:\new folder\"
New-Item -Path $movetopath -ItemType Directory -Force
$files = Get-ChildItem -Path F:\ -Recurse
$files | Where-Object {$($_.Extension -eq ".dll") -or $($_.Extension -eq ".txt")} | ForEach-Object {Copy-Item $_ -Destination $movetopath}
I suggest you use find command first
then pipe the output of find command to tar.
Untar the archive to the destination folder.
Try something like
Get-ChildItem -Path $path -Recurse | where { !$_.PSIsContainer } | where { $_.Extension -eq ".txt" -or $_.Extension -eq ".log" } | Copy-Item -Destination $dest
This is propably slower then robocopy. Also, next time please show some effort and ask a question rather then a full solution. This is not a webshop.