Windows Service operations on multiple remote servers in parallel - powershell

I have 3 servers on same network and having the same username and password to login, on which I want to perform following operations:
*Check if Service1 is running or not
*If it is running, stop the service
*Set Service1 to disable mode
*If it is not running, do nothing
*Check if Service2 is running
*If it is running, stop the service
*Set Service2 to disable mode
*If it is not running, do nothing
and so on for Service3,..4,..5...
I want to create a Master.bat file on 1st Server, which should perform above operations on all the 3 servers in parallel.
I am trying with below but not getting how i can do this for more than 1 services in same code and also its getting bit lengthy.Is there any other short method to do this in batch or powershell ?
original_serverlist.txt:
Server1
Server2
Server3
Code:
copy original_serverlist.txt serverlist.txt
:repeat
set currentserver=
for /f "eol=; tokens=1*" %%i in (serverlist.txt) do set currentserver=%%i
if "%currentserver%"=="" goto end
for /F "tokens=3 delims=: " %%H in ('SC query Service1 ^| findstr " STATE"') do (
if /I "%%H" "RUNNING" (
net stop Service1
echo Service1 stopped # %date% %time% > C:\result.txt
sc config Service1 start= disabled
echo Service1 set disabled # %date% %time% >> C:\result.txt
)
)
type serverlist.txt| find /v "%currentserver%"> serverlist1.txt
copy serverlist1.txt serverlist.txt
goto repeat
:end
del serverlist.txt
del serverlist1.txt
EDIT1
I am not that much comfortable in PS as in batch but i want to learn the things so putting my exact requirement here to learn how to implement it in powershell with code explanation.
I need to perform following same set of operations on all the three remote Servers in parallel (Server1,Server2,Server3) having Master.ps1 on Server1:
run command cmd /c iisreset/stop and set IIS service to Disabled mode
Stop service1 and set it to Disabled mode
Stop service2 and set it to Disabled mode
Stop service3 and set it to Disabled mode
Kill process jusched.exe
Kill process conhost.exe

In powershell 3.0
$services = "service1", "service2", "service3"
"server1", "server2", "server3" | % {
Get-Service -Computer $_ $services | ? State -eq "Running" | Stop-Service -Force -PassThru | Set-Service -StartupType Disabled
}
You need to enable powreshell remoting for this to work and add -Credential option anywhere you see -Computer argument if your current domain user doesn't have enough rights.
More generic option would be to use hash
$ServiceMap = #{ "server1": ("service11", "service12");
"server2": ("service21" ... ) }
You will also need to check for errors..
To achieve parallel execution you could do something like:
workflow set_services {
param(
[string[]]$Computers, [string[]]$Services
)
foreach -parallel ($computer in $computers) {
Get-Service -ComputerName $computer $services | ? State -eq "Running" | Stop-Service -Force -PassThru | Set-Service -StartupType Disabled
}
}
BTW, do not use batch scripts any more, anywhere.

Related

Stop a continuous Ping

I am trying to create Powershell script where
User will provide text file with ipaddress/ hostname and test Duration
• Script should take each ip address/ Hostname, open cmd/ powershell and run ping test
For this I created a bat file containing
ping -t %1 |find /v ""|cmd /q /v:on /c "for /l %%a in (0) do (set "data="&set /p "data="&if defined data echo(!Date! !time! !data!)" > %2
In powershell I am running it
$Script = "C:\Ping\pingTest\pingstat.cmd $hostName $outputFile"
$Runpingtest = cmd.exe /c $script
Please give me ideas to spot the contiguous ping as per test duration
You can't stop a continuous ping without signaling the ping process to stop. You would need to use ping /n COUNT for a number of pings.
But you can do something similar with pure PowerShell and Test-NetConnection, then export the results to CSV like so:
1..$pingCount | Foreach-Object {
Test-NetConnection google.com |
Select-Object #{
Name='Date'
Expression={ Get-Date -Format 'ddd MM/dd/yyyy hh:mm:ss.ff' }
}, ComputerName, SourceAddress, RemoteAddress, PingSucceeded,
#{
Name='Latency'
Expression={ "$($_.PingReplyDetails.RoundTripTime) ms" }
}
} | Export-Csv -NoTypeInformation C:\Path\To\file.csv
Note that Test-NetConnection doesn't have a -Count parameter, which is why the my above code wraps the Test-NetConnection call in a loop. You may also need to adjust the Get-Date format for your locale as my code uses a date formation suitable in the US.
Also note that I'm using Select-Object to create custom Date and Latency columns, as Test-NetConnection doesn't provide the current time it was run, and the ping latency is buried in a nested object.

Setting app pools to recycle at multiple specific times via powershell or appcmd does not display both times in GUI/IIS

