Friday, November 2, 2018

PowerShell Get, Filter, Where, Copy in a single line

The task is the following: create a simple script for gathering textual log files from several different places via network, filter them by name and recent update date, display files information like name, datetime, length and copy them to a specified destination. It is pretty achievable through the PowerShell functionality.

To retrieve data from any source folder we use Get-ChildItem cmdlet. To extend functionality to get files from more than one sources just separate them with comma.

PS C:\> Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\*

As we can see, the instruction returns just folders and files in the Logs folder only. If we need all the files from all subfolders just add -Recurse or -rec option.

PS C:\> Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\* -Recurse

If we'd like to see just files without folders add the following filter. Don't forget to use '`' (backtick) character if you want to make a multiline cmdlet.

PS C:\> Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\* -Recurse `
| where {!$_.PsIsContainer }

The filtration is very flexible so we can combine several clauses. For example, the following script retrive files updated during the latest hour and NOT containing 'ClientLogsRetrieval' string inside their fullnames (including folder names in the whole subfolder hierarchy)

PS C:\> Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\* -Recurse `
| where {!$_.PsIsContainer `
  -and $_.LastWriteTime -ge (Get-Date).AddHours(-1) `
  -and ($_.FullName -notlike '*ClientLogsRetrieval*')}

Instead of displaying the default file info we can use some kind of formatted output, i.e. display data in specific order, like FullName, LastWriteTime, length

Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\* -rec `
| where {!$_.PsIsContainer `
  -and $_.LastWriteTime -ge (Get-Date).AddHours(-1) `
  -and ($_.FullName -notlike '*ClientLogsRetrieval*')} `
| select-object FullName, LastWriteTime, length

If we want to copy selected files into some destination use Copy-Item option

Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\* -rec `
| where {!$_.PsIsContainer `
  -and $_.LastWriteTime -ge (Get-Date).AddHours(-1) `
  -and ($_.FullName -notlike '*ClientLogsRetrieval*')} `
| Copy-Item -Destination D:\Temp\

We can also copy files and display necessary file info at the same time, it will be a bit complicated script though

Get-ChildItem \\networksource1\Logs\*,\\networksource2\Logs\* -rec `
| where {!$_.PsIsContainer `
  -and $_.LastWriteTime -ge (Get-Date).AddHours(-1) `
  -and ($_.FullName -notlike '*ClientLogsRetrieval*')} `
| foreach {`
   copy $_.FullName D:\Temp\
   echo $_.FullName,$_.LastWriteTime,$_.length}

That's it. And as bonus the following cmdlet deleting all old log files (older than 30 days). But to perform this, write acces to the remote machine is necessary. You have to run PowerShell as different user - that user that has write access to the remote machine.

Get-ChildItem \\networksource1\Logs\* -rec `
| where {!$_.PsIsContainer -and $_.LastWriteTime -le (Get-Date).AddDays(-30) } `
| Remove-Item

No comments:

Post a Comment