I have created two functions in the Powershell script as below.
$date = Get-date
Write-Output $date.ToString("dd_MM_yyyy")
Function Oneday{
Param ($Name)
Write-Output "This funtion will run everyday"
}
Function Fiveday{
Param ($Name)
Write-Output "This funtion will run every 5 days"
}
My goal is to put this PowerShell script as a task scheduler and run the function 'Oneday' every day and function 'Fiveday' every 5 days. I tried to think of many ways by using function AddDays and all but couldn't get how can I achieve this task.
Use the modulo/remainder operator (%) on the value of the DayOfYear property of the current date to only run on every 5th day:
$date = Get-date
# Run every day
Oneday
if($date.DayOfYear % 5 -eq 0){
# Only every 5th day
Fiveday
}
To carry over multiple years, anchor against a starting date in the past:
$start = Get-Date 2020-01-01
$date = Get-date
# Run every day
Oneday
if(($date - $start).Days % 5 -eq 0){
# Only every 5th day
Fiveday
}
Related
I've created a script to stop and run some custom services we run on one of our servers. I want to stop the services at 5 pm (17:00) and then start them at 2 am (02:00). But on Friday I wanted the services to run past 5 pm and they're stopped at 1 am on Saturday.
I wrote the below script. I'm still new to PowerShell scripts. I used a switch case to execute the functions but I think there must be a better way to achieve this.
# PowerShell script to stop and start services.
# Variable assignement
$OnOffSwitch = Get-Date -Format 'dddd_HH:mm';
$ServiceNames = #('CAPS8','CAPS9'); # Array to store service names.
function serivcesOff {
# Checks the all the service in the above $serviceNames.
foreach ($SeviceName in $ServiceNames) {
# Check for service status if stopped this will start it and goes throug the loop again.
# until status matches running.
if ((Get-Service -Name $ServiceName).Status -eq "Running") {
do{
Start-Service $ServiceName
Start-Sleep -Seconds 20
} until ((Get-Service $ServiceName).Status -eq "Stopped")
} Return "$($ServiceName) has been shutdown."
}
}
function serviceOn{
# Checks the all the service in the above $serviceNames.
foreach ($SeviceName in $ServiceNames) {
# Check for service status if stopped this will start it and goes throug the loop again.
# until status matches running.
if ((Get-Service -Name $ServiceName).Status -eq "Stopped") {
do{
Start-Service $ServiceName
Start-Sleep -Seconds 20
} until ((Get-Service $ServiceName).Status -eq "Running")
} Return "$($ServiceName) has been turned on."
}
}
#søndag - Sunday,
#mandag - Monday,
#tirsdag - Tuesday
#onsdag - Wednesday,
#torsdag - Thursday,
#fredag - Friday,
#lørdag - Saturday
Switch ($OnOffSwitch){
'mandag_02:00' {serviceOn}
'mandag_17:00' {serivcesOff}
'tirsdag_02:00' {serviceOn}
'tirsdag_17:00' {serviceOff}
'onsdag_02:00' {serviceOn}
'onsdag_17:00' {serviceOff}
'torsdag_02:00' {serviceOn}
'lørdag_01:00' {serviceOff}
default {Write-Output "Nothing matched"}
}
Is this the best way or should I have used if ... else if ... else statements? Is there a better way?
Basically what stackprotector said. Using the native task scheduler would be the easiest way. Anyway, here are some tips to improve your code. I would normally put them into comments, but it wouldn’t fit:
In the function servicesOff you check if the status is running and if it is you Start-Service. I think you wanted to use Stop-Service here.
It’s not strictly necessary to sleep after starting or stopping a service. These cmdlets are not called asynchronous so the sleeping wouldn’t even start before the service is fully started. However, if they don’t start but cause an error, they might end up in another state than Running or Stopped, which would send your script in an endless loop of trying to start the broken Service.
I would try to avoid cultural customs like the weekdays in scripts. Sometimes the scripts are executed in the original culture setting of the server (English) instead of the culture you have available when you are logged in (learned that the hard way on a “German”-Server). Either define the culture in the beginning of the script:
[System.Threading.Thread]::CurrentThread.CurrentCulture = "da-DK"
Or make it culture neutral:
(get-date).DayOfWeek will always return an english weekday ([DayOfWeek].GetEnumNames()). Use [DateTime] objects (Get-Date) where possible instead of the string it represents.
Since the [DateTime] is accurate to the tick of the CPU you can’t compare it directly as -eq or in a switch. Either use -lt / -gt or $Date.Hour
In your script I would do it this way:
# PowerShell script to stop and start services.
# Variable assignement
$Date = Get-Date
$ServiceNames = #('CAPS8','CAPS9'); # Array to store service names.
function serivcesOff {
# Checks the all the service in the above $serviceNames.
foreach ($SeviceName in $ServiceNames) {
# Check for service status if stopped this will start it and goes throug the loop again.
# until status matches running.
if ((Get-Service -Name $ServiceName).Status -ne "Stopped") { # changed this to not stopped instead of running
do{
Stop-Service $ServiceName
#Start-Sleep -Seconds 20
} until ((Get-Service $ServiceName).Status -ne "Running") # changed this to not running instead of stopped
} Return "$($ServiceName) has been shutdown."
}
}
function serviceOn{
# Checks the all the service in the above $serviceNames.
foreach ($SeviceName in $ServiceNames) {
# Check for service status if stopped this will start it and goes throug the loop again.
# until status matches running.
if ((Get-Service -Name $ServiceName).Status -eq "Stopped") {
do{
Start-Service $ServiceName
#Start-Sleep -Seconds 20
} until ((Get-Service $ServiceName).Status -eq "Running")
} Return "$($ServiceName) has been turned on."
}
}
if ($Date.Hour -eq 2){
serviceOn
}elseif ($Date.DayOfWeek -ne "Friday"){ # or -notin "Friday","Sunday"
if ($Date.Hour -eq 17){
serviceOff
}
if ($Date.DayOfWeek -eq "Saturday" -and $Date.Hour -eq 1 ){
serviceOff
}
}
I am trying to create a script for my class to automatically create a folder monthDay wise and open it in Visual Studio Code. However, after the script executes the powershell console remains open until I close it manually or I close VSCode. I just want the console to go away after it executes. Here is the script: Please tell me how to do it..
# Hash table for months
$hash_month = #{1="jan";2="feb";3="mar";4="apr";5="may";6="june";7="july";8="aug";9="sep";10="oct";11="nov";12="dec"}
#extracting date
$date = (Get-Date).Day
#extracing month
$month = (Get-Date).Month
# getting month name from the hash table
$month_name= $hash_month[$month]
# Creating the Directory with monthDate
# This command will create a dir if it does not exist, or it will simply not execute if the directory exists
[System.IO.Directory]::CreateDirectory("$month_name$date")
# changing dir
cd $month_name$date
# opening the dir in vscode
code .
# currently not able to exit from console after execution of script
exit 0
I have attached the screenshot of the window, I just want the console to go away but NOT vscode.
Powershell and VSCode Screenshot
I made 2 changes here:
The path creation is handled differently, which has nothing to do with the question, but your way was not creating the path for me.
Used Start-Process with hidden window to instantiate VSCode and make the $pid kill method work.
Full script:
# Hash table for months
$hash_month = #{1 = "jan"; 2 = "feb"; 3 = "mar"; 4 = "apr"; 5 = "may"; 6 = "june"; 7 = "july"; 8 = "aug"; 9 = "sep"; 10 = "oct"; 11 = "nov"; 12 = "dec" }
#extracting date
$date = (Get-Date).Day
#extracing month
$month = (Get-Date).Month
# getting month name from the hash table
$month_name = $hash_month[$month]
# Creating the Directory with monthDate
# This command will create a dir if it does not exist, or it will simply not execute if the directory exists
$path = $month_name + $date
if (!(Test-Path $path)) {
New-Item $path -ItemType Directory
}
# # changing dir
cd $path
# # opening the dir in vscode with Start-Process
Start-Process -FilePath "code" -ArgumentList "." -WindowStyle Hidden
# # currently not able to exit from console after execution of script
Stop-Process $pid
I am doing an assignment for Powershell and one of the functions is to say when the last boot was. I am printing date and 'time since', date works fine but I think there is too much code for displaying the 'time since'. I want the first value to not be zero. Like this:
1 Hour, 0 Minutes, 34 Seconds
and not like this:
0 Days, 1 Hours, 0 Minutes, 34 Seconds
$bootDate = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
$bootTime = $(Get-Date).Subtract($bootDate)
# Think there is an easier way, but couldn't find any :/
$time = ""
if($bootTime.Days -ne 0) {
$time = "$($bootTime.Days) Days, $($bootTime.Hours) Hours, $($bootTime.Minutes) Minutes, "
} elseif($bootTime.Hours -ne 0){
$time = "$($bootTime.Hours) Hours, $($bootTime.Minutes) Minutes, "
} elseif($bootTime.Minutes -ne 0){
$time = "$($bootTime.Minutes) Minutes, "
}
echo "Time since last boot: $time$($bootTime.Seconds) Seconds"
echo "Date and time: $($bootDate.DateTime)"
This code prints it as I want it to be, but is just seems like too much code for something so little. Is there an easier way?
Make sure you inspect to TotalDays rather than Days. Additionally, I would split the code into a separate function:
function Get-TruncatedTimeSpan {
param([timespan]$TimeSpan)
$time = ""
if($TimeSpan.TotalDays -ge 1) {
$time += "$($TimeSpan.Days) Days, "
}
if($TimeSpan.TotalHours -ge 1){
$time += "$($TimeSpan.Hours) Hours, "
}
if($TimeSpan.TotalMinutes -ge 1){
$time += "$($TimeSpan.Minutes) Minutes, "
}
return "$time$($TimeSpan.Seconds) Seconds"
}
$bootDate = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
$bootTime = $(Get-Date).Subtract($bootDate)
echo "Time since last boot: $(Get-TruncatedTimeSpan $bootTime)"
echo "Date and time: $($bootDate.DateTime)"
A concise solution based on removing the longest run of 0-valued components from the start, using the -replace operator, which uses a regular expression for matching (and by not specifying a replacement string effectively removes the match):
function get-FriendlyTimespan {
param([timespan] $TimeSpan)
"{0} Days, {1} Hours, {2} Minutes, {3} Seconds" -f
$TimeSpan.Days, $TimeSpan.Hours, $TimeSpan.Minutes, $TimeSpan.Seconds -replace
'^0 Days, (0 Hours, (0 Minutes, )?)?'
}
# Invoke with sample values (using string-based initialization shortcuts):
"0:0:1", "0:1:0", "1:0:0", "1", "0:2:33" | % { get-FriendlyTimespan $_ }
The above yields:
1 Seconds
1 Minutes, 0 Seconds
1 Hours, 0 Minutes, 0 Seconds
1 Days, 0 Hours, 0 Minutes, 0 Seconds
2 Minutes, 33 Seconds
How can I add hours as well as subtract minutes to get one result?
I can add 4 hours using the following code:
//Current Time
$hourMin = date('H:i:s');
echo "Current time is: ". $hourMin."<br>";
$hourDiff = date('H:i:s', time()+14400000);
echo "New time is: " . $hourDiff;
I can subtract 7 minutes using the following code:
//Current Time
$hourMin = date('H:i:s');
echo "Current time is: ". $hourMin."<br>";
$hourDiff = date('H:i:s', time()-420000);
echo "New time is: " . $hourDiff;
How do I do this so that my time in variable $hourDiff is 4 hours ahead but 7 minutes behind?
$now = date("H:i:s", time());
$newTime = strtotime("$now +4 hours -7 minutes");
or
$newTime = strtotime("$now +3 hours +53 minutes");
echo "New time is: " . date("H:i:s", $newTime);
something like this?
I need help using time in the c-shell
I want to know how much time it took to execute a script,so i want to do in the following way
1.set start_time=time
2 script part
3.set end_time=time
4. set diff=end_time-start_time
5.echo "It took $diff seconds"
but i couldn't get the time value using any command.
could any one suggest a command to read the time value in c-shell
I think you want the "date" command, with the format to give you raw seconds:
# start_time = `date +%s`
script part
# end_time = `date +%s`
# diff = $end_time - $start_time
echo "It took $diff seconds"