assign current time to powershell variable - powershell

I pieced together a PowerShell script that is triggered (via Task Scheduler) every time the computer restarts.
The script will do the following:
Find a csv file located in a specific directory
Rename the file by appending a time/date stamp to the end
Move that file into an archive folder
During the day a software application automatically creates a new csv file. So next time the computer reboots, it repeats the steps above.
Final step - the script also looks in the archive folder and deletes any files which are > 7 days old.
Sometimes (not all the time) when the computer restarts and the script runs, it completes steps 1 and 2 but not step 3.
And so what this means is the csv file is renamed but the script did NOT move it into the archive folder.
Why?
I open the script in PowerShell ISE and run the script manually and I see the reason why:
A file with that name already exists in the archive folder.
How can that happen if the file name is always dynamically renamed using a date/time stamp (down to the second).
Turns out the variable which is assigned the value of Get-Date is not updated.
It still contains the old time.
Why does this happen if the very first thing I do in my PowerShell script is this:
$rightNow = Get-Date
I know it's not best practice to assign the current date and time to a variable and obviously the variable is not going to update itself as every second goes by. That's fine. I don't need it to. What I DO expect it to do is grab the current date and time (at the time this line of code runs) and assign it to my variable called $rightNow.
For some reason the variable is not getting updated.
Why does this happen? What's the best way for me to quickly grab the current date and time (down to the second) and use it as part of a file name?
Here is my current script:
$source = "C:\Logs"
$destination = "C:\Logs\archive"
$old = 7
$rightNow = Get-Date
# delete all files in the archive folder that are > 7 days old
Get-ChildItem $destination -Recurse |
Where-Object {-not $_.PSIsContainer -and
$rightNow.Subtract($_.CreationTime).Days -gt $old } |
Remove-Item
# rename all csv files in the Log folder by appending currentDate_currentTime
Get-ChildItem -Path $source\* -Include *.csv | % {
$name = $_.Name.Split(".")[0] + "_" + ($_.CreationTime | Get-Date -Format yyyyMMdd) + "_" + ($_.CreationTime | Get-Date -Format hhmmss) + ".csv"
Rename-Item $_ -NewName $name
Move-Item "$($_.Directory)\$name" -Destination $destination
}

You don't use the current date in the rename, you use the file's CreationTime property. If you want the current datetime try
$name = $_.BaseName + [datetime]::now.ToString('_yyyyMMdd_hhmmss') + $_.Extension
Or better yet just perform the rename as part of the move process.
$source = "C:\Logs"
$destination = "C:\Logs\archive"
$old = 7
# delete all files in the archive folder that are > 7 days old
Get-ChildItem $destination -Recurse -File |
Where-Object { $_.CreationTime -lt [datetime]::Today.AddDays(-$old) } |
Remove-Item
# rename all csv files in the Log folder by appending currentDate_currentTime
Get-ChildItem -Path $source\* -Include *.csv | % {
$_ | Move-Item -Dest $("$destination\" + $_.BaseName + [datetime]::now.ToString('_yyyyMMdd_hhmmss') + $_.Extension)
}

Related

PowerShell partial zip file name

Currently I have a code that extracts a zip file that is uploaded nightly and it has the name CallRecording_1-000-XXXXXXXX the X's represent the date and time that the zip file was generated. What I would like to do is have a powershell script that looks for the partial name. So for example it would look for just CallRecording_1-000 or CallRecording.
At the moment I have the following script:
#expand archive into folder
expand-archive ("Y:\CallRecording_1-000.zip") -destinationPath $folder
#rename zip file with yesterdays date
$yesDateName = $yesDate + ".zip"
Rename-Item "Y:\CallRecording_1-000.zip" -NewName $yesDateName
The scripts that I have found previously that use partial names seems to focus mostly on the extension rather than the name itself.
Any help would be appreciated!
It sounds like you only expect 1 zip file however I tailored this answer around the possibility of having more than 1
We are going to use Get-ChildItem to get any zip files from y:\ that match 'CallRecordings*.zip'
We then pipe these files one at a time to the ForEach-Object cmdlet where we
assign the extraction folder
unzip the file
and then rename the file.
$i is used to allow us different names for our renamed zip file in case there are more than 1 being processed.
$i = 0
Get-ChildItem -Path 'Y:\' -Filter 'CallRecording*.zip' | ForEach-Object -Process {
$extractFolder = "C:\temp\$($_.BaseName)"
$_ | Expand-Archive -DestinationPath $extractFolder
# ($? tells us if the last command completed successfully)
if ($?) {
# only rename file if Expand-Archive was successful
$_ | Rename-Item -NewName ((Get-Date).AddDays(-1).ToString('yyyyMMdd') + "_$((++$i)).zip")
}
}

