Current version:
# startAllAutoServices.ps1
# version 0.0.2
# Description:
# - This script to scan a list of Windows machines and start any non-running services that have been set to automatically start,
# - It will skip a list of service names as defined by the user
# - Multi-threading enabled
# Requirements:
# - Invoke function with Administrator privileges
$computerNames=@(
'server1','server2'
)
$skipServices=@('gupdate','MapsBroker','RemoteRegistry','sppsvc','WbioSrvc','twdservice','ShellHWDetection','edgeupdate')
$credentials=$null # Assuming session context of SysAdmin
function startAllAutoServices{
param(
[string[]]$computerNames=$env:computername,
$credentials=$null,
[string[]]$skipServices=@('gupdate','MapsBroker','RemoteRegistry','sppsvc','WbioSrvc','MSCRMAsyncService$maintenance','twdservice')
)
function startAutoServices{
param (
$computername=$env:computername,
$skipServices=@('gupdate','MapsBroker','RemoteRegistry','sppsvc','WbioSrvc','MSCRMAsyncService$maintenance','twdservice')
)
# Start all non-running Auto-Start services
$filterString=($skipServices|%{"AND name!='$_' "}) -join ''
$timeZoneName=[System.TimeZoneInfo]::Local.StandardName
$abbreviatedZoneName=if($timeZoneName -match ' '){[regex]::replace($timeZoneName,'([A-Z])\w+\s*', '$1')}else{$timeZoneName}
$timeStampFormat="yyyy-MM-dd HH:mm:ss $abbreviatedZoneName"
$timeStamp=[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetime]::UtcNow,$timeZoneName).ToString($timeStampFormat)
$nonRunningServices=Get-WmiObject win32_service -ComputerName $computerName -Filter "startmode='auto' AND state!='running' $filterString"
#$nonRunningServices=(Get-WmiObject -Query "select DisplayName, State from Win32_Service").Where( {$_.State -eq 'Stopped'})
if($nonRunningServices){
$null=$nonRunningServices|Invoke-WmiMethod -Name StartService
# Detect non-running services
$failedServices=(Get-WmiObject win32_service -ComputerName $computerName -Filter "startmode = 'auto' AND state != 'running' $filterString").Name #|select -expand Name
if($failedServices){
write-warning "$computerName`: services with 'stopped' status $failedServices"
}else{
write-host "$computerName`: all auto-start services are running." -ForegroundColor Green
}
return [pscustomobject]@{
timeStamp=$timeStamp
computername=$computerName
stoppedServices=($nonRunningServices.Name|out-string).trim()
failedToStart=if($failedServices){($failedServices|out-string).trim()}else{'None'}
}
}else{
write-host "$computerName all auto-start services are running." -ForegroundColor Green
return [pscustomobject]@{
timeStamp=$timeStamp
computername=$computerName
nonRunningServices='none'
failedToStart='none'
}
}
}
function testPort($remoteComputer=$env:computername,$port=135,$protocol='TCP'){
function includePortQry{
if (!(Get-Command portqry.exe -ErrorAction SilentlyContinue)){
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))}
choco install portqry -y
if (Get-Command portqry.exe -ErrorAction SilentlyContinue){return $true}else{return $false}
}else{
return $true
}
}
$portQryExists=includePortQry
if($portQryExists){
$reachable=if($port -ne 135){
$command={
param($remoteComputer,$protocol,$port)
$command="portqry -n $remoteComputer -p $protocol -e $port|find ': LISTENING'"
invoke-expression $command
}
$jobId=(Start-Job $command -Args $remoteComputer,$protocol,$port).Id
$startCount=0;$waitSeconds=5
do{
$jobStatus=(get-job -id $jobId).State
if($jobStatus -eq 'Completed'){
$jobResult=receive-job $jobId
}else{
if($startCount++ -eq $waitSeconds){
$jobStatus='Completed'
$null=remove-job -id $jobId -force
$jobResult=$false
}else{
sleep 1
}
}
}until($jobStatus -eq 'Completed')
[bool]($jobResult)
}else{
[bool](portqry -n $remoteComputer -p $protocol -e $port|find 'Total endpoints found: ')
}
write-host "$remoteComputer $port/$protocol`: $reachable"
}else{
write-warning "$env:computername doesn't have portqry. Now switching to unreliable porting testing methods"
$reachable=test-netconnection $remoteComputer -port $port -informationlevel Quiet
write-host "$remoteComputer $port/TCP: $reachable"
}
return $reachable
}
$results=@()
foreach ($computerName in $computerNames){
$rpcAvailable=testPort $computerName 135 'tcp'
$winRmAvailable=if($rpcAvailable){$false}else{testPort $computerName 5985 'tcp'}
if($rpcAvailable){
$results+=startAutoServices $computername $skipServices
}elseif($winRmAvailable){
$sessionTimeout=New-PSSessionOption -OpenTimeout 120000 # 2 minutes
$sessionIncludePort=New-PSSessionOption -IncludePortInSPN -OpenTimeout 120000
$session=if($credentials){
try{
New-PSSession -ComputerName $computername -Credential $credentials -ea Stop -SessionOption $sessionTimeout
}catch{
New-PSSession -ComputerName $computername -Credential $credentials -SessionOption $sessionIncludePort
}
}else{
try{
New-PSSession -ComputerName $computername -ea Stop -SessionOption $sessionTimeout
}catch{
New-PSSession -ComputerName $computername -SessionOption $sessionIncludePort
}
}
if($session.state -eq 'Opened'){
$result=invoke-command -Session $session -ScriptBlock{
param ($startAutoServices,$skipServices)
[scriptblock]::create($startAutoServices).invoke($skipServices)
} -args ${function:startAutoServices},$skipServices|select-object timeStamp,computername,StoppedServices,failedToStart
$results+=$result
Remove-PSSession $session
}else{
write-warning "$env:computername cannnot connect to $computername via WinRM"
$timeZoneName=[System.TimeZoneInfo]::Local.StandardName
$abbreviatedZoneName=if($timeZoneName -match ' '){[regex]::replace($timeZoneName,'([A-Z])\w+\s*', '$1')}else{$timeZoneName}
$timeStampFormat="yyyy-MM-dd HH:mm:ss $abbreviatedZoneName"
$timeStamp=[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetime]::UtcNow,$timeZoneName).ToString($timeStampFormat)
$results+=[pscustomobject]@{
timeStamp=$timeStamp
computerName=$computerName
stoppedServices='UnableToConnect'
failedToStart='UnableToConnect'
}
}
}else{
write-warning "$env:computername is unable to connect to $computerName"
write-host "Unable to connect to $computerName" -ForegroundColor Yellow
$timeZoneName=[System.TimeZoneInfo]::Local.StandardName
$abbreviatedZoneName=if($timeZoneName -match ' '){[regex]::replace($timeZoneName,'([A-Z])\w+\s*', '$1')}else{$timeZoneName}
$timeStampFormat="yyyy-MM-dd HH:mm:ss $abbreviatedZoneName"
$timeStamp=[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetime]::UtcNow,$timeZoneName).ToString($timeStampFormat)
$results+=[pscustomobject]@{
timeStamp=$timeStamp
computername=$computerName
nonRunningServices='UnableToConnect'
failedToStart='UnableToConnect'
}
}
}
return $results
}
# $results=startAllAutoServices $computerNames $skipServices
# $results|?{$_.computername}|ft -wrap
function checkServices{
param(
$computerNames,
$credentials,
$skipServices,
$maxMinutesPerJob=10,
$verbose=$false
)
$timer=[System.Diagnostics.Stopwatch]::StartNew()
$jobResults=@()
$lineBreak=60
$dotCount=0
$minute=0
$processorsCount=(Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
$cpuLoad=(Get-WmiObject win32_processor|Measure-Object -property LoadPercentage -Average).Average
$maxSimultaneousJobs=if($cpuLoad -gt 90){$processorsCount}else{($processorsCount*2)-1} # dynamically limiting concurrent jobs basing on available CPU cores
write-host "CPU load detected as: $cpuLoad`%`r`nSetting concurrent jobs max count to be $maxSimultaneousJobs"
$jobtimer=@{}
foreach($computerName in $computerNames){
$thisIterationCompleted=$false
do {
$jobsCount=(Get-Job -State 'Running').Count
if ($jobsCount -lt $maxSimultaneousJobs){
if($verbose){write-host "Initiating job for $computerName"}
$job=Start-Job -name $computerName -ScriptBlock {
param($startAllAutoServices,$computerName,$credentials,$skipServices)
[scriptblock]::create($startAllAutoServices).invoke($computerName,$credentials,$skipServices)
} -Args ${function:startAllAutoServices},$computerName,$credentials,$skipServices
$jobtimer[$job.Id] = [System.Diagnostics.Stopwatch]::startnew()
$thisIterationCompleted=$true
}else{
if($verbose){
if($dotCount++ -lt $lineBreak){
write-host '.' -NoNewline
}else{
$minute++
write-host "`r`n$minute`t:" -ForegroundColor Yellow -NoNewline
$dotCount=0
}
}
sleep -seconds 1
}
$expiredJobs=$jobtimer.GetEnumerator()|?{$_.value.elapsed.totalminutes -ge $maxMinutesPerJob}
if($expiredJobs){
stop-job -id $expiredJobs.Name
$expiredJobs.Name|%{$jobTimer.Remove($_)}
}
}until ($thisIterationCompleted)
}
$totalJobsCount=(get-job).count
$processedCount=0
while($processedCount -lt $totalJobsCount){
$completedJobs=get-job|?{$_.State -eq 'Completed'}
$stoppedJobs=get-job|?{$_.State -eq 'Stopped'}
$expiredJobs=$jobtimer.GetEnumerator()|?{$_.value.elapsed.totalminutes -ge $maxMinutesPerJob}
if($expiredJobs){
stop-job -id $expiredJobs.Name
$expiredJobs.Name|%{$jobTimer.Remove($_)}
}
if($completedJobs){
foreach ($job in $completedJobs){
$computer=$job.Name
if($verbose){
write-host "`r`n===================================================`r`n$computer job COMPLETED with these messages:`r`n===================================================`r`n"
}
$jobResult=receive-job -id $job.id
$jobResults+=,$jobResult
remove-job -id $job.id -force
$processedCount++
}
}
if($stoppedJobs){
foreach ($job in $stoppedJobs){
$computer=$job.Name
if($verbose){
write-host "`r`n===================================================`r`n$computer job STOPPED with these messages:`r`n===================================================`r`n" -ForegroundColor Red
}
$jobResult=receive-job -id $job.id
# $jobResults+=,$jobResult
$timeZoneName=[System.TimeZoneInfo]::Local.StandardName
$abbreviatedZoneName=if($timeZoneName -match ' '){[regex]::replace($timeZoneName,'([A-Z])\w+\s*', '$1')}else{$timeZoneName}
$timeStampFormat="yyyy-MM-dd HH:mm:ss $abbreviatedZoneName"
$timeStamp=[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetime]::UtcNow,$timeZoneName).ToString($timeStampFormat)
$jobResult=[pscustomobject]@{
timeStamp=$timeStamp
computerName=$computer
stoppedServices='serverTimeout'
failedToStart='Unknown'
}
$jobResults+=,$jobResult
remove-job -id $job.id -force
$processedCount++
}
}
}
$minutesElapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
$timer.stop()
write-host "$($computerNames.count) computers were processed in $minutesElapsed minutes."
return $jobResults #|select -property * -excludeproperty RunspaceId
}
$results=checkServices $computerNames $credentials $skipServices|select-object -Property timeStamp,computername,stoppedServices,failedToStart
$results|ft -wrap
Older version:
# startAllAutoServices.ps1
# This script to scan a list of Windows machines and start any non-running services that have been set to automatically start,
# It will skip a list of service names as defined by the user
# Requirement:
# Invoke function with Administrator privileges
$computerNames='sherver0001','sherver1000'
$skipServices=@('gupdate','MapsBroker','RemoteRegistry','sppsvc','WbioSrvc')
function startAllAutoServices{
param(
[string[]]$computerNames=$env:computername,
[string[]]$skipServices=@('gupdate','MapsBroker','RemoteRegistry','sppsvc','WbioSrvc')
)
$results=@()
foreach ($computerName in $computerNames){
# Start all non-running Auto-Start services
# $exceptions=($skipServices|%{"'$_'"}) -join ','
$filterString=($skipServices|%{"AND name!='$_' "}) -join ''
$nonRunningServices=Get-WmiObject win32_service -ComputerName $computerName -Filter "startmode='auto' AND state!='running' $filterString"
if($nonRunningServices){
$nonRunningServices|Invoke-WmiMethod -Name StartService
# Detect non-running services
$failedServices = Get-WmiObject win32_service -ComputerName $computerName -Filter "startmode = 'auto' AND state != 'running' $filterString" | select -expand Name
if($failedServices){
write-warning "$computerName`: services with 'stopped' status $failedServices"
}else{
write-host "$computerName`: all auto-start services are running." -ForegroundColor Green
}
$results+=[pscustomobject]@{
computername=$computerName
nonRunningServices=($nonRunningServices.Name|out-string).trim()
failedToStart=($failedServices|out-string).trim()
}
}else{
write-host "$computerName all auto-start services are running." -ForegroundColor Green
$results+=[pscustomobject]@{
computername=$computerName
nonRunningServices='none'
failedToStart='none'
}
}
}
return $results
}
startAllAutoServices $computerNames $skipServices
Prior version:
function startAllAutoServices($computer=$env:computername){
# Start all non-running Auto-Start services
$nonRunningServices=Get-WmiObject win32_service -ComputerName $computer -Filter "startmode = 'auto' AND state != 'running' AND name != 'sppsvc'"
$nonRunningServices|Invoke-WmiMethod -Name StartService
# Detect non-running service
$failedServices = Get-WmiObject win32_service -ComputerName $computer -Filter "startmode = 'auto' AND state != 'running' AND name != 'sppsvc'" | select -expand Name
if($failedServices){
write-host "$computer stopped services: $failedServices"
return $false
}else{
write-host "$computer all auto-start services are running."
return $true
}
}
startAllAutoServices
Categories: