2
\$\begingroup\$

I created this script to stop and then start specific services across an environment of 8 servers. The server names are Apollo-1 thru Apollo-8. I'm looking for suggested changes to make sure my script is acceptable for production.

#Create a credential to be used on remote machines
$User = "MyDomain\myusername"
$Password = ConvertTo-SecureString 'password' -asplaintext -force
$Credential = New-Object -typename System.Management.Automation.PSCredential 
-ArgumentList $User, $Password


$Server1 = New-Object System.Object
$Server1 | Add-Member -type NoteProperty -name Name -value "Apollo-1"
$arrServ1Services = @("MSSQLSERVER","QueueManager")
$Server1 | Add-Member -type NoteProperty -name Services -value $arrServ1Services



$Server2 = New-Object System.Object
$Server2 | Add-Member -type NoteProperty -name Name -value "Apollo-2"
$arrServ2Services = @("Analytics Engine", "MSSQLSERVER")
$Server2 | Add-Member -type NoteProperty -name Services -value $arrServ2Services



$Server3 = New-Object System.Object
$Server3 | Add-Member -type NoteProperty -name Name -value "Apollo-3"
$arrServ3Services = @("EDDS Agent Manager", "MSSQLSERVER", "Secret Store") 
$Server3 | Add-Member -type NoteProperty -name Services -value 
$arrServ3Services


