recursive display is not showing right format - powershell

Something wrong with my IF-ELSE statement and my dumb brain cannot figure out what the heck it is!
If I run the below code on its own it shows each directory and files in there in the below format:
get-childitem E:\LogArchive -recurse | where-object {$_.lastwritetime -gt 60}
Format of output:
Directory: E:\LogArchive\W3SVC100
Mode LastWriteTime Length Name
---- ------------- ------ ----
----- 29/03/2007 15:03 663 ex070329.log.gz
----- 30/03/2007 15:44 860 ex070330.log.gz
----- 03/04/2007 13:41 354 ex070403.log.gz
----- 05/04/2007 14:00 704 ex070405.log.gz
----- 10/04/2007 17:56 921 ex070410.log.gz
----- 11/04/2007 14:55 987 ex070411.log.gz
----- 12/04/2007 15:12 539 ex070412.log.gz
However, when this is run in a code it shows as the below, WITHOUT all the folder structure and dates etc:
W3SVC100
W3SVC102
W3SVC105
W3SVC106
W3SVC1108492480
W3SVC112
W3SVC116
W3SVC118
W3SVC1209046175
W3SVC123110214
W3SVC1262336480
W3SVC127
W3SVC134
W3SVC134239081
W3SVC137
W3SVC139
W3SVC145
W3SVC147
W3SVC1499983181
W3SVC15
How do I get the first results when the below script is run - so show all the modified date, last write time etc . I am currently inputting a message to the user if no files are found in the date range then a message is displayed - however, if it did find anyfiles then display them as listed in the first output type.......
I actually think the fault is on this line but cannot figure out how to amend this:
if ( $runchilditem.lastwritetime -gt DateToCompare)
......In fact - I want to put the output to CSV - any ideas how I can do this?
CODE:
$path = Read-Host "Please enter the path of the folder yu wish to check - this will check sub-folders as well"
Write-Host "`n"
$days = Read-Host "Please enter in number of DAYS you wish to go back"
$DateToCompare = (Get-Date).AddDays(-$days)
$runningtrue = Get-ChildItem $path -Recurse | where-object {$_.lastwritetime -gt $DateToCompare}
Write-Host "`n"
$runchilditem = #(Get-ChildItem $path -Recurse)
if ( $runchilditem.lastwritetime -gt DateToCompare)
{
Write-Host "No Files Matching Date Criteria Found"
}
else
{
$runningtrue
}

If I understand your need, here is how I would do it:
$path = Read-Host 'Path'
[int]$dayDiff = Read-Host 'Number of days to go back'
$offset = $dayDiff * -1
$files = Get-ChildItem $path -Recurse | Where-Object{$_.LastWriteTime -gt (Get-Date).AddDays($offset)}
if(($files.Count -eq 0) -OR ($files -eq $null)){
'There are no files after {0} in {1}' -f (Get-Date).AddDays($offset), $path
}else{
$files
$files | Export-CSV C:\PATH\TO\FILE.csv -NoTypeInfo
}

Related

Turn this cmdlet into a script: Get-Content -Path C:\Users\Einar\Desktop\log\* -filter *1234567.log.txt | Select -First 2 | Select -last 1

Basically, I want to input 7 digits and get second line in the log file as an output.
This is my first time attempting anything in powershell btw
Get-Content -Path C:\Users\Einar\Desktop\log* -filter *1234567.log.txt | Select -First 2 | Select -last 1
I have a folder with log files, that all end with (random7digits).log.txt, and I want to output only the second line by inputting a set of 7 digits.
Any help is appreciated :)
In very basic form, this achieves what you want. You can save this is a .ps1 and save it on your desktop. If you right click and Run with PowerShell, then the console will close after immediately returning. Either call the script from a pre-existing console session, or add a pause or something at the end.
I recommend you expand upon it as a learning exercise with some of these ideas:
Check whether the file exists and provide sensible error handling or message to the user
Check if the file contains your 'ideal' content, or even two lines at all, and provide sensible error handling or message to the user
Perhaps add another parameter, with a default value to your desktop, in case you ever need to run it with logs elsewhere on disk
param(
[Parameter(Mandatory)]
[int]$Digit
)
Get-ChildItem -Path <path_containing_files> -File -Filter *$Digit.log.txt | ForEach-Object {
Get-Content -Path $_ | Select-Object -Index 1
}
function Get-Logline
function Get-Loglines{
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true, HelpMessage='Enter Path to Log Folder:' )]
[string]$Path,
[Parameter(Mandatory=$true, ValueFromPipeline=$true, HelpMessage='Enter string to filter for: *(string).log.txt')]
[int]$filename,
[Parameter(Mandatory=$true, ValueFromPipeline=$true, HelpMessage='Enter line number to read back:')]
[int]$linenumber
)
process{
$lookdepth = $linenumber - 1
Get-ChildItem -Path $Path -File -Filter ('*{0}.log.txt' -f $filename) -force -Verbose |`
ForEach-Object{
Get-Content $_ -Verbose |`
Select-Object -Skip $lookdepth -First 1 -Verbose
}
}
}
Test Case
C:\> Get-Loglines
cmdlet Get-Loglines at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Path: C:\Downloads\Newfolder
filename: 666666
linenumber: 2
line 2
Example Data
C:\Downloads\Newfolder [master +39 ~0 -0 !]> Get-ChildItem
Directory: C:\Downloads\Newfolder
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/21/2022 2:37 PM 38 ab123456.log.txt
-a---- 4/21/2022 2:37 PM 38 ab666666.log.txt
-a---- 4/21/2022 2:37 PM 38 ab666667.log.txt
-a---- 4/21/2022 2:37 PM 38 acb666666.log.txt
C:\Downloads\Newfolder> Get-Content .\ab666666.log.txt
line 1
line 2
line 3
line 4
line 5