I am attempting to set app pools to recycle at multiple times in the day in iis 8.5, I've tried using powershell and app command and when testing on a server that has no sites/applications in the pool it seems to work perfectly, however when trying to set using either method on a server that has sites in the app pools I'm seeing strange behavior, It seems to work however in the GUI of IIS if i look at the recycling settings of the app pool it only shows one of the times specified.
Powershell script initially tried using is:
function Set-ApplicationPoolRecycleTimes {
param (
[string]$ApplicationPoolName,
[string[]]$RestartTimes
)
Import-Module WebAdministration
Write-Output "Updating recycle times for $ApplicationPoolName"
# Delete all existing recycle times
Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.schedule
Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.time
foreach ($restartTime in $RestartTimes) {
Write-Output "Adding recycle at $restartTime"
# Set the application pool to restart at the time we want
New-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.schedule -Value #{value=$restartTime}
Set-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.time -Value "00:00:00"
} # End foreach restarttime
} # End function Set-ApplicationPoolRecycleTimes
$apppoolname1 = "app pool's name"
$restartat = #("1:45", "18:45")
Set-ApplicationPoolRecycleTimes -ApplicationPoolName $apppoolname1 -RestartTimes $restartat
Again this seems to work perfectly unless there are sites in the application pool. When sites exist it seems to work except that the gui only shows one of the times set:
however querying the value show's both times:
Import-Module WebAdministration
(Get-ItemProperty ('IIS:\AppPools\app pool name') -Name Recycling.periodicRestart.schedule.collection) | select value
value
-----
18:45:00
01:45:00
also attempted using appcmd but finding the same results, works perfectly on a server with no sites in the app pool, but when run against servers with sites, missing one of the times in the gui, querying shows both times. I have turned logging on for app pool recycles to confirm it's happening at both times but wondering if I'm just overlooking something obvious.
appcmd script:
CD C:\windows\System32\inetsrv
$V1 = "app pool name"
#clears any existing schedule
cmd.exe /c appcmd.exe set apppool /apppool.name: $V1 /-recycling.periodicRestart.schedule
#setting desired recycles
cmd.exe /c appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='$v1'].recycling.periodicRestart.schedule.[value='01:45:00']" /commit:apphost
cmd.exe /c appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='$v1'].recycling.periodicRestart.schedule.[value='18:45:00']" /commit:apphost
I tried your PowerShell script with the application pool which contains a site or without site.in both the condition your posted script is working.
you could try to use the below script:
function Set-ApplicationPoolRecycleTimes {
param (
[string]$ApplicationPoolName,
[string[]]$RestartTimes
)
Import-Module WebAdministration
Write-Output "Updating recycle times for $ApplicationPoolName"
# Delete all existing recycle times
Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.schedule
foreach ($restartTime in $RestartTimes) {
Write-Output "Adding recycle at $restartTime"
# Set the application pool to restart at the time we want
New-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.schedule -Value #{value=$restartTime}
} # End foreach restarttime
} # End function Set-ApplicationPoolRecycleTimes
$apppoolname = "abcsite"
$restartat = #("05:55", "12:55", "17:00")
Set-ApplicationPoolRecycleTimes -ApplicationPoolName $apppoolname -RestartTimes $restartat
or
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='test1'].recycling.periodicRestart.schedule.[value='07:00:00']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='test1'].recycling.periodicRestart.schedule.[value='18:25:00']" /commit:apphost
or
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/applicationPools/add[#name='test1']/recycling/periodicRestart/schedule" -name "." -value #{value='07:00:00'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/applicationPools/add[#name='test1']/recycling/periodicRestart/schedule" -name "." -value #{value='18:25:00'}
The above scripts are tested with the IIS 10 (Windows 10) and IIS 8.5(windows server 2012r2)

Is there a way to disable and enable network connection when internet is lost

this is my first post so hopefully I am doing it right.
I am looking for a way to automate the process of disabling my Ethernet network connection and then reenable it.
I am on a camp internet connection (work away for weeks at a time) and the internet connection is fine besides it dropping out every half an hour or so and requiring me to refresh the connection. Usually I just disconnect the Ethernet plug for a second and plug it back in but I am wanting to automate the process so I can remote connect to the pc when I am away.
Any help on how to accomplish this would be appreciated.
Edit: I left a vital part out of my description. I am wanting the script to detect when the internet connection is lost and then refresh the connection. Once the connection is lost it never regains it until I refresh the connection.
If you are using DHCP
Then Dollars to donuts you are just needing to renew your DHCP lease.
That is something you can do in CMD easily (I'm sure there is likely as easy a method in PS, but I don't know it offhand)
This will release the currently assigned DHCP Address wait a few seconds and then renew it.
IPConfig /Release & timeout 5 & IPConfig /Renew
At the CLI or in a batch script you could set up a do-while loop to loop until you return an expected up address if you wanted.
Example of a costume loop in cmd cli.
For /L %L (1,1,2147483648) DO (
IPConfig /Release & timeout 3 & IPConfig /Renew &timeout 3 &(
Ping -n 2 4.2.2.2 | find /I "Reply From" | find /I " 4.2.2.2" &&(
Exit /b 0
)
)
)
Disabling and enabling your NIC can be done through CMD or Powershell.
Here Powershell is easier.
Get only currently enabled adapters, use that to disable them wait a few seconds and enable them again
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Combine with checking the ping to the internet (as in cmd example) to generate a loop until we have a good connection.
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
DO {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
} While ( ! $(test-connection -TargetName 4.2.2.2 -Quiet ) )
Now, PowerShell will need to be instantiated from a CMD prompt, I usually write a .cmd script wrapper for the .ps1 script to be called from in task scedualer or by hand.
Sometimes I will write a combo .cmd script with the ps code embedded and just create a hardline. To the original .cmd script as a. .ps1 to execute the ps code.
Although for something this simple it might be simplest to use PowerShell.exe to run the script as an in-line command.
But all roads lead to Rome, you do you on executing PowerShell, but in order to run it periodically, you will need to schedule the script to run, and by default there is no way to run ps scripts directly, so pick a method that you like that works for running the script and then use windows scheduler to schedule the task to run every x interval you like (say hourly)
Make surw you select a new task (not a basic task) and select run with highest priviledges" checkbox, and select the newest version of windows available in the compatibility list-box.
Make sure to provide a useename and password of an administrator, and select to save the password/run whether the user is logged on or not.
Set your triggers and put in the method you chose to execute the script and run some tests to make sure it works as expected.
Edit:
The original method is int he form DO { Action } WHILE ( Condition To Check Returns True) Since the While is at the end it guarantees one iteration.
Since you don't want to disable and enable the NIC even once if the internet is pingable, you can use a WHILE ( Condition To Check Returns True) { Action }
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
While ( ! $( test-connection -ComputerName 4.2.2.2 -Quiet ) ) {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
}
You absolutely need to have a scheduled task to run this regularly.
Even if you want to only start it once and leave it in the background, and havit checking always (which we could do) you'll need to set up a scheduled task to kill it if still running and start it again at some interval as it's possible to have a process become unresponsive or be killed or have the computer restart etc and you forget to start the script etc.
This version will just loop every one minute to check, and only executes when the internet is not reachable.
while ($true) {
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
While ( ! $( test-connection -ComputerName 4.2.2.2 -Quiet ) ) {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
}
sleep 60
}
Again, you ca just run this in powershell, sure, btu then if it gets stopped for any reason it won;t be started again.
Use task scheduler ad set up an action to run this o Startup and once an hour, killing any previously running copy of the script.
Usually for running a CMD script I just write a simple cmd script so if I want to edit any part of anything I only change the script never the task.
<# ## & REM Script Name:
#(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
(
NET SESSION 2>&1 >NUL
) || (
powershell.exe -Command "Start-Process cmd \"/k %~dpnx0\" -Verb RunAs"
pause
GOTO :EOF
)
IF EXIST "%~dpn0.ps1" (
DEL /Q /F %~dpn0.ps1"
)
MKLINK /H "%~dpn0.ps1" "%~f0"
)
Powershell.exe -ExecutionPolicy Bypass -File "%~dpn0.ps1"
(
ENDLOCAL
EXIT /B %_eLvl%
)
#>
## Script:
## Powershell Portion Begins
while ($true) {
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
While ( ! $( test-connection -ComputerName 4.2.2.2 -Quiet ) ) {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
}
sleep 60
}
You can handle this using Get-NetAdapter , Enable-NetAdapter and Disable-NetAdapter commands.

Powershell script Stop process and proceed

I have a script where i run the shutdown.exe command on a list of computers. The script works fine until it hangs for some reason.
Is there a way that i can "ctrl + c" the shutdown command and then proceed to the next PC.
here is what im using.
buttonRestartWorkstations_Click={
#TODO: Place custom script here
$online = $checkedlistbox1.CheckedItems | where { Test-Connection -
ComputerName $_ -Count 1 -Quiet }
$computercount = $online.Items.Count
$progressbar1.Maximum = $online.Count
$progressbar1.Step = 1
$progressbar1.Value = 0
foreach ($computer in $online)
{
$progressbar1.PerformStep()
shutdown -r -t $textbox3.Text -m $computer
Start-Sleep -s 1
}
$label2.Visible = $true
$label2.Text = "Selected Servers will reboot on the " + $textbox1.text
The Restart-Computer cmdlet would give you the ability to target multiple computers in parallel, without a problem on one computer affecting execution on others.
As you state, Restart-Computer is not an option for you because you want to have a delay before the restart is initiated on a given computer (which is what shutdown -r -t <secs> gives you; note that while Restart-Computer does have a -Delay parameter, its purpose is different).
If:
your target computers are set up for PowerShell remoting
and you can run your script elevated (with administrative privileges)
you can use Invoke-Command to target the computers in parallel and then locally run shutdown.exe on them (PSv3+ syntax):
$delay = $textbox3.Text
Invoke-Command -ComputerName $online {
shutdown -r -t $using:delay
"$(('FAILED to initiate', 'Successfully initiated')[$LASTEXITCODE -eq 0]) reboot on $env:COMPUTERNAME."
} | ForEach-Object { $progressbar1.PerformStep() }
Just like with your original code, execution on each target computer will return once the restart has been initiated, though execution will happen in parallel, and the responses received from the target computers are not guaranteed to be in input order.
If you wanted to verify and wait for successful restarts, more work would be needed.
Any errors are printed to the console in red and can later be examined in the $Error collection.
Note the primary purpose of "$(('FAILED to initiate', 'Successfully initiated')[$LASTEXITCODE -eq 0]) reboot on $env:COMPUTERNAME." is to unconditionally produce some (non-error) output on each computer, so that the ForEach-Object script block is invoked for each (shutdown produces no stdout output by default, and stderr output is not acted on by ForEach-Object).

Installing a windows service through powershell

I have a batch script which install a windows service and I want to convert it to a powershell script or command to do the same job.
I have been trying to use the New-Service cmdlet without much success
The batch script is given below:
cd %~dp0%
set SERVICE_NAME=ESL_SERVICE
IF %PROCESSOR_ARCHITECTURE% == x86 (
set PR_INSTALL=%~dp0prunsrv_32.exe
) ELSE (
set PR_INSTALL=%~dp0prunsrv_64.exe
)
echo $PR_INSTALL
set PR_DESCRIPTION=ESL-Server
set PR_DISPLAYNAME=%SERVICE_NAME%
set PR_STARTUP=auto
set PR_CLASSPATH=server.jar
set PR_JVMOPTIONS="-Xmx1024M"
set PR_STARTMODE=jvm
set PR_STARTCLASS=at.mrdevelopment.esl.server.Server
set PR_STARTMETHOD=main
set PR_STOPMODE=jvm
set PR_STOPCLASS=at.mrdevelopment.esl.server.ServerServiceStarter
set PR_STOPMETHOD=stop
IF %PROCESSOR_ARCHITECTURE% == x86 (
prunsrv_32.exe //IS//%SERVICE_NAME%
) ELSE (
prunsrv_64.exe //IS//%SERVICE_NAME%
)
This is what I have done so far..and the service gets installed but it does not start the sevice
$PR_CLASSPATH = "server.jar"
$PR_JVMOPTIONS = '"-Xmx1024M"'
$PR_STARTMODE = "jvm"
$PR_STARTCLASS = "at.mrdevelopment.esl.server.Server"
$PR_STARTMETHOD = "main"
$PR_STOPMODE = "jvm"
$PR_STOPCLASS = "at.mrdevelopment.esl.server.ServerServiceStarter"
$PR_STOPMETHOD = "stop"
New-Service -Name ESL_SERVICE -binaryPathName "C:\imagotag\server\prunsrv_64.exe //RS//ESL_SERVICE" -Description "ESL-Server" -DisplayName ESL_SERVICE -StartupType Auto
Are you missing the Start-Service command, after the New-Service -Name ESL_SERVICE -binaryPathName ... line?
Start-Service -Name ESL_SERVICE
New-Service only creates the service. The -StartupType Automatic will only start this after next reboot.
From Get-Help New-Service -full:
-StartupType Automatic: The service is to be started (or was started) by the operating system, at system start-up.
Thanks for the help guys but I finally managed to figure it out..using a different way
I managed to write the procrun service by using command line parameters instead of variables (the batch script used variables to run the procrun service) and now its installing and working fine.
.\prunsrv_64.exe //IS//ESL_SERVICE --Description ESL-Server --DisplayName ESL_SERVICE --Startup auto --Classpath server.jar ++JvmOptions '"-Xmx1024M"' --StartMode jvm --StartClass at.mrdevelopment.esl.server.Server --StartMethod main --StopMode jvm --StopClass at.mrdevelopment.esl.server.ServerServiceStarter --StopMethod stop --LogPath $LOG_PATH
Start-Service -Name ESL_SERVICE