$Server4 = New-Object System.Object
$Server4 | Add-Member -type NoteProperty -name Name -value "Apollo-4"
$arrServ4Services = @("Service Host Manager", "MSSQLSERVER","Service Bus 
Gateway","Service Bus Message Broker","Service Bus Resource 
Provider","Service Bus VSS","EDDS Agent Manager","Analytics Engine") 
$Server4 | Add-Member -type NoteProperty -name Services -value arrServ4Services


$Server5 = New-Object System.Object
$Server5 | Add-Member -type NoteProperty -name Name -value "Apollo-5"
$arrServ5Services = @("MSSQLSERVER")
$Server5 | Add-Member -type NoteProperty -name Services -value $arrServ5Services


$Server6 = New-Object System.Object
$Server6 | Add-Member -type NoteProperty -name Name -value "Apollo-6"
$arrServ6Services = @("Web Processing Manager", "Service Host Manager") 
$Server6 | Add-Member -type NoteProperty -name Services -value $arrServ6Services


$Server7 = New-Object System.Object
$Server7 | Add-Member -type NoteProperty -name Name -value "Apollo-7"
$arrServ7Services = @("Web Processing Manager", "Service Host Manager") 
$Server7 | Add-Member -type NoteProperty -name Services -value 
$arrServ7Services


$Server8 = New-Object System.Object
$Server8 | Add-Member -type NoteProperty -name Name -value "Apollo-8"
$arrServ8Services = @("elasticsearch-service-x64")
$Server8 | Add-Member -type NoteProperty -name Services -value 
$arrServ8Services



#Create an object to represent the entire Server environment
$ServerEnvironment = New-Object System.Object
$ServerEnvironment | Add-Member -type NoteProperty -name Machines -value 
@($Server1, $Server2, $Server3, $Server4, $Server5, $Server6, $Server7, 
$Server8)


#Iterate through each machine in the environment and stop the services.
for ($x = $ServerEnvironment.Machines.Length-1; $x -gt -1; $x--) {
Write-Host " "
Write-Host " "
Write-Host "Machine:" $ServerEnvironment.Machines[$x].Name
Write-Host "No. of Services we are monitoring:" 
$ServerEnvironment.Machines[$x].Services.Length

#iterate through services 
for ($c = 0; $c -lt $ServerEnvironment.Machines[$x].Services.Length; $c++) {
   $_s = Invoke-Command -ComputerName $ServerEnvironment.Machines[$x].Name - 
Credential $Credential -Command{param($SERV) Get-Service -Name $SERV} - 
ArgumentList $ServerEnvironment.Machines[$x].Services[$c]
Write-Host $ServerEnvironment.Machines[$x].Services[$c]  $_s.Status 
$_s.StartType

Invoke-Command -ComputerName $ServerEnvironment.Machines[$x].Name - 
Credential $Credential -Command{param($SERV) Stop-Service -Name $SERV} - 
ArgumentList $ServerEnvironment.Machines[$x].Services[$c]   
}
 }


#Iterate through each machine in the environment.  Here we are starting the 
services.
for ($x = 0; $x -lt $ServerEnvironment.Machines.Length; $x++) {

Write-Host " "
Write-Host " "

Write-Host "Machine:" $ServerEnvironment.Machines[$x].Name
Write-Host "No. of Services we are monitoring:" 
$ServerEnvironment.Machines[$x].Services.Length

#iterate through service 
for ($c = 0; $c -lt $ServerEnvironment.Machines[$x].Services.Length; $c++) {
$_s = Invoke-Command -ComputerName $ServerEnvironment.Machines[$x].Name - 
Credential $Credential -Command{param($SERV) Get-Service -Name $SERV} -ArgumentList $ServerEnvironment.Machines[$x].Services[$c]
Write-Host $ServerEnvironment.Machines[$x].Services[$c]  $_s.Status $_s.StartType

 Invoke-Command -ComputerName $ServerEnvironment.Machines[$x].Name - 
 Credential $Credential -Command{param($SERV) Start-Service -Name $SERV} - 
 ArgumentList $ServerEnvironment.Machines[$x].Services[$c]

}

  }


 Write-Host "Done"
\$\endgroup\$
1
\$\begingroup\$

I don't understand why you build a coplicated structure with separate $server variables. You have a list of server names with associated services.

That's a simple list that could be contained in a csv file. If read into a variable object you could iterate through the list without the need of an index.

BTW proper indenting helps reading the code.
There are several unintended line breaks.

#Create a credential to be used on remote machines
$User = "MyDomain\myusername"
$Password = ConvertTo-SecureString 'password' -asplaintext -force
$Credential = New-Object -typename System.Management.Automation.PSCredential -ArgumentList $User, $Password

$ServerServices = @"
"Name","Services"
"Apollo-1","MSSQLSERVER,QueueManager"
"Apollo-2","Analytics Engine,MSSQLSERVER"
"Apollo-3","EDDS Agent Manager,MSSQLSERVER,Secret Store "
"Apollo-4","Service Host Manager,MSSQLSERVER,Service Bus "
"Apollo-5","MSSQLSERVER"
"Apollo-6","Web Processing Manager,Service Host Manager "
"Apollo-7","Web Processing Manager,Service Host Manager "
"Apollo-8","elasticsearch-service-x64"
"@ | ConvertFrom-Csv


#Iterate through each machine in the environment and stop the services.

ForEach ($Server in $ServerServices){
    $Services = $Server.Services -split ','
    Write-Host " "
    Write-Host " "
    Write-Host "Machine:" $Server.Name
    Write-Host ("No. of Services we are monitoring: {0}" -f $Services.Length)

    #iterate through services 
    ForEach ($Service in $Services) {
        Write-Host ("Proceesing service: {0} on server:{1}" -f $Service,$Server.Name)
    #    $_s = Invoke-Command -ComputerName $Server.Name -Credential $Credential -Command {
    #        param($SERV) Get-Service -Name $SERV} -ArgumentList $Service
    #    }
#...
    }
}

#Iterate through each machine in the environment.  Here we are starting the 

# same as above

Write-Host "Done"

Sample output:

Machine: Apollo-1
No. of Services we are monitoring: 2
Proceesing service: MSSQLSERVER on server:Apollo-1
Proceesing service: QueueManager on server:Apollo-1


Machine: Apollo-2
No. of Services we are monitoring: 2
Proceesing service: Analytics Engine on server:Apollo-2
Proceesing service: MSSQLSERVER on server:Apollo-2

...snip...
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for the advice on formatting. I'll improve upon that in the future. I guess the reason I went with objects is for two reasons. 1) PowerShell does a pretty good job of displaying objects to the console screen. 2) I guess I was thinking about potential future use and adding other properties and methods if need be. \$\endgroup\$ – Bill Greer Aug 10 '18 at 14:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.