Getting path of a selected item in PowerShell - powershell

I am trying to get a path of a folder.
Here is what i got. This code checks latest file and selects it.
$dir = "C:\Users\%PATH%\downloads"
$latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$latest.path
I need to check the path of the file to use it later on to move this folder using Move-Item function.

This is what you are looking for:
$latest.directoryname will give you the path for the same and you can store that in the variable and use it in move-item whenever required.
$dir = "C:\Users\Ranadip\Downloads"
$latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$destination= $latest.DirectoryName
Move-Item C:\scripts\temp* $destination

Related

Powershell: how to loop through folders and execute the same code for each of the folders

Currently I have a script that will sort files in a folder (on their lastwritetime), keep the latest file and move the other files to a different folder. This works correctly:
Get-ChildItem "\\networkfolder\RawData\2_ActionData_Prep\CustomerA\" -Recurse -Filter "*.rpt" -File |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Force -Destination "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"
The problem is that I have several 'customer' folders and I want to execute the code above in each of those folders.
I tried the following:
$CustomerFolders = Get-ChildItem -Path "\\networkfolder\RawData\2_ActionData_Prep\" -Directory -Recurse
foreach ($folder in $CustomerFolders) {Get-ChildItem -Filter "*.rpt" -File | Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Force -Destination "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"}
When I execute this script, nothing happens. Also no error comes up. Hopefully someone could help me on this.
Santiago Squarzon noticed that a $folder was missing, so I added $folder in loop for Get-Childitem:
$CustomerFolders = Get-ChildItem -Path "\\networkfolder\RawData\2_ActionData_Prep\" -Directory -Recurse
foreach ($folder in $CustomerFolders) {Get-ChildItem $folder -Filter "*.rpt" -File | Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Force -Destination "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"}
Now I get an error message:
Get-ChildItem : Cannot find path '\networkfolder\CustomerA' because it does not exist.
It somehow misses the part \RawData\2_ActionData_Prep\ in the path, although I defined it in the $CustomerFolders variable?
You could do the process all with pipelines like this:
$base = "\\networkfolder\RawData\2_ActionData_Prep\"
$destination = "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"
Get-ChildItem -Path $base -Directory -Recurse | ForEach-Object {
$_ | Get-ChildItem -Filter "*.rpt" -File | Sort-Object LastWriteTime -Descending |
Select-Object -Skip 1 | Move-Item -Force -Destination $destination
}
To briefly explain why Get-ChildItem $folder... failed but $folder | Get-ChildItem ... worked, when we do Get-ChildItem $folder, $folder is being passed as argument for the -Path parameter and the parameter type for it is [string[]]. So, in your code when $folder (a DirectoryInfo instance) is passed as argument, it is being converted to a string and, very unfortunately in Windows PowerShell, when we type convert a DirectoryInfo (and a FileInfo too!) object to string what we get as a result is the Directory Name (this is not the case in PowerShell Core, where the string representation of this object becomes the Directory FullName (a.k.a. Absolute Path) so Get-ChildItem thinks it's being fed a relative path and it looking for the folders in your current location.
However when we do $folder | Get-ChildItem ..., $folder gets bound to the -LiteralPath parameter by Property Name on the PSPath ETS property, in other words, the cmdlet receives the object's provider path (you can think of it as the absolute path of the folder) hence why it works fine.

How to delete all but the most recent files in a directory of folders and files

I have a folder that has a bunch of backups in in separated by folder. I want a script to use the directory (C:\Users\user\Desktop\TEST) and in that directory I have any number of folders with any number of files in them, I only want to keep the latest in the folder for every folder in the directory and delete the rest.
I have this but it only does 1 folder at a time and it has to be hardcoded.
$path = "C:\Users\user\Desktop\TEST\Folder1"
$FileNumber = (get-childitem $path).count - 1
get-childitem -path $path | sort CreationTime -Descending | select -last $FileNumber | Remove-Item -Force -WhatIf
Is there any way to automate this?
Thanks,
You can try this:
$Path = "C:\Users\user\Desktop\TEST"
$Folders = Get-ChildItem $Path
foreach ($Folder in $Folders)
{
$FolderName = $Folder.FullName
$Files = Get-ChildItem -Path $FolderName
$FileNumber = $Files.Count - 1
$Files | sort CreationTime -Descending | select -last $FileNumber | Remove-Item -Force -WhatIf
}
You would need a loop of your choice to accomplish this, this example uses ForEach-Object. Instead of using Select-Object -Last N you could just use Select-Object -Skip 1 to skip the newest file. Also note the use of -Directory and -File with Get-ChildItem to filter only directories or only files.
$path = "C:\Users\user\Desktop\TEST\Folder1"
# Get all Directories in `$path`
Get-ChildItem $path -Directory | ForEach-Object {
# For each Directory, get the Files
Get-ChildItem $_.FullName -File |
# Sort them from Newest to Oldest
Sort-Object CreationTime -Descending |
# Skip the first 1 (the newest)
Select-Object -Skip 1 |
# Remove the rest
Remove-Item -Force -WhatIf
}

Find the oldest file in each subdirectory with Powershell

My company recently moved to outlook365. We are entirely VDI based so our user profiles are stored on a single server. As a result our users all now have 2+ .ost files taking up storage space on the server. I'd like to write a script to find and delete the extraneous .ost files. In addition I'd like to schedule the script to run on a monthly basis to clean up any orphaned .ost's that occur for any other reason.
I've tried a few different solutions but can't seem to find the right syntax to identify just the oldest/original .ost in each subdirectory, all attempts have identified the oldest file from the whole directory or all .ost files in the directory.
$Path = "<path>"
$SubFolders = dir $Path -Recurse | Where-Object {$_.PSIsContainer} | ForEach-Object -Process {$_.FullName}
ForEach ($Folder in $SubFolders)
{
$FullFileName = dir $Folder | Where-Object {!$_.PSIsContainer} | Sort-Object {$_.LastWriteTime} -Descending | Select-Object -First 1
}
Inside of your loop, you could use the following to list the .ost file that has the oldest LastWriteTime value. Just add the -Descending flag to Sort-Object to list the newest file.
$FullFileName = foreach ($folder in $Subfolders) {
$Get-ChildItem -Path $folder -Recurse -File -Filter "*.ost" |
Sort-Object -Property LastWriteTime |
Select-Object -Property FullName -First 1
}
$FullFileName
If there is only one .ost file found in the $folder path, it will still find that file. So you will need logic to not delete when there is only one file. This does not guarantee it is the oldest file. You probably want a combination of the oldest CreationTime and newest LastWriteTime. The following will list the oldest .ost file based on CreationTime.
$FullFileName = foreach ($folder in $Subfolders) {
Get-ChildItem -Path $folder -Recurse -File -Filter "*.ost" |
Sort-Object -Property CreationTime |
Select-Object -Property FullName -First 1
}
$FullFileName
Another issue is setting the $FullFileName variable inside of the foreach loop. This means it will be overwritten through each loop iteration. Therefore, if you retrieve the value after the loop completes, it will only have the last value found. Setting the variable to be the result of the foreach loop output will create an array with multiple values.
To only output an OST file path when there are multiple OST files, you can do something like the following:
$FullFileName = foreach ($folder in $Subfolders) {
$files = Get-ChildItem -Path $folder -Recurse -File -Filter "*.ost" |
Sort-Object -Property LastWriteTime -Descending
if ($files.count -ge 2) {
$files | Select-Object -Property FullName -First 1
}
$FullFileName
This one liner should do the job, keeping the ost file with the newest LastWriteTime
gci -Path $Path -directory | where {(gci -Path $_\*.ost).count -gt 1}|%{gci -Path $_\*.cmd|Sort-Object LastWriteTime -Descending|Select-Object -Skip 1|Remove-Item -WhatIf}
Longer variant follows.
$Path = '<path>'
$Ext = '*.ost'
Get-ChildItem -Path $Path -directory -Recurse |
Where-Object {(Get-ChildItem -Path "$_\$Ext" -File -EA 0).Count -gt 1} |
ForEach-Object {
Get-ChildItem -Path "$_\$Ext" -File -EA 0| Sort-Object LastWriteTime -Descending |
Select-Object -Skip 1 | Remove-Item -WhatIf
}
The first two lines evaluate folders with more than one .ost file
The next lines iterates those folders and sort them descending by LastWriteTime, skips the first (newest) and pipes the other to Remove-Item with the -WhatIf parameter to only show what would be deleted while testing.
You can of course also move them to a backup location instead.

Pointing script to latest file

Looking to pull in latest file that does an update loop nightly. The script is pointing to a folder that has several files with the same naming convention, but different times.
Example:
File_Test04212019.csv
File_Test04222019.csv
File_Test04232019.csv
File_Test04242019.csv
File_Test04252019.csv
etc.
When I first ran this script it worked out fine, but after i edited a few files to update them to see if it'll pull another updated file...it is still trying to pull the previous file it originally pulled. This is the script I used below.
$dir = "C:\temp\File_Test*"
$filter = "*.csv"
$latest = Get-ChildItem -Path $dir -Filter $filter |
Sort-Object LastAccessTime -Descending |
Select-Object -First 1
$latest.Name
Import-Csv -Path $dir | ForEach-Object {
This is the error message I get:
Import-Csv : Cannot perform operation because the path resolved to more than
one file. This command cannot operate on multiple files.
At line:7 char:1
+ Import-Csv -Path $dir | ForEach-Object {
Any idea on how this can be resolved?
Thanks to Lee Dailey, below is the answer.
$dir = "C:\temp\File_Test*"
$filter = "*.csv"
$latest = Get-ChildItem -Path $dir -Filter $filter | Sort-Object LastWriteTime -
Descending | Select-Object -First 1
$latest.Name $outFile = 'C:\temp\empid_log.csv'
Import-Csv -Path $latest | ForEach-Object {

How to export Txt/Text file to new folder?

This code does taking newest text file from the folder.
$dir = "C:\logsnew\Application"
$latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$latest.name
showing like this
C:\Users\kimi> $dir = "C:\logsnew\Application"
C:\Users\kimi> $latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
C:\Users\kimi> $latest.name
4552-4084-63585921993.txt
I would like to put this newest txt file "4552-4084-63585921993.txt" to new folder name "logstop1".
So I try like this:
$dir = "C:\logsnew\Application"
Get-ChildItem -Path $dir |
Sort-Object LastAccessTime -Descending |
Select-Object -First 1 |
Add-Content C:\logsTop1
but this error happens:
Add-Content : Access to the path 'C:\logsTop1' is denied.
How can I fix this problem?
Use Move-Item instead of Add-Content if you want to move the file or Copy-Item if you want to copy it.
Get-ChildItem -Path "C:\logsnew\Application" | Sort-Object LastAccessTime -Descending | Select-Object -First 1 | Move-Item -Destination "C:\logspath1"