Home > Software engineering >  Is there a better way to achieve the on/off of the services using PowerShell
Is there a better way to achieve the on/off of the services using PowerShell

Time:12-04

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?

CodePudding user response:

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
    }
}
  • Related