Powershell Script to clean up logs on a Monthly Basis

Powershell newbie here again with another question.
We currently have a log folder accumulating text files. My supervisor would like for me to create a script where only the current month's logs are visible. All previous months should be moved to an archive folder. He would like for me to create a powershell script we can run once a month to achieve this.
For example, our log folder should only have logs from January 2021. Anything older than January 2021 should be archived. Once February 1, 2021 hits, all the logs from January 2021 should be moved to the archive folder, and so on.
How can I achieve a script that looks at the folder and only keeps the logs for the current month? Any guidance, resources, videos, etc are greatly appreciated! I've been scouring the internet for resources, but I haven't quite found anything that suits my needs.
Update: Was able to find a wonderful script here: PowerShell: Sort and Move Files by Date to month and year provided by Thomas Maurer (all credit to him!)
# Get the files which should be moved, without folders
$files = Get-ChildItem 'C:\Users\testuser\Desktop\log' -Recurse | where {!$_.PsIsContainer}
# List Files which will be moved
$files
# Target Filder where files should be moved to. The script will automatically create a folder for the year and month.
$targetPath = 'C:\Users\testuser\Desktop\log\archive'
foreach ($file in $files)
{
# Get year and Month of the file
# I used LastWriteTime since this are synced files and the creation day will be the date when it was synced
$year = $file.LastWriteTime.Year.ToString()
$month = $file.LastWriteTime.Month.ToString()
# Out FileName, year and month
$file.Name
$year
$month
# Set Directory Path
$Directory = $targetPath + "\" + $year + "\" + $month
# Create directory if it doesn't exsist
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
# Move File to new location
$file | Move-Item -Destination $Directory
}
What I would like to achieve now: This script works great, but I am trying to tinker with it so I can move everything EXCEPT the current month. I'm still researching and investigating, so I will make sure to update my post if I am able to figure out this missing piece for me. Thank you all for your help!
One approach to leave the files that were last modified in this month is to use a small helper function that formats the LastWriteTime date into a string yyyy\MM.
function Format-YearMonth ([datetime]$date) {
# simply output a string like "2021\01"
return '{0:yyyy\\MM}' -f $date
}
$sourcePath = 'C:\Users\testuser\Desktop\log'
$targetPath = 'C:\Users\testuser\Desktop\log\archive'
$thisMonth = Format-YearMonth (Get-Date)
# Get the files which should be moved, without folders
# this can be more efficient if all files have the same extension on which
# you can use -Filter '*.log' for instance.
Get-ChildItem -Path $sourcePath -File -Recurse |
# filter out the files that have a LastWriteTime for this year and month
Where-Object {(Format-YearMonth $_.LastWriteTime) -ne $thisMonth } |
ForEach-Object {
# Set destination Path
$Directory = Join-Path -Path $targetPath -ChildPath (Format-YearMonth $_.LastWriteTime)
# Create directory if it doesn't exsist
if (!(Test-Path $Directory)) {
$null = New-Item $Directory -type Directory
}
Write-Host "Moving file '$($_.FullName)' to '$Directory'"
# Move File to new location
$_ | Move-Item -Destination $Directory -Force
}

Copy file from directories with today's date to another location

