powershell
coding
3 min reading time
Finding the specific day of the month with powershell could be a pretty common thing. Finding the first, second, third, or last weekday of the month is simpler than we might think.
For a recent process I was needing to run a process on the 10th of the month but if it was a weekend, send it the Friday before.
Getting started
As I started the coding process I thought, this would just make more sense if I ran this on the first Friday of the month. I was going to use Windows Task Scheduler to run the final process every day and had the script to the deciding of the right day. Task Scheduler failed to provide such scheduled timing.
Trying a few things first, I then found a few approaches that worked, but were complicated in achieving the final result.
= DateTimeYear Month ::DaysInMonthYear Month = ::Friday DayOfWeek 0 AddDays 7- AddDays While this might work, there’s a lot of math involved. After creating a DateTime object, you find the number of days in the month, and do a lot of math. The other issue I had, I was wanting to find the first Friday, or second Tuseday, etc.
Returns the date of the requested day of the month.
This function will return the date for searches such as the third Tuesday of July 2018 or the Second Friday in August 2002.
What day to find: First, Second, Third, Fourth, Last. (Numbers 1-5 are also valid, 1 being First 5 being last.)
What day of the week to look for: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday.
The month to search. 1-12.
The four digit year to search.
None, returns a date object.
Find the second Tuesday of January 2020
Get-XDayOfMonth -Find Second -Weekday Tuesday -Month 1 -Year 2020
Find the last Monday of July 2017
Get-XDayOfMonth -Find Last -Weekday Monday -Month 7 -Year 2017
Find the first Friday of June 2020
Get-XDayOfMonth -Find First -Weekday Friday -Month 6 -Year 2020
Cast $Find to an integer so it’s easy to work with.
Find all days in the given month that match $Weekday
There aren’t 32 days in any month so we make sure we iterate through all days in a month
If we found fewer matching days than we are seeking, subtract 1 from $intFind.
For example, if there are only four Mondays in a month, not Five.
Put the result on the PowerShell pipeline.
Condition d’execution
Update not allowed the 1 and 2 of each month
Update not allowed Monday
Reboot allowed only between 02:00AM <=> 04:00AM
— Cleaning locked update —
HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending
HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress
HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending
Added test to check first if key exists, using “ErrorAction ignore” will incorrectly return $true
Added test to check first if keys exists, if not each group will return $Null
May need to evaluate what it means if one or both of these keys do not exist
Added test to check first if key exists
— Running Windows Update —
IsInstalled=0 and Type=’Software’ and AutoSelectOnWebSites=1
List of applicable items on the machine:
There are no applicable updates.
Reboot system now !!
List of downloaded updates:
All updates are already downloaded.
Not ready for installation.
All updates installed successfully.
Some updates could not installed.
One or more updates are requiring reboot.
Reboot system now !!
Finished. Reboot are not required.
I want a Skript that checks if the current weekday is in a file in german with multiple weekdays.
I can just ckeck in i enter the Weekdays directly in a variable like this:
# Pfad zur Datei
$dateiPfad = "D:\Scriptz\RunDay.txt"
# Gesuchtes Wort
$gesuchtesWort = "Mittwoch"
# Lese die Wörter aus der Datei
$inhalt = Get-Content -Path $dateiPfad
$woerterListe = $inhalt -split ','
# Überprüfe, ob das gesuchte Wort in der Liste ist
if ($woerterListe -contains $gesuchtesWort) { Write-Host "Das Wort '$gesuchtesWort' wurde in der Datei gefunden."
} else { Write-Host "Das Wort '$gesuchtesWort' wurde nicht in der Datei gefunden."
}but if i use something like this:
#get german weekday
$deutscheKultur = New-Object System.Globalization.CultureInfo "de-DE"
$heute = Get-Date
$deutscherWochentag = $heute.ToString("dddd", $deutscheKultur)
#test if var is correct until now
Write-Host "Der heutige Wochentag ist: $deutscherWochentag"
#Weekday file path
$dateiPfad = "D:\Scriptz\RunDay.txt"
# read content of file and split
$wochentagAusDatei = Get-Content -Path $dateiPfad
$wochentageListe = $wochentageInDatei -split ','
#testcomparison
if ($wochentageListe -contains $wochentagAusDatei) { # Führen Sie hier Ihr Skript oder Ihre Befehle aus Write-Host "Heute ist $wochentagAusDatei. Das Skript wird ausgeführt."
} else { Write-Host "Heute ist nicht $wochentagAusDatei. Das Skript wird nicht ausgeführt."
}the output i get is the german weekdav is getting correct,
but here it seems it cant use if ($wochentageListe -contains $wochentagAusDatei) here both vars n ot with each other.
I found something, that the weekdays from the file has to be converted into get date fornmat, but i couldnt find an example how i could convert a list of weekdays – just single dates.
Thank you in advance!
Modifies active full backup schedule for Veeam Agent backup jobs.
: Community, Standard, Enterprise, Enterprise Plus, Veeam Universal License
- Compact full backup schedules
- Active full backup schedules
To modify settings, specify new values for the necessary parameters. The cmdlet will overwrite the previous parameter values with new values. The parameters that you omit will remain unchanged. |
Accept Pipeline Input | |||||
|---|---|---|---|---|---|
Specifies the active full backup schedule that you want to modify. | object. To get this object, run the New-VBRFullBackupOptions | ||||
Enables the option for the Veeam Agent backup job to create active full backups. | |||||
Specifies the type of active full backup schedule.
| |||||
For weekly full backups. Specifies the day of the week when active full backups will be created. | |||||
For monthly backups. Specifies the day of the month when active full backups will be created (for example, Saturday):
| |||||
For monthly backups. Specifies the day of the week, when the job creates active full backups. | |||||
For monthly backups with the Specifies the day of the month, when the job creates active full backups. For example, on the 3rd day of November. | |||||
Specifies the months, when the job creates active full backups. |
This cmdlet returns the object that contains schedule for backup jobs.
Modifying Active Full Backup Schedule from Weekly to Monthly
This example shows how to modify an active full backup schedule. Veeam Backup & Replication will change the schedule from weekly to monthly.
$activefull = New-VBRFullBackupOptions -Enable -ScheduleType Weekly -SelectedDays Sunday, Wednesday
Set-VBRFullBackupOptions -Options $activefull -Enable -ScheduleType Monthly -DayNumber OnDay -DayOfWeek Friday
- New-VBRFullBackupOptions cmdlet. Provide the parameter. Specify the parameter values. Save the result to the
- Run the Set-
- variable as the
- option for the
- option for the
- option for the
Modifies advanced job backup settings.
: VMware, Hyper-V
: Standard, Enterprise, Enterprise Plus, Veeam Universal License
This cmdlet modifies advanced backup options of a selected job.
You can select backup method: reverse incremental or incremental, and set schedule settings for synthetic full backups.
To modify settings, specify new values for the necessary parameters. The cmdlet will overwrite the previous parameters values with new values. The parameters that you omit will remain unchanged. |
Specifies the array of jobs. The cmdlet will modify advanced backup options of these jobs. | |||||
Specifies backup method:
: To enable forever forward incremental backup method, disable the | |||||
For incremental backup method. Defines whether the job will create a full synthetic backup. parameter to set the days to perform the synthetic full backups. | |||||
For synthetic full schedule. Specifies the active full backup schedule type:
| |||||
For synthetic full schedule. Specifies days when the job will perform the synthetic fulls: | |||||
For synthetic full schedule: Specifies months to perform the synthetic full backup: | |||||
Specifies the day of week to run the backup job: Use this parameter to set the day for the parameter, for example, to run the job on first Saturday every month. | |||||
For synthetic full schedule: parameter set to Specifies the day of month to perform an active full backup. | |||||
Specifies the number of day in month (for example, Saturday):
| |||||
Defines whether the job will create active full backups. parameters to set the full backup schedule. | |||||
For active full schedule: Specifies days when the job will perform the active full backup: | |||||
For active full schedule. Specifies the active full backup schedule type:
| |||||
For active full schedule: Specifies months to perform the full backup: | |||||
For active full schedule: Specifies the number of day in month (for example, Saturday):
| |||||
For active full schedule: Specifies the day of month to perform an active full backup. | |||||
Sets backup schedule. Specifies the day of week to run the backup job: Use this parameter to set the day for the parameter, i.e. to run the job on first Saturday every month. |
- The backup algorithm is set to
- The active full backup schedule is set to
$job = Get-VBRJob -Name “Backup Job”
- Get-VBRJob cmdlet. Specify the Name parameter value. Save the result to the
- Pipe the cmdlet output to the cmdlet. Set the option for the parameter. Set the option for the
- The backup algorithm is set to
- The synthetic full backup is enabled on every
- The active full backup schedule is set to every second Sunday monthly
- Get-VBRJob cmdlet. Specify the
- Pipe the cmdlet output to the
- option for the
- value for the
- value for the
- option for the
- option for the
Example PowerShell code to generate paydays and holidays with or without full calendar. The Holiday function could be shorter and more elegant, but it works for my needs.
<#
Basic functions to get bi-weekly pay and major holidays.
May need alterations on Windows or Mac. I am on Linux.
Author: C. Nichols
#>
function Get-Paydays () { param ( [int]$FirstPayMonth = 1, [int]$FirstPayDay = 12, [int]$Year = 2024 ) $WeekNum = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6 } if (-not($Year)) { $CurrentYear = (Get-Date).Year } else { $CurrentYear = $Year } $FirstPayOfYear = Get-Date -Year $CurrentYear -Month $FirstPayMonth -Day $FirstPayDay $EndOfYear = Get-Date -Year $CurrentYear -Month 12 -Day 31 $CurrentDate = $FirstPayOfYear $Paydays = New-Object -TypeName "System.Collections.ArrayList" While ($CurrentDate -lt $EndOfYear) { If ($CurrentDate.DayOfWeek -eq 'Friday') { $MonthName = (Get-Culture).DateTimeFormat.GetMonthName($CurrentDate.Month) $DayName = $CurrentDate.DayOfWeek.ToString() $PayDate = [PsCustomObject]@{ MonthName=$MonthName; Month=$CurrentDate.Month; WeekIndex=$WeekNum[$DayName]; DayName=$DayName; Day=$CurrentDate.Day; Year=$CurrentYear; Desc="payday" } $Paydays += $PayDate } $CurrentDate = $CurrentDate.AddDays(14) } return $Paydays
}
function Get-Holidays() { PARAM ( [int]$Year=2024 ) $WeekNum = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6 } $FIXED_HOLIDAYS = @{12=@{25="Christmas Day"}; 1=@{1="New Year's Day"}; 6=@{19="Juneteenth"}; 7=@{4="Independence Day"}; 11=@{11="Veteran's Day"} } $HOLIDAYS = @{1=@{3="Martin Luther King, Jr.Birthday"}; # 3rd Monday in Jan. 2=@{3="President's Day"}; # 3rd Monday in Feb. (President's Day) #5="memorial"; # Last Monday in May. Handled separately. 9=@{1="Labor Day"}; # 1st Monday in Sept. 10=@{2="Columbus Day"}; # 2nd Monday in Oct. 11=@{4="Thanksgiving"} # 4th Thursday in Nov. } $HolidayCalendar = @{} $Calendar = @{} $Rows = New-Object -TypeName "System.Collections.ArrayList" if (-not($Year)) { $Year = (Get-Date).Year } # Link month name to day names for year. ForEach ($Month in 1..12) { $DaysInMonth = [datetime]::DaysInMonth($Year,$Month) ForEach ($Day in 1..$DaysInMonth) { $DateObject = Get-Date -Year $Year -Month $Month -Day $Day $DayName = $DateObject.DayOfWeek if (-not($Calendar.ContainsKey($Month))) { $Calendar[$Month] = @{} } $Calendar[$Month][$Day] = $DayName } } # Get a increamental count of each weekday in month. $MonthKeys = $Calendar.Keys ForEach ($MonthKey in $MonthKeys | Sort-Object) { $DayHash = $Calendar[$MonthKey] $MonCount = 0 $MemArray = @() $DayKeys = $DayHash.Keys ForEach ($DayKey in $DayKeys | Sort-Object) { $MonthDays = $DayHash[$DayKey] $Holiday = "" if ($FIXED_HOLIDAYS.ContainsKey($MonthKey)) { $Holiday = $FIXED_HOLIDAYS[$MonthKey][$DayKey] } if ($MonthDays -eq "Monday") { $MonCount += 1 if ($HOLIDAYS.ContainsKey($MonthKey)) { if ($HOLIDAYS[$MonthKey].ContainsKey($MonCount)) { $Holiday = $HOLIDAYS[$MonthKey][$MonCount] } } } if ($MonthKey -eq 5) { if ($MonthDays -eq "Monday") { $MemArray += $DayKey } } if (-not($HolidayCalendar.ContainsKey($MonthKey))) { $HolidayCalendar[$MonthKey] = @{} } if (-not($HolidayCalendar[$MonthKey].ContainsKey($DayKey))) { $HolidayCalendar[$MonthKey][$DayKey] = "" } $HolidayCalendar[$MonthKey][$DayKey] = $Holiday } if ($MemArray[-1]) { $Memday = $MemArray[-1] $HolidayCalendar[5][$Memday] = "Memorial Day" } } $MthKeys = $HolidayCalendar.Keys ForEach ($mk in $MthKeys | Sort-Object) { $MonthName = (Get-Culture).DateTimeFormat.GetMonthName($mk) #Write-Host $MonthName $DayKeys = $HolidayCalendar[$mk].Keys ForEach ($dk in $DayKeys | Sort-Object) { $DateObject = Get-Date -Year $Year -Month $mk -Day $dk $DayName = $DateObject.DayOfWeek.ToString() $HolidayDesc = $null if ($HolidayCalendar[$mk][$dk]) { $HolidayDesc = $HolidayCalendar[$mk][$dk] } if ($DayName -eq "Saturday") { $DateObject = $DateObject.AddDays(-1) $DayName = $DateObject.DayOfWeek.ToString() } if ($DayName -eq "Sunday") { $DateObject = $DateObject.AddDays(1) $DayName = $DateObject.DayOfWeek.ToString() } $Columns = [PsCustomObject]@{ MonthName=$MonthName; Month=$mk; WeekIndex=$WeekNum[$DayName]; DayName=$DayName; Day=$dk; Year=$Year; Desc=$HolidayDesc } $Rows += $Columns } } return $Rows
}
<# Main :: Merge and offset clashes.
#>
$WeekNum = @{ Sunday=0; Monday=1; Tuesday=2; Wednesday=3; Thursday=4; Friday=5; Saturday=6
}
$MergedRows = @()
$DateHash = @{}
# Ge major holidays.
$MyHolidays = Get-Holidays #-Year 2026
$MyPaydays = Get-Paydays #-Year 2026 -FirstPayMonth 1 -FirstPayDay 9
ForEach ($p in $MyPaydays) { $Pdate = Get-Date -Year $p.Year -Month $p.Month -Day $p.Day if (-not($DateHash.ContainsKey($Pdate.Date))) { $DateHash[$Pdate.Date] = $p }
}
ForEach ($h in $MyHolidays) { if ($h.Desc) { $Hdate = Get-Date -Year $h.Year -Month $h.Month -Day $h.Day if (-not($DateHash.ContainsKey($Hdate.Date))) { $DateHash[$Hdate.Date] = $h } else { $Pdate = Get-Date -Year $DateHash[$Hdate.Date].Year -Month $DateHash[$Hdate.Date].Month -Day $DateHash[$Hdate.Date].Day $Pdate = $Pdate.AddDays(-1) $MonthName = (Get-Culture).DateTimeFormat.GetMonthName($Pdate.Month) $DayName = $Pdate.DayOfWeek.ToString() $Column = [PsCustomObject]@{ MonthName=$MonthName; Month=$Pdate.Month; WeekIndex=$WeekNum[$DayName]; DayName=$DayName; Day=$Pdate.Day; Year=$Pdate.Year; Desc="payday" } $DateHash[$Hdate.Date] = $h $DateHash[$Pdate.Date] = $Column } }
}
# create report.
$ReportRows = @()
$DateKeys = $DateHash.Keys
ForEach ($mdate in $DateKeys | Sort-Object) { Write-Host $DateHash[$mdate] $ReportRows += $DateHash[$mdate]
}
# Save as CSV.
#$ReportRows | Export-Csv -Path "~/PrCal.csv" -NoTypeInformation
<# OUTPUT
@{MonthName=January; Month=1; WeekIndex=1; DayName=Monday; Day=1; Year=2024; Desc=New Year's Day}
@{MonthName=January; Month=1; WeekIndex=5; DayName=Friday; Day=12; Year=2024; Desc=payday}
@{MonthName=January; Month=1; WeekIndex=1; DayName=Monday; Day=15; Year=2024; Desc=Martin Luther King, Jr.Birthday}
@{MonthName=January; Month=1; WeekIndex=5; DayName=Friday; Day=26; Year=2024; Desc=payday}
@{MonthName=February; Month=2; WeekIndex=5; DayName=Friday; Day=9; Year=2024; Desc=payday}
@{MonthName=February; Month=2; WeekIndex=1; DayName=Monday; Day=19; Year=2024; Desc=President's Day}
@{MonthName=February; Month=2; WeekIndex=5; DayName=Friday; Day=23; Year=2024; Desc=payday}
@{MonthName=March; Month=3; WeekIndex=5; DayName=Friday; Day=8; Year=2024; Desc=payday}
@{MonthName=March; Month=3; WeekIndex=5; DayName=Friday; Day=22; Year=2024; Desc=payday}
@{MonthName=April; Month=4; WeekIndex=5; DayName=Friday; Day=5; Year=2024; Desc=payday}
@{MonthName=April; Month=4; WeekIndex=5; DayName=Friday; Day=19; Year=2024; Desc=payday}
@{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=3; Year=2024; Desc=payday}
@{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=17; Year=2024; Desc=payday}
@{MonthName=May; Month=5; WeekIndex=1; DayName=Monday; Day=27; Year=2024; Desc=Memorial Day}
@{MonthName=May; Month=5; WeekIndex=5; DayName=Friday; Day=31; Year=2024; Desc=payday}
@{MonthName=June; Month=6; WeekIndex=5; DayName=Friday; Day=14; Year=2024; Desc=payday}
@{MonthName=June; Month=6; WeekIndex=3; DayName=Wednesday; Day=19; Year=2024; Desc=Juneteenth}
@{MonthName=June; Month=6; WeekIndex=5; DayName=Friday; Day=28; Year=2024; Desc=payday}
@{MonthName=July; Month=7; WeekIndex=4; DayName=Thursday; Day=4; Year=2024; Desc=Independence Day}
@{MonthName=July; Month=7; WeekIndex=5; DayName=Friday; Day=12; Year=2024; Desc=payday}
@{MonthName=July; Month=7; WeekIndex=5; DayName=Friday; Day=26; Year=2024; Desc=payday}
@{MonthName=August; Month=8; WeekIndex=5; DayName=Friday; Day=9; Year=2024; Desc=payday}
@{MonthName=August; Month=8; WeekIndex=5; DayName=Friday; Day=23; Year=2024; Desc=payday}
@{MonthName=September; Month=9; WeekIndex=1; DayName=Monday; Day=2; Year=2024; Desc=Labor Day}
@{MonthName=September; Month=9; WeekIndex=5; DayName=Friday; Day=6; Year=2024; Desc=payday}
@{MonthName=September; Month=9; WeekIndex=5; DayName=Friday; Day=20; Year=2024; Desc=payday}
@{MonthName=October; Month=10; WeekIndex=5; DayName=Friday; Day=4; Year=2024; Desc=payday}
@{MonthName=October; Month=10; WeekIndex=1; DayName=Monday; Day=14; Year=2024; Desc=Columbus Day}
@{MonthName=October; Month=10; WeekIndex=5; DayName=Friday; Day=18; Year=2024; Desc=payday}
@{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=1; Year=2024; Desc=payday}
@{MonthName=November; Month=11; WeekIndex=1; DayName=Monday; Day=11; Year=2024; Desc=Veteran's Day}
@{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=15; Year=2024; Desc=payday}
@{MonthName=November; Month=11; WeekIndex=1; DayName=Monday; Day=25; Year=2024; Desc=Thanksgiving}
@{MonthName=November; Month=11; WeekIndex=5; DayName=Friday; Day=29; Year=2024; Desc=payday}
@{MonthName=December; Month=12; WeekIndex=5; DayName=Friday; Day=13; Year=2024; Desc=payday}
@{MonthName=December; Month=12; WeekIndex=3; DayName=Wednesday; Day=25; Year=2024; Desc=Christmas Day}
@{MonthName=December; Month=12; WeekIndex=5; DayName=Friday; Day=27; Year=2024; Desc=payday}
#>Future plans
The process so far looks at the current month and the specific days. If we’d like to look at a future month, we can do that as well. PowerShell lets us pass a month to the Get-Date function and get the date accordingly.
Month 08 Day 1
Thursday August 1 2024 1:09:03 PMNow to apply this we can make a few adjustments along the way. We need to update the Get-Date to pass the month and day, this is also setting the starting point for our monthly date lookup.
031 Month 08 Day 1AddDays?DayOfWeek
Friday August 2 2024 1:09:03 PM
Friday August 9 2024 1:09:03 PM
Friday August 16 2024 1:09:03 PM
Friday August 23 2024 1:09:03 PM
Friday August 30 2024 1:09:03 PMWrap-up
After going through this date finding excursion, I learned some new neat tricks you can do with Get-Date and manipulating the object data for what I need.
Another awesome module I came across was the PSCalendar and the Show-Calendar function.
May 2024 Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Getting closer
Later on I found a simpler solution. Each month has max of 31 days. So loop over each day, have Get-Date add 1 day, then select the object where the day is the one I’m looking for.
031 AddDays?DayOfWeek
Friday May 3 2024 1:09:03 PM
Friday May 10 2024 1:09:03 PM
Friday May 17 2024 1:09:03 PM
Friday May 24 2024 1:09:03 PM
Friday May 31 2024 1:09:03 PMSince this returns and array, we can select the index we want. We pass along 0..31 and for each number we add that number to the Get-Date of today. Next we can select the day of the week we’d like, Friday, in this case.
031 AddDays?DayOfWeek First 1
Friday May 3 2024 1:09:03 PM
031 AddDays?DayOfWeek Last 1
Friday May 31 2024 1:09:03 PMIf we would like the third Friday we can get that as well!
031 AddDays?DayOfWeek 2
Friday May 17 2024 1:09:03 PM