Resolve-Path: cannot find path because it does not exist. error in powershell

Firstly: what My code does it counts the number of duplicate files in a particular path entered by the user.
It does this by first calculating which files have the same length. and from the files that have the same length, it checks which files also have the same hash. And then in the end I am making an object which contains the information that I need to print in a table.
Problem:
In my code,
I am getting an error which I am pretty sure is coming from the Get-FileHash commandlet.
when I ctrl + click on the link that is given in the "At" section of the error, It takes me to the Get-FileHash commandlet utility in powershell
C: >WIndows > system32 > WindowsPowershell > v1.0 > Modules > Microsoft.Powershell.Utility > Microsoft.Powershell.Utility.psm1 > Get-FileHash{}
the error only comes up for some .msg and .pdf files
the code works perfectly fine on a path with lesser files.
Here is the Error:
Resolve-Path : Cannot find path '<path of File>' because it does not exist.
At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Utility\Micro
+ ... $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Forea ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (<nameOfFile>:String)
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.ResolvePathComm
And here is the code:
#taking the input of the user!
$pathInputByUser = Read-Host ("Please Enter the Path where you want to check for duplicate files")
#Accessing the path entered by the user
cd $pathInputByUser
write-host ("Loading: Please Wait! This can take a upto 2.5 hrs") -ForegroundColor Green
$Stopwatch = [System.Diagnostics.Stopwatch]::StartNew();
$totalNumOfFiles = 0;
#the variable "filesGroupedAccordingToLength" contains all the files grouped according to their size. files with same size , are in the same group
$filesGroupedAccordingToLength = Get-ChildItem -Recurse -File `
| Group-Object -Property Length
#below calculating the number of total Files that we have found till now
$totalNumOfFiles = $filesGroupedAccordingToLength | Measure-Object -Property Count -Sum | % { $_.sum };
#the below variable "filesWhichHaveSameLengths" contains group of files that have the same size as some other file
$filesWhichHaveSameLengths = $filesGroupedAccordingToLength | ? { $_.Count -gt 1 } `
| % { $_.Group }
#the below variable "hash" contains group of files that have the same hash as some other file
$groupedFilesWithSameHash = $filesWhichHaveSameLengths | Get-FileHash `
| Group-Object -Property Hash `
| ? { $_.Count -gt 1 }
$numOfDuplicates= 0;
$calculatingCountDuplicates= $groupedFilesWithSameHash| Select-Object -ExpandProperty Count| %{ $numOfDuplicates= $numOfDuplicates + ($_ - 1) };
"The number of duplicate files are: $numOfDuplicates"
#the below variables contains hash of duplicate files
$hashOfDuplicateFiles= $groupedFilesWithSameHash | % { $_.Group }
#making objects to be able to display result as a table
$res= #();
$hashValue=0;
foreach ($tuple in $hashOfDuplicateFiles) {
foreach ($var in $filesWhichHaveSameLengths) {
if ($var.FullName -eq $tuple.Path) {
$obj= new-object psobject -Property #{
LastWriteTime = $var.LastWriteTime
Name = $var.Name
length = $var.length
FullName = $var.FullName
hash = $tuple.Hash
RelativePath = $var.PSPath.Replace("Microsoft.PowerShell.Core\FileSystem::F:\", "")
}
if($tuple.Hash -ne $hashValue){
$obj|Add-Member -NotePropertyName U/D -NotePropertyValue "Unikat"
$res= $res+$obj;
$hashValue= $tuple.Hash;
}
else{
$obj|Add-Member -NotePropertyName U/D -NotePropertyValue "Duplikat"
$res= $res+$obj;
}
}
}
}
$res | Format-Table -AutoSize -Property Name, U/D, LastWriteTime, hash, length, RelativePath |Out-File -FilePath C:\Users\Public\Documents\Ebrahim_iris\DuplicateFinderTool\testLog.txt
"the number of total files is : $totalNumOfFiles"
"The number of duplicate files are: $numOfDuplicates"
"The number of unique files are: $($totalNumOfFiles-$numOfDuplicates)"
$Stopwatch.Stop();
"The script ran for: $($Stopwatch.Elapsed.TotalMinutes) minutes"
Any advice to remove this error will be appreciated.

