Delete Directories based on time modified - powershell

I am using Powershell scripts to deploy the codebase on our remote servers.
One Major part of the script copies the current release to the server. Now I just need to keep the last two releases on the remote server and delete all others.
I Need to keep the latest two releases
Eg:
In the remote server, I have
//server001/Application/
Build_1_0_0_19
Build_1_0_0_18
Build_1_0_0_17
Build_1_0_0_16
I need to clear Builds _17 and _16 while deploying _19.
We can sort out the directories according to the time modified and the last two will come on top. Rest all are not required.
Can this be done through Powershell Scripts ?
P.S. The builds are not always in sequential order

You can do something like this:
#requires -version 2
Get-ChildItem //server001/Application/|
Sort-Object CreationTime -Descending|
Select-Object -Skip 2|
Remove-Item -Recurse -Confirm
Just remove the -Confirm switch once you are sure that it does what you want.
Here is a v1 compatible method:
$dirs = #(Get-ChildItem //server001/Application/)
$dirs|
Sort-Object CreationTime -Descending|
Select-Object -Last ($dirs.Count - 2)|
Remove-Item -Recurse -Confirm

Related

Powershell - Selective moving files into subfolder (keeping the newest of each FIRST13 letter grouping)

extreme powershell newbie here so please be gentle...
I have a filing system where where files in folders are generated semi-automatically, with multiple versions being kept as redundancy (we really do revert regularly).
Files within the folder are named with the first 13 characters as the identifier, with various dates or initials afterwards.
12345-A-01-01_XYZ_20191026.pdf
i.e. the file is 12345-A-01-01 and everything past the first 13 characters is "unpredictable"
FILE000000001xxxxxxx.pdf
FILE000000001yyyy.pdf
FILE000000001zzzzzz.pdf
FILE000000002xxxx.pdf
FILE000000002yyy.pdf
FILE000000002zz.pdf
FILE000000003xx.pdf
FILE000000003yyy.pdf
FILE000000003zzzz.pdf
I'm trying to write a script that can determine the newest version (by date modified file property) of each file "group"
i.e. the newest FILE000000001*.pdf etc
and slide all the others into the .\Superseded subfolder
All I've managed to get so far is a "list" sorting to show the newest at the top of "each" group... now I need to know how to keep that file, and move the others... any direction or help would be great thanks :)....
$_SourcePath = "C:\testfiles"
$_DestinationPath = "C:\testfiles\Superseded"
Get-ChildItem $_SourcePath |
Where-Object {-not $_.PSIsContainer} |
Group-Object { $_.Basename.Substring(0,12) } |
foreach {
$_.Group |
sort LastWriteTime -Descending
} | Move-Item -Destination $_DestinationPath
I think you are pretty close. Since you sorted descending order you should just skip the first file:
$SourcePath = "C:\testfiles"
$DestinationPath = "C:\testfiles\Superseded"
Get-ChildItem $SourcePath -File |
Group-Object { $_.Basename.Substring(0,12) } |
ForEach-Object {
$_.Group |
Sort-Object LastWriteTime -Descending |
Select-Object -skip 1 |
Move-Item -Destination $DestinationPath -WhatIf
# Note: Above, the move has to be in each iteration of the loop
# so we skip the first (newest) of each file.
}
You don't need Where-Object {-not $_.PSIsContainer} , use the -File Parameter instead.
Also I wouldn't name your variables $_***. That's bound to get confused with $_ like the pipeline variable.
I added -WhatIf to the move command so you can test without causing any damage ...
I didn't test it, but it looks about right.

Azure Devops - PowerShell task on self-hosted agent

I have an Azure Devops deployment pipeline setup which is building and I am able to deploy to a self hosted virtual machine with no issue.
I have the following powershell script that correctly clears down my destination directory leaving 2 folders that are not part of source control
Get-ChildItem -Path 'C:\inetpub\wwwroot\testDeploy\' -Recurse -exclude "pod","photos" |
Select -ExpandProperty FullName |
Where {$_ -notlike '*\pod\*' -and $_ -notlike '*\photos\*'} |
sort length -Descending |
Remove-Item -force
I have tried adding a "PowerShell Script" task but i'm don;t know how to get the PowerShell script in to a folder that the task can access i.e. $(System.DefaultWorkingDirectory). Can anyone advise how I should be either generating the file or where to store it in my repo that is then accessible by the self-hosted Windows agent
Agree with Shayki, you can create a powershell(.ps1) file in repos and paste your script in it to achieve that. And then, use powershell task to execute the script which in ps1 file.
But, as you said that you want it be maintained within the repos easily. Need made some change on your script:
Param(
[string]$RootPath,
[string]$File1,
[string]$File2,
[string]$NonLike1,
[string]$NonLike2
)
Get-ChildItem -Path $RootPath -Recurse -include $File1,$File2 |
Select -ExpandProperty FullName |
Where {$_ -notlike $NonLike1 -and $_ -notlike $NonLike2} |
sort length -Descending |
Remove-Item -Recurse -force
The first change is, you need to replace the hard code with variable. Pass the value with task, this is a good way to maintain your script.
The second which also the important change is add -Recurse after Remove-Item, or you will get the error showed below while the value of $RootPath is hard code, such as 'C:\Users\'.
Remove-Item : Windows PowerShell is in NonInteractive mode. Read and
Prompt functionality is not available.
And then, you can add task in your build pipeline. Add the Script path where the .ps1 file located and input the Arguments with the value:
If you want to access $(System.DefaultWorkingDirectory), pass it to $RootPath.
Hope my sample can help you achieve what you want.