AD Manager Plus generates reports hourly to a time stamped file path and I would like to copy these files to another location - overwriting the existing file. I will then schedule the script to run hourly after the files have been generated. Unfortunately the location the reports are extracted to cannot be modified and it creates date & time stamped folders.
Example:
C:\ADManager Plus\audit-data\reports\16042019\DailyTrue-Up01-55-07\Real Last Logon.xls
C:\ADManager Plus\audit-data\reports\ddmmyyyy\DailyTrue-Uphh-mm-ss\Real Last Logon.xls
I thought the easiest approach would be to:
Get the last modified folder in the Reports Folder - eg Apr162019
Get the last modified folder in the Apr162019 Folder - eg DailyTrue-Up01-55-07
Filter for the Real Last Logon.xls spreadsheet in folder DailyTrue-Up01-55-07
$Path = "C:\ADManager Plus\audit-data\reports"
$DestinationPath = "\\domain\networkshare\Reports\"
Get-ChildItem -Path $Path -Directory | ForEach-Object {
Get-ChildItem -Path "$Path\$_" -File -Filter "Real Last Logon.xlsx" |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 |
Copy-Item -Force -Destination (New-Item -Force -Type Directory -Path (Join-Path $DestinationPath ($_.FullName.Replace("$Path\", ''))))
}
The code we have seems to copy all folders to the location and can't look in multiple directories.
I got a feeling we are approaching this wrong, Can anyone suggest the best way to achieve this? There are few posts online that explain how to retrieve files from time stamped folders.

PowerShell - Move file, Rename & Rotate

I am fairly new to powershell and still learning. I have completed my first script and now trying to add some logging into it. I am able to append to log file OK but stuck on backing up the log and rotating it. This is what I have so far
$CheckFile = Test-Path $Logfilepath
IF ($CheckFile -eq $false) {
$Date = (Get-Date).tostring()
$Date + ' - Automonitor log created - INFO' | Out-File -Append -Force $Logfilepath }
Else {
IF ((Get-Item $Logfilepath).length -gt $Size) {
Move-Item $Logfilepath -Destination $LogsOldFolder -Force}
}
This is where I am stuck. If the file is bigger than 5MB I need it to move to another folder (which I have in the script) but when moved into that folder I only want to keep the 5 newest files to avoid storage issues. I will need the files named like the below.
Automonitor.log.1
Automonitor.log.2
Automonitor.log.3
Automonitor.log.4
Automonitor.log.5
Automonitor.log.1 being the newest created file. So I am really baffled on the process I would take and how to rename the files to match the above format and when new file is copied over, to rename all of them again dependent on date created and deleting the oldest so only 5 files ever exist.
I hope that makes sense, if anyone has any ideas that would be great.
You can go this way:
$a = gci $destfolder
if ( $a.count -gt 5)
{
$a | sort lastwritetime | select -first ($a.count - 5) | remove-item
}
This will get you every file older than the first 5.
So, this script doesnt care about the filenames. If you want that, you should Change the $a = gci $destfolder part to some Wildcards.

Moving every n files into a separate folder

I have several files with a repetitive naming convention, e.g.
1*Intro*
2*
3*
…
10*intro*
….
I want to move each module into a separate folder. So, I should separate from every *intro* till the next one.
Also, I should note that files are numbered and sorted.
I guess, the easiest way to do this is to:
1. Get a list of intros.
2. Separate their numbers.
3. Start moving files starting from one number till their smaller than the next one.
$i = 1
Ls *intro* | ft {$_.name -replace '\D.*', ''}
// The reason for .* is that the files are `mp4`.
Ls * | ? {$_.name -match '[^firstNumber-SecondNumber-1]'} | move-item -literalpath {$_.fullname} -destination $path + $i++ + '/' +{$_.name}
So the last command should be something like:
Ls *intro* | % { ls * | ? {…} | move-item … }
Or maybe the move-item itself can do the filtering job.
The regular expression doesn't work and I don't have enough Powershell knowledge to write anything better. Can you think of any script to do that? Also how should I permit move-item to create the folder?
I'll be thankful if someone could edit this post with a better title.
This could be done with a simple Switch. The switch will be run against all items in the current folder (items gotten with the Get-ChildItem cmdlet which you use by it's alias 'LS'). It looks to see if the file has the string "Intro" in the file name. If it does, it creates a new folder with that file's name, and stores that folder's info in the $TargetFolder variable (variable created previously to avoid scoping issues). It then moves the file to that folder, and continues to the next file. If the file does not have "Intro" in its file name it simply moves the file to whatever the last assigned $TargetFolder is that was created.
$TargetFolder = ""
Switch(Get-ChildItem .\*){
{$_.BaseName -match "intro"} {$TargetFolder = New-Item ".\$($_.BaseName)" -ItemType Directory; Move-Item $_ -Destination $TargetFolder; Continue}
default {Move-Item $TargetFolder}
}