How can I get the average lastwritetime from multiple files?

I have a PowerShell script that is modifying multiple files. I would like to verify that they were modified by checking the last write time property and comparing it to the current time minus 30 minutes.
Is there anyway to get the average time from multiple different files?
For example:
$Var = Get-Childitem -path "C:\users\User\Documents\*.txt"
$lastwt = $var.Lastwritetime
If($lastwt -ge (Get-Date).addminutes(-30)){
Do stuff
}
The above won't work because multiple dates are returned all around the same time give or take a few milliseconds.
I want to just get the average of all the times and use that as time comparison instead. Any way to do this?
About
So you should probably use New-Timespan to do time comparisons. So your update code:
Code
$Files = Get-Childitem -path "C:\users\User\Documents*.txt"
$Files | ? {
# Filter by a timespan criteria (last write on this file is greater than 30 minutes before now)
$Mins = New-Timespan $_.LastWriteTime (Get-Date) | % TotalMinutes
return $Mins -ge 30
} | % {
# Work only on files that matched the top criteria
}
Does that help? If you still want the averaging solution, lmk, I'll add it in :)
To get an average (median) LastWriteTime [DateTime] object of a series of files, this may be what you want:
$files = Get-Childitem -Path 'C:\users\User\Documents' -Filter '*txt' -File
# get an array of the LastWriteTime properties and sort that
$dates = $files | Select-Object -ExpandProperty LastWriteTime | Sort-Object
$oldest = $dates[0]
$newest = $dates[-1]
# create a new DateTime object that holds the middle of the oldest and newest file time
$average = [datetime]::new((($oldest.Ticks + $newest.Ticks) / 2), 'Local')
# show what you've got:
Write-Host "Oldest LastWriteTime: $oldest"
Write-Host "Average LastWriteTime: $average" -ForegroundColor Green
Write-Host "Newest LastWriteTime: $newest"

Powershell Script to parse selected information from txt file and output to csv

checked the FAQ's on parsing data and have tried a couple ideas but nothing is working the way I need it. I need a suggestion on how to build a PS script that will read the following information in my .txt file and output only selected information to .csv
eamoptns.ftr.0009: LoyaltyPrint3 = " included with your TV purchase"
eamoptns.ftr.0010: LoyaltyPrint3 = " included with your TV purchase"
Grand Total: 2 match(es) found.
CSV file will contain three columns:
Store Install Date
Need PS script to grab the store # (0009) and add it under the Store column. If that line contains "included with your TV purchase" under the install column add True if not add False and then add the date in date column.
Code try from comment
$PSRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
Get-ChildItem $PSRoot -Filter "*Results.txt" |
Where-Object { $_.Attributes -ne "Directory" } | ForEach-Object {
If (Get-Content $_.FullName | Select-String -Pattern "included with your TV purchase") {
New-Object -TypeName PSCustomObject -Property #{
Club = $A
Install = $B
Date = $C
} | Export-CSV -Path $PSRoot\Test.csv -Append
}
}
As suggested
choose a regular expression that matches your requrements (see regex101.com)
iterate the matches and compare the ,matched text
generate a [PSCustomObject] for your csv
## Q:\Test\2018\10\17\SO_52857274.ps1
$RE = [RegEx]'^.*?\.(\d{4}):[^"]+"\s*(included with your TV purchase|.*)"$'
$CSV = Select-String '.\my.txt' -Pattern $RE | ForEach-Object {
IF ($_.Matches.Groups[2].Value -eq 'included with your TV purchase'){
$Install = $True
} else {
$Install = $False
}
[PSCustomObject]#{
Store = $_.Matches.Groups[1].Value
Install = $Install
Date = (Get-Date).Date
}
}
$CSV
# $CSV | Export-CSV '.\my.csv' -NoTypeInformation
Sample output:
> Q:\Test\2018\10\17\SO_52857274.ps1
Store Install Date
----- ------- ----
0009 True 2018-10-17 00:00:00
0010 True 2018-10-17 00:00:00
0010 False 2018-10-17 00:00:00

Count number of files in each subfolder, ignoring files with certain name