Removing old folders and keeping the most recent

I have been working on a script of late and have come across a snag. I am in the process of removing folders which are automatically created. I want to delete the older versions of those files whilst keeping the new folders untouched, for example:
18.212.1021.0008 //Created on the 19/11/2018 12:12
18.212.1021.0008_1 //Created on the 19/11/2018 12:23
18.212.1021.0008_2 //Created on the 19/11/2018 12:27
18.212.1021.0008_3 //Created on the 19/11/2018 12:32
I would want to keep 18.212.1021.008_3 so I guess I would need to keep the folder with the most recent creation date.
Please see the code below:
$Versionarray = 13..20
Get-ChildItem "$env:LOCALAPPDATA\Microsoft\OneDrive" -Recurse | Where-Object {
# Recusivly deletes OneDrive version folders within
# Appdata\local which build up everytime OneDrive
# is installed/script is run
$item = $_
$item -is [System.IO.DirectoryInfo] -and (
$Versionarray | Where-Object { $item.Name.Contains($_) }
)
} | Remove-Item -Recurse -Confirm:$false -ErrorAction SilentlyContinue
If the newest folder you want to keep is also the one with the newest creation time, you can use this simple one-liner:
Get-ChildItem "$env:LOCALAPPDATA\Microsoft\OneDrive" -Directory | sort CreationTime | select -SkipLast 1 | Remove-Item -Recurse -Force
If you want to filter out only a specific type of folders by name, you could use a simple regex match. I cannot help you with the exact regex (since I would have to know your folder naming pattern) but it would look something like this:
Get-ChildItem "$env:LOCALAPPDATA\Microsoft\OneDrive" -Directory | where Name -match '\d\d+' | sort CreationTime | select -SkipLast 1 | Remove-Item -Recurse -Force
(Note that this is syntax might not work if you use an old Powershell version. If that's the case, let me know and I will provide a compatible fallback solution.)
UPDATE
In response to your comment: Your requirements are still a bit unclear, but here is something to get you started:
If you want to make sure to only delete folders that "look like" version folders, you can adjust the regex in the where-filter. _\d+$ will match anything with an underscore and numbers at the end:
where $_.Name -match '_\d+$'
If you also want to make sure, that this is actually a versioned copy of another existing folder, you could check that too:
where { $_.FullName -match '^(?<OriginalPath>.+)_\d+$' -and (Test-Path $Matches.OriginalPath) }

How can I delete all of the contents of a directory (including subdirectories) except one subdirectory?

I'm trying to write an automated build and deploy script using PowerShell 2 for my angular2 app, but seeing as how our ASP.NET Web API lives in api/, I want to delete all of the old angular code without touching the API.
Here's what I've got so far:
Get-ChildItem -Path $destination -Recurse -exclude somefile.txt |
Select -ExpandProperty FullName |
Where {$_ -notlike $destination+'\api*'} |
sort length -Descending |
Remove-Item -force -recurse
$destination is the directory where the app gets installed.
Quick folder tree in case I wasn't clear above:
$destination
api\
app\
assets\
vendor\
index.html
main.js
system-config.js
As above, I want to delete everything but api\
I don’t have access to PowerShell 2. But, using PowerShell 3 (and later versions), you should be able to simplify your code by using something like this:
$path = "C:\test path"
Remove-Item $path -recurse -Exclude "api"
I created the same folder structure you specified assuming that api, app, assets, and vendor are sub-folders. I ran the script in the PowerShell IDE and it removed everything under the test path except for the api folder. I would assume that PowerShell 2 supports the same parameters on the command.

get the latest created folder from a path using powershell

How to get the latest created folder from a path using Windows PowerShell?
I have the path C:\temp and I want to find the most recently created folder in this path.
PowerShell works mainly with the pipeline, so most of what you'd write will consist of creating objects representing some information, and filtering and manipulating them. In this case, the objects are a bunch of folders.
Get all items in the folder. This will get files and folders, that's why step 2 is necessary. The | at the end of the line signals that the pipeline will continue in the next line – objects created by Get-ChildItem will then be passed one by one to another command.
Get-ChildItem c:\temp |
Filter for folders. There is no really elegant way, sadly. Don't worry about that it says “container”, not “folder” – Those commands work with many different things, not only files and folders, so a more general concept was used in naming.
Where { $_.PSIsContainer } |
Sort by date, descending, so the newest folder is the first one.
Sort CreationTime -Descending |
Select the first (newest) folder.
Select -First 1
So in short:
gci c:\temp | ? { $_.PSIsContainer } | sort CreationTime -desc | select -f 1
or
(gci c:\temp | ? { $_.PSIsContainer } | sort CreationTime)[-1]
Both of those lines make heavy use of default aliases for commands in PowerShell, such as ? for Where-Object. You should use the full names in scripts, though, as you'll never know what the aliases will look like on other machines the code might run on.
EDIT: PowerShell 3 has additional parameters for Get-ChildItem that allow you to do filtering for files or folders directly, so you don't need the Where:
Get-ChildItem -Directory C:\temp | ...
Generally you will work with objects and their properties in PowerShell. Two very helpful commands are Get-Member and its alias gm and Get-Command or just gcm. Get-Member will tell you what properties and methods an object has; you just pipe something else into it for that:
Get-ChildItem | gm
will tell you what properties files and directories have.
Get-Command will list all commands there are or those that match a particular pattern. PowerShell commands try to be very consistent in their use of verbs and nouns. To find all commands that end in Object you can try gcm *-Object – those are general commands working with pretty much everything. Get-Help ForEach-Object then would tell you about a particular command, ForEach-Object in this case.