I created a script that will start or stop a service based on it's display name. My script works on the local machine but I would like to make sure that it can be done on a remote machine and the local machine. I am not sure how to get it working on a remote machine.
any help would be appreciated.
$serviceName = Read-Host -Prompt 'Please enter service name: '
# Check that service name exists
If (Get-Service $serviceName -ErrorAction SilentlyContinue)
{
# Check that service name is not empty
if([string]::IsNullOrEmpty($serviceName))
{
Write-Host "Service name is NULL or EMPTY"
}
else
{
$Choice = Read-Host -Prompt 'Would you like to start or stop the service'
#Start service
If ($Choice -eq 'start') {
Start-Service -displayname $serviceName
Write-Host $serviceName "Starting..." -ForegroundColor Green
}
#Stop service
If ($Choice -eq 'stop') {
Stop-Service -displayname $serviceName
Write-Host $serviceName "Stopping..." -ForegroundColor Green
}
}
}
else {
Write-Host "Service name does not exist"
}
You can't use Start-Service/Stop-Service for a remote computer, you can however pass a service object from Get-Service (using the ComputerName parameter) to Set-Service which can perform the same start/stop actions for a remote computer:
Get-Service $ServiceName -ComputerName $ComputerName | Set-Service -Status Running
I find this to be much easier than using PowerShell Remoting or WMI commands.
You can easily update your code with minimal code changes:
$serviceName = Read-Host -Prompt 'Please enter service name: '
#get computername or use localhost for local computer
if(($ComputerName = Read-Host 'Enter Computer Name, leave blank for local computer') -eq ''){$ComputerName = 'localhost'}
$Service = Get-Service -DisplayName $serviceName -ComputerName $ComputerName -ErrorAction SilentlyContinue
# Check that service name exists
if ($Service) {
# Check that service name is not empty
if([string]::IsNullOrEmpty($serviceName)){Write-Host 'Service name is NULL or EMPTY'}
else {
$Choice = Read-Host -Prompt 'Would you like to start or stop the service'
#Start service
If ($Choice -eq 'start') {
$Service | Set-Service -Status Running
Write-Host $serviceName 'Starting...' -ForegroundColor Green
}
#Stop service
If ($Choice -eq 'stop') {
$Service | Set-Service -Status Stopped
Write-Host $serviceName 'Stopping...' -ForegroundColor Green
}
}
}
else {
Write-Host 'Service name does not exist'
}
Assuming that you have not disabled PowerShell remoting, the easiest way to do it is to wrap it in a function with ComputerName as an optional parameter, and then use Invoke-Command and splat PSBoundParameters.
Function Toggle-Service{
[cmdletbinding()]
Param([string[]]$ComputerName)
$serviceName = Read-Host -Prompt 'Please enter service name: '
# Check that service name exists
If (Invoke-Command -ScriptBlock {Get-Service $serviceName -ErrorAction SilentlyContinue} #PSBoundParameters)
{
# Check that service name is not empty
if([string]::IsNullOrEmpty($serviceName))
{
Write-Host "Service name is NULL or EMPTY"
}
else
{
$Choice = Read-Host -Prompt 'Would you like to start or stop the service'
#Start service
If ($Choice -eq 'start') {
Invoke-Command -ScriptBlock {Start-Service -displayname $serviceName} #PSBoundParameters
Write-Host $serviceName "Starting..." -ForegroundColor Green
}
#Stop service
If ($Choice -eq 'stop') {
Invoke-Command -ScriptBlock {Stop-Service -displayname $serviceName} #PSBoundParameters
Write-Host $serviceName "Stopping..." -ForegroundColor Green
}
}
}
else {
Write-Host "Service name does not exist"
}
}
Then you can call Toggle-Service without a parameter to perform it locally, or include the name of a remote server to perform the actions on that server.
Start-Service and Stop-Service do not work against remote computers. You will either need to do PowerShell remoting, or use WMI. In my environment, PowerShell remoting is blocked by default, but we use WMI instead; service objects retrieved through Get-WMIObject have a method called Start-Service() which can be called on the retrieved service object:
(Get-WmiObject -ComputerName $ComputerName -Class Win32_Service -Filter "Name='$ServiceName'").StartService()
Stopping a service on a remote computer using WMI works the same way; you would call the service object's StopService() method instead.
I recommend that you read the information in Get-Help Get-WMIObject and the MSDN reference on the Win32_Service class.
ETA: It should be noted that by omitting the -ComputerName parameter, WMI will work on the local computer as well.
Related
Below is the script that I'm running that always gives either a Program error or a The term 'x86' is not recognized as the name of a cmdlet error. The service stops but the Invoke-Command seems to be the problem.
$Servers = Get-Content "C:\DTServerScript\Servers.txt"
ForEach ($Server in $Servers) {
$Status = ""
do
{
#Stopping Service
$ServiceAgent = Get-Service -ComputerName $Server | Where {$_.Name -like "*oneagent*"}
Write-Host "Pending Stop on $Server"
Stop-Service $ServiceAgent
sleep 1
$Status = $ServiceAgent.Status
} until ($Status -eq "Stopped")
Write-Host "Service state is $Status on $Server"
# Execute config change
# Invoking Commands on Server
Invoke-Command -ComputerName $Server {cmd.exe/ c:\Program Files (x86)\WinPcap\uninstall.exe /S }
write-host "Service is starting on $Server"
# Starting Service
Start-Service $ServiceAgent
$ServiceAgent = Get-Service -ComputerName $Server | Where {$_.Name -like "*oneagent*"}
$Status = $ServiceAgent.Status
}
Try quoting the path and using braces around the name containing ()..
Invoke-Command -ComputerName $Server { & $Env:ComSpec /C "${Env:ProgramFiles(x86)}\WinPcap\uninstall.exe" /S }
If i use the
$service.stopservice()
method i get an error because of the dependencies, What i need to do is to restart the service and all of its dependancies.
Similar to if using the GUI and i selected the top line service and pressed restart, first i would get a warning, then a list of other services that will be restarted too, which then goes through stopping each dependancy before restarting the top one and then restarting the dependancies.
I need to do this in powershell
Try {
Write-host "Connecting to remote computer"
$service = Get-WmiObject -Class Win32_Service -ComputerName $ip -Credential $cred -Filter "Name='$servname'"
if ($service.Status -eq 'Running'){$ServiceStarted = $true}
if($ServiceStarted -eq $true) {
$StopResponse = $service.stopservice()
$StopReturnCode = Switch ($StopResponse.ReturnValue) {
0{ "The request was accepted" }
5{ "The service is already stopped" }
10{ "The service failed to stop - run the script again" }
default{ "Something unexpected happened" }
}
}
Write-Host $StopReturnCode
} catch {
Write-Host "script noped out bro" :fore RED
}
The above works (albeit slowly) for a single service.
I've tried using -Force but this doesnt work and -Force -Confirm gives an error.
There are a few thoughts on this use case.
You can get the dependencies a couple of ways... and start as needed, before your try and restart the one you are after.
# Review Dependent Services
Get-Service -Name Winmgmt -DependentServices
or
Use Windows PowerShell to Display Service Dependencies
Get-Service -CN $env:COMPUTERNAME |
Where-Object { $_.status -eq ‘running’} |
ForEach-Object {
write-host -ForegroundColor 9 "Service name $($_.name)"
if ($_.DependentServices)
{
write-host -ForegroundColor 3 "tServices that depend on $($_.name)"
foreach ($s in $_.DependentServices)
{ "tt" + $s.name }
} #end if DependentServices
if ($_.RequiredServices)
{
Write-host -ForegroundColor 10 "tServices required by $($_.name)"
foreach ($r in $_.RequiredServices)
{ "tt" + $r.name }
} #end if DependentServices
} #end foreach-object
Addressing them can have different approaches, here is a discussion on the topic.
How to restart services with dependencies via PowerShell Scripting (128574)
# For services with just a few dependencies, running
Restart-Service winmgmt -Force -PassThru
May suffice as all the currently running dependencies are restarted.
However, this is an unsafe way do to the restart as some services may
have been previously stopped.
For production machines, the following approach is recommended (the
example is using the WMI service):
cls
Write-Host "Restarting Service with Dependencies`r`n" -f Green
# 1. Get wmi dependencies
$wmidependents = (get-service winmgmt).dependentservices
if desired to get only the running dependent services, pipe | where {$_.status -eq "running"}
# 2. Get all necessary information about dependent services
$wmidependentservices = Get-WmiObject Win32_Service |
Select-object name,state,startmode |
Where-Object {$wmidependents.name -contains $_.name}
# 3. Stop wmi dependencies
Write-Host "`r`nStopping Services`r`n-----------------`r`n" -f Yellow
ForEach ($service in $wmidependentservices)
{
Write-Host "`r`nAnalyzing $($service.name)" -f Yellow
if($service.startmode -eq "auto" -or $service.status -eq "Running")
{
Write-Host "Stopping $($service.name)"
stop-service $service.name
#you can add more logic in the block
}
else
{
"$($service.name) is $($service.state) with the startmode: $($service.startmode)"
}
}
#equivalent to stop-service $wmidependents.name
# 4. Stop the WMI service
Stop-Service winmgmt -force
Write-Host "`r`nStarting Services`r`n -----------------`r`n" -f Yellow
# 5. start dependencies
ForEach ($service in $wmidependentservices)
{
Write-Host "`r`nAnalyzing $($service.name)" -f Yellow
if($service.startmode -eq "auto")
{
"Starting $($service.name)"
start-service $service.name
#you can add more logic in the block
}
else
{
"$($service.name) is $($service.state) with the startmode: $($service.startmode)"
}
}
#equivalent to start-service $wmidependents.name
# 6. start WMI
Start-Service winmgmt
Please note that both delayed-auto and auto startup types are shown as
"auto" by WMI.
I have a script which scans given computers in domain for identifying and disables mobile hotspot function in windows 10. Script works properly , but i want to scan all my domain comupters, not only specified.. can anyone help me for adjusting this script?
$username = "domain\administrator"
$password = "Your password"
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $password
$computers = #("nr1", "nr2", "nr3")
foreach($computer in $computers){
$hotspot = Invoke-Command -ComputerName $computer -credential $credential -scriptblock {
$hotspot = Get-Service "icssvc"
if($hotspot.Status -eq "Running"){
Write-Host "Hotspot is turned on on $computer" -ForegroundColor Red
try{
Stop-Service "icssvc"
Write-Host "Successfully stopped service on $computer" -ForegroundColor Green
}catch{
Write-Host "Unable to stop service on $computer" -ForegroundColor Red
}
}else{
Write-Host "No Hotspot running on $computer" -ForegroundColor Green
}
}
If you replace $computers = #("nr1", "nr2", "nr3") with something like:
Import-Module ActiveDirectory
$computers = Get-ADComputer -Properties DNSHostName
That should return an array of hostnames. You may need to provide credentials via -Credential, and you can -Filter the results if you need to exclude any machines.
See docs and examples of Get-ADComputer here.
First, I want to stop the services and then turn them on manually
$getservicestatus = (Get-Service -DisplayName $servicename -ComputerName $server).status
if ($getservicestatus -eq "Running") {
Set-Service -Name $servicename -ComputerName $server -Status Stopped
else
{
Write-Host "$server $servicename var redan Running!" -ForegroundColor Yellow
Stop-Service spooler
Set-Service spooler Manual
Your problem is Set-Service does not have a ComputerName parameter so it cannot act against remote services.
Get-Service can act against a remote computer (it does have the ComputerName parameter), this command returns a service object that can be piped to Set-Service to act remotely.
Assuming you want to Stop a remote service and set it to Manual startup, this would be the code:
$servicename = 'spooler'
$server = 'server2'
$service = Get-Service -Name $servicename -ComputerName $server
if ($service.Status -eq 'Running') {
$service | Set-Service -Status Stopped
}
if ($service.StartType -eq 'Automatic') {
$service | Set-Service -StartupType Manual
}
# If you need to start the service again
# $service | Set-Service -Status Running
try this: change
Set-Service -Name $servicename -ComputerName $server -Status Stopped
to
Invoke-Command -ComputerName $server -ScriptBlock {Stop-Service -Name $servicename -Force}
I want to create a Windows Service using Powershell. Creating it for a given user is piece of cake. I used this function adapted from here.
function ReinstallService1 ($serviceName, $binaryPath, $login, $pass)
{
Write-Host "installing service"
# creating credentials which can be used to run my windows service
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpasswd)
# creating widnows service using all provided parameters
New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic -credential $mycreds
Write-Host "installation completed"
}
My question is: How can I create for "Network Service" account?
If I modify New-Service line and remove credential parameter, the service is created for "Local System" account. Nearly miss.
New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic
I googled a lot and saw no way of indicating service account. If I try to use Credential parameter for user "NETWORK SSERVICE", I don't know what password to put and if I invent one (just in case cmdlet ignores it) it doesn't work. The error is:
New-Service : Service 'XXXX (XXXX)'
cannot be created due to the following error: The account name is
invalid or does not exist, or the password is invalid for the account
name specified
The correct name of the account is NT AUTHORITY\NETWORK SERVICE.
This is the final version of Reinstall Service for everyone's benefit, specially for Aniket.
function ReinstallService ($serviceName, $binaryPath, $description, $login, $password, $startUpType)
{
Write-Host "Trying to create service: $serviceName"
#Check Parameters
if ((Test-Path $binaryPath)-eq $false)
{
Write-Host "BinaryPath to service not found: $binaryPath"
Write-Host "Service was NOT installed."
return
}
if (("Automatic", "Manual", "Disabled") -notcontains $startUpType)
{
Write-Host "Value for startUpType parameter should be (Automatic or Manual or Disabled) and it was $startUpType"
Write-Host "Service was NOT installed."
return
}
# Verify if the service already exists, and if yes remove it first
if (Get-Service $serviceName -ErrorAction SilentlyContinue)
{
# using WMI to remove Windows service because PowerShell does not have CmdLet for this
$serviceToRemove = Get-WmiObject -Class Win32_Service -Filter "name='$serviceName'"
$serviceToRemove.delete()
Write-Host "Service removed: $serviceName"
}
# if password is empty, create a dummy one to allow have credentias for system accounts:
#NT AUTHORITY\LOCAL SERVICE
#NT AUTHORITY\NETWORK SERVICE
if ($password -eq "")
{
#$secpassword = (new-object System.Security.SecureString)
# Bug detected by #GaTechThomas
$secpasswd = (new-object System.Security.SecureString)
}
else
{
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
}
$mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpasswd)
# Creating Windows Service using all provided parameters
Write-Host "Installing service: $serviceName"
New-Service -name $serviceName -binaryPathName $binaryPath -Description $description -displayName $serviceName -startupType $startUpType -credential $mycreds
Write-Host "Installation completed: $serviceName"
# Trying to start new service
Write-Host "Trying to start new service: $serviceName"
$serviceToStart = Get-WmiObject -Class Win32_Service -Filter "name='$serviceName'"
$serviceToStart.startservice()
Write-Host "Service started: $serviceName"
#SmokeTest
Write-Host "Waiting 5 seconds to give time service to start..."
Start-Sleep -s 5
$SmokeTestService = Get-Service -Name $serviceName
if ($SmokeTestService.Status -ne "Running")
{
Write-Host "Smoke test: FAILED. (SERVICE FAILED TO START)"
Throw "Smoke test: FAILED. (SERVICE FAILED TO START)"
}
else
{
Write-Host "Smoke test: OK."
}
}
You could get a cred of network service straightforward like this:
$login = "NT AUTHORITY\NETWORK SERVICE"
#### #just set a dummy psw since it's just used to get credentials
$psw = "dummy"
$scuritypsw = ConvertTo-SecureString $psw -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential($login, $scuritypsw)
#### #then you can use the cred to new a windows service
$serviceName = "Test"
$binaryPath = "C:\Test\Test.exe"
New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType Automatic -credential $mycreds
Get-WmiObject is deprecated now. However, PowerShell now has built in cmdlets to work with services. Here is the updated version of ReinstallService from Oscar Foley's answer tweaked accordingly along with convenient default values and wrappers to start and stop a service:
# https://stackoverflow.com/questions/35064964/powershell-script-to-check-if-service-is-started-if-not-then-start-it
function TryStopService([string] $serviceName)
{
Write-Host "Attempting to stop service: $serviceName..."
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if($service)
{
if ($service.Status -ne 'Running')
{
Write-Host " Service: $serviceName is not running."
}
else
{
Stop-Service -name $serviceName
Write-Host " Stopped service: $serviceName."
}
}
else
{
Write-Host " Service: $serviceName is not found."
}
}
function UninstallService([string] $serviceName)
{
Write-Host "Attempting to uninstall service: $serviceName..."
if (Get-Service $serviceName -ErrorAction SilentlyContinue)
{
Remove-Service -Name $serviceName
Write-Host " Uninstalled service: $serviceName."
}
else
{
Write-Host " Service: $serviceName is not found."
}
}
function StartSertice([string] $serviceName)
{
Write-Host "Attempting to start service: $serviceName..."
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if($service)
{
if ($service.Status -eq 'Running')
{
Write-Host " Service: $serviceName is already running."
return
}
}
# Trying to start new service.
Write-Host " Trying to start new service: $serviceName."
Start-Service -Name $serviceName
#Check that service has started.
Write-Host " Waiting 5 seconds to give service time to start..."
Start-Sleep -s 5
$testService = Get-Service -Name $serviceName
if ($testService.Status -ne "Running")
{
[string] $errMessage = " Failed to start service: $serviceName"
Write-Host $errMessage
Throw $errMessage
}
else
{
Write-Host " Started service: $serviceName."
}
}
function ReinstallService ([string] $serviceName, [string] $binaryPath, [string] $description = "", [string] $login = "NT AUTHORITY\NETWORK SERVICE", [string] $password = "", [string] $startUpType = "Automatic")
{
Write-Host "Attempting to reinstall service: $serviceName..."
#Check Parameters
if ((Test-Path $binaryPath)-eq $false)
{
Write-Host " BinaryPath to service was not found: $binaryPath."
Write-Host " Service was NOT installed."
return
}
if (("Automatic", "Manual", "Disabled") -notcontains $startUpType)
{
Write-Host " Value for startUpType parameter should be (Automatic or Manual or Disabled) and it was $startUpType"
Write-Host " Service was NOT installed."
return
}
TryStopService -serviceName $serviceName
UninstallService -serviceName $serviceName
# if password is empty, create a dummy one to allow having credentias for system accounts:
# NT AUTHORITY\LOCAL SERVICE
# NT AUTHORITY\NETWORK SERVICE
if ($password -eq "")
{
$secpassword = (new-object System.Security.SecureString)
}
else
{
$secpassword = ConvertTo-SecureString $password -AsPlainText -Force
}
$mycreds = New-Object System.Management.Automation.PSCredential ($login, $secpassword)
# Creating Windows Service using all provided parameters.
Write-Host "Installing service: $serviceName with user name: '$login'..."
New-Service -name $serviceName -binaryPathName $binaryPath -Description $description -displayName $serviceName -startupType $startUpType -credential $mycreds
Write-Host " Installed service: $serviceName."
# Trying to start new service.
StartSertice -serviceName $serviceName
}