Consider the following directory tree
ROOT
BAR001
foo_1.txt
foo_2.txt
foo_ignore_this_1.txt
BAR001_a
foo_3.txt
foo_4.txt
foo_ignore_this_2.txt
foo_ignore_this_3.txt
BAR001_b
foo_5.txt
foo_ignore_this_4.txt
BAR002
baz_1.txt
baz_ignore_this_1.txt
BAR002_a
baz_2.txt
baz_ignore_this_2.txt
BAR002_b
baz_3.txt
baz_4.txt
baz_5.txt
baz_ignore_this_3.txt
BAR002_c
baz_ignore_this_4.txt
BAR003
lor_1.txt
The structure will always be like this, so no deeper subfolders. I'm working on a script to count the number of files:
for each BARXXX folder
for each BARXXX_Y folder
textfiles with "ignore_this" in the name, should be ignored in the count
For the example above, this would result into:
Folder Filecount
---------------------
BAR001 2
BAR001_a 2
BAR001_b 1
BAR002 1
BAR002_a 1
BAR002_b 3
BAR002_c 0
BAR003 1
I now have:
Function Filecount {
param(
[string]$dir
)
$childs = Get-ChildItem $dir | where {$_.Attributes -eq 'Directory'}
Foreach ($childs in $child) {
Write-Host (Get-ChildItem $dir | Measure-Object).Count;
}
}
Filecount -dir "C:\ROOT"
(Not ready yet but building) This however, does not work. $child seems to be empty. Please tell me what I'm doing wrong.
Well, to start, you're running ForEach ($childs in $child), this syntax is backwards, so that will cause you some issues! If you swap it, so that you're running:
ForEach ($child in $childs)
You'll get the following output:
>2
>2
>1
>1
>1
>3
>0
Alright, I'm back now with the completed answer. For one, instead of using Write-Out, I'm using a PowerShell custom object to let PowerShell do the hard work for me. I'm setting FolderName equal to the $child.BaseName, and then running a GCI on the $Child.FullName to get the file count. I've added an extra parameter called $ignoreme, that should have an asterisk value for the values you want to ignore.
Here's the complete answer now. Keep in mind that my file structure was a bit different than yours, so my file count is different at the bottom as well.
Function Filecount {
param(
[string]$dir="C:\TEMP\Example",
[string]$ignoreme = "*_*"
)
$childs = Get-ChildItem $dir | where {$_.Attributes -eq 'Directory'}
Foreach ($child in $childs) {
[pscustomobject]#{FolderName=$child.Name;ItemCount=(Get-ChildItem $child.FullName | ? Name -notlike $ignoreme | Measure-Object).Count}
}
}
>Filecount | ft -AutoSize
>FolderName ItemCount
>---------- ---------
>BAR001 2
>BAR001_A 1
>BAR001_b 2
>BAR001_C 0
>BAR002 0
>BAR003 0
If you're using PowerShell v 2.0, use this method instead.
Function Filecount {
param(
[string]$dir="C:\TEMP\Example",
[string]$ignoreme = "*_*"
)
$childs = Get-ChildItem $dir | where {$_.Attributes -eq 'Directory'}
Foreach ($child in $childs) {
$ObjectProperties = #{
FolderName=$child.Name
ItemCount=(Get-ChildItem $child.FullName | ? Name -notlike $ignoreme | Measure-Object).Count}
New-Object PSObject -Property $ObjectProperties
}
}
I like that way of creating an object 1RedOne, haven't seen that before, thanks.
We can improve the performance of the code in a few of ways. By using the Filter Left principle, which states that the provider for any cmdlet is inherently more efficient than running things through PowerShell, by performing fewer loops and by removing an unnecessary step:
Function Filecount
{
param
(
[string]$dir = ".",
[parameter(mandatory=$true)]
[string]$ignoreme
)
Get-ChildItem -Recurse -Directory -Path $dir | ForEach-Object `
{
[pscustomobject]#{FolderName=$_.Name;ItemCount=(Get-ChildItem -Recurse -Exclude "*$ignoreme*" -Path $_.FullName).count}
}
}
So, firstly we can use the -Directory switch of Get-Childitem in the top-level directory (I know this is available in v3.0 and above, not sure about v2.0).
Then we can pipe the output of this directly in to the next loop, without storing it first.
Then we can replace another Where-Object with a provider -Exclude.
Finally, we can remove the Measure-Object as a simple count of the array will do:
Filecount "ROOT" "ignore_this" | ft -a
FolderName ItemCount
---------- ---------
BAR001 2
BAR001_a 2
BAR001_b 1
BAR002 1
BAR002_a 1
BAR002_b 3
BAR002_c 0
BAR003 1
Cheers Folks!