LastAccessTime and get-date Comparison - date

I am parsing through a directory with multiple sub-directories and want to compare the LastAccessed time with the get-date time to see if the file has been accessed since yesterday, and based on that I will either delete the file or leave it alone. I have tried piping the get-date results out to a text file and pull it back as a string, I have tried wildcard I have even gone as far as using the -like as opposed to -eq in order to get the comparison to work, but it is not properly comparing the data. Any help would be greatly appreciated.
Here is my current code:
$servers="servera","serverb"
$date3=get-date -Format d
foreach($a in $servers){
$CTXGPDir="\C$\ProgramData\Citrix\GroupPolicy"
$CTXGPDirFP="\\"+"$a"+"$CTXGPDir"
$CTXGPUserDirstoRM=Get-ChildItem "$CTXGPDirFP"|where-Object{$_.Name -notlike "*.gpf"}
foreach($i in $CTXGPUserDirstoRM){
$datestring="$date3"+" *"
$CTXUserGPPath="\C$\ProgramData\Citrix\GroupPolicy\$i"
$CTXUserGPFP="\\"+"$a"+"$CTXUserGPPath"
$file=get-item $CTXUserGPFP
$isFileInactive=$file|select-object -expandproperty LastAccessTime
write-host $file
write-host $isFileInactive
write-host $datestring
if($isFileInactive -like "$datestring *"){write-host "$CTXUserGPFP on $a has lastwritetime of $isFileInactive and should NOT BE deleted"}
if($isFileInactive -notlike "$datestring *"){write-host "$CTXUserGPFP on $a has lastwritetime of $isFileInactive and SHOULD BE deleted"}
}

Your date comparison is deeply flawed.
get-date -format d returns a String representing the current date based on your regional settings.
get-childitem <file> | select -expandproperty lastaccesstime returns a DateTime object, which gets formatted as a "long" date/time using your regional settings.
To compare these two dates effectively, you need to convert the latter to the same format.
$isFileInactive=($file|select-object -expandproperty LastAccessTime).ToShortDateString()
$isFileInactive is now a String formatted the same as you get with get-date -format d and you can make a proper comparison.
if($isFileInactive -eq $datestring){write-host "$CTXUserGPFP on $a has lastwritetime of $isFileInactive and should NOT BE deleted"}
If you have to deal with timezones, you may want to amend it to add .ToLocalTime() before ToShortDateString();

Related

Copy from Specific Folder with Multiple Folders

I am creating a backup and restore tool with powershell script and I am trying to make it so that when restoring, the script picks the last folder created and restores from that directory structure. Basically I am having the script start with making a backup directory with a date/time stamp like so:
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$CurrentDomainName = $CurrentUser.split("\")[0]
$CurrentUserName = $CurrentUser.split("\")[1]
$folderdate = Get-Date -f MMddyyyy_Hm
$homedir = Get-Aduser $CurrentUserName -prop HomeDirectory | select -ExpandProperty
HomeDirectory
New-Item $homedir -Name "TXBackup\$folderdate" -ItemType Directory
$cbookmarks = "$env:userprofile\Appdata\Local\Google\Chrome\User Data\Default\Bookmarks"
md $homedir\TXBackup\$folderdate\Chrome
Copy-Item $cbookmarks "$homedir\TXBackup\$folderdate\Chrome" -Recurse
Backup Folder Structure
Basically everytime someone runs the backup tool it will create a subfolder under the Backup directory with the date/time name to track the latest one. The problem comes when I want to restore from the last one create I can no longer use a $folderdate variable since it will pull the whatever the time is while the tool is being run. Here is the code without taking into account what the last folder is. I tried using sort but that doesn't appear to give me a clear path to select the last one created or I just am such a noob I didn't use it right :(
##Restoring Files from Backup
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$CurrentDomainName = $CurrentUser.split("\")[0]
$CurrentUserName = $CurrentUser.split("\")[1]
$homedir = get-aduser $CurrentUserName -prop HomeDirectory | select -ExpandProperty HomeDirectory
##Restoring Chrome Bookmarks
Sort-Object -Property LastWriteTime |
Select-Object -Last 1
$rbookmarks = "$homedir\TXBackup\$folderdate\Chrome\Bookmarks"
Copy-Item $rbookmarks "C:\Test\"
I know I didn't use that correctly but any direction would be awesome for this newbie :)
You can use Sort-Object with a script block and use [DateTime] methods to parse the date from the folder name, using the same format string you used to create them.
# Sort directory names descending
Get-ChildItem -Directory | Sort-Object -Desc {
# Try to parse the long format first
$dt = [DateTime]::new( 0 )
if( [DateTime]::TryParseExact( $_.Name, 'MMddyyyy_HHmm', [CultureInfo]::InvariantCulture, [Globalization.DateTimeStyles]::none, [ref] $dt ) ) {
return $dt
}
# Fallback to short format
[DateTime]::ParseExact( $_.Name, 'MMddyyyy', [CultureInfo]::InvariantCulture )
} | Select-Object -First 1 | ForEach-Object Name
Note: I've changed the time format from Hm to HHmm, because Hm would cause a parsing ambiguity, e. g. 01:46 would be formatted as 146, but parsed as 14:06.
Also I would move the year to the beginning, e. g. 20220821_1406, so you could simply sort by name, without having to use a script block. But that is not a problem, just an (in)convenience and you might have a reason to put the year after the day.
Given these folders:
08212022
08222022
08222022_1406
08222022_1322
08222022_1324
08222022_1325
08222022_1343
The code above produces the following output:
08222022_1406
To confirm the ordering is correct, I've removed the Select-Object call:
08222022_1406
08222022_1343
08222022_1325
08222022_1324
08222022_1322
08222022
08212022
Note that the ordering is descending (-Desc), so Select-Object -First 1 can be used to more effectively select the latest folder.

Powershell - Formatting column as date

I am importing a CSV which has 5 "columns". One of them is a date and time. The 3rd party software that is reading this column, then does not sort the date well.
IE: (4/8/2022 1:24:08 PM) will sort above (4/13/2022 8:51:52 AM)
Even though 4/13 is after 4/8 it will not sort it properly. I would like to add a leading zero in front of the month and date with powershell. I did do some searching but nothing seems to make sense to me, I am not a HUGE programmer.
Thanks for any help!
This is what I am currently doing. I am using unique to remove duplicate rows (this is needed for what I am doing).
$FinalSessions = Import-Csv -Path "C:\Windows\AdminArsenal\UserSessions.csv" | Sort-Object * -Unique
$FinalSessions | Export-Csv -Path "C:\Windows\AdminArsenal\UserSessions.csv" -NoTypeInformation
$FinalSessions
You can use Get-Date to actually get a datetime object and then reformat it.
It would look something like this:
$FinalSessions = Import-Csv -Path "C:\Windows\AdminArsenal\UserSessions.csv"| Sort-Object * -Unique
$FinalSessions | % { $_.DateColumn = Get-Date $_.DateColumn -Format "MM/dd/yyyy hh:mm:ss tt" }
$FinalSessions | Export-Csv -Path
"C:\Windows\AdminArsenal\UserSessions.csv" -NoTypeInformation
$FinalSessions
Just replace "DateColumn" with the name of your column
Assuming that the column that contains the date-time string is named Date (adjust as needed):
Import-Csv -Path C:\Windows\AdminArsenal\UserSessions.csv |
ForEach-Object { $_.Date = ([datetime] $_.Date).ToString('s') } |
Sort-Object * -Unique -OutVariable finalSessions |
Export-Csv -Path C:\Windows\AdminArsenal\UserSessions.csv -NoTypeInformation
$finalSessions
Note that the s format specifier (in ISO 8601 format) is used to reformat the date-time strings, as that results in a string whose lexical sorting reliably indicates chronological order, across year boundaries; e.g. 2022-05-05T17:52:47

Powershell copy files with creation date equals given date

I'm trying to copy files with creation date equals to given date with no luck
args passed is current date 2/12/2020 and created a few files today but it copy nothing
what am I missing?
CODE
function findLogs ($searchDate)
{
Get-ChildItem c:\logs | Where-Object{ $_.CreationTime -eq $searchDate -and $_.Name -like "logs*" } | ForEach-Object {
$fileName = $_.Name
Copy-Item "c:\$fileName" -Destination c:\backup
}
}
you need truncate time
function findLogs ($searchDate)
{
Get-ChildItem c:\logs | Where-Object{ ([DateTime]::Parse($_.CreationTime.ToString("yyyy-MM-dd") -eq $searchDate -and $_.Name -like "logs*" } | ForEach-Object {
$fileName = $_.Name
Copy-Item "c:\$fileName" -Destination c:\backup
}
}
When working with PowerShell, there are two things to remember.
PowerShell is object-oriented.
PowerShell uses pipelines.
To the extent you can stick to these rules, you will have more options and your work will be easier.
You've done a good job with the pipeline.
Here are some tools to investigate the object side of things.
What objects are being compared?
Here I'll use the date format for my locale. I see you're using day-month-year.
You can use Get-Member to investigate objects in PowerShell.
> "12/2/2020" | Get-Member
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Objec…
CompareTo Method int CompareTo(System.Object value),…
Contains Method bool Contains(string value), bool C…
...
Here we see that our date string is a System.String.
I'd like to know what type of object CreationTime is.
> Get-ChildItem -File | Select-Object -First 1 | ForEach-Object CreationTime | Get-Member
TypeName: System.DateTime
Name MemberType Definition
---- ---------- ----------
Add Method datetime Add(timespan value)
AddDays Method datetime AddDays(double value)
AddHours Method datetime AddHours(double value)
...
Here we see that CreationTime is a System.DateTime.
Let's get our values to be the same type.
If you want to do shell-style string comparisons, there is nothing stopping you. But then you would be missing all the richness of PowerShell objects.
In principle, we're comparing two dates. So, let's convert our string input to a DateTime object.
> [DateTime] "12/2/2020"
Wednesday, December 2, 2020 12:00:00 AM
Notice that when we type cast a date string like "12/2/2020" to a DateTime object, a time is automatically filled in for the Hour, Minute, and Second properties. By default, midnight is used.
Solving the problem with the date comparison.
Let's look at one of the DateTime objects from my earlier query.
> Get-ChildItem -File | Select-Object -First 1 | ForEach-Object CreationTime
Saturday, September 26, 2020 10:57:33 AM
In my particular case, my file shows the date Saturday, September 26, 2020 10:57:33 AM.
DateTime objects always include the time. In our case, we don't care about the time. So, one way to solve our problem is to set the time portion of our objects to the same value. Then, when we compare two objects, only the date portion can affect the outcome.
Let's look at the properties and methods of DateTime to see if there is anything that can help us.
The first property on the list is Date. That seems like it might be interesting. Let's look at that.
The description of Date is:
Gets the date component of this instance.
A new object with the same date as this instance, and the time value set to 12:00:00 midnight (00:00:00).
This sounds like it might be useful.
Remember, when we type cast our string date, we got a DateTime object with the time portion set to midnight.
Here, we're taking a date and returning the same date with the time set to midnight.
Now we have a method of setting both our string input and file creation times to the same value. So, when we compare those DateTime objects, we'll just be comparing the date portions. This will solve our problem.
Let's demonstrate the necessary code.
> [DateTime] "12/2/2020"
Wednesday, December 2, 2020 12:00:00 AM
> Get-ChildItem -File | Select-Object -First 1 | ForEach-Object { $_.CreationTime.Date }
Saturday, September 26, 2020 12:00:00 AM
Final Answer
So, let's use [DateTime] type casting and the Date property to fix our function.
Here, I've also added parameters with default values. We can call findLogs in the same way as before. But we also have the option of changing the way the function works without having to rewrite it.
I've also used the FullName property to simplify the file copy.
function findLogs ([string] $searchDate, [string] $source = "c:\logs", [string] $destination = "c:\backup", [string] $nameLike = "logs*" )
{
Get-ChildItem -Path $source -File |
Where-Object { ($_.CreationTime.Date -eq (([DateTime] $searchDate).Date)) -and ($_.Name -like $nameLike) } |
ForEach-Object { Copy-Item -Path $_.FullName -Destination $destination }
}
In my environment, I was able to copy one of my bookmarklets to a backup folder:
$a = "C:\Users\Michael\Desktop\Bookmarklets"
$b = "C:\Users\Michael\Desktop\Backup"
findLogs -searchDate "12/3/2020" -source $a -destination $b -nameLike "Mark*"

Where statement in foreach loop, comparing dates

Trying to import a list of users with Name, Email, Termination Date, Stop Date and first check if either stop date or termination date has passed.
Tried adding [datetime] and using get-date $user.'stop date' but without any luck.
It seems to work with the below code without the same issues though, or I get the same error, but it does check and write out that one of the values is greater:
$StopFolder = Get-ChildItem C:\test\123\*.csv |sort LastWriteTime -descending|select -first 1
$Stoplist = Import-Csv $StopFolder -delimiter ';'
$CurrentDate = Get-Date
foreach($Date in $Stoplist){
if($CurrentDate -eq (get-date $Date.'Stop Date')){write-host Equal}
if($CurrentDate -gt (get-date $Date.'Stop Date')){write-host Greater}
if($CurrentDate -lt (get-date $Date.'Stop Date')){write-host Less}}
But the same didn't seem to work for the below and can't really figure out why. I think I need to convert it to a date, but not sure why it's working in the above and not the below, nor how exactly to convert it if get-date doesn't work.
$StopFolder = Get-ChildItem C:\test\123\*.csv |sort LastWriteTime -descending|select -first 1
$Stoplist = Import-Csv $StopFolder -delimiter ';'
$CurrentDate = Get-Date
foreach($User in $Stoplist|where($_.'stop date' -lt $CurrentDate)){
try{
$Usermail = $User.'e-mail address'
$Username = get-aduser -Filter "EmailAddress -eq '$Usermail'" -properties Enabled
if($Username.enabled){
echo $Username 'still exists and is NOT disabled' >> C:\NotDisabled.txt
}
if($Username.enabled -eq $false){
echo $Username 'still exists and is disabled' >> C:\NotDeleted.txt
}
}
catch{continue}
}
Expected result is to have it only initiate the loop if the current users stop date is less than the current date. Currently nothing happens, removing the where part and the rest seems to run fine.
Any help is much appreciated.
Edit:
CSV dates are like this:
stop date
01-02-2023
21-09-2019
21-01-2019
01-01-2019
01-01-2019
Edit: the error was not just within the logic but a typo: | where needs curly braces > | where {} not parenthesis.
Create a date from 'stop date':
(get-date -date $_.'stop date')
in one line:
foreach($User in $Stoplist|where{(get-date -date $_.'stop date') -lt $CurrentDate}){...}
Here $Stoplist|where{(get-date -date $_.'stop date') -lt $CurrentDate} is one unit and could be encapsulated in brackets:
foreach($User in ($Stoplist|where{(get-date -date $_.'stop date') -lt $CurrentDate}) ){...}
But without brackets around $User in $Stoplist the pipe | only refers to the last object $Stoplist

Powershell variable in file name

Everyday a file is being saved with the current date in format testDDMMYYY.csv for an example test24112017.csv.
I need to open the current day's file with Powershell, however, I haven't found a way for it to work with variables.
#Date (24112017)
[String]$a=(Get-Date).ToShortDateString() | Foreach-Object {$_ -replace "\.", ""}
#Open the file called test24112017
[int] $S1=Get-Content "D:\test$($a).csv" -Tail 1 | Foreach-Object {$_ -replace "`"", ""} | ForEach-Object{$_.Split(",")[1]} | write-host
How can I get that variable working inside that path?
Do not use (Get-Date).ToShortDateString() | Foreach-Object {$_ -replace "\.", ""}, just use Get-Date -Format 'ddMMyyyy' to format the date the way you want :
Get-Content "D:\test$(Get-Date -Format 'ddMMyyyy').csv" -Tail 1
Formatting Dates and Times
Hmm aren't you over-complicating things a bit?
First of all,
(Get-Date).ToShortDateString() doesn't give me 24112017 but 24-11-2017.
So i'm guessing we have different regional settings, what part of the world are you from?
Have you printed out $a? What does it give you?
I would go for a different approach. Since your filename is literally always newer than the previous one (because it holds a date).
I would just sort on the Name and select the first one (aka the newest file).
$newestfile = Get-ChildItem c:\temp | Sort-Object Name -Desc | select * -First 1
Now go do whatever you want with your latest file.
get-content $newestfile.fullname