Deleting log files that are buried with powershell - powershell

So I am trying to figure out a script to delete log files that are buried in many folders. Same path to the end folder minus the client name folder that changes. Below is an example of the code I thought would work which is failing horribly. Any advice would be appreciated.
gci X:\ -directory -recurse | ?{$_.FullName -match \\temp\\company\\.+?\\AppData\\logfiles -and $_.CreationTime -lt (get-date).AddDays(-20)}|Remove-Item -recurse -whatif
so the Directory is X and the path to the logfiles that I want to delete is temp\company\NAME\appdata\logfiles and the NAME folder is the one that could be one of any number of different clients names.
Error I keep getting.
At line:1 char:51
+ gci X:\ -directory -recurse | ?{$_.FullName -match \\temp\\company\\.+?\\ ...
+ ~
You must provide a value expression on the right-hand side of the '-match' operator.
At line:1 char:52
+ gci x:\ -directory -recurse | ?{$_.FullName -match \\Temp\\company\\.+?\\ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token '\\Temp\\company\\.+?\\AppData\\logfiles' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedValueExpression
Does anyone have any ideas what we are doing wrong or how to accomplish this goal?
Thanks in advance!

The errors are because second argument to -match needs to be in quotes.
But there may be a way to do this without needing the complexity of your example. Get-ChildItem can take both a -Path and a -Include (or -Filter) argument. So you might use something like this:
Get-ChildItem -path c:\xxx -Include *log.tmp -Recurse | ... | Remove-Item

Related

I want to take the output of Get-PSDrive to get the drive letter of all drives and do a search for ISO's and use the path from the Get-PSDrive

I am trying to use Get-PSDrive to put all the drive letters used by disks into a string that returns each letter (That works)
I am having problems using the $ISODeviceLetter variable to use it as a path to search all drives for .ISO files.
$ISODeviceLetter = Get-PSDrive | Select-Object -ExpandProperty 'Name' | Select-String -Pattern '^[a-z]:$'
$ISOLocation = Get-ChildItem -Path $ISODeviceLetter -Recurse -Include *.ISO
This is the error I get:
Get-ChildItem : Cannot find path 'C:\Users\Administrator\C' because it does not exist.
At line:1 char:16
+ ... OLocation = Get-ChildItem -Path $ISODeviceLetter -Recurse -Include *. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\C:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
I see by the error the get-childitem is using the default location which is the C:\Users\Administrator.
The desired output is to pass $ISODriveLetter as the Path for all drives on the server "C:","D:","E:", so all the drives can be searched for .ISO files.
Thanks ahead of time for the help.
The issue is that when referencing drives, they have to be distinguished using a colon (:) to disambiguate the drive from a regular folder/file:
Use the Foreach-Object command to append the Colon to each drive letter returned.
Changed the filter from -Include to -Filter, to speed up the process as -Filter is implemented by the FileSystemProvider, and you're also not looking for multiple files.
Added -File switch for a more efficient query as well, since an .ISO extension is associated to a file.
$ISODeviceLetter = [array](Get-PSDrive |
Where-Object -FilterScript {$_.Name -match "^.$"}).Foreach{
$_.Name + ':'
}
$ISOLocation = Get-ChildItem -Path $ISODeviceLetter -File -Recurse -Filter *.ISO
Bonus:
You can use Simplified Syntax to achieve the same results as above for better readability:
$ISODeviceLetter = (Get-PSDrive).Where{$_.Name -match "^.$"} |
Select -exp Name | Foreach Insert -ArgumentList 1,':'
Only real "downside" of this is, that you're using the pipeline even more. Even though it may not affect the speed in your return for this example, other time sensitive tasks can take quite a performance hit using the pipeline.

Need to list all new files in directory with Powershell

I have to create a list of all latest or accessed files in a directory in .csv format. However my current script doesn't output a useful file. (always 0KB)
Get-ChildItem -Path X:\ -Directory -Recurse -ErrorAction SilentlyContinue |
ForEach-Object { Get-ChildItem $_.Name -Recurse |
select Name, *time |
Sort-Object -Property LastAccessTime -Descending |
Select-Object -First 1 } |
Export-Csv -Path C:\...\testfile.csv
Does anyone have a better idea?
EDIT: The errors look like this:
+ CategoryInfo : ReadError: (X:\xxx:String) [Get-ChildItem], DirectoryNotFoundException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand
That code might generate some errors if you don't cd to X:\ before running it. You can remediate that with changing:
# this
Get-ChildItem $_.Name -Recurse
# to this
Get-ChildItem $_.FullName -Recurse
Then it always uses absolute path rather than relative one.
NOTE: as #mklement0 pointed out in the comments, it's worth noting that in PowerShell 6 and higher the same can be achieved by using the object directly (no need to use .FullName property).
Here's his helpful answer explaining it in details - really worth reading!

Get-ChildItem and wildcards and filtering

I have two different ways of getting files with a wildcard pattern:
Get-ChildItem "$ActivityLogDirectory/*.csv"
and
Get-ChildItem "$ActivityLogDirectory" -Filter *.csv
I prefer to use the latter instead of the former because the former (Get-ChildItem "$ActivityLogDirectory/*.csv") has, on occasion, given me a permission denied error.
They both appear to return the same results, but when I try to compress the resulting files with this command:
Compress-Archive -Update -Path $CsvFiles -DestinationPath C:\Users\admin\Downloads\foo.zip
the former succeeds while the latter fails with the following error:
Compress-Archive : The path 'rgb dev automation store a_1-1_2194_20181120.csv'
either does not exist or is not a valid file system path.
At line:1 char:1
+ Compress-Archive -Update -Path $CsvFiles -DestinationPath C:\Users\ad ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (rgb dev automat...94_20181120.csv:String) [Compress-Archive], InvalidOperationException
+ FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive
So what's the difference between these two ways of getting a listing of files using wildcards? Or perhaps asked another way, why does using -Filter *.csv cause the Compress-Archive cmdlet to fail?
The reason you're seeing different behavior is the - obscurely situational - stringification behavior of the objects output by Get-ChildItem:
This answer details when Get-ChildItem output happens to stringify to a mere filename vs. a full path, and it so happens that Get-ChildItem "$ActivityLogDirectory" -Filter *.csv stringifies to mere filenames.
The workaround is to explicitly stringify the objects as their full paths via their FullName property (PSv3+ syntax):
$CsvFiles = (Get-ChildItem "$ActivityLogDirectory" -Filter *.csv).FullName
If you are running this from a shell with the location of the folder where the CSV files are located then this will work. What you are doing by passing the $CsvFiles variable into Compress-Archive is trying to run against the file name in the current context. To fix this pass the full path $CsvFiles.FullName:
$Csvfiles = (Get-Childitem $ActivityLogDirectory -Filter *.csv)
Compress-Archive -Update -Path $Csvfiles.fullname -DestinationPath C:\Users\admin\Downloads\foo.zip

Count number of folders in directory and ignore shortcuts

I have a script which will accurately tell me how many folders are in a directory, and the subdirectories within. However, for one directory which I am working with, there are shortcut folders which seem to cause the script to fail.
Below is the error message which I receive:
Get-ChildItem : Could not find a part of the path 'C:\Folder\SubFolder\folder1\jpos'.
At C:\Desktop\Script Files\fileCount.ps1:34 char:10
+ $items = Get-ChildItem C:\Folder\SubFolder\ -Recurse
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ReadError: (C:\Folder\SubFolder\folder1\jpos:String) [Get-ChildItem],
DirectoryNotFoundException
+ FullyQualifiedErrorId :
DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand`
The script runs fine for directories without shortcuts, but it seems to always fail when there are shortcuts within the directory.
Below is the code snippet for this section:
$items = Get-ChildItem C:\Folder\SubFolder -Recurse
$termFolder = ($items | Where-Object {$_.PSIsContainer}).count
Is there any way to skip over shortcuts or a better way to do a folder count?
(gci path |?{$_.Extension -ne ".lnk"}).Count
Shortcuts have .lnk extension and gci means Get-Childitem.
Just use -directory like this (for PowerShell 3 or +):
$items = Get-ChildItem C:\Folder\SubFolder -Recurse -Directory
$termFolder = $items.Count
If you don't need the directory collection folder subsequently in script, then you can simply use
$countDirs = $(Get-ChildItem -path c:\folder\subfolder -Recurse -Directory).count

How to pipe a directory name into Remove-Item?

I'm not very savvy with powershell, so any help is appreciated.
I have a drive that holds users profiles. I need to remove a specific file from each user's profile. It's structured something like this. (Names changed to protect the innocent.)
E:\Profiles
UserID
Documents
OtherFolders
DirectoryToDeleteFrom
FileToDelete.txt
UserID2
...
...
I could use the following command to delete all of the files I need to get to, but it's unbearably slow as it's recursing through all of the other folders under UserID.
#this one would work perfectly, but is terribly slow
Get-ChildItem -Path E:\Profiles -Include FileToDelete.txt -Recurse
I know exactly where each file resides, so I thought that I could do this.
(Get-ChildItem -Path 'E:\Profiles' -Exclude *.lnk)|ForEach-Object{Remove-item -path 'E:\Profiles\' + $_.Name + '\Path\To\File\FileToDelete.txt'}
But I get the following error message:
Remove-Item : A positional parameter cannot be found that accepts
argument '+'. At line:1 char:70
+ (Get-ChildItem -Path 'E:\Profiles' -Exclude *.lnk)|ForEach-Object{Remove-item ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
I thought it was because I was passing Remove-Item a bad file path, but the following command generates the correct paths.
(Get-ChildItem -Path 'E:\Profiles' -Exclude *.lnk)|ForEach-Object{'E:\Profiles\' + $_.Name + '\Path\To\File\FileToDelete.txt'}
So what am I doing wrong here?
If you construct a string on the fly to be used inline, by another command, then put brackets around the path:
..{Remove-item -path ('E:\Profiles\' + $_.Name + '\Path\To\File\FileToDelete.txt')}